module Goal.Geometry.Map.Multilinear (
Tensor (Tensor)
, (>.<)
, (<#>)
, matrixRank
, matrixInverse
, matrixTranspose
, matrixSquareRoot
, matrixApply
, matrixMap
, matrixDiagonalConcatenate
, coordinateTransform
, linearProjection
, toHMatrix
, fromHMatrix
, Affine (Affine)
, splitAffine
, joinAffine
) where
import Prelude hiding (map,minimum,maximum)
import Goal.Core
import Goal.Geometry.Set
import Goal.Geometry.Manifold
import Goal.Geometry.Linear
import Goal.Geometry.Map
import qualified Data.Vector.Storable as C
import qualified Numeric.LinearAlgebra.HMatrix as H
data Affine m n = Affine m n deriving (Eq, Read, Show)
splitAffine :: (Manifold m, Manifold n) => Function c d :#: Affine m n -> (d :#: m, Function c d :#: Tensor m n)
splitAffine aff =
let (Affine m n) = manifold aff
tns = Tensor m n
css = coordinates aff
(mcs,mtxcs) = C.splitAt (dimension m) css
in (fromCoordinates m mcs, fromCoordinates tns mtxcs)
joinAffine :: (Manifold m, Manifold n) => d :#: m -> Function c d :#: Tensor m n -> Function c d :#: Affine m n
joinAffine dm mtx =
let (Tensor m n) = manifold mtx
in fromCoordinates (Affine m n) $ coordinates dm C.++ coordinates mtx
data Tensor m n = Tensor m n deriving (Eq, Read, Show)
toHMatrix :: Manifold n => c :#: Tensor m n -> H.Matrix Double
toHMatrix pq =
let (Tensor _ m) = manifold pq
in H.reshape (dimension m) $ coordinates pq
fromHMatrix :: (Manifold m, Manifold n) => Tensor m n -> H.Matrix Double -> c :#: Tensor m n
fromHMatrix tns = fromCoordinates tns . H.flatten
matrixRank :: (Manifold m, Manifold n) => c :#: Tensor m n -> Int
matrixRank = H.rank . toHMatrix
(>.<) :: (Manifold m, Manifold n) => d :#: m -> c :#: n -> Function (Dual c) d :#: Tensor m n
(>.<) p q = fromHMatrix (Tensor (manifold p) $ manifold q) $ coordinates p `H.outer` coordinates q
(<#>) :: (Manifold m, Manifold n, Manifold o)
=> Function d e :#: Tensor m n -> Function c d :#: Tensor n o -> Function c e :#: Tensor m o
(<#>) p q =
let (Tensor m _) = manifold p
(Tensor _ o) = manifold q
in fromHMatrix (Tensor m o) $ toHMatrix p <> toHMatrix q
matrixSquareRoot :: Manifold m => c :#: Tensor m m -> c :#: Tensor m m
matrixSquareRoot pq = fromHMatrix (manifold pq) . H.sqrtm $ toHMatrix pq
matrixInverse :: (Manifold n, Manifold m) => Function c d :#: Tensor m n -> Function d c :#: Tensor n m
matrixInverse pq =
let Tensor m n = manifold pq
in fromHMatrix (Tensor n m) . H.inv $ toHMatrix pq
matrixTranspose :: (Manifold m, Manifold n) => Function c d :#: Tensor m n -> Function (Dual d) (Dual c) :#: Tensor n m
matrixTranspose pq =
let Tensor m n = manifold pq
in fromHMatrix (Tensor n m) . H.tr $ toHMatrix pq
matrixDiagonalConcatenate :: (Manifold m, Manifold n, Manifold o, Manifold p)
=> Function c d :#: Tensor m n
-> Function e f :#: Tensor o p
-> Function (c,e) (d,f) :#: Tensor (m,o) (n,p)
matrixDiagonalConcatenate cdmn efop =
let (Tensor m n) = manifold cdmn
(Tensor o p) = manifold efop
in fromHMatrix (Tensor (m,o) (n,p)) $ H.diagBlock [toHMatrix cdmn, toHMatrix efop]
coordinateTransform :: Manifold m => [c :#: m] -> Function Cartesian c :#: Tensor m Euclidean
coordinateTransform bss =
fromHMatrix (Tensor (manifold $ head bss) . Euclidean $ length bss) . H.fromColumns $ coordinates <$> bss
linearProjection :: Manifold m => [Cartesian :#: m] -> Function Cartesian Cartesian :#: Tensor m m
linearProjection bss =
let mtx = coordinateTransform bss
mtxt = matrixTranspose mtx
in mtx <#> matrixInverse (mtxt <#> mtx) <#> mtxt
matrixApply :: (Manifold m, Manifold n) => (Function c d :#: Tensor n m) -> (c :#: m) -> d :#: n
matrixApply pq p =
let (Tensor n _) = manifold pq
in fromCoordinates n $ toHMatrix pq H.#> coordinates p
matrixMap :: (Manifold m, Manifold n) => (Function c d :#: Tensor m n) -> [c :#: n] -> [d :#: m]
matrixMap pq ps =
let (Tensor n _) = manifold pq
mtx = toHMatrix pq
xs = H.fromColumns $ coordinates <$> ps
in map (fromCoordinates n) . H.toColumns $ mtx <> xs
instance (Manifold m, Manifold n) => Manifold (Tensor n m) where
dimension (Tensor n m) = dimension m * dimension n
instance (Manifold m, Manifold n) => Map (Tensor m n) where
type Domain (Tensor m n) = n
domain (Tensor _ n) = n
type Codomain (Tensor m n) = m
codomain (Tensor m _) = m
instance (Manifold m, Manifold n) => Apply c d (Tensor m n) where
(>.>) = matrixApply
(>$>) = matrixMap
instance (Manifold m, Manifold n) => Manifold (Affine m n) where
dimension (Affine m n) = dimension m * dimension n + dimension m
instance (Manifold m, Manifold n) => Map (Affine m n) where
type Domain (Affine m n) = n
domain (Affine _ n) = n
type Codomain (Affine m n) = m
codomain (Affine m _) = m
instance (Manifold m, Manifold n) => Apply c d (Affine m n) where
(>.>) p x =
let (b,mtx) = splitAffine p
in mtx >.> x <+> b
(>$>) p xs =
let (b,mtx) = splitAffine p
in map (<+> b) $ mtx >$> xs