# Adaptive Sampling of Function Values for Plotting

## Situations to Handle

- Regions near singularities where the value changes sharply (e.g. singularities of the Gamma function).
- Edges of the domain (e.g. the edges of `asin`, `acos`).
- Regions of rapid oscillation (e.g. functions like `sin(1/x)`).
- Regions with a jump discontinuity (e.g. the `floor` function).

The basic approach is to sample at a fixed resolution in `x` first,
then insert additional points between samples as needed to satisfy the required accuracy.

## Criteria for Adding a Point Between Two Samples

- The change in coordinates between two adjacent points is large.
  - A threshold is set on the change in the `y` coordinate.
    - The threshold is a value relative to the range of `y` shown in the plot.
- The change across three consecutive points is large.
  - The slope between each pair of adjacent points is computed, and a threshold is set on the change in slope.
    - The threshold is specified relative to the plot area: the slope is computed as the ratio of the change in `y` to the change in `x`, each normalized by the plot area.
- A point inside the plot range is adjacent to a point that is `inf` or `nan`.
  - Without an inserted point, the line would be cut off instead of connecting to the edge of the plot.

## Criteria for Not Adding a Point

- Both of two adjacent points are outside the plot range, or are `inf` or `nan`.
  - If only one of the two is inside the range, a point is still added (see above).
- The `x` distance between two adjacent points is already too small.
  - This prevents an infinite loop of repeatedly subdividing around a singularity.
    - This threshold is set relative to the range of `x`.
  - A lower bound is set on this threshold to limit the number of recursions (roughly 1/1000 of the size of the domain).
  - Whether to connect the two points with a line when this threshold is reached needs further consideration:
    - When the change in `y` is large, the function is likely piecewise, so the points should not be connected with a line (this is handled in the plotting step).
      However, this resulted in discontinuities of the line in many cases where the function is actually continuous, so not implemented for now.
- The total number of points becomes too large.
  - Even after applying the criteria above, a maximum point count is set as a last resort to give up further subdivision.
    - A feature to warn the user when this limit is reached would be useful.

## Constraints

- A spike within an extremely narrow range cannot be handled reliably.
  - Handling this in general would require prior knowledge of the function, so instead the number of initial samples is made tunable, leaving the trade-off to the user.

## Requirements for the Algorithm

- Keep processing time low.
  - Repeatedly inserting points into the middle of a `vector` that already holds many elements is slow.
    Therefore, the initial sampling is kept in a separate `vector` from the final `vector` that includes the inserted points,
    to reduce the amount of copying within a `vector`.
