{-# LANGUAGE FlexibleContexts #-} ----------------------------------------------------------------------------- -- | -- Module : Numeric.LinearAlgebra.Exterior -- Copyright : (c) Alberto Ruiz 2009 -- License : BSD3 -- Maintainer : Alberto Ruiz -- Stability : experimental -- -- Exterior Algebra. -- -- ----------------------------------------------------------------------------- module Numeric.LinearAlgebra.Exterior ( (/\), inner, leviCivita, dual, (\/), module Numeric.LinearAlgebra.Tensor, asMultivector, fromMultivector ) where import Numeric.LinearAlgebra.Tensor import Numeric.LinearAlgebra.Array.Internal import Numeric.LinearAlgebra.Multivector(Multivector,fromTensor,maxDim,grade) import qualified Numeric.LinearAlgebra.Multivector as MV import Data.List -- import Debug.Trace -- debug x = trace (show x) x interchanges :: (Ord a) => [a] -> Int interchanges ls = sum (map (count ls) ls) where count l p = length $ filter (>p) $ take pel l where Just pel = elemIndex p l signature :: (Num t, Ord a) => [a] -> t signature l | length (nub l) < length l = 0 | even (interchanges l) = 1 | otherwise = -1 gsym f t = mkNArray (dims t) (coords $ sum ts) where ns = map show [1 .. order t] t' = cov $ renameRaw t ns per = permutations ns ts = map (flip renameRaw ns . f . flip reorder t') per -- symmetrize t = gsym id t antisymmetrize t = gsym scsig t where scsig x = scalar (signature (namesR x)) * x fact n = product [1..n] wedge a b = antisymmetrize (a*b) * (recip . fromIntegral) (fact (order a) * fact (order b)) infixl 5 /\ -- | The exterior (wedge) product of two tensors. Obtains the union of subspaces. -- -- Implemented as the antisymmetrization of the tensor product. (/\) :: (Coord t, Fractional t) => Tensor t -> Tensor t -> Tensor t a /\ b = renseq (wedge a' b') where a' = renseq a b' = renseq' b -- levi n = antisymmetrize $ product $ zipWith renameRaw ts is -- where is = map (return.show) [1 .. n] -- ts = map (listTensor [n]) (toLists $ ident n) levi n = listTensor (replicate n n) $ map signature $ sequence (replicate n [1..n]) -- | The full antisymmetric tensor of order n (contravariant version). leviCivita :: Int -> Tensor Double leviCivita = (map levi [0..] !!) infixl 4 \/ -- | The \"meet\" operator. Obtains the intersection of subspaces. -- -- @a \\\/ b = dual (dual a \/\\ dual b)@ (\/) :: Tensor Double -> Tensor Double -> Tensor Double a \/ b = dual (dual a /\ dual b) dual' n t = inner (leviCivita n) t -- | Inner product of a r-vector with the whole space. -- -- @dual t = inner (leviCivita n) t@ dual :: Tensor Double -> Tensor Double dual t | isScalar t = error $ "cannot deduce dimension for dual of a scalar. Use s * leviCivita n" | otherwise = dual' n t where n = case common iDim (dims t) of Just x -> x Nothing -> error $ "dual with different dimensions" -- | Euclidean inner product of multivectors. inner :: (Coord t, Fractional t) => Tensor t -> Tensor t -> Tensor t inner a b | order a < order b = switch (renseq a) * renseq b * k | otherwise = renseq a * switch (renseq b) * k where k = recip . fromIntegral $ fact $ min (order a) (order b) renseq t = renameRaw t (map show [1..order t]) renseq' t = renameRaw t (map ((' ':).show) [1..order t]) isScalar = null . dims -- | Extract a compact multivector representation from a full antisymmetric tensor. -- -- asMultivector = Multivector.'fromTensor'. -- -- (We do not check that the tensor is actually antisymmetric.) asMultivector :: Tensor Double -> Multivector asMultivector = fromTensor -- | Create an explicit antisymmetric 'Tensor' from the components of a Multivector of a given grade. fromMultivector :: Int -> Multivector -> Tensor Double fromMultivector k t = sum $ map f (MV.coords $ grade k t) where f (x,es) = scalar x * foldl1' (/\) (map g es) n = maxDim t g i = vector $ replicate (i-1) 0 ++ 1 : replicate (n-i) 0