{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}

-- SPDX-License-Identifier: MPL-2.0

{- | Small law-oriented numeric interfaces. Ring operations obey the usual
associative/distributive laws for exact instances; IEEE instances approximate
them and retain ordinary rounding/overflow. Field inversion is checked.
Instances are open, so custom exact domains can use the same generic Horner
and inner-product algorithms without pretending to be RealFloat.
-}
module HMath.API.Algebra (
    Ring (..),
    Field (..),
    Scalar (..),
    FloatingPoint (..),
    Numeric (..),
    MatrixLike (..),
    TensorLike (..),
    VectorSpace (..),
    Differentiable (..),
    horner,
    innerProduct,
    Exact (..),
) where

import Data.Complex (Complex ((:+)), conjugate, imagPart, realPart)
import qualified Data.Ratio as R
import qualified HMath.Autodiff as AD
import HMath.Error
import qualified HMath.Matrix as M
import qualified HMath.Tensor as T
import qualified HMath.Vector as V

{- | Implement zero, one, additive inverse, addition, multiplication and integer
embedding. No ordering or approximate division is imposed on exact rings.
-}
class (Eq a) => Ring a where
    -- | Additive identity of this ring.
    zero :: a

    -- | Multiplicative identity of this ring.
    one :: a

    -- | Add two ring elements; exact instances obey ring laws and IEEE instances retain host rounding.
    plus :: a -> a -> a

    -- | Multiply two ring elements using the instance arithmetic.
    times :: a -> a -> a

    -- | Return the additive inverse of a ring element.
    negative :: a -> a

    -- | Embed an unbounded Integer into the domain; instance representation/rounding rules apply.
    integer :: Integer -> a

{- | Ring supporting checked multiplicative inversion. Invalid zero/domain or
unrepresentable inverse returns MathError.
-}
class (Ring a) => Field a where
    -- | Return multiplicative inverse of a nonzero domain element, or Left MathError for zero/invalid/nonrepresentable inverse.
    invert :: a -> Either MathError a

-- | Ring with conjugation,used by Hermitian inner-product algorithms.
class (Ring a) => Scalar a where
    -- | Return scalar conjugate; real/exact instances use identity and complex instances conjugate imaginary components.
    conjugateScalar :: a -> a

{- | Scalar domain exposing precision epsilon and finite-value classification,including
complex component checks.
-}
class (Scalar a) => FloatingPoint a where
    -- | Given a type proxy, return floating precision epsilon as Double (2^-52 for Double,2^-23 for Float).
    machineEpsilon :: proxy a -> Double

    -- | Test whether all real/complex components are finite for this instance.
    finiteScalar :: a -> Bool

{- | A numeric domain's conversion from a rational may fail, for example when
an exact ring cannot represent a non-integral value.
-}
class (Ring a) => Numeric a where
    -- | Convert exact Rational into the domain, returning Left MathError if it cannot be represented under the instance contract.
    rational :: Rational -> Either MathError a

instance Ring Integer where
    zero :: Integer
zero = Integer
0
    one :: Integer
one = Integer
1
    plus :: Integer -> Integer -> Integer
plus = Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
(+)
    times :: Integer -> Integer -> Integer
times = Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
(*)
    negative :: Integer -> Integer
negative = Integer -> Integer
forall a. Num a => a -> a
negate
    integer :: Integer -> Integer
integer = Integer -> Integer
forall a. a -> a
id
instance Scalar Integer where conjugateScalar :: Integer -> Integer
conjugateScalar = Integer -> Integer
forall a. a -> a
id
instance Numeric Integer where
    rational :: Rational -> Either MathError Integer
rational Rational
q
        | Rational -> Integer
forall a. Ratio a -> a
R.denominator Rational
q Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1 = Integer -> Either MathError Integer
forall a b. b -> Either a b
Right (Rational -> Integer
forall a. Ratio a -> a
R.numerator Rational
q)
        | Bool
otherwise = MathError -> Either MathError Integer
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"Integer cannot represent a non-integral rational")
instance Ring Rational where
    zero :: Rational
zero = Rational
0
    one :: Rational
one = Rational
1
    plus :: Rational -> Rational -> Rational
plus = Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
(+)
    times :: Rational -> Rational -> Rational
times = Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
(*)
    negative :: Rational -> Rational
negative = Rational -> Rational
forall a. Num a => a -> a
negate
    integer :: Integer -> Rational
integer = Integer -> Rational
forall a. Num a => Integer -> a
fromInteger
instance Field Rational where
    invert :: Rational -> Either MathError Rational
invert Rational
x
        | Rational
x Rational -> Rational -> Bool
forall a. Eq a => a -> a -> Bool
== Rational
0 = MathError -> Either MathError Rational
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"field inverse of zero")
        | Bool
otherwise = Rational -> Either MathError Rational
forall a b. b -> Either a b
Right (Rational -> Rational
forall a. Fractional a => a -> a
recip Rational
x)
instance Scalar Rational where conjugateScalar :: Rational -> Rational
conjugateScalar = Rational -> Rational
forall a. a -> a
id
instance Numeric Rational where rational :: Rational -> Either MathError Rational
rational = Rational -> Either MathError Rational
forall a b. b -> Either a b
Right
instance Ring Double where
    zero :: Double
zero = Double
0
    one :: Double
one = Double
1
    plus :: Double -> Double -> Double
plus = Double -> Double -> Double
forall a. Num a => a -> a -> a
(+)
    times :: Double -> Double -> Double
times = Double -> Double -> Double
forall a. Num a => a -> a -> a
(*)
    negative :: Double -> Double
negative = Double -> Double
forall a. Num a => a -> a
negate
    integer :: Integer -> Double
integer = Integer -> Double
forall a. Num a => Integer -> a
fromInteger
instance Field Double where
    invert :: Double -> Either MathError Double
invert Double
x
        | Double
x Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 Bool -> Bool -> Bool
|| Bool -> Bool
not (Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Double
x) = MathError -> Either MathError Double
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"finite nonzero field inverse required")
        | Bool
otherwise = let y :: Double
y = Double -> Double
forall a. Fractional a => a -> a
recip Double
x in if Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Double
y then Double -> Either MathError Double
forall a b. b -> Either a b
Right Double
y else MathError -> Either MathError Double
forall a b. a -> Either a b
Left MathError
NonFiniteResult
instance Scalar Double where conjugateScalar :: Double -> Double
conjugateScalar = Double -> Double
forall a. a -> a
id
instance FloatingPoint Double where
    machineEpsilon :: forall (proxy :: * -> *). proxy Double -> Double
machineEpsilon proxy Double
_ = Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (-Double
52)
    finiteScalar :: Double -> Bool
finiteScalar Double
x = Bool -> Bool
not (Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x Bool -> Bool -> Bool
|| Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x)
instance Numeric Double where
    rational :: Rational -> Either MathError Double
rational Rational
q = let x :: Double
x = Rational -> Double
forall a. Fractional a => Rational -> a
fromRational Rational
q in if Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Double
x then Double -> Either MathError Double
forall a b. b -> Either a b
Right Double
x else MathError -> Either MathError Double
forall a b. a -> Either a b
Left MathError
NonFiniteResult
instance Ring Float where
    zero :: Float
zero = Float
0
    one :: Float
one = Float
1
    plus :: Float -> Float -> Float
plus = Float -> Float -> Float
forall a. Num a => a -> a -> a
(+)
    times :: Float -> Float -> Float
times = Float -> Float -> Float
forall a. Num a => a -> a -> a
(*)
    negative :: Float -> Float
negative = Float -> Float
forall a. Num a => a -> a
negate
    integer :: Integer -> Float
integer = Integer -> Float
forall a. Num a => Integer -> a
fromInteger
instance Field Float where
    invert :: Float -> Either MathError Float
invert Float
x
        | Float
x Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
== Float
0 Bool -> Bool -> Bool
|| Bool -> Bool
not (Float -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Float
x) = MathError -> Either MathError Float
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"finite nonzero field inverse required")
        | Bool
otherwise = let y :: Float
y = Float -> Float
forall a. Fractional a => a -> a
recip Float
x in if Float -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Float
y then Float -> Either MathError Float
forall a b. b -> Either a b
Right Float
y else MathError -> Either MathError Float
forall a b. a -> Either a b
Left MathError
NonFiniteResult
instance Scalar Float where conjugateScalar :: Float -> Float
conjugateScalar = Float -> Float
forall a. a -> a
id
instance FloatingPoint Float where
    machineEpsilon :: forall (proxy :: * -> *). proxy Float -> Double
machineEpsilon proxy Float
_ = Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (-Double
23)
    finiteScalar :: Float -> Bool
finiteScalar Float
x = Bool -> Bool
not (Float -> Bool
forall a. RealFloat a => a -> Bool
isNaN Float
x Bool -> Bool -> Bool
|| Float -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Float
x)
instance Numeric Float where
    rational :: Rational -> Either MathError Float
rational Rational
q = let x :: Float
x = Rational -> Float
forall a. Fractional a => Rational -> a
fromRational Rational
q in if Float -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Float
x then Float -> Either MathError Float
forall a b. b -> Either a b
Right Float
x else MathError -> Either MathError Float
forall a b. a -> Either a b
Left MathError
NonFiniteResult
instance Ring (Complex Double) where
    zero :: Complex Double
zero = Complex Double
0
    one :: Complex Double
one = Complex Double
1
    plus :: Complex Double -> Complex Double -> Complex Double
plus = Complex Double -> Complex Double -> Complex Double
forall a. Num a => a -> a -> a
(+)
    times :: Complex Double -> Complex Double -> Complex Double
times = Complex Double -> Complex Double -> Complex Double
forall a. Num a => a -> a -> a
(*)
    negative :: Complex Double -> Complex Double
negative = Complex Double -> Complex Double
forall a. Num a => a -> a
negate
    integer :: Integer -> Complex Double
integer = Integer -> Complex Double
forall a. Num a => Integer -> a
fromInteger
instance Scalar (Complex Double) where conjugateScalar :: Complex Double -> Complex Double
conjugateScalar = Complex Double -> Complex Double
forall a. Num a => Complex a -> Complex a
conjugate
instance FloatingPoint (Complex Double) where
    machineEpsilon :: forall (proxy :: * -> *). proxy (Complex Double) -> Double
machineEpsilon proxy (Complex Double)
_ = Double
2 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (-Double
52)
    finiteScalar :: Complex Double -> Bool
finiteScalar Complex Double
z = Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar (Complex Double -> Double
forall a. Complex a -> a
realPart Complex Double
z) Bool -> Bool -> Bool
&& Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar (Complex Double -> Double
forall a. Complex a -> a
imagPart Complex Double
z)
instance Field (Complex Double) where
    invert :: Complex Double -> Either MathError (Complex Double)
invert Complex Double
z
        | Complex Double
z Complex Double -> Complex Double -> Bool
forall a. Eq a => a -> a -> Bool
== Complex Double
0 Bool -> Bool -> Bool
|| Bool -> Bool
not (Complex Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Complex Double
z) = MathError -> Either MathError (Complex Double)
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"finite nonzero complex inverse required")
        | Bool
otherwise =
            let a :: Double
a = Complex Double -> Double
forall a. Complex a -> a
realPart Complex Double
z
                b :: Double
b = Complex Double -> Double
forall a. Complex a -> a
imagPart Complex Double
z
                s :: Double
s = Double -> Double -> Double
forall a. Ord a => a -> a -> a
max (Double -> Double
forall a. Num a => a -> a
abs Double
a) (Double -> Double
forall a. Num a => a -> a
abs Double
b)
                x :: Double
x = Double
a Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
s
                y :: Double
y = Double
b Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
s
                d :: Double
d = Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
y Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
y
                w :: Complex Double
w = ((Double
x Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
d) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
s) Double -> Double -> Complex Double
forall a. a -> a -> Complex a
:+ ((-Double
y Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
d) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
s)
             in if Complex Double -> Bool
forall a. FloatingPoint a => a -> Bool
finiteScalar Complex Double
w then Complex Double -> Either MathError (Complex Double)
forall a b. b -> Either a b
Right Complex Double
w else MathError -> Either MathError (Complex Double)
forall a b. a -> Either a b
Left MathError
NonFiniteResult
instance Numeric (Complex Double) where
    rational :: Rational -> Either MathError (Complex Double)
rational Rational
q = (Double -> Double -> Complex Double
forall a. a -> a -> Complex a
:+ Double
0) (Double -> Complex Double)
-> Either MathError Double -> Either MathError (Complex Double)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Rational -> Either MathError Double
forall a. Numeric a => Rational -> Either MathError a
rational Rational
q :: Either MathError Double)

{- | An example user-definable domain, exact rationals with the explicit algebra
contracts. It deliberately does not need a Num or RealFloat instance.
-}
newtype Exact = Exact
    { Exact -> Rational
getExact :: Rational
    -- ^ Extract the exact Rational stored in the example Exact algebra domain.
    }
    deriving (Exact -> Exact -> Bool
(Exact -> Exact -> Bool) -> (Exact -> Exact -> Bool) -> Eq Exact
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Exact -> Exact -> Bool
== :: Exact -> Exact -> Bool
$c/= :: Exact -> Exact -> Bool
/= :: Exact -> Exact -> Bool
Eq, Eq Exact
Eq Exact =>
(Exact -> Exact -> Ordering)
-> (Exact -> Exact -> Bool)
-> (Exact -> Exact -> Bool)
-> (Exact -> Exact -> Bool)
-> (Exact -> Exact -> Bool)
-> (Exact -> Exact -> Exact)
-> (Exact -> Exact -> Exact)
-> Ord Exact
Exact -> Exact -> Bool
Exact -> Exact -> Ordering
Exact -> Exact -> Exact
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Exact -> Exact -> Ordering
compare :: Exact -> Exact -> Ordering
$c< :: Exact -> Exact -> Bool
< :: Exact -> Exact -> Bool
$c<= :: Exact -> Exact -> Bool
<= :: Exact -> Exact -> Bool
$c> :: Exact -> Exact -> Bool
> :: Exact -> Exact -> Bool
$c>= :: Exact -> Exact -> Bool
>= :: Exact -> Exact -> Bool
$cmax :: Exact -> Exact -> Exact
max :: Exact -> Exact -> Exact
$cmin :: Exact -> Exact -> Exact
min :: Exact -> Exact -> Exact
Ord, Int -> Exact -> ShowS
[Exact] -> ShowS
Exact -> String
(Int -> Exact -> ShowS)
-> (Exact -> String) -> ([Exact] -> ShowS) -> Show Exact
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Exact -> ShowS
showsPrec :: Int -> Exact -> ShowS
$cshow :: Exact -> String
show :: Exact -> String
$cshowList :: [Exact] -> ShowS
showList :: [Exact] -> ShowS
Show)

instance Ring Exact where
    zero :: Exact
zero = Rational -> Exact
Exact Rational
0
    one :: Exact
one = Rational -> Exact
Exact Rational
1
    plus :: Exact -> Exact -> Exact
plus (Exact Rational
a) (Exact Rational
b) = Rational -> Exact
Exact (Rational
a Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
b)
    times :: Exact -> Exact -> Exact
times (Exact Rational
a) (Exact Rational
b) = Rational -> Exact
Exact (Rational
a Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
b)
    negative :: Exact -> Exact
negative (Exact Rational
a) = Rational -> Exact
Exact (-Rational
a)
    integer :: Integer -> Exact
integer = Rational -> Exact
Exact (Rational -> Exact) -> (Integer -> Rational) -> Integer -> Exact
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Rational
forall a. Num a => Integer -> a
fromInteger
instance Field Exact where invert :: Exact -> Either MathError Exact
invert (Exact Rational
a) = Rational -> Exact
Exact (Rational -> Exact)
-> Either MathError Rational -> Either MathError Exact
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Rational -> Either MathError Rational
forall a. Field a => a -> Either MathError a
invert Rational
a
instance Scalar Exact where conjugateScalar :: Exact -> Exact
conjugateScalar = Exact -> Exact
forall a. a -> a
id
instance Numeric Exact where rational :: Rational -> Either MathError Exact
rational = Exact -> Either MathError Exact
forall a b. b -> Either a b
Right (Exact -> Either MathError Exact)
-> (Rational -> Exact) -> Rational -> Either MathError Exact
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rational -> Exact
Exact

-- | Coefficients are highest degree first; an empty polynomial is zero.
horner :: (Ring a) => [a] -> a -> a
horner :: forall a. Ring a => [a] -> a -> a
horner [a]
coefficients a
x = (a -> a -> a) -> a -> [a] -> a
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\a
value a
coefficient -> a -> a -> a
forall a. Ring a => a -> a -> a
plus (a -> a -> a
forall a. Ring a => a -> a -> a
times a
value a
x) a
coefficient) a
forall a. Ring a => a
zero [a]
coefficients

{- | Return sum(conjugate a[i] * b[i]) using the Scalar and Ring operations. Equal list
lengths are required; mismatch returns VectorLengthMismatch. Empty lists give the ring
zero; instance arithmetic controls precision/overflow.
-}
innerProduct :: (Scalar a) => [a] -> [a] -> Either MathError a
innerProduct :: forall a. Scalar a => [a] -> [a] -> Either MathError a
innerProduct [a]
a [a]
b
    | [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
a Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
b = MathError -> Either MathError a
forall a b. a -> Either a b
Left (Int -> Int -> MathError
VectorLengthMismatch ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
a) ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
b))
    | Bool
otherwise = a -> Either MathError a
forall a b. b -> Either a b
Right ((a -> a -> a) -> a -> [a] -> a
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl a -> a -> a
forall a. Ring a => a -> a -> a
plus a
forall a. Ring a => a
zero ((a -> a -> a) -> [a] -> [a] -> [a]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\a
x a
y -> a -> a -> a
forall a. Ring a => a -> a -> a
times (a -> a
forall a. Scalar a => a -> a
conjugateScalar a
x) a
y) [a]
a [a]
b))

-- | Container interface for matrix dimensions,row-major elements,and checked construction.
class MatrixLike m where
    -- | Return logical (rows,columns) of a matrix-like container.
    matrixDimensions :: m a -> (Int, Int)

    -- | Return matrix elements in logical row-major order.
    matrixElements :: m a -> [a]

    -- | Given rows,columns,flat row-major elements, construct a matrix-like value or return checked shape/count failure.
    matrixConstruct :: Int -> Int -> [a] -> Either MathError (m a)

instance MatrixLike M.Matrix where
    matrixDimensions :: forall a. Matrix a -> (Int, Int)
matrixDimensions = Matrix a -> (Int, Int)
forall a. Matrix a -> (Int, Int)
M.shape
    matrixElements :: forall a. Matrix a -> [a]
matrixElements = Matrix a -> [a]
forall a. Matrix a -> [a]
M.toList
    matrixConstruct :: forall a. Int -> Int -> [a] -> Either MathError (Matrix a)
matrixConstruct = Int -> Int -> [a] -> Either MathError (Matrix a)
forall a. Int -> Int -> [a] -> Either MathError (Matrix a)
M.fromListChecked

{- | Container interface for tensor dimensions,row-major logical elements,and checked
construction.
-}
class TensorLike t where
    -- | Return tensor-like dimensions in axis order; [] denotes scalar.
    tensorDimensions :: t a -> [Int]

    -- | Return tensor-like elements in logical row-major coordinate order.
    tensorElements :: t a -> [a]

    -- | Given dimensions then flat values, construct a tensor-like value or return shape/count failure.
    tensorConstruct :: [Int] -> [a] -> Either MathError (t a)

instance TensorLike T.Tensor where
    tensorDimensions :: forall a. Tensor a -> [Int]
tensorDimensions = Tensor a -> [Int]
forall a. Tensor a -> [Int]
T.tensorShape
    tensorElements :: forall a. Tensor a -> [a]
tensorElements = Tensor a -> [a]
forall a. Tensor a -> [a]
T.tensorValues
    tensorConstruct :: forall a. [Int] -> [a] -> Either MathError (Tensor a)
tensorConstruct = [Int] -> [a] -> Either MathError (Tensor a)
forall a. [Int] -> [a] -> Either MathError (Tensor a)
T.tensor

-- | Container interface for checked shape-compatible addition and scalar multiplication.
class VectorSpace v where
    -- | Add identically shaped vector-space values, returning checked dimension errors on mismatch.
    vectorPlus :: (Num a) => v a -> v a -> Either MathError (v a)

    -- | Given scalar then vector-space value, return its coordinatewise scalar multiple.
    vectorScale :: (Num a) => a -> v a -> v a

instance VectorSpace V.Vector where vectorPlus :: forall a.
Num a =>
Vector a -> Vector a -> Either MathError (Vector a)
vectorPlus = Vector a -> Vector a -> Either MathError (Vector a)
forall a.
Num a =>
Vector a -> Vector a -> Either MathError (Vector a)
V.vectorAdd; vectorScale :: forall a. Num a => a -> Vector a -> Vector a
vectorScale = a -> Vector a -> Vector a
forall a. Num a => a -> Vector a -> Vector a
V.vectorScale
instance VectorSpace M.Matrix where vectorPlus :: forall a.
Num a =>
Matrix a -> Matrix a -> Either MathError (Matrix a)
vectorPlus = Matrix a -> Matrix a -> Either MathError (Matrix a)
forall a.
Num a =>
Matrix a -> Matrix a -> Either MathError (Matrix a)
M.addMatrixChecked; vectorScale :: forall a. Num a => a -> Matrix a -> Matrix a
vectorScale = a -> Matrix a -> Matrix a
forall a. Num a => a -> Matrix a -> Matrix a
M.scaleMatrix

-- | Differential extraction reuses the existing nested forward-mode Dual type.
class Differentiable a where
    type Differential a

    -- | Extract associated differential; the Dual instance returns its tangent component.
    differential :: a -> Differential a

instance Differentiable (AD.Dual a) where
    type Differential (AD.Dual a) = a
    differential :: Dual a -> Differential (Dual a)
differential = Dual a -> a
Dual a -> Differential (Dual a)
forall a. Dual a -> a
AD.tangent