packages feed

clif 0.1.0.0 → 0.1.1.0

raw patch · 10 files changed

+246/−30 lines, 10 filesdep ~QuickCheckdep ~basedep ~tastyPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: QuickCheck, base, tasty, tasty-quickcheck, tasty-th, time

API changes (from Hackage documentation)

+ Clif.Algebra: toList :: Clif b a -> [([b], a)]
+ Clif.Internal: toList :: Clif b a -> [([b], a)]
- Clif.Basis: class (Ord b, Num a) => Basis b a where canonical (b, a) = [orderOrthoBasis [] b a] basisMul a b = [orthoMul a b]
+ Clif.Basis: class (Ord b, Num a) => Basis b a

Files

clif.cabal view
@@ -1,12 +1,12 @@ name:                clif-version:             0.1.0.0+version:             0.1.1.0 synopsis:            A Clifford algebra number type for Haskell description:         Clif is a library for symbolic and numeric computations on Clifford algebras using Haskell. It is general enough to handle finite and infinite-dimensional Clifford algebras arising from arbitrary bilinear forms, within limitations of computability. To get started, read "Clif.Tutorial". license:             MIT license-file:        LICENSE author:              Matti Eskelinen maintainer:          matti.a.eskelinen@gmail.com-copyright:           (c) 2016-2017 Matti Eskelinen +copyright:           (c) 2016-2018 Matti Eskelinen category:            Math, Algebra build-type:          Simple -- extra-source-files:  @@ -19,7 +19,7 @@ source-repository this   type:     git   location: git@github.com:maaleske/clif.git-  tag:      0.1.0.0+  tag:      0.1.1.0  library   exposed-modules:     Clif@@ -28,14 +28,14 @@                      , Clif.Internal                      , Clif.Arbitrary                      , Clif.Tutorial-  other-modules:       +  other-modules:   ghc-options:         -Wall   other-extensions:    FlexibleInstances                      , MultiParamTypeClasses                      , GeneralizedNewtypeDeriving                      , DeriveGeneric-  build-depends:       base >=4.8 && <4.10-                     , QuickCheck >=2.8 && <2.9+  build-depends:       base >=4.8 && <4.12+                     , QuickCheck >=2.8 && <2.12                      , containers >=0.5 && <0.6   hs-source-dirs:      src   default-language:    Haskell2010@@ -43,15 +43,17 @@ test-suite Tests   hs-source-dirs:      tests   main-is:             tests.hs+  other-modules:       ClifTests+                     , BasisTests+                     , InternalTests   ghc-options:         -Wall   type:                exitcode-stdio-1.0   build-depends:       clif-                     , base >=4.8 && <4.10+                     , base >=4.8 && <4.12                      , containers >=0.5 && <0.6-                     , QuickCheck >=2.8 && <2.9-                     , tasty-                     , tasty-th-                     , tasty-quickcheck+                     , tasty >=0.11 && <1.1+                     , tasty-th >= 0.1 && <0.2+                     , tasty-quickcheck >= 0.8   default-language:    Haskell2010  Benchmark bench-clifProduct@@ -60,6 +62,6 @@   ghc-options:         -Wall -O2   type:                exitcode-stdio-1.0   build-depends:       clif-                     , base>=4.8 && <4.10-                     , time>=1.5 && <1.8+                     , base >=4.8 && <4.12+                     , time >=1.5 && <1.10   default-language:    Haskell2010
src/Clif.hs view
@@ -9,6 +9,7 @@ This helper module exports the main modules needed to construct and operate on Clifford algebra values. If you just want to use the library for computations, this should be all you need. To get started, read "Clif.Tutorial".  -}+{-# LANGUAGE Safe #-} module Clif     (      -- * Construction of a basis
src/Clif/Algebra.hs view
@@ -11,6 +11,7 @@ See /The inner products of geometric algebra/ by Leo Dorst for a concise explanation of the different inner products. -} {-# LANGUAGE +    Safe,     FlexibleInstances,     MultiParamTypeClasses   #-}@@ -23,6 +24,7 @@     , blade, (*:)     , vec     , fromList+    , toList       -- * Geometric algebra operations     , grade, rev@@ -89,7 +91,10 @@ -- prop> hodge (E <$> "abc") $ blade [E 'b'] 1 == blade (E <$> "ac") 1  -- hodge :: (Eq a, Basis b a) => [b] -> Clif b a -> Clif b a-hodge = flip (*) . flip blade (-1)+hodge bs = flip (*) (sgnm * i)+    where +        i = blade bs 1   -- pseudoscalar times the sign of the metric+        sgnm = i * rev i -- sign of the metric calculated from the unit pseudoscalar  -- | Projection of Clif x in the direction of Clif y, defined as --
src/Clif/Arbitrary.hs view
@@ -9,6 +9,7 @@ This module provides (orphan) Arbitrary instances and various other generators for creating random 'Clif's and 'Basis' elements using "Test.QuickCheck".  -}+{-# LANGUAGE Safe #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Clif.Arbitrary      (
src/Clif/Basis.hs view
@@ -15,8 +15,9 @@ While not strictly necessary for the abstraction, functions 'canonical' and 'basisMul' are included in the class with respective default implementations ('orderOrthoBasis' and 'orthoMul') in order to provide an easy way to override them using a more efficient implementation for a user-supplied basis. Note that the default implementations are only valid for a diagonal metric; Use 'orderBasis' and 'nonOrthoMul' if you define a non-diagonal metric.  -}-{-# LANGUAGE -    MultiParamTypeClasses+{-# LANGUAGE+    Safe+  , MultiParamTypeClasses   , FlexibleInstances   , DeriveGeneric    #-}@@ -93,9 +94,8 @@ -- Note that this relation holds only for a basis with a diagonal bilinear form, for others use the more general (albeit slower) 'orderBasis'. orderOrthoBasis, backOrderOrtho :: Basis b a => [b] -> [b] -> a -> ([b], a) orderOrthoBasis pre (a:b:rest) c-     -- Vectors are in order: move on.-    | a < b  = orderOrthoBasis (pre ++ [a]) (b:rest) c+    | a < b  = orderOrthoBasis (a:pre) (b:rest) c      -- Same vector: simplify using the metric signature for the vector     | a == b = backOrderOrtho pre rest $ metric a b * c@@ -103,11 +103,11 @@     -- Wrong order: flip and back up one step. Since the vectors are     -- orthogonal, we flip the sign of the geometric product.     | a > b  = backOrderOrtho pre (b:a:rest) (-c)-orderOrthoBasis pre rest c = (pre ++ rest, c)+orderOrthoBasis pre rest c = (reverse (rest ++ pre), c)  -- Backwards gnome sort for orthogonal basis-backOrderOrtho []  rest c = orderOrthoBasis []         rest            c-backOrderOrtho pre rest c = orderOrthoBasis (init pre) (last pre:rest) c+backOrderOrtho (a:pre) rest c = orderOrthoBasis pre (a:rest) c+backOrderOrtho []  rest c = orderOrthoBasis [] rest c   -- | Canonical (ordered) form of a scaled basis blade of vectors
src/Clif/Internal.hs view
@@ -15,9 +15,11 @@ As development continues, some of the definitions here may be exported from the other modules. Comments and suggestions are welcomed.  -}-{-# LANGUAGE -    GeneralizedNewtypeDeriving+{-# LANGUAGE+    Safe+  , DeriveFunctor   #-} +{-# OPTIONS_HADDOCK not-home #-} module Clif.Internal where  import Clif.Basis@@ -40,7 +42,6 @@ -- -- >>> fromList [([], 42), ([E 1, E 2], 1)] -- 42 *: [] + 1 *: [E 1,E 2]--- fromList :: (Eq a, Basis b a) => [([b], a)] -> Clif b a fromList = Clif . canon' . M.fromListWith (+) @@ -82,6 +83,12 @@     recip v | isScalar v = fmap recip v             | otherwise  = revM . recip $ revM v                 where revM = gMul (rev v)++-- * Deconstruction++-- | Return a list of the blades and coefficients of a Clif. Note that 'toList' is not an inverse of 'fromList' due to nonuniquess of zeros in the current implementation.+toList :: Clif b a -> [([b], a)]+toList = M.toList . unClif  -- * Operations 
src/Clif/Tutorial.hs view
@@ -78,7 +78,7 @@         In that case, @'T' a@ for any @'Char' a@ would have the same signature as the character \'t\' in our definition. However, defining a metric for the plain 'Char' is useful for demonstration, since it provides us with pretty printouts.      -     - Note that as in the definition for @'Basis' ('Lorentzian' b) a@, we do not actually need to fix the field @ə@ apart from the 'Num' constraint while defining the basis. +     - Note that as in the definition for @'Basis' ('Lorentzian' b) a@, we do not actually need to fix the field @a@ apart from the 'Num' constraint while defining the basis.        - If the metric is not diagonal (@'metric' a b /= 0@ for some @a /= b@), we need to replace the default implementations of the functions 'canonical' and 'basisMul' in the instance with more general implementations. See "Clif.Basis" for details.      @@ -87,23 +87,31 @@  {- $construction -    Using our 'Char' basis, we can start constructing values of type @'Clif' 'Char' 'Double'@ using the provided constructors. We can start by introducing the vectors needed to represent __Cl__(1,3)(R):+    Using our 'Char' basis, we can start constructing values of type @'Clif' 'Char' 'Double'@ using the provided constructors. We can start by introducing the vectors needed to represent __Cl__(1,3)(R) using the 'vec' constructor:  > t = vec 't' 1 > x = vec 'x' 1 > y = vec 'y' 1 > z = vec 'z' 1 -    To make it specific that we are working in __Cl__(1,3)(R), we can define the /pseudoscalar/ @txyz@. All the following definitions are equivalent:+    To make it specific that we are working in __Cl__(1,3)(R), we can define the /pseudoscalar/ @txyz@. This can be done in a number of ways:   +    - by multiplying our existing 'Clif's together using either the Clifford or 'wedge' products:+         > i = t * x * y * z+> i = t /\ x  /\ y /\ z -> i = blade "txyz" 1+    - by using the 'blade' constructor or its infix synonym '*:' to explicitly create a blade consisting of the same basis vectors: +> i = blade "txyz" 1 > i = 1 *: "txyz"     -    Note that the last form using the infix operator '(*:)' is used for the 'Show' instance to produce concise output.-    p+    Note that the last form using the infix operator '*:' is used for the 'Show' instance to produce concise output. Each of the previous definitions will yield the following output in GHCI for i:++>>> i+1.0 *: "txyz"+    +     Due to the 'Num' instance, we do not usually need to explicitly embed scalars. If we want to be specific, we can write  > answer = 42 :: Clif Char Double
+ tests/BasisTests.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE TemplateHaskell #-}+module BasisTests (tests) where+import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.TH++import Clif.Basis+import Clif.Arbitrary++-- Utilities++-- Save some characters+type EInt  = Euclidean Integer+--type LInt  = Lorentzian Integer++-- Counts the swaps needed the reverse a list+swaps :: Int -> Int+swaps = (map swaps' [0..] !!)+    where swaps' 0 = 0+          swaps' 1 = 0+          swaps' n = n - 1 + swaps' (n - 1)++-- Properties+++-- Properties for orderBasis and orderOrthoBasis++prop_orderBasis_is_freeMul_for_ordered :: Property+prop_orderBasis_is_freeMul_for_ordered = forAll ascLists orderBasis_is_freeMul ++orderBasis_is_freeMul :: ([EInt],[EInt]) -> NonZero Integer -> NonZero Integer -> Bool+orderBasis_is_freeMul (a,b) (NonZero c) (NonZero d) = [freeMul (a, c) (b, d)] == orderBasis [(a,c)] b d++prop_orderOrthoBasis_is_freeMul_for_ordered :: Property+prop_orderOrthoBasis_is_freeMul_for_ordered = forAll ascLists orderOrthoBasis_is_freeMul++orderOrthoBasis_is_freeMul :: ([EInt],[EInt]) -> NonZero Integer -> NonZero Integer -> Bool+orderOrthoBasis_is_freeMul (a,b) (NonZero c) (NonZero d) = freeMul (a, c) (b, d) == orderOrthoBasis (reverse a) b (c*d)++prop_orderBasis_reverse_ordered_is_nswaps :: Property+prop_orderBasis_reverse_ordered_is_nswaps = forAll ascList orderBasis_reverse_ordered_is_nswaps++orderBasis_reverse_ordered_is_nswaps :: [EInt] -> NonZero Integer -> Bool+orderBasis_reverse_ordered_is_nswaps a (NonZero b) = [(a, (-1)^swaps (length a) * b)] == orderBasis [] (reverse a) b++prop_orderOrthoBasis_reverse_ordered_is_nswaps :: Property+prop_orderOrthoBasis_reverse_ordered_is_nswaps = forAll ascList orderOrthoBasis_reverse_ordered_is_nswaps ++orderOrthoBasis_reverse_ordered_is_nswaps :: [EInt] -> NonZero Integer -> Bool+orderOrthoBasis_reverse_ordered_is_nswaps a (NonZero b) = (a, (-1)^swaps (length a) * b) == orderOrthoBasis [] (reverse a) b+++-- Properties for orthoMul and nonOrthoMul++prop_ortho_nonortho_id_diag_metric :: ([EInt], Integer) -> ([EInt], Integer) -> Bool+prop_ortho_nonortho_id_diag_metric a b = +    filter ((/=(0::Integer)) . snd) [orthoMul a b] == nonOrthoMul a b++-- Template Haskell to generate a TestTree for Tasty from each prop_* property+tests :: TestTree+tests = $(testGroupGenerator)
+ tests/ClifTests.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE TemplateHaskell #-}+module ClifTests (tests) where+import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.TH++import Clif+import Clif.Arbitrary++-- * Utilities++-- Save some characters+type EClif = Clif (Euclidean Integer) Integer+--type LClif = Clif (Lorentzian Integer) Integer++-- Repeat a constraint for multiple (2 or 3) parameters+forAll2 :: (Show a, Testable b) => Gen a -> (a -> a -> b) -> Property+forAll2 gen f = forAll gen (\a -> forAll gen $ f a)++forAll3 :: (Show a, Testable b) => Gen a -> (a -> a -> a -> b) -> Property+forAll3 gen f = forAll gen (\a -> forAll gen (\b -> forAll gen $ f a b) )++-- Limit the size of Clifs for some tests+sizeLimit :: Int+sizeLimit = 20++smallClif :: Gen (EClif)+smallClif = resize sizeLimit arbitrary++-- * Identities for contractions +-- See "The inner products of geometric algebra" by Dorst++-- Rewriting rule applies for the left contraction of a wedge product+prop_rewriting_rule :: Int -> Int -> Int -> Property+prop_rewriting_rule k l m = forAll (kBlade k) $ \a -> forAll (kBlade l) $ \b -> forAll (kBlade m) $ rewriting_rule a b++rewriting_rule :: EClif -> EClif -> EClif -> Bool+rewriting_rule u v w = (u `wedge` v) `lContract` w == u `lContract` (v `lContract` w)++-- Sum of contractions equals the sums of scalar and dot product+prop_contractions_eq_scalar_products :: Property +prop_contractions_eq_scalar_products = forAll2 smallClif contractions_eq_scalar_products++contractions_eq_scalar_products :: EClif -> EClif -> Bool+contractions_eq_scalar_products a b = a `lContract` b + a `rContract` b == a `scalarProd` b + a `dot` b++-- Scalar product of a wedge from the right is the scalar product of a left contraction from the right+prop_lContract_duality :: Property+prop_lContract_duality = forAll3 (smallClif) lContract_duality++lContract_duality :: EClif -> EClif -> EClif -> Bool+lContract_duality u v w = (u `wedge` v) `scalarProd` w == u `scalarProd` (v `lContract` w)++-- Same for the right contraction+prop_rContract_duality :: Property+prop_rContract_duality = forAll3 (smallClif) rContract_duality++rContract_duality :: EClif -> EClif -> EClif -> Bool+rContract_duality u v w = u `scalarProd` (v `wedge` w) == (u `rContract` v) `scalarProd` w++-- Left contraction of reverse clifs is the reverse of a right contraction+prop_revContraction :: Property+prop_revContraction = forAll2 (smallClif) revContraction++revContraction :: EClif -> EClif -> Bool+revContraction u v = rev (u `rContract` v) == rev v `lContract` rev u++-- Scalar product is invariant w.r.t. reversion+prop_scalarProdReversibility :: Property+prop_scalarProdReversibility = forAll2 (smallClif) scalarProdReversibility++scalarProdReversibility :: EClif -> EClif -> Bool+scalarProdReversibility u v = scalarProd u v == scalarProd (rev u) (rev v)++-- Template Haskell to generate a TestTree for Tasty from each prop_* property+tests :: TestTree+tests = $(testGroupGenerator)
+ tests/InternalTests.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE TemplateHaskell #-}+module InternalTests (tests) where+import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.TH++import Data.Map (Map)+import Clif.Basis+import Clif.Internal+import Clif.Arbitrary()++-- * Construction / deconstruction tests++-- fromList . toList == id+prop_toFrom :: Clif (Euclidean Integer) Integer -> Bool+prop_toFrom x = x == (fromList . toList) x++-- toList . fromList == id+-- TODO: Needs fix for unique zero+--prop_fromTo :: [([Euclidean Integer], Integer)] -> Bool+--prop_fromTo x = x == (toList . fromList) x++-- * Properties of the Clif type and instances++-- vec should equal a blade of 1 vector+prop_vec_blade :: Euclidean Integer -> Integer -> Bool+prop_vec_blade e s = vec e s == blade [e] s ++-- Equality should be considered on canonical form for Clifs+prop_eq_on_canon :: Clif (Euclidean Integer) Integer -> Bool+prop_eq_on_canon a = canon a == a++-- canon' should be idempotent (on the implementation level)+prop_canon_idempotent :: Map [Euclidean Integer] Integer -> Bool+prop_canon_idempotent a = canon' (canon' a) == canon' a++-- rev' should be involutive+prop_rev_inv :: Map [Integer] Integer -> Bool+prop_rev_inv a = rev' (rev' a) == a++-- isScalar should be True for these+prop_isScalar_scalar :: Integer -> Bool +prop_isScalar_scalar a = isScalar $ blade (mempty :: [Euclidean Integer]) a++prop_isScalar_vecProd :: Euclidean Integer -> Integer -> Bool+prop_isScalar_vecProd e s = let v = vec e s in isScalar $ v * v++-- isScalar should be False for these+prop_isScalar_vec :: Euclidean Integer -> NonZero Integer -> Bool+prop_isScalar_vec e (NonZero s) = not . isScalar $ vec e s++-- Template Haskell to generate a TestTree for Tasty from each prop_* property+tests :: TestTree+tests = $(testGroupGenerator)