{-# 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 :: (Num n, 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) -- _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