---
title: "Querying a numeric series"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Querying a numeric series}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(discretes)
```

Once you have a numeric series, you can materialize it as a numeric vector, check which values are in it, count values in a range, and query limit points (sinks).
This vignette covers these query functions.

## Materializing values from a series

Materializing a series means producing its discrete values as an ordinary numeric vector.
There are three ways to do it.

### Traversing: `next_discrete()` and `prev_discrete()`

`next_discrete()` returns the next `n` discrete values in the series starting from a reference point;
`prev_discrete()` does the same in the opposite direction.
They return a numeric vector of values (of length at most `n`).

```{r}
x <- integers()
next_discrete(x, from = 10)
next_discrete(x, from = 10, n = 5, include_from = TRUE)
prev_discrete(x, from = 1.3, n = 5)
```

When `x` is a modified series, traversal is delegated to the underlying series, and the result is mapped back.

### Pulling values: `get_discretes_at()` and `get_discretes_in()`

Rather than traversing from a reference point, you can ask for values in a range or at specific values.

**`get_discretes_at()`** — Gets specified discrete values from the series, if they can be found in the series (within `tol` of the base series).

```{r}
get_discretes_at(integers(), values = c(-10, 4, 3.5, 10, NA))
get_discretes_at(integers(), values = 5.5)
```

**`get_discretes_in()`** — Gets all discrete values within a range. The result is ordered from smallest to largest.
If there are infinitely many discrete values in the range, `get_discretes_in()` throws an error; use `num_discretes()` first to check.

```{r}
get_discretes_in(integers(), from = 6.6, to = 10.1)
get_discretes_in(1 / integers(0, 5))
```

### Subsetting by position: `[`

When a series has a well-defined first element (e.g. `natural1()`), you can subset by position with `[`.

```{r}
natural1()[2]
natural1()[c(1, 3, 5)]
```

Unlike `dsct_keep()` and `dsct_drop()`, which return a _new series_, `[` materializes the series as a numeric vector.

The behaviour of subsetting is delegated to that of numeric vectors, so you can expect similar behaviour:

```{r}
x <- as_discretes(1:4)
x[-1]
x[c(0, NA, 1, 4, 1, 5)]
x[]
```

However, not some functionality available with numeric vectors is not supported for numeric _series_:

- Assignment via `[`, like `x[1:3] <- ...`
- Subsetting by name, like `x["foo"]`
- Subsetting by logical vector, like `x[x < 3]` (futher, comparisons like `x < 3` or `x == 3` do not result in a supported structure).

## Counting: `num_discretes()`

`num_discretes()` returns how many discrete values lie in a range.
It returns `Inf` for infinite-length series.

```{r}
num_discretes(integers(), from = -2, to = 5)
num_discretes(1 / 2^integers(), from = 0, to = 1)
```

## Which values are in the series?

Use `has_discretes()` to check whether given values are in the series.
It returns a logical vector, one per queried value.

```{r}
has_discretes(natural1(), c(0, 1, 2, 2.5))
has_discretes(integers(), c(-10, 0, 10, NA))
```

`NA` in the queried values yields `NA` in the result.

## Querying sinks

A **sink** is a limit point of a numeric series:
discrete values get arbitrarily close to it, and there are infinitely many discrete values near the sink.

`sinks()` lists all sinks in a matrix of locations and directions: approached from the left (-1) or right (+1).

```{r}
sinks(integers())
sinks(0.5^natural0())
reciprocals <- 1 / integers()
sinks(reciprocals)
```

`has_sink_in()` or `has_sink_at()` are convenience functions that test for a sink in an interval or at a value.

```{r}
has_sink_in(integers())
has_sink_at(integers(), Inf)
has_sink_at(integers(), -Inf, dir = "right")
```

For `has_sink_at()`, `dir` can be `"either"` (any direction), `"left"` or `"right"` (sink approached from that side), or `"both"` (approached from both sides). When a series has a sink, there is no “next” or “previous” discrete value on the far side of the sink (e.g. `next_discrete(reciprocals, from = -1)` returns nothing).

