-- | Exterior algebra where the variable set -- looks like @{x_1, x_2, ... , x_N}@ -- -- See {-# LANGUAGE BangPatterns, TypeFamilies, DataKinds, KindSignatures, ScopedTypeVariables, FlexibleContexts, StandaloneDeriving #-} module Math.Algebra.Polynomial.Exterior.Indexed ( ExtAlg(..) , unExtAlg , polyVar , nOfExtAlg , ZExtAlg , QExtAlg , embed , Ext(..) ) where -------------------------------------------------------------------------------- import Data.Maybe import Data.List import Data.Array.Unboxed import Data.Typeable import GHC.TypeLits import Data.Proxy import Data.Foldable as F import qualified Math.Algebra.Polynomial.FreeModule as ZMod import Math.Algebra.Polynomial.FreeModule ( FreeMod , FreeModule(..) ) -- , ZMod , QMod ) import Math.Algebra.Polynomial.Monomial.Exterior.Indexed import Math.Algebra.Polynomial.Class import Math.Algebra.Polynomial.Pretty import Math.Algebra.Polynomial.Misc -------------------------------------------------------------------------------- -- * Exterior algebra -- | An exterior polynomial in with a given coefficient ring. -- -- It is also indexed by the (shared) /name/ of the variables and the /number of/ -- variable. For example @ExtAlgn Rational "x" 3@ the type of polynomials in the -- variables @x1, x2, x3@ with rational coefficients. newtype ExtAlg (coeff :: *) (var :: Symbol) (n :: Nat) = ExtAlg (FreeMod coeff (Ext var n)) deriving (Eq,Ord,Show,Typeable) unExtAlg :: ExtAlg c v n -> FreeMod c (Ext v n) unExtAlg (ExtAlg p) = p -- | Name of the variables polyVar :: KnownSymbol var => ExtAlg c var n -> String polyVar = symbolVal . varProxy where varProxy :: ExtAlg c var n -> Proxy var varProxy _ = Proxy -- | Number of variables nOfExtAlg :: KnownNat n => ExtAlg c var n -> Int nOfExtAlg = fromInteger . natVal . natProxy where natProxy :: ExtAlg c var n -> Proxy n natProxy _ = Proxy instance FreeModule (ExtAlg c v n) where type BaseF (ExtAlg c v n) = Ext v n type CoeffF (ExtAlg c v n) = c toFreeModule = unExtAlg fromFreeModule = ExtAlg -------------------------------------------------------------------------------- type ZExtAlg = ExtAlg Integer type QExtAlg = ExtAlg Rational -------------------------------------------------------------------------------- instance (Ring c, KnownSymbol v, KnownNat n) => AlmostPolynomial (ExtAlg c v n) where type CoeffP (ExtAlg c v n) = c type MonomP (ExtAlg c v n) = Ext v n type VarP (ExtAlg c v n) = Index zeroP = ExtAlg ZMod.zero isZeroP = ZMod.isZero . unExtAlg oneP = ExtAlg (ZMod.generator emptyExt) fromListP = ExtAlg . ZMod.fromList toListP = ZMod.toList . unExtAlg variableP = ExtAlg . ZMod.generator . variableExt singletonP = error "ExtAlg/singletonP: not implemented (because it is meaningless)" monomP = \m -> ExtAlg $ ZMod.generator m monomP' = \m c -> ExtAlg $ ZMod.singleton m c scalarP = \s -> ExtAlg $ ZMod.singleton emptyExt s addP = \p1 p2 -> ExtAlg $ ZMod.add (unExtAlg p1) (unExtAlg p2) subP = \p1 p2 -> ExtAlg $ ZMod.sub (unExtAlg p1) (unExtAlg p2) negP = ExtAlg . ZMod.neg . unExtAlg mulP = \p1 p2 -> ExtAlg $ ZMod.mulWith'' mulExtCoeff (unExtAlg p1) (unExtAlg p2) coeffOfP = \m p -> ZMod.coeffOf m (unExtAlg p) productP = \ps -> ExtAlg $ ZMod.productWith'' emptyExt mulExtCoeff $ map unExtAlg ps mulByMonomP = \m p -> ExtAlg $ ZMod.mapMaybeBaseCoeff (mulExtCoeff m) (unExtAlg p) -- not injective!!! scaleP = \s p -> ExtAlg $ ZMod.scale s (unExtAlg p) {- evalP = error "ExtAlg/evalP: not implemented" varSubsP = error "ExtAlg/varSubsP: not implemented" coeffSubsP = error "ExtAlg/coeffSubsP: not implemented" subsP = error "ExtAlg/subsP: not implemented" -} instance (Ring c, KnownSymbol v, KnownNat n) => Num (ExtAlg c v n) where fromInteger = scalarP . fromInteger (+) = addP (-) = subP negate = negP (*) = mulP abs = id signum = \_ -> scalarP 1 instance (Ring c, KnownSymbol v, KnownNat n, Pretty (Ext v n)) => Pretty (ExtAlg c v n) where pretty poly@(ExtAlg fm) = if isSignedR (proxyCoeffP poly) then prettyFreeMod' True pretty fm else prettyFreeMod'' pretty pretty fm -- hackety hack hack... instance IsSigned (ExtAlg c v n) where signOf = const (Just Plus) -- So that we can use it again as a coefficient ring instance (Ring c, KnownSymbol v, KnownNat n) => Ring (ExtAlg c v n) where isZeroR = ZMod.isZero . unExtAlg isAtomicR = const False isSignedR = const False absR = id signumR = const (Just Plus) -------------------------------------------------------------------------------- -- | You can always increase the number of variables; -- you can also decrease, if don't use the last few ones. -- -- This will throw an error if you try to eliminate variables which are in fact used. -- To do that, you can instead substitute 1 or 0 into them. -- embed :: (Ring c, KnownNat n, KnownNat m) => ExtAlg c v n -> ExtAlg c v m embed old@(ExtAlg old_fm) = new where n = nOfExtAlg old m = nOfExtAlg new new = ExtAlg $ case compare m n of LT -> ZMod.unsafeMapBase project old_fm EQ -> ZMod.unsafeMapBase keep old_fm GT -> ZMod.unsafeMapBase extend old_fm extend (Ext int) = Ext int keep (Ext int) = Ext int project (Ext int) = let new = Ext int in if isNormalExt new then new else error "Exterior/Indexed/embed: the projected variables are actually used!" --------------------------------------------------------------------------------