-- | Functions often used to design fields.
module Numerics.Functions (
    -- * Ramps
    --
    -- | Ramps vary from 0 to 1 over their ramping interval.
      logisticRamp
    , smoothstep

    -- * Falloffs and bumps
    --
    -- | Falloffs are bounded functions with \(f(0)=1\) that asymptotically
    --   reach 0. Bumps are falloffs that reach 0 in finite distance.
    , gaussianFalloff
    , logisticFalloff
    , cauchyFalloff
    , smoothBump
) where



import Data.Ord.Extended
import Numerics.Interpolation



-- | Logistic sigmoid function, varying smoothly from 0 to 1 along the real axis.
--
-- Solution to the logistic equation \(y'(x) = -\frac1\beta y(x) \left(1-y(x)\right)\) shifted by \(\mu\).
--
-- \[
-- f_{\mu,\beta}(x) = \frac{1}{1+\exp\left(-\frac{x-\mu}\beta\right)}
-- \]
logisticRamp
    :: Double -- ^ Center \(\mu\)
    -> Double -- ^ Wideness \(\beta\) of the transition. Higher is wider.
    -> Double
    -> Double
logisticRamp :: Double -> Double -> Double -> Double
logisticRamp Double
center Double
beta Double
x = Double
1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/(Double
1Double -> Double -> Double
forall a. Num a => a -> a -> a
+Double -> Double
forall a. Floating a => a -> a
exp(-(Double
xDouble -> Double -> Double
forall a. Num a => a -> a -> a
-Double
center)Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
beta))

-- | Smoothstep function, varying symmetrically from 0 to 1 between its parameters.
-- It should be called smoothstepRamp to follow this module’s nomenclature, but the
-- name /smoothstep/ is very much standard.
--
-- https://en.wikipedia.org/wiki/Smoothstep
smoothstep
    :: Double -- ^ Start ramping here
    -> Double -- ^ Finish ramping here
    -> Double
    -> Double
smoothstep :: Double -> Double -> Double -> Double
smoothstep Double
lo Double
hi =
    let smoothstep01 :: a -> a
smoothstep01 a
x = a
xa -> a -> a
forall a. Num a => a -> a -> a
*a
xa -> a -> a
forall a. Num a => a -> a -> a
*a
xa -> a -> a
forall a. Num a => a -> a -> a
*(a
xa -> a -> a
forall a. Num a => a -> a -> a
*(a
xa -> a -> a
forall a. Num a => a -> a -> a
*a
6a -> a -> a
forall a. Num a => a -> a -> a
-a
15)a -> a -> a
forall a. Num a => a -> a -> a
+a
10)
    in Double -> Double
forall {a}. Num a => a -> a
smoothstep01 (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double, Double) -> (Double, Double) -> Double -> Double
forall vec.
VectorSpace vec =>
(Double, Double) -> (vec, vec) -> Double -> vec
lerp (Double
lo, Double
hi) (Double
0, Double
1) (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double, Double) -> Double -> Double
forall a. Ord a => (a, a) -> a -> a
clamp (Double
lo,Double
hi)

-- | Smooth bump function: nonzero between -1 and 1, smooth over all of \(\mathbb R\).
--
-- \[
-- f(x) =
-- \begin{cases}
--     \exp \left(-{\frac1{1-x^2}}\right) & x \in (-1,1) \\
--     0                                  & \text{otherwise}
-- \end{cases}
-- \]
smoothBump :: Double -> Double
smoothBump :: Double -> Double
smoothBump Double
x
    | -Double
1 Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
x Bool -> Bool -> Bool
&& Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
1 = Double -> Double
forall a. Floating a => a -> a
exp(-Double
1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/(Double
1Double -> Double -> Double
forall a. Num a => a -> a -> a
-Double
xDouble -> Integer -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^Integer
2))
    | Bool
otherwise = Double
0

-- | Gaussian falloff. Equivalent to the Gaussian distribution, but normalized to
-- \(f(\mu)=1\), \(\int = \sigma\sqrt{2\pi}\).
--
-- \[
-- f_{\mu,\sigma}(x) = \exp\left(-\frac12\left(\frac{x-\mu}\sigma\right)^2\right)
-- \]
gaussianFalloff
    :: Double -- ^ Mean \(\mu\)
    -> Double -- ^ Standard deviation \(\sigma\)
    -> Double
    -> Double
gaussianFalloff :: Double -> Double -> Double -> Double
gaussianFalloff Double
mu Double
sigma Double
x = Double -> Double
forall a. Floating a => a -> a
exp (-Double
1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
2Double -> Double -> Double
forall a. Num a => a -> a -> a
*((Double
xDouble -> Double -> Double
forall a. Num a => a -> a -> a
-Double
mu)Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
sigma)Double -> Integer -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^Integer
2)

-- | Logistic distribution, normalized to normalized to \(f(\mu)=1\), \(\int =
-- \beta\). Compared to a Gaussian falloff, this has a heavier tail (higher
-- kurtosis).
--
-- \[
-- f_{\mu,\beta}(x) = \frac{\exp\left(-\frac{x-\mu}\beta\right)}{\left(1+\exp\left(-\frac{x-\mu}\beta\right)\right)^2}
-- \]
logisticFalloff
    :: Double -- ^ Center \(\mu\)
    -> Double -- ^ Falloff parameter \(\beta\)
    -> Double
    -> Double
logisticFalloff :: Double -> Double -> Double -> Double
logisticFalloff Double
center Double
beta Double
x =
    let expTerm :: Double
expTerm = Double -> Double
forall a. Floating a => a -> a
exp (-(Double
xDouble -> Double -> Double
forall a. Num a => a -> a -> a
-Double
center)Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
beta)
    in Double
expTerm Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
expTerm)Double -> Integer -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^Integer
2

-- | Cauchy falloff. This is a much gentler (quadratic) falloff than Gaussian
-- (exponential). Normalized to \(f(\mu)=1\), \(\int = \pi\gamma\). Its falloff is
-- in fact so slow that it does not have a standard deviation (or any higher
-- moments, for that matter).
--
-- \[
-- f_{\mu,\gamma}(x) = \frac1{1 + \left(\frac{x-\mu}\gamma\right)^2}
-- \]
cauchyFalloff
    :: Double -- ^ Mean \(\mu\)
    -> Double -- ^ Falloff parameter \(\gamma\)
    -> Double
    -> Double
cauchyFalloff :: Double -> Double -> Double -> Double
cauchyFalloff Double
mu Double
gamma Double
x = Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ ((Double
xDouble -> Double -> Double
forall a. Num a => a -> a -> a
-Double
mu)Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
gamma)Double -> Integer -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^Integer
2)