# `Feel.Analysis.Images.Number.Preimage`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/analysis/images/number/preimage.ex#L1)

The numbers an argument of a number built-in can be when the result is in a set (D-161, step C).

`Feel.Analysis.Images.Number` goes from the argument to the result. This goes back, for `abs(x) < 100`: the comparison
says the result is in `[-max..100)` (`Feel.Analysis.TestSets`), so `x` is in `(-100..100)`. Given the set that the
result is in, `operand/3` gives the set that the argument has to be in for the call to give a number in it: every
number the run gives such a result for is in it, and so is a few more where the rounding of the run is in the way.
`Feel.Analysis.Narrowing` reads a comparison of a call with it, as it reads the comparison of an operation with
`Feel.Analysis.Preimage`.

| Function | The argument | Exact? |
| -------- | ------------ | ------ |
| `abs` | the results and their negatives (for the two kinds of duration too) | yes |
| `floor`, `ceiling`, `round *`, `decimal` at a scale | the numbers between the steps next to the results that are multiples of the step | yes |
| `modulo` by a number | the numbers of the argument's own set that are a remainder of the results away from a multiple of the divisor (`modulo_within/3`) | yes |
| `sqrt`, `exp`, `log` | the numbers that give a result in the set, found from the inverse of the function and the run | the ends of a result that the comparison has, and not the ends that it has not (below) |

**The rounding functions** are step functions of `x * 10^scale`, increasing by one at a time, so a set of results is a
set of steps (`m * 10^-scale` for the whole numbers `m` of it), and the numbers that give them are the numbers from the
start of the first step to the end of the last: `floor(x) = 3` is `[3..4)`, `round half up(x) = 3` is `[2.5..3.5)`, and
`round up(x) = 3` is `(2..3]`. A result that is not a multiple of the step is given by no number, and the set is empty.

**The roots, the logarithm and the exponential** are increasing, and the run rounds their value to 34 digits, to the
nearest. The end of a result that is not in the set (`sqrt(x) > 3`, `sqrt(x) < 10`) is exact: the rounding keeps the
order, and a bound of 34 digits is not changed by it, so a number that gives a result above 3 has a root above 3, which is
`x > 9`. The end that is in (`>=`, `<=`, `=`) is one that the value can be half a unit of its last digit short of, and still
be rounded to, so it is looked for from there in: the inverse of the function (`ln` for the exponential, `exp` for the
logarithm, from the run, with a unit of the last digit either way to hold the true value) gives a number a unit of the last
digit out, and the run itself brings it in to the first number that gives a result in the set, in at most 24 numbers; where
it does not come to one, the number from the inverse stays, which is a larger set. So `sqrt(x) >= 10` is `[100..max]`,
`sqrt(x) >= 3` is `[8.999999999999999999999999999999998..max]` (the first number whose root the run rounds to 3), and
`sqrt(x) <= 10` is `[0..100.0000000000000000000000000000001]`, since that is a number whose root rounds to 10.

An end of the argument is where the run has no result any more: `exp(x)` is a number up to `Real.exp_range/0`'s `high`, so
`exp(x) > 1` is `(0..14149.38539644841072829055748903541]`.

# `modulo_within`

```elixir
@spec modulo_within(Feel.Type.NumberSet.t(), Decimal.t(), Feel.Type.NumberSet.t()) ::
  Feel.Type.NumberSet.t()
```

The numbers of a set that give a remainder in the results when divided by a number, for a divisor that is one number: the
numbers of the set that are a remainder of the results away from a multiple of the divisor, `modulo(x, 7) = 3` being the 3,
10, 17 ... of it. The set of the argument is needed since the numbers are many, as many as the multiples of the divisor there
are; a set with more than a few of them is returned as it is.

    iex> alias Feel.Type.NumberSet
    iex> alias Feel.Analysis.Images.Number.Preimage
    iex> to_20 = NumberSet.interval(Decimal.new(0), Decimal.new(20))
    iex> Preimage.modulo_within(to_20, Decimal.new(7), NumberSet.point(Decimal.new(3))) |> NumberSet.format()
    "3, 10, 17"
    iex> Preimage.modulo_within(to_20, Decimal.new(-7), NumberSet.point(Decimal.new(-3))) |> NumberSet.format()
    "4, 11, 18"
    iex> results = NumberSet.interval(Decimal.new(0), {Decimal.new(2), :open})
    iex> Preimage.modulo_within(to_20, Decimal.new(7), results) |> NumberSet.format()
    "[0..2), [7..9), [14..16)"

# `names`

```elixir
@spec names() :: [String.t()]
```

The functions that have a preimage.

# `neighbor`

```elixir
@spec neighbor(Decimal.t(), :up | :down) :: Decimal.t()
```

The number of 34 digits next to a number, above or below it.

    iex> alias Feel.Analysis.Images.Number.Preimage
    iex> Preimage.neighbor(Decimal.new(100), :up) |> Decimal.to_string(:normal)
    "100.0000000000000000000000000000001"
    iex> Preimage.neighbor(Decimal.new(100), :down) |> Decimal.to_string(:normal)
    "99.99999999999999999999999999999999"

# `operand`

```elixir
@spec operand(String.t(), integer() | nil, Feel.Type.NumberSet.t()) ::
  {:ok, Feel.Type.NumberSet.t()} | :error
```

The numbers an argument can be for the call `name(argument)` (`name(argument, scale)` for a rounding function, with the
scale that `scale/1` gives) to give a result in the set, or `:error` for a function and a scale it has no preimage for.

    iex> alias Feel.Type.NumberSet
    iex> alias Feel.Analysis.Images.Number.Preimage
    iex> lt_100 = NumberSet.interval(Decimal.negate(NumberSet.max_value()), {Decimal.new(100), :open})
    iex> {:ok, set} = Preimage.operand("abs", nil, lt_100)
    iex> NumberSet.format(set)
    "(-100..100)"
    iex> {:ok, set} = Preimage.operand("floor", 0, NumberSet.point(Decimal.new(3)))
    iex> NumberSet.format(set)
    "[3..4)"
    iex> {:ok, set} = Preimage.operand("sqrt", nil, lt_100)
    iex> NumberSet.format(set)
    "[0..10000)"

# `scale`

```elixir
@spec scale(Decimal.t()) :: {:ok, integer()} | :error
```

The scale of a call of a rounding function, as the run takes it (a whole number in `-6111..6176`, the fraction cut off), for
the number the scale is, or `:error` if the scale is out of range (the call is `null`).

    iex> Feel.Analysis.Images.Number.Preimage.scale(Decimal.new("2.9"))
    {:ok, 2}
    iex> Feel.Analysis.Images.Number.Preimage.scale(Decimal.new(6177))
    :error

---

*Consult [api-reference.md](api-reference.md) for complete listing*
