module Numeric.Coalgebra.Geometric
(
BasisCoblade(..)
, Comultivector
, Eigenbasis(..)
, Eigenmetric(..)
, Euclidean(..)
, grade
, filterGrade
, reverse
, gradeInversion
, cliffordConjugate
, geometric
, outer
, contractL
, contractR
, hestenes
, dot
, liftProduct
) where
import Control.Monad (mfilter)
import Data.Bits
import Data.Word
import Data.Data
import Data.Ix
import Data.Array.Unboxed
import Numeric.Algebra
import Prelude hiding ((),(*),(+),negate,reverse)
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
)
class Eigenbasis m where
euclidean :: proxy m -> Bool
antiEuclidean :: proxy m -> Bool
v :: m -> BasisCoblade m
e :: Int -> m
lsb :: BasisCoblade m -> Int
lsb n = fromIntegral $ ix ! shiftR ((n .&. (n)) * 0x07EDD5E59A4E28C2) 58
where
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)
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 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)
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)
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
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
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
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
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 :: 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