| Title: | Discrete Numeric Series |
|---|---|
| Description: | Provides a framework for representing discrete numeric series (enumerable sets of numbers) that may be finite or infinite. Series can be traversed, combined using arithmetic operations, tested for membership, and queried for limit points ("sinks"), without explicit enumeration of all elements. |
| Authors: | Vincenzo Coia [aut, cre, cph] |
| Maintainer: | Vincenzo Coia <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-05-31 07:45:11 UTC |
| Source: | https://github.com/vincenzocoia/discretes |
When a series has a well-defined "first" element (e.g. natural1() starts at
1), subsetting with [] materializes a specified part of the series, and
mirrors the behaviour of numeric vector subsetting.
Positive i returns the discrete values at those positions, and
negative i tries to return the full series with the specified positions
dropped.
## S3 method for class 'discretes' x[i] ## S3 replacement method for class 'discretes' x[i] <- value## S3 method for class 'discretes' x[i] ## S3 replacement method for class 'discretes' x[i] <- value
x |
A numeric series (object of class |
i |
Numeric vector of indices. Omit for the full series (finite only). |
value |
Replacement value; ignored, because replacement via |
Subsetting via [] tries to delegate to native behaviour on numeric vectors
as quickly as possible by first
materializing the series as a vector, and then conducting the subsetting.
If i is missing or has negative values, subsetting is delegated to the
full series materialized via get_discretes_in() (if possible).
If i is NULL or length-0, subsetting is delegated to a representative
value of the series.
If i doesn't have negative values, subsetting is delegated to the series
materialized as far out as needed to cover all is, via next_discrete()
from -Inf.
A vector of discrete values. When the series has no first element or
too few values for positive i, R returns NA as for ordinary vectors.
For negative i or missing i, the full series is obtained first;
infinite series behaviour defaults to that of get_discretes_in().
Unlike subsetting numeric vectors, the following actions are not supported:
Replacement via [<- (throws an error).
Subsetting by a character vector, as though subsetting by entry names.
Subsetting by a logical vector.
natural1()[2] natural1()[c(1, 3, 5)] integers(1, 5)[-1] # full series with first value dropped # Subsetting from the other side of a sink x <- 1 / natural1() x[1:3] # No such thing as a "first" value; returns NA. y <- dsct_union(x, -1) y[1:3] # "-1" is the 1st value, but no such thing as 2nd or 3rd value.natural1()[2] natural1()[c(1, 3, 5)] integers(1, 5)[-1] # full series with first value dropped # Subsetting from the other side of a sink x <- 1 / natural1() x[1:3] # No such thing as a "first" value; returns NA. y <- dsct_union(x, -1) y[1:3] # "-1" is the 1st value, but no such thing as 2nd or 3rd value.
Construct an arithmetic progression, with possibly infinite values.
The progression is anchored at representative and extends n_left steps
to the left (decreasing values) and n_right steps to the right
(increasing values) with constant spacing between consecutive terms.
arithmetic(representative, spacing, ..., n_left = Inf, n_right = Inf)arithmetic(representative, spacing, ..., n_left = Inf, n_right = Inf)
representative |
Numeric scalar giving a known term in the progression. |
spacing |
Non-negative numeric scalar describing the distance between adjacent terms. |
... |
Reserved for future extensions; must be empty. |
n_left, n_right
|
Non-negative counts (possibly |
A numeric series (class dsct_arithmetic, inheriting from
discretes).
While spacing can be zero, this results in a numeric series
containing only the representative value as its single discrete value.
The series can only contain -0 if the representative is set as such.
arithmetic(representative = -0.6, spacing = 0.7) arithmetic(representative = 0.6, spacing = 0.7, n_right = 0) arithmetic(representative = 0, spacing = 2, n_left = 2, n_right = 2) # Negative zero, resulting in `-Inf` upon inversion: has_negative_zero(arithmetic(-0, 1))arithmetic(representative = -0.6, spacing = 0.7) arithmetic(representative = 0.6, spacing = 0.7, n_right = 0) arithmetic(representative = 0, spacing = 2, n_left = 2, n_right = 2) # Negative zero, resulting in `-Inf` upon inversion: has_negative_zero(arithmetic(-0, 1))
Convert a foreign object to a "discretes" object.
as_discretes(x) ## S3 method for class 'discretes' as_discretes(x) ## S3 method for class 'numeric' as_discretes(x)as_discretes(x) ## S3 method for class 'discretes' as_discretes(x) ## S3 method for class 'numeric' as_discretes(x)
x |
Object to convert to object of class "discretes". |
A numeric series (object of class "discretes"). When x is
a numeric vector, the series contains all unique values of x.
as_discretes(discretes): Convert a numeric vector to discretes object.
as_discretes(numeric): Keeps the discretes object as-is.
as_discretes(0:10)as_discretes(0:10)
Return all discrete values in the numeric series, if finite. Throws an error if infinite.
## S3 method for class 'discretes' as.double(x, ...)## S3 method for class 'discretes' as.double(x, ...)
x |
Numeric series
( |
... |
Arguments to pass downstream to |
A numeric vector containing all discrete values in x,
ordered from smallest to largest. Returns numeric(0) when the interval
contains no discrete values. Numeric outputs are wrapped in as.numeric().
as.numeric(integers(-3.5, 10))as.numeric(integers(-3.5, 10))
Subset a numeric series
dsct_drop( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE ) dsct_keep( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE )dsct_drop( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE ) dsct_keep( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE )
x |
Numeric series
( |
from, to
|
Numeric values defining the range to keep; single numerics
with |
... |
Reserved for future extensions; must be empty. |
include_from, include_to
|
Logical values indicating whether the
|
A numeric series representing the subset of discrete values within the specified range.
x <- integers(from = -3) dsct_keep(x, from = -1.5, to = 2.5) dsct_keep(x, to = 2)x <- integers(from = -3) dsct_keep(x, from = -1.5, to = 2.5) dsct_keep(x, to = 2)
Apply a function that is strictly increasing or strictly decreasing to a numeric series.
dsct_transform(x, fun, ...) ## S3 method for class 'discretes' dsct_transform( x, fun, inv, ..., domain = c(-Inf, Inf), range = c(-Inf, Inf), dir = c("increasing", "decreasing") )dsct_transform(x, fun, ...) ## S3 method for class 'discretes' dsct_transform( x, fun, inv, ..., domain = c(-Inf, Inf), range = c(-Inf, Inf), dir = c("increasing", "decreasing") )
x |
Numeric series
( |
fun, inv
|
A vectorized, strictly monotonic function to apply to the
discrete values, and its inverse, |
... |
Arguments to pass to specific methods. |
domain, range
|
Numeric vectors of length 2, indicating the domain and
range of |
dir |
A string, either "increasing" or "decreasing", indicating the
monotonicity of the function |
Strictly increasing means that for any x1 < x2, it holds that
fun(x1) < fun(x2), for all values on the real line. The function -1/x,
for example, is not strictly increasing: its derivative is increasing,
but switches to smaller values after x = 0, therefore is not strictly
increasing. Strictly decreasing is the opposite, in that we have
fun(x1) > fun(x2).
If a decreasing function is provided, the transformation is negated internally first, and then transformed with fun(-x).
A numeric series with the transformation applied.
dsct_transform(integers(), fun = pnorm, inv = qnorm, range = c(0, 1)) dsct_transform( as_discretes(0:3), fun = cos, inv = acos, domain = c(0, pi), range = c(-1, 1), dir = "decreasing" ) # For numeric inputs, function is applied directly. # Other arguments beyond `fun` get absorbed in `...` and are not used. dsct_transform(0:5, exp) dsct_transform(0:5, exp, log)dsct_transform(integers(), fun = pnorm, inv = qnorm, range = c(0, 1)) dsct_transform( as_discretes(0:3), fun = cos, inv = acos, domain = c(0, pi), range = c(-1, 1), dir = "decreasing" ) # For numeric inputs, function is applied directly. # Other arguments beyond `fun` get absorbed in `...` and are not used. dsct_transform(0:5, exp) dsct_transform(0:5, exp, log)
Combine one or more numeric series (or numeric vectors interpreted as numeric series) into a single union, where each unique discrete value is counted once.
dsct_union(...)dsct_union(...)
... |
Objects to combine. Each must be either a numeric series or a numeric vector. |
Values are flattened
A numeric series (inheriting from dsct_union).
While both -0 and +0 can both exist,
x1 <- natural1() x2 <- -natural1() dsct_union(x1, x2)x1 <- natural1() x2 <- -natural1() dsct_union(x1, x2)
Create a numeric series with no discrete values.
empty_series(mode = c("double", "integer"))empty_series(mode = c("double", "integer"))
mode |
Character vector of length 1 indicating the numeric type of the numeric series; either "double" (the default) or "integer". |
An empty numeric series of the specified mode.
empty_series()empty_series()
Extract a finite subset of discrete values from a numeric series by asking
for specific values (get_discretes_at()) or by setting a range
(get_discretes_in()). For get_discretes_at(), each value in values is
checked against the series using tol (passed down to the underlying series);
if it is in the series, the corresponding discrete value is returned,
otherwise it is dropped. NA values are kept in place.
get_discretes_at(x, values, ..., tol = sqrt(.Machine$double.eps)) get_discretes_in( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE, tol = sqrt(.Machine$double.eps) )get_discretes_at(x, values, ..., tol = sqrt(.Machine$double.eps)) get_discretes_in( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE, tol = sqrt(.Machine$double.eps) )
x |
Numeric series
( |
values |
Numeric vector of values to pull from the numeric series |
... |
Reserved for future extensions; must be empty. |
tol |
Numerical tolerance when checking if a value is in the series.
Single non-negative numeric. See |
from, to
|
Reference values, possibly infinite. |
include_from, include_to
|
Should the |
A numeric vector containing all discrete values in the provided series x:
For get_discretes_in(), all discrete values between from and to,
ordered from smallest to largest.
For get_discretes_at(), the discrete values in the series that match the given
values. Whether a value is in the series is decided with tol at the underlying series,
returning the discrete values in the series rather than the supplied
values. Discrete values not within tol of the supplied values
are dropped.
An error will be thrown in get_discretes_in() if there are infinitely
many points in the range.
get_discretes_in(integers(), from = 6.6, to = 10.1) get_discretes_in(1 / arithmetic(1, 4, n_left = 3, n_right = 5)) get_discretes_at(integers(), values = c(-10, 4, 3.5, 10, NA)) get_discretes_at(integers(), values = 5.5)get_discretes_in(integers(), from = 6.6, to = 10.1) get_discretes_in(1 / arithmetic(1, 4, n_left = 3, n_right = 5)) get_discretes_at(integers(), values = c(-10, 4, 3.5, 10, NA)) get_discretes_at(integers(), values = 5.5)
Check which values are in a numeric series
has_discretes(x, values, ..., tol = sqrt(.Machine$double.eps))has_discretes(x, values, ..., tol = sqrt(.Machine$double.eps))
x |
Numeric series
( |
values |
A vector of values to check. |
... |
Reserved for future extensions; must be empty. |
tol |
Numerical tolerance when checking if a value is in the series.
Single non-negative numeric. See |
A logical vector indicating whether each value is in the numeric
series x. NA values are preserved such that NA in values results
in NA in the output.
This function does not distinguish between +0 and -0. For that,
use has_negative_zero() or has_positive_zero().
has_discretes(natural0(), c(-1, 0, 1, 12.5, NA)) has_discretes(1 / natural1(), 0)has_discretes(natural0(), c(-1, 0, 1, 12.5, NA)) has_discretes(1 / natural1(), 0)
Check if a numeric series contains zero with a negative sign (-0)
or a positive sign (+0). See details.
has_negative_zero(x) has_positive_zero(x)has_negative_zero(x) has_positive_zero(x)
x |
Numeric series
( |
While +0 and -0 are identical in R, they have a latent sign that
appears in reciprocals: 1 / +0 is Inf, while 1 / -0 is -Inf. The
has_negative_zero() and has_positive_zero() functions report whether
-0 and +0 are discrete values in the numeric series. Behaviour is
consistent with signed zero in numeric vectors.
A numeric series can contain both -0 and +0, like c(0, -0). Only one
zero is returned by next_discrete(), prev_discrete(), or
get_discretes_in(), as with unique(c(0, -0)). Their presence remains
latent and appears when the series is inverted, giving both Inf and
-Inf. See the examples.
A single logical: whether -0 is a discrete value in the series
for has_negative_zero(), and whether +0 is a discrete value for
has_positive_zero(). Both can be TRUE; see details.
has_negative_zero(integers()) has_positive_zero(integers()) # Integer 0 can never be negative, but double can: has_negative_zero(-integers()) has_negative_zero(-1.5 * integers()) # -0 and +0 can co-exist, but are never double counted. However, they # get expressed differently when the series is inverted. a <- c(0, -0) num_discretes(a) num_discretes(1 / a) b <- dsct_union(integers(from = -1, to = 1), -0) num_discretes(b) num_discretes(1 / b)has_negative_zero(integers()) has_positive_zero(integers()) # Integer 0 can never be negative, but double can: has_negative_zero(-integers()) has_negative_zero(-1.5 * integers()) # -0 and +0 can co-exist, but are never double counted. However, they # get expressed differently when the series is inverted. a <- c(0, -0) num_discretes(a) num_discretes(1 / a) b <- dsct_union(integers(from = -1, to = 1), -0) num_discretes(b) num_discretes(1 / b)
has_sink_in() tests whether a numeric series has a sink in the interval
[from, to]. has_sink_at() tests whether there is a sink at a
given value, optionally with a specific direction.
has_sink_in(x, from = -Inf, to = Inf) has_sink_at(x, value, dir = c("either", "left", "right", "both"))has_sink_in(x, from = -Inf, to = Inf) has_sink_at(x, value, dir = c("either", "left", "right", "both"))
x |
Numeric series
( |
from, to
|
Reference values, possibly infinite. |
value |
Single numeric to check for the existence of a sink. |
dir |
Single character: direction of the sink. |
A length-one logical: TRUE if a sink exists in the range
(has_sink_in) or at value with the given dir
(has_sink_at); FALSE otherwise.
See sinks() to get all sinks, and a description of sinks.
# The set of integers have sinks at +Inf and -Inf has_sink_in(integers()) has_sink_at(integers(), Inf) has_sink_at(integers(), -Inf, dir = "right") # The set 1, 1/2, 1/4, 1/8, ... has a sink at 0 approached from the right. halves <- 0.5^natural0() has_sink_in(halves, to = 0) has_sink_at(halves, 0, dir = "right") # Reciprocal of integers: sink at 0 from both sides reciprocals <- 1 / integers() has_sink_at(reciprocals, 0, dir = "both")# The set of integers have sinks at +Inf and -Inf has_sink_in(integers()) has_sink_at(integers(), Inf) has_sink_at(integers(), -Inf, dir = "right") # The set 1, 1/2, 1/4, 1/8, ... has a sink at 0 approached from the right. halves <- 0.5^natural0() has_sink_in(halves, to = 0) has_sink_at(halves, 0, dir = "right") # Reciprocal of integers: sink at 0 from both sides reciprocals <- 1 / integers() has_sink_at(reciprocals, 0, dir = "both")
Use integers() to create a numeric series whose discrete values are
integers within a specified range, possibly unbounded on either end. Use
natural0() and natural1() for the natural numbers starting at 0 or 1.
integers(from = -Inf, to = Inf) natural1() natural0()integers(from = -Inf, to = Inf) natural1() natural0()
from, to
|
Numeric values defining the range of integers.
Defaults to |
A numeric series (arithmetic, class "dsct_arithmetic")
whose discrete values are the integers in the specified range.
integers() # All integers integers(from = 0) # Non-negative integers integers(to = 1.5) # Ends at 1. integers(-5, 5) # Integers from -5 to 5. natural1() natural0() # Infinity is never contained in the series. has_discretes(integers(), Inf)integers() # All integers integers(from = 0) # Non-negative integers integers(to = 1.5) # Ends at 1. integers(-5, 5) # Integers from -5 to 5. natural1() natural0() # Infinity is never contained in the series. has_discretes(integers(), Inf)
Returns TRUE if an object inherits the class "discretes" or is a
numeric vector.
is_series(x)is_series(x)
x |
Object to check. |
TRUE if x is treated as a numeric series, FALSE otherwise.
is_series(natural0()) is_series(c(1, 2, 3)) is_series("not a numeric series")is_series(natural0()) is_series(c(1, 2, 3)) is_series("not a numeric series")
Support for exp, log, log10, log2, and sqrt on numeric series.
The new series behaves as though the function is applied to each discrete
value in the series.
## S3 method for class 'discretes' Math(x, ...)## S3 method for class 'discretes' Math(x, ...)
x |
Numeric series
( |
... |
Passed to |
A numeric series with the math function applied.
exp(integers(from = 0, to = 3)) log(natural1()) sqrt(integers(from = 0, to = 10))exp(integers(from = 0, to = 3)) log(natural1()) sqrt(integers(from = 0, to = 10))
next_discrete() and prev_discrete() find the n discrete values
in a numeric series next to a reference point. num_discretes() finds
the number of discrete values within a range.
next_discrete( x, from, ..., n = 1L, include_from = FALSE, tol = sqrt(.Machine$double.eps) ) prev_discrete( x, from, ..., n = 1L, include_from = FALSE, tol = sqrt(.Machine$double.eps) )next_discrete( x, from, ..., n = 1L, include_from = FALSE, tol = sqrt(.Machine$double.eps) ) prev_discrete( x, from, ..., n = 1L, include_from = FALSE, tol = sqrt(.Machine$double.eps) )
x |
Numeric series
( |
from |
Reference value to start searching from; single numeric. |
... |
Reserved for future extensions; must be empty. |
n |
Number of discrete values to find; single positive integer. |
include_from |
Should the |
tol |
Numerical tolerance when checking if a value is in the series.
Single non-negative numeric. See |
For a transformed or combined series (e.g. 1 / integers()), traversal is
delegated to the base series, and tol is passed through to those calls.
This means that tol is only realized on the underlying series:
Numeric vector (or as_discretes(...)): a value is a member if it is
within tol of a stored value.
Arithmetic series: the implied step index (distance from the
representative in steps) is treated as an integer if it is within tol
of an integer.
See the Tolerance vignette for examples.
A vector of sequential points starting from from, which is
included in the vector if it is a discrete value in the numeric series and
include_from = TRUE. The length of the vector is at most n, and
will return an empty numeric vector if there is no such discrete
value. next_discrete() is increasing, while prev_discrete() is
decreasing, so that earlier values are encountered sooner.
x <- integers(from = 2) next_discrete(x, from = 1.3) prev_discrete(x, from = 4, n = 10) next_discrete(x - 0.7, from = 1.3, n = 4)x <- integers(from = 2) next_discrete(x, from = 1.3) prev_discrete(x, from = 4, n = 10) next_discrete(x - 0.7, from = 1.3, n = 4)
Return the number of discrete values in x that lie between
from and to, or test whether the number of discrete values is infinite.
num_discretes( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE, tol = sqrt(.Machine$double.eps) )num_discretes( x, from = -Inf, to = Inf, ..., include_from = TRUE, include_to = TRUE, tol = sqrt(.Machine$double.eps) )
x |
Numeric series
( |
from, to
|
Reference values, possibly infinite. |
... |
Reserved for future extensions; must be empty. |
include_from, include_to
|
Should the |
tol |
Numerical tolerance when checking if a value is in the series.
Single non-negative numeric. See |
For num_discretes(),
a single non-negative integer, or possibly Inf for infinitely many
discrete values.
num_discretes(-3:3) num_discretes(c(0.4, 0.4, 0.4, 0)) x <- arithmetic(-3.2, spacing = 0.5) num_discretes(x) num_discretes(x, from = -2, to = 2) num_discretes(1 / x, from = -2, to = 2)num_discretes(-3:3) num_discretes(c(0.4, 0.4, 0.4, 0)) x <- arithmetic(-3.2, spacing = 0.5) num_discretes(x) num_discretes(x, from = -2, to = 2) num_discretes(1 / x, from = -2, to = 2)
Support for +, -, *, /, and ^ between a numeric series and a
single number. One operand must be a numeric series and the other a number.
## S3 method for class 'discretes' Ops(e1, e2)## S3 method for class 'discretes' Ops(e1, e2)
e1, e2
|
Operands; one must be a numeric series (class |
A numeric series resulting from the operation (e.g. series + number, number * series, series^number).
integers() + 1 2 * natural1() 1 / integers(from = 1, to = 5) natural0()^2integers() + 1 2 * natural1() 1 / integers(from = 1, to = 5) natural0()^2
Plot the discrete values in a numeric series within a specified interval.
## S3 method for class 'discretes' plot( x, from = -Inf, to = Inf, ..., closeness = 0.01, tol = sqrt(.Machine$double.eps) )## S3 method for class 'discretes' plot( x, from = -Inf, to = Inf, ..., closeness = 0.01, tol = sqrt(.Machine$double.eps) )
x |
Numeric series
( |
from, to
|
Numeric values defining the range to plot; single numerics. |
... |
Additional arguments passed to the underlying |
closeness |
Numeric value indicating how close to the (non-infinite) sinks the points should no longer be plotted. This is because there are an infinite number of points around each sink. |
tol |
Passed to |
Sinks at finite values are indicated by vertical dotted gray lines. A red tick mark is used to indicate that a finite sink value is part of the series.
When the series extends to infinity in either direction, three arrows
(< or >) are drawn to indicate this. When infinity is part of the series,
the last arrow is red.
This is a simple plotting scheme with naive handling of infinite discrete values:
The closeness parameter does not adjust with the scale of the data, so
may require tuning more often by the user.
When the series extends to infinity (in either direction), an arbitrary
cutoff of 10 units beyond the last finite sink or representative()
value (whichever is closer to the infinite sink) is used. This can be
manually adjusted by changing the from and to parameters.
Invisibly returns the input x object after printing a plot
in Base R.
If this function takes a long time to plot, it's likely because
your series has
slowly varying
behaviour next to a sink,
like 1 / natural1(), where discrete values pile up rapidly
while approaching the sink very slowly. To avoid so many points from
being plotted, increase the closeness argument.
plot(integers()) plot(integers(), from = -50, to = 50) plot(0.5^natural1(), closeness = 1e-3) plot(dsct_union(0.5^natural1(), 0), closeness = 1e-3)plot(integers()) plot(integers(), from = -50, to = 50) plot(0.5^natural1(), closeness = 1e-3) plot(dsct_union(0.5^natural1(), 0), closeness = 1e-3)
Print a numeric series to the console.
## S3 method for class 'discretes' print(x, len = 6, ...)## S3 method for class 'discretes' print(x, len = 6, ...)
x |
Numeric series
( |
len |
Number of discrete values to display. |
... |
Further arguments to pass to downstream methods; currently not used. |
Invisibly returns the input object x.
print(integers()) print(1 / natural1()) print(-1 / natural1()) print(1 / integers()) print(1 / integers(), len = 1) print(1 / integers(), len = 0)print(integers()) print(1 / natural1()) print(-1 / natural1()) print(1 / integers()) print(1 / integers(), len = 1) print(1 / integers(), len = 0)
Get a representative discrete value in a numeric series
representative(x)representative(x)
x |
Numeric series
( |
A single numeric: a representative discrete value from the numeric series, with the proper mode.
representative(integers()) representative(natural1() + 7)representative(integers()) representative(natural1() + 7)
Sinks are limit points in a numeric series. That means that discrete values get arbitrarily close to the sink (from the left or right), and there are infinitely many discrete values around the sink. This function returns a matrix of all sinks in the numeric series.
sinks(x)sinks(x)
x |
Numeric series
( |
A matrix with two columns: location and direction. Each row
corresponds to a sink, where location is the location of the sink
(possibly infinite), and direction indicates whether the sink is
approached from the left (-1) or right (1).
# The set of integers have sinks at +Inf and -Inf sinks(integers()) # The set 1, 1/2, 1/4, 1/8, ... has a sink at 0 approached from the right. halves <- 0.5^natural0() sinks(halves) # The reciprocal of the integers has a sink at 0 approached from both the # left and right; while the integer 0 gets mapped to Inf, infinity is not a # sink because discrete values don't get arbitrarily close to it. reciprocals <- 1 / integers() sinks(reciprocals) has_discretes(reciprocals, Inf) # Yet Inf is a discrete value.# The set of integers have sinks at +Inf and -Inf sinks(integers()) # The set 1, 1/2, 1/4, 1/8, ... has a sink at 0 approached from the right. halves <- 0.5^natural0() sinks(halves) # The reciprocal of the integers has a sink at 0 approached from both the # left and right; while the integer 0 gets mapped to Inf, infinity is not a # sink because discrete values don't get arbitrarily close to it. reciprocals <- 1 / integers() sinks(reciprocals) has_discretes(reciprocals, Inf) # Yet Inf is a discrete value.