module Data.LinearMap.HerMetric (
HerMetric(..), HerMetric'(..)
, toDualWith, fromDualWith
, metricSq, metricSq', metric, metric', metrics, metrics'
, projector, projector', projectors, projector's
, euclideanMetric'
, spanHilbertSubspace
, spanSubHilbertSpace
, IsFreeSpace
, factoriseMetric, factoriseMetric'
, productMetric, productMetric'
, tryMetricAsLength, metricAsLength, metricFromLength, metric'AsLength
, transformMetric, transformMetric', dualCoCoProduct
, dualiseMetric, dualiseMetric'
, recipMetric, recipMetric', safeRecipMetric, safeRecipMetric'
, eigenSpan, eigenSpan'
, eigenCoSpan, eigenCoSpan'
, eigenSystem, HasEigenSystem, EigenVector
, metriNormalise, metriNormalise'
, metriScale', metriScale
, volumeRatio, euclideanRelativeMetricVolume
, adjoint
, extendMetric
, applyLinMapMetric, applyLinMapMetric'
, imitateMetricSpanChange
, HasMetric
, HasMetric'(..)
, (^<.>)
, MetricScalar
, FiniteDimensional(..)
, Stiefel1(..)
, linMapAsTensProd, linMapFromTensProd
, covariance
, outerProducts
, orthogonalComplementSpan
) where
import Data.VectorSpace
import Data.LinearMap
import Data.Basis
import Data.Semigroup
import Data.Tagged
import qualified Data.List as List
import qualified Prelude as Hask
import qualified Control.Applicative as Hask
import qualified Control.Monad as Hask
import Control.Category.Constrained.Prelude hiding ((^))
import Control.Arrow.Constrained
import Data.Manifold.Types.Primitive
import Data.CoNat
import qualified Data.Vector as Arr
import qualified Numeric.LinearAlgebra.HMatrix as HMat
import Data.VectorSpace.FiniteDimensional
import Data.LinearMap.Category
import Data.Embedding
infixr 7 <.>^, ^<.>
newtype HerMetric v = HerMetric {
metricMatrix :: Maybe (Linear (Scalar v) v (DualSpace v))
}
matrixMetric :: HasMetric v => HMat.Matrix (Scalar v) -> HerMetric v
matrixMetric = HerMetric . Just . DenseLinear
instance (HasMetric v) => AdditiveGroup (HerMetric v) where
zeroV = HerMetric Nothing
negateV (HerMetric m) = HerMetric $ negateV <$> m
HerMetric Nothing ^+^ HerMetric n = HerMetric n
HerMetric m ^+^ HerMetric Nothing = HerMetric m
HerMetric (Just m) ^+^ HerMetric (Just n) = HerMetric . Just $ m ^+^ n
instance HasMetric v => VectorSpace (HerMetric v) where
type Scalar (HerMetric v) = Scalar v
s *^ (HerMetric m) = HerMetric $ (s*^) <$> m
newtype HerMetric' v = HerMetric' {
metricMatrix' :: Maybe (Linear (Scalar v) (DualSpace v) v)
}
extendMetric :: (HasMetric v, Scalar v~ℝ) => HerMetric v -> v -> HerMetric v
extendMetric (HerMetric Nothing) _ = HerMetric Nothing
extendMetric (HerMetric (Just (DenseLinear m))) v
| isInfinite' detm = HerMetric . Just $ DenseLinear m
| isInfinite' detmninv = singularMetric
| otherwise = HerMetric . Just $ DenseLinear mn
where
(minv, (detm, _)) = HMat.invlndet m
(mn, (detmninv, _)) = HMat.invlndet (minv + HMat.outer vv vv)
vv = asPackedVector v
matrixMetric' :: HasMetric v => HMat.Matrix (Scalar v) -> HerMetric' v
matrixMetric' = HerMetric' . Just . DenseLinear
instance (HasMetric v) => AdditiveGroup (HerMetric' v) where
zeroV = HerMetric' Nothing
negateV (HerMetric' m) = HerMetric' $ negateV <$> m
HerMetric' Nothing ^+^ HerMetric' n = HerMetric' n
HerMetric' m ^+^ HerMetric' Nothing = HerMetric' m
HerMetric' (Just m) ^+^ HerMetric' (Just n) = HerMetric' . Just $ m ^+^ n
instance HasMetric v => VectorSpace (HerMetric' v) where
type Scalar (HerMetric' v) = Scalar v
s *^ (HerMetric' m) = HerMetric' $ (s*^) <$> m
projector :: HasMetric v => DualSpace v -> HerMetric v
projector u = HerMetric . pure $ u ⊗ u
projector' :: HasMetric v => v -> HerMetric' v
projector' v = HerMetric' . pure $ v ⊗ v
projectors :: HasMetric v => [DualSpace v] -> HerMetric v
projectors [] = zeroV
projectors us = HerMetric . pure . outerProducts $ zip us us
projector's :: HasMetric v => [v] -> HerMetric' v
projector's [] = zeroV
projector's vs = HerMetric' . pure . outerProducts $ zip vs vs
singularMetric :: forall v . HasMetric v => HerMetric v
singularMetric = matrixMetric $ HMat.scale (1/0) (HMat.ident dim)
where (Tagged dim) = dimension :: Tagged v Int
singularMetric' :: forall v . HasMetric v => HerMetric' v
singularMetric' = matrixMetric' $ HMat.scale (1/0) (HMat.ident dim)
where (Tagged dim) = dimension :: Tagged v Int
metricSq :: HasMetric v => HerMetric v -> v -> Scalar v
metricSq (HerMetric Nothing) _ = 0
metricSq (HerMetric (Just (DenseLinear m))) v = vDecomp `HMat.dot` HMat.app m vDecomp
where vDecomp = asPackedVector v
metricSq' :: HasMetric v => HerMetric' v -> DualSpace v -> Scalar v
metricSq' (HerMetric' Nothing) _ = 0
metricSq' (HerMetric' (Just (DenseLinear m))) u = uDecomp `HMat.dot` HMat.app m uDecomp
where uDecomp = asPackedVector u
metric :: (HasMetric v, Floating (Scalar v)) => HerMetric v -> v -> Scalar v
metric m = sqrt . metricSq m
metric' :: (HasMetric v, Floating (Scalar v)) => HerMetric' v -> DualSpace v -> Scalar v
metric' m = sqrt . metricSq' m
toDualWith :: HasMetric v => HerMetric v -> v -> DualSpace v
toDualWith (HerMetric Nothing) = const zeroV
toDualWith (HerMetric (Just m)) = (m$)
fromDualWith :: HasMetric v => HerMetric' v -> DualSpace v -> v
fromDualWith (HerMetric' Nothing) = const zeroV
fromDualWith (HerMetric' (Just m)) = (m$)
metriNormalise :: (HasMetric v, Floating (Scalar v)) => HerMetric v -> v -> v
metriNormalise m v = v ^/ metric m v
metriNormalise' :: (HasMetric v, Floating (Scalar v))
=> HerMetric' v -> DualSpace v -> DualSpace v
metriNormalise' m v = v ^/ metric' m v
metriScale :: (HasMetric v, Floating (Scalar v)) => HerMetric v -> v -> v
metriScale m v = metric m v *^ v
metriScale' :: (HasMetric v, Floating (Scalar v))
=> HerMetric' v -> DualSpace v -> DualSpace v
metriScale' m v = metric' m v *^ v
metrics :: (HasMetric v, Floating (Scalar v)) => HerMetric v -> [v] -> Scalar v
metrics m vs = sqrt . sum $ metricSq m <$> vs
metrics' :: (HasMetric v, Floating (Scalar v)) => HerMetric' v -> [DualSpace v] -> Scalar v
metrics' m vs = sqrt . sum $ metricSq' m <$> vs
transformMetric :: ∀ s v w . (HasMetric v, HasMetric w, Scalar v~s, Scalar w~s)
=> Linear s w v -> HerMetric v -> HerMetric w
transformMetric _ (HerMetric Nothing) = HerMetric Nothing
transformMetric t (HerMetric (Just m)) = HerMetric . Just $ adjoint t . m . t
transformMetric' :: ∀ s v w . (HasMetric v, HasMetric w, Scalar v~s, Scalar w~s)
=> Linear s v w -> HerMetric' v -> HerMetric' w
transformMetric' _ (HerMetric' Nothing) = HerMetric' Nothing
transformMetric' t (HerMetric' (Just m)) = HerMetric' . Just $ t . m . adjoint t
dualCoCoProduct :: (HasMetric v, HasMetric w, Scalar v ~ s, Scalar w ~ s)
=> Linear s w v -> Linear s w v -> HerMetric w
dualCoCoProduct (DenseLinear smat) (DenseLinear tmat)
= ( (sArr `HMat.dot` (t²PLUSs² HMat.<\> sArr))
* (tArr `HMat.dot` (t²PLUSs² HMat.<\> tArr)) )
*^ matrixMetric t²PLUSs²
where tArr = HMat.flatten tmat
sArr = HMat.flatten smat
t²PLUSs² = tmat HMat.<> HMat.tr tmat + smat HMat.<> HMat.tr smat
dualiseMetric :: HasMetric v => HerMetric (DualSpace v) -> HerMetric' v
dualiseMetric (HerMetric m) = HerMetric' m
dualiseMetric' :: HasMetric v => HerMetric' v -> HerMetric (DualSpace v)
dualiseMetric' (HerMetric' m) = HerMetric m
recipMetric :: HasMetric v => HerMetric' v -> HerMetric v
recipMetric m' | Option (Just m) <- safeRecipMetric m' = m
recipMetric _ = singularMetric
recipMetric' :: HasMetric v => HerMetric v -> HerMetric' v
recipMetric' m | Option (Just m') <- safeRecipMetric' m = m'
recipMetric' _ = singularMetric'
safeRecipMetric :: HasMetric v => HerMetric' v -> Option (HerMetric v)
safeRecipMetric (HerMetric' Nothing) = empty
safeRecipMetric (HerMetric' (Just (DenseLinear m)))
| isInfinite' detm = empty
| otherwise = return $ matrixMetric minv
where (minv, (detm, _)) = HMat.invlndet m
safeRecipMetric' :: HasMetric v => HerMetric v -> Option (HerMetric' v)
safeRecipMetric' (HerMetric Nothing) = empty
safeRecipMetric' (HerMetric (Just (DenseLinear m)))
| isInfinite' detm = empty
| otherwise = return $ matrixMetric' minv
where (minv, (detm, _)) = HMat.invlndet m
isInfinite' :: (Eq a, Num a) => a -> Bool
isInfinite' 0 = False
isInfinite' x = x==x*2
eigenSpan :: (HasMetric v, Scalar v ~ ℝ) => HerMetric' v -> [v]
eigenSpan (HerMetric' Nothing) = []
eigenSpan (HerMetric' (Just (DenseLinear m))) = map fromPackedVector eigSpan
where (μs,vsm) = HMat.eigSH' m
eigSpan = zipWith (HMat.scale . sqrt) (HMat.toList μs) (HMat.toColumns vsm)
eigenSpan' :: (HasMetric v, Scalar v ~ ℝ) => HerMetric v -> [DualSpace v]
eigenSpan' (HerMetric Nothing) = []
eigenSpan' (HerMetric (Just (DenseLinear m))) = map fromPackedVector eigSpan
where (μs,vsm) = HMat.eigSH' m
eigSpan = zipWith (HMat.scale . sqrt) (HMat.toList μs) (HMat.toColumns vsm)
eigenCoSpan :: (HasMetric v, Scalar v ~ ℝ) => HerMetric' v -> [DualSpace v]
eigenCoSpan (HerMetric' Nothing) = []
eigenCoSpan (HerMetric' (Just (DenseLinear m))) = map fromPackedVector eigSpan
where (μs,vsm) = HMat.eigSH' m
eigSpan = map (uncurry $ HMat.scale . recip . sqrt)
. filter ((>0) . fst)
$ zip (HMat.toList μs) (HMat.toColumns vsm)
eigenCoSpan' :: (HasMetric v, Scalar v ~ ℝ) => HerMetric v -> [v]
eigenCoSpan' (HerMetric Nothing) = []
eigenCoSpan' (HerMetric (Just (DenseLinear m))) = map fromPackedVector eigSpan
where (μs,vsm) = HMat.eigSH' m
eigSpan = map (uncurry $ HMat.scale . recip . sqrt)
. filter ((>0) . fst)
$ zip (HMat.toList μs) (HMat.toColumns vsm)
class HasEigenSystem m where
type EigenVector m :: *
eigenSystem :: m -> ( [Stiefel1 (EigenVector m)]
, [(EigenVector m, DualSpace (EigenVector m))] )
instance (HasMetric v, Scalar v ~ ℝ) => HasEigenSystem (HerMetric' v) where
type EigenVector (HerMetric' v) = v
eigenSystem (HerMetric' Nothing) = (fmap Stiefel1 completeBasisValues, [])
eigenSystem (HerMetric' (Just (DenseLinear m))) = concat***concat $ unzip eigSpan
where (μs,vsm) = HMat.eigSH' m
eigSpan = zipWith (\μ v
-> if μ>0
then let sμ = sqrt μ
in ([], [( fromPackedVector $ HMat.scale sμ v
, fromPackedVector $ HMat.scale (recip sμ) v )])
else ([Stiefel1 $ fromPackedVector v], [])
) (HMat.toList μs) (HMat.toColumns vsm)
instance (HasMetric v, Scalar v ~ ℝ) => HasEigenSystem (HerMetric v) where
type EigenVector (HerMetric v) = DualSpace v
eigenSystem (HerMetric Nothing) = (fmap Stiefel1 completeBasisValues, [])
eigenSystem (HerMetric (Just (DenseLinear m))) = concat***concat $ unzip eigSpan
where (μs,vsm) = HMat.eigSH' m
eigSpan = zipWith (\μ v
-> if μ>0
then let sμ = sqrt μ
in ([], [( fromPackedVector $ HMat.scale sμ v
, fromPackedVector $ HMat.scale (recip sμ) v )])
else ([Stiefel1 $ fromPackedVector v], [])
) (HMat.toList μs) (HMat.toColumns vsm)
instance (HasMetric v, Scalar v ~ ℝ) => HasEigenSystem (HerMetric' v, HerMetric' v) where
type EigenVector (HerMetric' v, HerMetric' v) = v
eigenSystem (n, HerMetric' (Just (DenseLinear m))) | not $ null nSpan
= (++nKernel).concat***concat $ unzip eigSpan
where (μs,vsm) = HMat.eigSH' $ fromv2ℝn HMat.<> m HMat.<> fromℝn2v'
eigSpan = zipWith (\μ v
-> if μ>0
then let sμ = sqrt μ
in ([], [( fromPackedVector $
fromℝn2v HMat.#> HMat.scale sμ v
, fromPackedVector $
fromℝn2v' HMat.#> HMat.scale (recip sμ) v )
])
else ([Stiefel1 $ fromPackedVector v], [])
) (HMat.toList μs) (HMat.toColumns vsm)
fromv2ℝn = HMat.fromRows $ map (asPackedVector . snd) nSpan
fromℝn2v' = HMat.tr fromv2ℝn
fromℝn2v = HMat.fromColumns $ map (asPackedVector . fst) nSpan
(nKernel, nSpan) = eigenSystem n
eigenSystem (_, HerMetric' Nothing) = (fmap Stiefel1 completeBasisValues, [])
instance (HasMetric v, Scalar v ~ ℝ) => HasEigenSystem (HerMetric v, HerMetric v) where
type EigenVector (HerMetric v, HerMetric v) = DualSpace v
eigenSystem (n, HerMetric (Just (DenseLinear m))) | not $ null nSpan
= (++nKernel).concat***concat $ unzip eigSpan
where (μs,vsm) = HMat.eigSH' $ fromv'2ℝn HMat.<> m HMat.<> fromℝn2v
eigSpan = zipWith (\μ v
-> if μ>0
then let sμ = sqrt μ
in ([], [( fromPackedVector $
fromℝn2v' HMat.#> HMat.scale sμ v
, fromPackedVector $
fromℝn2v HMat.#> HMat.scale (recip sμ) v )
])
else ([Stiefel1 $ fromPackedVector v], [])
) (HMat.toList μs) (HMat.toColumns vsm)
fromv'2ℝn = HMat.fromRows $ map (asPackedVector . snd) nSpan
fromℝn2v = HMat.tr fromv'2ℝn
fromℝn2v' = HMat.fromColumns $ map (asPackedVector . fst) nSpan
(nKernel, nSpan) = eigenSystem n
eigenSystem (_, _) = (fmap Stiefel1 completeBasisValues, [])
type MetricScalar s = ( SmoothScalar s
, Ord s
)
type HasMetric v = (HasMetric' v, HasMetric' (DualSpace v), DualSpace (DualSpace v) ~ v)
class ( FiniteDimensional v, FiniteDimensional (DualSpace v)
, VectorSpace (DualSpace v), HasBasis (DualSpace v)
, MetricScalar (Scalar v), Scalar v ~ Scalar (DualSpace v) )
=> HasMetric' v where
type DualSpace v :: *
type DualSpace v = v
(<.>^) :: DualSpace v -> v -> Scalar v
functional :: (v -> Scalar v) -> DualSpace v
doubleDual :: HasMetric' (DualSpace v) => v -> DualSpace (DualSpace v)
doubleDual' :: HasMetric' (DualSpace v) => DualSpace (DualSpace v) -> v
basisInDual :: Tagged v (Basis v -> Basis (DualSpace v))
basisInDual = bid
where bid :: ∀ v . HasMetric' v => Tagged v (Basis v -> Basis (DualSpace v))
bid = Tagged $ bi >>> ib'
where Tagged bi = basisIndex :: Tagged v (Basis v -> Int)
Tagged ib' = indexBasis :: Tagged (DualSpace v) (Int -> Basis (DualSpace v))
(^<.>) :: HasMetric v => v -> DualSpace v -> Scalar v
ket ^<.> bra = bra <.>^ ket
euclideanMetric' :: forall v . (HasMetric v, InnerSpace v) => HerMetric v
euclideanMetric' = HerMetric . pure . DenseLinear $ HMat.ident n
where (Tagged n) = dimension :: Tagged v Int
instance (MetricScalar k) => HasMetric' (ZeroDim k) where
Origin<.>^Origin = zeroV
functional _ = Origin
doubleDual = id; doubleDual'= id; basisInDual = pure id
instance HasMetric' Double where
(<.>^) = (<.>)
functional f = f 1
doubleDual = id; doubleDual'= id; basisInDual = pure id
instance ( HasMetric v, HasMetric w, Scalar v ~ Scalar w
) => HasMetric' (v,w) where
type DualSpace (v,w) = (DualSpace v, DualSpace w)
(v,w)<.>^(v',w') = v<.>^v' + w<.>^w'
functional f = (functional $ f . (,zeroV), functional $ f . (zeroV,))
doubleDual = id; doubleDual'= id
basisInDual = bid
where bid :: ∀ v w . (HasMetric v, HasMetric w) => Tagged (v,w)
(Basis v + Basis w -> Basis (DualSpace v) + Basis (DualSpace w))
bid = Tagged $ \case Left q -> Left $ bidv q
Right q -> Right $ bidw q
where Tagged bidv = basisInDual :: Tagged v (Basis v -> Basis (DualSpace v))
Tagged bidw = basisInDual :: Tagged w (Basis w -> Basis (DualSpace w))
instance (SmoothScalar s, Ord s, KnownNat n) => HasMetric' (s^n) where
type DualSpace (s^n) = s^n
(<.>^) = (<.>)
functional = fnal
where fnal :: ∀ s n . (SmoothScalar s, KnownNat n) => (s^n -> s) -> s^n
fnal f = FreeVect . Arr.generate n $
\i -> f . FreeVect . Arr.generate n $ \j -> if i==j then 1 else 0
where Tagged n = theNatN :: Tagged n Int
doubleDual = id; doubleDual'= id; basisInDual = pure id
instance (HasMetric v, s~Scalar v) => HasMetric' (FinVecArrRep t v s) where
type DualSpace (FinVecArrRep t v s) = FinVecArrRep t (DualSpace v) s
FinVecArrRep v <.>^ FinVecArrRep w = HMat.dot v w
functional = fnal
where fnal :: ∀ v . HasMetric v =>
(FinVecArrRep t v (Scalar v) -> Scalar v)
-> FinVecArrRep t (DualSpace v) (Scalar v)
fnal f = FinVecArrRep . (n HMat.|>)
$ (f . FinVecArrRep) <$> HMat.toRows (HMat.ident n)
Tagged n = dimension :: Tagged v Int
doubleDual = id; doubleDual'= id
basisInDual = bid
where bid :: ∀ s v t . (HasMetric v, s~Scalar v)
=> Tagged (FinVecArrRep t v s) (Basis v -> Basis (DualSpace v))
bid = Tagged bid₀
where Tagged bid₀ = basisInDual :: Tagged v (Basis v -> Basis (DualSpace v))
instance (HasMetric v, HasMetric w, s ~ Scalar v, s ~ Scalar w)
=> HasMetric' (Linear s v w) where
type DualSpace (Linear s v w) = Linear s w v
DenseLinear bw <.>^ DenseLinear fw
= HMat.sumElements (HMat.tr bw * fw)
functional = completeBasisFunctional
doubleDual = id; doubleDual' = id
completeBasisFunctional :: ∀ v . HasMetric' v => (v -> Scalar v) -> DualSpace v
completeBasisFunctional f = recompose [ (bid b, f $ basisValue b) | b <- cb ]
where Tagged cb = completeBasis :: Tagged v [Basis v]
Tagged bid = basisInDual :: Tagged v (Basis v -> Basis (DualSpace v))
adjoint :: (HasMetric v, HasMetric w, s~Scalar v, s~Scalar w)
=> (Linear s v w) -> Linear s (DualSpace w) (DualSpace v)
adjoint (DenseLinear m) = DenseLinear $ HMat.tr m
adjoint_fln :: (HasMetric v, HasMetric w, Scalar w ~ Scalar v)
=> (v :-* w) -> DualSpace w :-* DualSpace v
adjoint_fln m = linear $ \w -> functional $ \v
-> w <.>^lapply m v
metrConst :: forall v. (HasMetric v, v ~ DualSpace v, Num (Scalar v))
=> Scalar v -> HerMetric v
metrConst μ = matrixMetric $ HMat.scale μ (HMat.ident dim)
where (Tagged dim) = dimension :: Tagged v Int
instance (HasMetric v, v ~ DualSpace v, Num (Scalar v)) => Num (HerMetric v) where
fromInteger = metrConst . fromInteger
(+) = (^+^)
negate = negateV
HerMetric m * HerMetric n = HerMetric . fmap DenseLinear
$ liftA2 (HMat.<>) (getDenseMatrix<$>m) (getDenseMatrix<$>n)
abs = error "abs undefined for HerMetric"
signum = error "signum undefined for HerMetric"
metrNumFun :: (HasMetric v, v ~ Scalar v, v ~ DualSpace v, Num v)
=> (v -> v) -> HerMetric v -> HerMetric v
metrNumFun f (HerMetric Nothing) = matrixMetric . HMat.scalar $ f 0
metrNumFun f (HerMetric (Just (DenseLinear m)))
= matrixMetric . HMat.scalar . f $ m HMat.! 0 HMat.! 0
instance (HasMetric v, v ~ Scalar v, v ~ DualSpace v, Fractional v)
=> Fractional (HerMetric v) where
fromRational = metrConst . fromRational
recip = metrNumFun recip
instance (HasMetric v, v ~ Scalar v, v ~ DualSpace v, Floating v)
=> Floating (HerMetric v) where
pi = metrConst pi
sqrt = metrNumFun sqrt
exp = metrNumFun exp
log = metrNumFun log
sin = metrNumFun sin
cos = metrNumFun cos
tan = metrNumFun tan
asin = metrNumFun asin
acos = metrNumFun acos
atan = metrNumFun atan
sinh = metrNumFun sinh
cosh = metrNumFun cosh
asinh = metrNumFun asinh
atanh = metrNumFun atanh
acosh = metrNumFun acosh
normaliseWith :: HasMetric v => HerMetric v -> v -> Option v
normaliseWith m v = case metric m v of
0 -> empty
μ -> pure (v ^/ μ)
orthonormalPairsWith :: forall v . HasMetric v => HerMetric v -> [v] -> [(v, DualSpace v)]
orthonormalPairsWith met = mkON
where mkON :: [v] -> [(v, DualSpace v)]
mkON [] = []
mkON (v:vs) = let onvs = mkON vs
v' = List.foldl' (\va (vb,pb) -> va ^-^ vb ^* (pb <.>^ va)) v onvs
p' = toDualWith met v'
in case sqrt (p' <.>^ v') of
0 -> onvs
μ -> (v'^/μ, p'^/μ) : onvs
factoriseMetric :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric (v,w) -> (HerMetric v, HerMetric w)
factoriseMetric (HerMetric Nothing) = (HerMetric Nothing, HerMetric Nothing)
factoriseMetric met = (projectors *** projectors) . unzip $ eigenSpan' met
factoriseMetric' :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric' (v,w) -> (HerMetric' v, HerMetric' w)
factoriseMetric' met = (projector's *** projector's) . unzip $ eigenSpan met
productMetric :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric v -> HerMetric w -> HerMetric (v,w)
productMetric (HerMetric Nothing) (HerMetric Nothing) = HerMetric Nothing
productMetric (HerMetric (Just mv)) (HerMetric (Just mw)) = HerMetric . Just $ mv *** mw
productMetric (HerMetric Nothing) (HerMetric (Just mw)) = HerMetric . Just $ zeroV *** mw
productMetric (HerMetric (Just mv)) (HerMetric Nothing) = HerMetric . Just $ mv *** zeroV
productMetric' :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric' v -> HerMetric' w -> HerMetric' (v,w)
productMetric' (HerMetric' Nothing) (HerMetric' Nothing) = HerMetric' Nothing
productMetric' (HerMetric' (Just mv)) (HerMetric' (Just mw)) = HerMetric' . Just $ mv***mw
productMetric' (HerMetric' Nothing) (HerMetric' (Just mw)) = HerMetric' . Just $ zeroV***mw
productMetric' (HerMetric' (Just mv)) (HerMetric' Nothing) = HerMetric' . Just $ mv***zeroV
applyLinMapMetric :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric (Linear ℝ v w) -> DualSpace v -> HerMetric w
applyLinMapMetric met v' = transformMetric ap2v met
where ap2v :: Linear ℝ w (Linear ℝ v w)
ap2v = denseLinear $ \w -> denseLinear $ \v -> w ^* (v'<.>^v)
applyLinMapMetric' :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric' (Linear ℝ v w) -> v -> HerMetric' w
applyLinMapMetric' met v = transformMetric' ap2v met
where ap2v :: Linear ℝ (Linear ℝ v w) w
ap2v = denseLinear ($v)
imitateMetricSpanChange :: ∀ v . (HasMetric v, Scalar v ~ ℝ)
=> HerMetric v -> HerMetric' v -> Linear ℝ v v
imitateMetricSpanChange (HerMetric (Just m)) (HerMetric' (Just n)) = n . m
imitateMetricSpanChange _ _ = zeroV
covariance :: ∀ v w . (HasMetric v, HasMetric w, Scalar v ~ ℝ, Scalar w ~ ℝ)
=> HerMetric' (v,w) -> Option (Linear ℝ v w)
covariance (HerMetric' Nothing) = pure zeroV
covariance (HerMetric' (Just m))
| isInfinite' detvnm = empty
| otherwise = return $ snd . m . (id&&&zeroV) . DenseLinear vnorml
where (vnorml, (detvnm, _))
= HMat.invlndet . getDenseMatrix $ fst . m . (id&&&zeroV)
volumeRatio :: HasMetric v => HerMetric v -> HerMetric v -> Scalar v
volumeRatio (HerMetric Nothing) (HerMetric Nothing) = 1
volumeRatio (HerMetric _) (HerMetric Nothing) = 0
volumeRatio (HerMetric (Just (DenseLinear m₁)))
(HerMetric (Just (DenseLinear m₂)))
= HMat.det m₂ / HMat.det m₁
volumeRatio (HerMetric Nothing) (HerMetric _) = 1/0
euclideanRelativeMetricVolume :: (HasMetric v, InnerSpace v) => HerMetric v -> Scalar v
euclideanRelativeMetricVolume (HerMetric Nothing) = 1/0
euclideanRelativeMetricVolume (HerMetric (Just (DenseLinear m))) = recip $ HMat.det m
tryMetricAsLength :: HerMetric ℝ -> Option ℝ
tryMetricAsLength m = case metricSq m 1 of
o | o > 0 -> pure . sqrt $ recip o
| otherwise -> empty
metricAsLength :: HerMetric ℝ -> ℝ
metricAsLength m = case metricSq m 1 of
o | o >= 0 -> sqrt $ recip o
| o < 0 -> error "Metric fails to be positive definite!"
| otherwise -> error "Metric yields NaN."
metricFromLength :: ℝ -> HerMetric ℝ
metricFromLength = projector . recip
metric'AsLength :: HerMetric' ℝ -> ℝ
metric'AsLength = sqrt . (`metric'`1)
spanHilbertSubspace :: ∀ s v w
. (HasMetric v, Scalar v ~ s, IsFreeSpace w, Scalar w ~ s)
=> HerMetric v
-> [v]
-> Option (Embedding (Linear s) w v)
spanHilbertSubspace met = emb . orthonormalPairsWith met
where emb onb'
| n'==n = return $ Embedding emb prj . arr identityMatrix
| otherwise = empty
where emb = DenseLinear . HMat.fromColumns $ (asPackedVector . fst) <$> onb
prj = DenseLinear . HMat.fromRows $ (asPackedVector . snd) <$> onb
n' = length onb'
onb = take n onb'
(Tagged n) = theNatN :: Tagged (FreeDimension w) Int
spanSubHilbertSpace :: ∀ s v w
. (HasMetric v, InnerSpace v, Scalar v ~ s, IsFreeSpace w, Scalar w ~ s)
=> [v]
-> Option (Embedding (Linear s) w v)
spanSubHilbertSpace = spanHilbertSubspace euclideanMetric'
orthogonalComplementSpan :: ∀ v . (HasMetric v, Scalar v ~ ℝ)
=> [Stiefel1 (DualSpace v)] -> [Stiefel1 v]
orthogonalComplementSpan avoidSpace
= fst ( iterate nextOVect ( [], ( cycle completeBasisValues
, pseudoRieszPair <$> avoidSpace ) )
!! (d lav) )
where Tagged d = dimension :: Tagged v Int
lav = length avoidSpace
nextOVect (result, (v:src, avoid))
| Option (Just newAvoid@(vfin', _)) <- mkPseudoRieszPair vPurged
= (Stiefel1 vfin':result, (src, newAvoid : avoid))
where vPurged = foldl (\vp (av', av) -> vp ^-^ av ^* (vp^<.>av')) v avoid
newtype Stiefel1 v = Stiefel1 { getStiefel1N :: DualSpace v }
pseudoRieszPair :: (HasMetric v, Scalar v ~ ℝ) => Stiefel1 v -> (v, DualSpace v)
pseudoRieszPair (Stiefel1 v')
= (fromPackedVector $ HMat.scale (1/HMat.norm_2 vp) vp, v')
where vp = asPackedVector v'
mkPseudoRieszPair :: (HasMetric v, Scalar v ~ ℝ) => DualSpace v -> Option (v, DualSpace v)
mkPseudoRieszPair v'
| nv' > 0 = pure (fromPackedVector $ HMat.scale (1/nv') vp, v')
| otherwise = empty
where vp = asPackedVector v'
nv' = HMat.norm_2 vp
instance (HasMetric v, Scalar v ~ Double, Show (DualSpace v)) => Show (HerMetric v) where
showsPrec p m
| null eigSp = showString "zeroV"
| otherwise = showParen (p>5)
. foldr1 ((.) . (.(" ^+^ "++)))
$ ((("projector "++).).showsPrec 10)<$>eigSp
where eigSp = eigenSpan' m
instance (HasMetric v, Scalar v ~ Double, Show v) => Show (HerMetric' v) where
showsPrec p m
| null eigSp = showString "zeroV"
| otherwise = showParen (p>5)
. foldr1 ((.) . (.(" ^+^ "++)))
$ ((("projector' "++).).showsPrec 10)<$>eigSp
where eigSp = eigenSpan m
linMapAsTensProd :: (FiniteDimensional v, FiniteDimensional w, Scalar v~Scalar w)
=> v:-*w -> DualSpace v ⊗ w
linMapAsTensProd f = DensTensProd $ asPackedMatrix f
linMapFromTensProd :: (FiniteDimensional v, FiniteDimensional w, Scalar v~Scalar w)
=> DualSpace v ⊗ w -> v:-*w
linMapFromTensProd (DensTensProd m) = linear $
asPackedVector >>> HMat.app m >>> fromPackedVector
(⊗) :: (HasMetric v, FiniteDimensional w, Scalar v ~ s, Scalar w ~ s)
=> w -> DualSpace v -> Linear s v w
w ⊗ v' = DenseLinear $ HMat.outer wDecomp v'Decomp
where wDecomp = asPackedVector w
v'Decomp = asPackedVector v'
outerProducts :: (HasMetric v, FiniteDimensional w, Scalar v ~ s, Scalar w ~ s)
=> [(w, DualSpace v)] -> Linear s v w
outerProducts [] = zeroV
outerProducts pds = DenseLinear $ HMat.fromColumns (asPackedVector.fst<$>pds)
HMat.<> HMat.fromRows (asPackedVector.snd<$>pds)
instance ∀ v w s . ( HasMetric v, FiniteDimensional w
, Show (DualSpace v), Show w, Scalar v ~ s, Scalar w ~ s )
=> Show (Linear s v w) where
showsPrec p f = showParen (p>9) $ ("outerProducts "++)
. shows [ (w, v' :: DualSpace v)
| (v,v') <- zip completeBasisValues completeBasisValues
, let w = f $ v ]