algebra-3.0: src/Numeric/Coalgebra/Geometric.hs
{-# LANGUAGE
MultiParamTypeClasses,
GeneralizedNewtypeDeriving,
BangPatterns,
TypeOperators,
DeriveDataTypeable,
FlexibleInstances,
TypeFamilies,
PatternGuards,
UndecidableInstances,
ScopedTypeVariables #-}
module Numeric.Coalgebra.Geometric
(
-- * Geometric coalgebra primitives
BasisCoblade(..)
, Comultivector
-- * Operations over an eigenbasis
, Eigenbasis(..)
, Eigenmetric(..)
, Euclidean(..)
-- * Grade
, grade
, filterGrade
-- * Inversions
, reverse
, gradeInversion
, cliffordConjugate
-- * Products
, geometric
, outer
-- * Inner products
, contractL
, contractR
, hestenes
, dot
, liftProduct
) where
import Control.Monad (mfilter)
import Data.Bits
import Data.Functor.Representable.Trie
import Data.Word
import Data.Data
import Data.Ix
import Data.Array.Unboxed
import Numeric.Algebra
import Prelude hiding ((-),(*),(+),negate,reverse)
-- a basis vector for a simple geometric coalgebra with the Euclidean inner product
newtype BasisCoblade m = BasisCoblade { runBasisCoblade :: Word64 } deriving
( Eq,Ord,Num,Bits,Enum,Ix,Bounded,Show,Read,Real,Integral
, Additive,Abelian,LeftModule Natural,RightModule Natural,Monoidal
, Multiplicative,Unital,Commutative
, Semiring,Rig
, DecidableZero,DecidableAssociates,DecidableUnits
)
instance HasTrie (BasisCoblade m) where
type BaseTrie (BasisCoblade m) = BaseTrie Word64
embedKey = embedKey . runBasisCoblade
projectKey = BasisCoblade . projectKey
-- A metric space over an eigenbasis
class Eigenbasis m where
euclidean :: proxy m -> Bool
antiEuclidean :: proxy m -> Bool
v :: m -> BasisCoblade m
e :: Int -> m
-- assuming n /= 0, find the index of the least significant set bit in a basis blade
lsb :: BasisCoblade m -> Int
lsb n = fromIntegral $ ix ! shiftR ((n .&. (-n)) * 0x07EDD5E59A4E28C2) 58
where
-- a 64 bit deBruijn multiplication table
ix :: UArray (BasisCoblade m) Word8
ix = listArray (0, 63)
[ 63, 0, 58, 1, 59, 47, 53, 2
, 60, 39, 48, 27, 54, 33, 42, 3
, 61, 51, 37, 40, 49, 18, 28, 20
, 55, 30, 34, 11, 43, 14, 22, 4
, 62, 57, 46, 52, 38, 26, 32, 41
, 50, 36, 17, 19, 29, 10, 13, 21
, 56, 45, 25, 31, 35, 16, 9, 12
, 44, 24, 15, 8, 23, 7, 6, 5
]
class (Ring r, Eigenbasis m) => Eigenmetric r m where
metric :: m -> r
type Comultivector r m = Covector r (BasisCoblade m)
-- Euclidean basis, we can work with basis vectors for euclidean spaces of up to 64 dimensions without
-- expanding the representation of our basis vectors
newtype Euclidean = Euclidean Int deriving
( Eq,Ord,Show,Read,Num,Ix,Enum,Real,Integral
, Data,Typeable
, Additive,LeftModule Natural,RightModule Natural,Monoidal,Abelian,LeftModule Integer,RightModule Integer,Group
, Multiplicative,TriviallyInvolutive,InvolutiveMultiplication,InvolutiveSemiring,Unital,Commutative
, Semiring,Rig,Ring
)
instance HasTrie Euclidean where
type BaseTrie Euclidean = BaseTrie Int
embedKey (Euclidean i) = embedKey i
projectKey = Euclidean . projectKey
instance Eigenbasis Euclidean where
euclidean _ = True
antiEuclidean _ = False
v n = shiftL 1 (fromIntegral n)
e = fromIntegral
instance Ring r => Eigenmetric r Euclidean where
metric _ = one
grade :: BasisCoblade m -> Int
grade = fromIntegral . count 5 . count 4 . count 3 . count 2 . count 1 . count 0 where
count c x = (x .&. mask) + (shiftR x p .&. mask) where
p = shiftL 1 c
mask = (-1) `div` (shiftL 1 p + 1)
m1powTimes :: (Bits n, Group r) => n -> r -> r
m1powTimes n r
| (n .&. 1) == 0 = r
| otherwise = negate r
reorder :: Group r => BasisCoblade m -> BasisCoblade m -> r -> r
reorder a0 b = m1powTimes $ go 0 (shiftR a0 1)
where
go !acc 0 = acc
go acc a = go (acc + grade (a .&. b)) (shiftR a 1)
-- <A>_k
filterGrade :: Monoidal r => BasisCoblade m -> Int -> Comultivector r m
filterGrade b k | grade b == k = zero
| otherwise = return b
instance Eigenmetric r m => Coalgebra r (BasisCoblade m) where
comult f n m = scale (n .&. m) $ reorder n m $ f $ xor n m where
scale b
| euclidean n = id
| otherwise = (go one b *)
go :: Eigenmetric r m => r -> BasisCoblade m -> r
go acc 0 = acc
go acc n' | b <- lsb n'
, m' <- metric (e b :: m)
= go (acc*m') (clearBit n' b)
instance Eigenmetric r m => CounitalCoalgebra r (BasisCoblade m) where
counit f = f (BasisCoblade zero)
-- instance Group r => InvertibleModule r BasisCoblade where
-- reversion (A~) is an involution for the outer product
reverse :: Group r => BasisCoblade m -> Comultivector r m
reverse b = shiftR (g * (g - 1)) 1 `m1powTimes` return b where
g = grade b
cliffordConjugate :: Group r => BasisCoblade m -> Comultivector r m
cliffordConjugate b = shiftR (g * (g + 1)) 1 `m1powTimes` return b where
g = grade b
-- A^
gradeInversion :: Group r => BasisCoblade m -> Comultivector r m
gradeInversion b = grade b `m1powTimes` return b
geometric :: Eigenmetric r m => BasisCoblade m -> BasisCoblade m -> Comultivector r m
geometric = multM
outer :: Eigenmetric r m => BasisCoblade m -> BasisCoblade m -> Comultivector r m
outer m n | m .&. n == 0 = geometric m n
| otherwise = zero
-- A _| B
-- grade (A _| B) = grade B - grade A
contractL :: Eigenmetric r m => BasisCoblade m -> BasisCoblade m -> Comultivector r m
contractL a b
| ga Prelude.> gb = zero
| otherwise = mfilter (\r -> grade r == gb - ga) (geometric a b)
where
ga = grade a
gb = grade b
-- A |_ B
-- grade (A |_ B) = grade A - grade B
contractR :: Eigenmetric r m => BasisCoblade m -> BasisCoblade m -> Comultivector r m
contractR a b
| ga Prelude.< gb = zero
| otherwise = mfilter (\r -> grade r == ga - gb) (geometric a b)
where
ga = grade a
gb = grade b
-- the modified Hestenes' product
dot :: Eigenmetric r m => BasisCoblade m -> BasisCoblade m -> Comultivector r m
dot a b = mfilter (\r -> grade r == abs(grade a - grade b)) (geometric a b)
-- Hestenes' inner product
-- if 0 /= grade a <= grade b then
-- dot a b = hestenes a b = leftContract a b
hestenes :: Eigenmetric r m => BasisCoblade m -> BasisCoblade m -> Comultivector r m
hestenes a b
| ga == 0 || gb == 0 = zero
| otherwise = mfilter (\r -> grade r == abs(ga - gb)) (geometric a b)
where
ga = grade a
gb = grade b
liftProduct :: (BasisCoblade m -> BasisCoblade m -> Comultivector r m) -> Comultivector r m -> Comultivector r m -> Comultivector r m
liftProduct f ma mb = do
a <- ma
b <- mb
f a b