-- SPDX-License-Identifier: MPL-2.0

{- | Constants with machine-readable provenance and uncertainty. Mathematical
decimal literals carry an absolute truncation bound of 10^-50; conversion to
Float/Double adds the target format's rounding error. Physical values are the
CODATA 2022 adjustment (NIST SRD 121), not an unversioned latest-value promise.
-}
module HMath.Constants (
    piConstant,
    eConstant,
    tau,
    goldenRatio,
    eulerMascheroni,
    catalanConstant,
    aperyConstant,
    sqrt2,
    sqrt3,
    ln2,
    ln10,
    infinity,
    nan,
    Constant (..),
    constantAs,
    mathematicalConstants,
    physicalConstants,
    speedOfLight,
    planckConstant,
    elementaryCharge,
    boltzmannConstant,
    avogadroConstant,
    gravitationalConstant,
    electronMass,
    astronomicalUnit,
    NumericLimits (..),
    numericLimits,
    integerLimits,
) where

import HMath.Numeric (NumericLimits (..), integerLimits, numericLimits)

piConstant
    , eConstant
    , tau
    , goldenRatio
    , eulerMascheroni
    , catalanConstant
    , aperyConstant
    , sqrt2
    , sqrt3
    , ln2
    , ln10 ::
        (Floating a) => a

{- | The circle constant pi at the target Floating precision. Example: piConstant :: Double.
For decimal provenance and an approximation bound, use mathematicalConstants.
-}
piConstant :: forall a. Floating a => a
piConstant = a
forall a. Floating a => a
pi

{- | Euler number exp(1) at the target Floating precision. Use mathematicalConstants for
rational decimal provenance.
-}
eConstant :: forall a. Floating a => a
eConstant = a -> a
forall a. Floating a => a -> a
exp a
1

-- | One full turn in radians, 2*pi, at target Floating precision.
tau :: forall a. Floating a => a
tau = a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
forall a. Floating a => a
pi

-- | Golden ratio (1+sqrt 5)/2 at the target Floating precision.
goldenRatio :: forall a. Floating a => a
goldenRatio = (a
1 a -> a -> a
forall a. Num a => a -> a -> a
+ a -> a
forall a. Floating a => a -> a
sqrt a
5) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2

{- | Euler-Mascheroni constant from the stored 50-decimal-place literal, rounded to the
chosen Floating type. Provenance is in mathematicalConstants.
-}
eulerMascheroni :: forall a. Floating a => a
eulerMascheroni = a
0.57721566490153286060651209008240243104215933593992

{- | Catalan constant from a 50-decimal-place literal, rounded to the target Floating type;
distinct from the integer Catalan-number sequence.
-}
catalanConstant :: forall a. Floating a => a
catalanConstant = a
0.91596559417721901505460351493238411077414937428167

{- | Apery constant zeta(3), from a 50-decimal-place literal rounded to the chosen Floating
type.
-}
aperyConstant :: forall a. Floating a => a
aperyConstant = a
1.20205690315959428539973816151144999076498629234049

-- | Positive square root of two in the target Floating type.
sqrt2 :: forall a. Floating a => a
sqrt2 = a -> a
forall a. Floating a => a -> a
sqrt a
2

-- | Positive square root of three in the target Floating type.
sqrt3 :: forall a. Floating a => a
sqrt3 = a -> a
forall a. Floating a => a -> a
sqrt a
3

-- | Natural logarithm of two in the target Floating type.
ln2 :: forall a. Floating a => a
ln2 = a -> a
forall a. Floating a => a -> a
log a
2

-- | Natural logarithm of ten in the target Floating type.
ln10 :: forall a. Floating a => a
ln10 = a -> a
forall a. Floating a => a -> a
log a
10

infinity, nan :: (RealFloat a) => a

{- | Positive IEEE infinity (1/0) for a RealFloat type. This value is intentionally
non-finite and is rejected by checked finite-input APIs.
-}
infinity :: forall a. RealFloat a => a
infinity = a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
0

{- | IEEE not-a-number (0/0) for a RealFloat type. NaN is not equal to itself; use isNaN to
inspect it.
-}
nan :: forall a. RealFloat a => a
nan = a
0 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
0

{- | Exact stored decimal Rational with name,unit,provenance,measurement uncertainty,and
separate approximation bound. constantAs converts the value without its metadata.
-}
data Constant = Constant
    { Constant -> String
constantName :: String
    -- ^ Human-readable name of this mathematical or physical constant.
    , Constant -> Rational
constantValue :: Rational
    -- ^ Exact Rational representation of the stored decimal value; measurement/approximation uncertainties are separate fields.
    , Constant -> Rational
standardUncertainty :: Rational
    -- ^ Absolute one-standard-deviation measurement uncertainty; zero for definitions.
    , Constant -> Rational
approximationBound :: Rational
    -- ^ Absolute decimal truncation bound, separate from measurement uncertainty.
    , Constant -> String
constantUnit :: String
    -- ^ Display unit string; mathematical dimensionless constants use 1.
    , Constant -> String
constantSource :: String
    -- ^ Provenance URL and adjustment/definition identifier for the stored value.
    }
    deriving (Constant -> Constant -> Bool
(Constant -> Constant -> Bool)
-> (Constant -> Constant -> Bool) -> Eq Constant
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Constant -> Constant -> Bool
== :: Constant -> Constant -> Bool
$c/= :: Constant -> Constant -> Bool
/= :: Constant -> Constant -> Bool
Eq, Int -> Constant -> ShowS
[Constant] -> ShowS
Constant -> String
(Int -> Constant -> ShowS)
-> (Constant -> String) -> ([Constant] -> ShowS) -> Show Constant
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Constant -> ShowS
showsPrec :: Int -> Constant -> ShowS
$cshow :: Constant -> String
show :: Constant -> String
$cshowList :: [Constant] -> ShowS
showList :: [Constant] -> ShowS
Show)

{- | Convert a Constant record's exact stored Rational decimal to the target Fractional
type. The result omits its uncertainty metadata; retain the record when reporting
measurements.
-}
constantAs :: (Fractional a) => Constant -> a
constantAs :: forall a. Fractional a => Constant -> a
constantAs = Rational -> a
forall a. Fractional a => Rational -> a
fromRational (Rational -> a) -> (Constant -> Rational) -> Constant -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Constant -> Rational
constantValue

{- | Catalog of mathematical constants with names, Rational decimal values, source URLs, and
absolute decimal truncation bounds of 10^-50. Measurement uncertainties are zero;
target Float/Double conversion adds rounding error.
-}
mathematicalConstants :: [Constant]
mathematicalConstants :: [Constant]
mathematicalConstants =
    [ String -> Rational -> String -> Constant
math String
"pi" Rational
3.14159265358979323846264338327950288419716939937510 String
"https://dlmf.nist.gov/4.19"
    , String -> Rational -> String -> Constant
math String
"e" Rational
2.71828182845904523536028747135266249775724709369995 String
"https://dlmf.nist.gov/4.2"
    , String -> Rational -> String -> Constant
math String
"tau" Rational
6.28318530717958647692528676655900576839433879875021 String
"https://dlmf.nist.gov/4.19"
    , String -> Rational -> String -> Constant
math
        String
"golden ratio"
        Rational
1.61803398874989484820458683436563811772030917980576
        String
"https://dlmf.nist.gov/3.10"
    , String -> Rational -> String -> Constant
math
        String
"Euler-Mascheroni"
        Rational
0.57721566490153286060651209008240243104215933593992
        String
"https://dlmf.nist.gov/5.2"
    , String -> Rational -> String -> Constant
math String
"Catalan" Rational
0.91596559417721901505460351493238411077414937428167 String
"https://dlmf.nist.gov/25.11"
    , String -> Rational -> String -> Constant
math String
"Apery" Rational
1.20205690315959428539973816151144999076498629234049 String
"https://dlmf.nist.gov/25.6"
    , String -> Rational -> String -> Constant
math String
"sqrt 2" Rational
1.41421356237309504880168872420969807856967187537694 String
"https://dlmf.nist.gov/4.2"
    , String -> Rational -> String -> Constant
math String
"sqrt 3" Rational
1.73205080756887729352744634150587236694280525381038 String
"https://dlmf.nist.gov/4.2"
    , String -> Rational -> String -> Constant
math String
"ln 2" Rational
0.69314718055994530941723212145817656807550013436025 String
"https://dlmf.nist.gov/4.2"
    , String -> Rational -> String -> Constant
math String
"ln 10" Rational
2.30258509299404568401799145468436420760110148862877 String
"https://dlmf.nist.gov/4.2"
    ]
  where
    math :: String -> Rational -> String -> Constant
math String
name Rational
value String
source = String
-> Rational -> Rational -> Rational -> String -> String -> Constant
Constant String
name Rational
value Rational
0 (Rational
1 Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
10 Rational -> Int -> Rational
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
50 :: Int)) String
"1" String
source

speedOfLight
    , planckConstant
    , elementaryCharge
    , boltzmannConstant
    , avogadroConstant
    , gravitationalConstant
    , electronMass
    , astronomicalUnit ::
        Constant

{- | Speed of light in vacuum: stored value 299792458 m s^-1, absolute standard uncertainty
0, from CODATA 2022. Returns a Constant metadata record; use constantAs for a numeric
conversion.
-}
speedOfLight :: Constant
speedOfLight = String -> Rational -> Rational -> String -> Constant
physical String
"speed of light in vacuum" Rational
299792458 Rational
0 String
"m s^-1"

{- | Planck constant: stored value 6.62607015e-34 J s, absolute standard uncertainty 0, from
CODATA 2022. Returns a Constant metadata record; use constantAs for a numeric
conversion.
-}
planckConstant :: Constant
planckConstant = String -> Rational -> Rational -> String -> Constant
physical String
"Planck constant" Rational
6.62607015e-34 Rational
0 String
"J s"

{- | Elementary charge: stored value 1.602176634e-19 C, absolute standard uncertainty 0,
from CODATA 2022. Returns a Constant metadata record; use constantAs for a numeric
conversion.
-}
elementaryCharge :: Constant
elementaryCharge = String -> Rational -> Rational -> String -> Constant
physical String
"elementary charge" Rational
1.602176634e-19 Rational
0 String
"C"

{- | Boltzmann constant: stored value 1.380649e-23 J K^-1, absolute standard uncertainty 0,
from CODATA 2022. Returns a Constant metadata record; use constantAs for a numeric
conversion.
-}
boltzmannConstant :: Constant
boltzmannConstant = String -> Rational -> Rational -> String -> Constant
physical String
"Boltzmann constant" Rational
1.380649e-23 Rational
0 String
"J K^-1"

{- | Avogadro constant: stored value 6.02214076e23 mol^-1, absolute standard uncertainty 0,
from CODATA 2022. Returns a Constant metadata record; use constantAs for a numeric
conversion.
-}
avogadroConstant :: Constant
avogadroConstant = String -> Rational -> Rational -> String -> Constant
physical String
"Avogadro constant" Rational
6.02214076e23 Rational
0 String
"mol^-1"

{- | Newtonian constant of gravitation: stored value 6.67430e-11 m^3 kg^-1 s^-2, absolute
standard uncertainty 0.00015e-11, from CODATA 2022. Returns a Constant metadata record;
use constantAs for a numeric conversion.
-}
gravitationalConstant :: Constant
gravitationalConstant = String -> Rational -> Rational -> String -> Constant
physical String
"Newtonian constant of gravitation" Rational
6.67430e-11 Rational
0.00015e-11 String
"m^3 kg^-1 s^-2"

{- | Electron mass: stored value 9.1093837139e-31 kg, absolute standard uncertainty
0.0000000028e-31, from CODATA 2022. Returns a Constant metadata record; use constantAs
for a numeric conversion.
-}
electronMass :: Constant
electronMass = String -> Rational -> Rational -> String -> Constant
physical String
"electron mass" Rational
9.1093837139e-31 Rational
0.0000000028e-31 String
"kg"

{- | IAU 2012 exact astronomical unit: 149597870700 metres, with zero measurement
uncertainty and approximation bound. Returns a Constant record with its source URL.
-}
astronomicalUnit :: Constant
astronomicalUnit =
    String
-> Rational -> Rational -> Rational -> String -> String -> Constant
Constant
        String
"astronomical unit"
        Rational
149597870700
        Rational
0
        Rational
0
        String
"m"
        String
"https://www.iau.org/static/resolutions/IAU2012_English.pdf (Resolution B2)"

physical :: String -> Rational -> Rational -> String -> Constant
physical :: String -> Rational -> Rational -> String -> Constant
physical String
name Rational
value Rational
uncertainty String
unit =
    String
-> Rational -> Rational -> Rational -> String -> String -> Constant
Constant
        String
name
        Rational
value
        Rational
uncertainty
        Rational
0
        String
unit
        String
"https://physics.nist.gov/cuu/Constants/Table/allascii.txt (CODATA 2022)"

{- | Catalog of supported physical constants, retaining unit, source, standard measurement
uncertainty, and approximation-bound metadata. Values use CODATA 2022 except the
IAU-defined astronomical unit.
-}
physicalConstants :: [Constant]
physicalConstants :: [Constant]
physicalConstants =
    [ Constant
speedOfLight
    , Constant
planckConstant
    , Constant
elementaryCharge
    , Constant
boltzmannConstant
    , Constant
avogadroConstant
    , Constant
gravitationalConstant
    , Constant
electronMass
    , Constant
astronomicalUnit
    ]