packages feed

HaskellForMaths 0.1.5 → 0.1.6

raw patch · 7 files changed

+140/−31 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Math.Algebra.Commutative.GBasis: gb :: (Ord (Monomial ord), Fractional k, Ord k) => [MPoly ord k] -> [MPoly ord k]
+ Math.Algebra.Commutative.MPoly: a :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: b :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: c :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: d :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: s :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: t :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: u :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: v :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: var :: String -> MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: w :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: x :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: x0 :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: x1 :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: x2 :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: x3 :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: y :: MPoly Grevlex Q
+ Math.Algebra.Commutative.MPoly: z :: MPoly Grevlex Q
+ Math.Algebra.Group.PermutationGroup: (~^) :: (Ord t, Show t) => Permutation t -> Permutation t -> Permutation t
+ Math.Algebra.Group.PermutationGroup: _A :: (Integral a) => a -> [Permutation a]
+ Math.Algebra.Group.PermutationGroup: _C :: (Integral a) => a -> [Permutation a]
+ Math.Algebra.Group.PermutationGroup: _S :: (Integral a) => a -> [Permutation a]
+ Math.Algebra.Group.PermutationGroup: order :: (Num a, Ord a) => [a] -> Int
+ Math.Algebra.Group.SchreierSims: elts :: (Ord t, Show t) => [Permutation t] -> [Permutation t]
+ Math.Algebra.Group.SchreierSims: isMember :: (Ord t, Show t) => [Permutation t] -> Permutation t -> Bool
+ Math.Algebra.Group.SchreierSims: order :: (Ord t, Show t) => [Permutation t] -> Integer
+ Math.Combinatorics.Graph: c :: (Integral t) => t -> Graph t
+ Math.Combinatorics.Graph: combinationsOf :: (Integral t) => t -> [a] -> [[a]]
+ Math.Combinatorics.Graph: fromDigits :: (Integral a) => Graph [a] -> Graph a
+ Math.Combinatorics.Graph: k :: (Integral t) => t -> Graph t

Files

HaskellForMaths.cabal view
@@ -1,5 +1,5 @@    Name:                HaskellForMaths
-   Version:             0.1.5
+   Version:             0.1.6
    Category:            Math
    Description:         Math library - combinatorics, group theory, commutative algebra, non-commutative algebra
    License:             BSD3
Math/Algebra/Commutative/GBasis.hs view
@@ -159,6 +159,10 @@ -- Giovini et al
 -- The point of sugar is, given fi, fj, to give an upper bound on the degree of sPoly fi fj without having to calculate it
 -- We can then select by preference pairs with lower sugar, expecting therefore that the s-polys will have lower degree
+
+-- |Given a list of polynomials over a field, return a Groebner basis for the ideal generated by the polynomials
+gb :: (Ord (Monomial ord), Fractional k, Ord k) =>
+     [MPoly ord k] -> [MPoly ord k]
 gb fs =
     -- let fs' = sort $ filter (/=0) fs
     let fs' = sort $ map toMonic $ filter (/=0) fs
Math/Algebra/Commutative/MPoly.hs view
@@ -15,6 +15,9 @@ 
 -- MULTIVARIATE POLYNOMIALS
 
+-- |Type for multivariate polynomials
+-- |ord is a phantom type defining how terms are ordered, r is the type of the ring we are working over
+-- |For example, a common choice will be MPoly Grevlex Q, meaning polynomials over Q with the grevlex term ordering
 newtype MPoly ord r = MP [(Monomial ord,r)] deriving (Eq)
 -- deriving instance (Ord (Monomial ord), Ord r) => Ord (MPoly ord r)
 -- standalone deriving supported from GHC 6.8
@@ -72,8 +75,12 @@     -- recip (MP [(m,c)]) | m == fromInteger 1 = MP [(m, recip c)]
     recip _ = error "MPoly.recip: only supported for (non-zero) constants or monomials"
 
-
+-- |Create a variable with the supplied name.
+-- |By convention, variable names should usually be a single letter followed by none, one or two digits
+var :: String -> MPoly Grevlex Q
 var v = MP [(Monomial $ M.singleton v 1, 1)] :: MPoly Grevlex Q
+
+a, b, c, d, s, t, u, v, w, x, y, z :: MPoly Grevlex Q
 a = var "a"
 b = var "b"
 c = var "c"
@@ -88,6 +95,8 @@ z = var "z"
 
 x_ i = var ("x" ++ show i)
+
+x0, x1, x2, x3 :: MPoly Grevlex Q
 x0 = x_ 0
 x1 = x_ 1
 x2 = x_ 2
@@ -97,12 +106,15 @@ -- convertMP :: Ord (Monomial ord') => MPoly ord k -> MPoly ord' k
 convertMP (MP ts) = MP $ sortBy cmpTerm $ map (first convertM) ts
 
+-- |Convert a polynomial to lex term ordering
 toLex :: MPoly ord k -> MPoly Lex k
 toLex = convertMP
 
+-- |Convert a polynomial to glex term ordering
 toGlex :: MPoly ord k -> MPoly Glex k
 toGlex = convertMP
 
+-- |Convert a polynomial to grevlex term ordering
 toGrevlex :: MPoly ord k -> MPoly Grevlex k
 toGrevlex = convertMP
 
Math/Algebra/Commutative/Monomial.hs view
@@ -30,9 +30,17 @@     -- can only do the above if (*) is doing filter (/=0)
     -- Monomial a / Monomial b = Monomial $ M.filter (/=0) $ M.unionWith (+) a (M.map negate b)
 
+-- |Phantom type representing lex term ordering
 data Lex
+
+-- |Phantom type representing glex term ordering
 data Glex
+
+-- |Phantom type representing grevlex term ordering
 data Grevlex
+
+-- |Phantom type for an elimination term ordering
+-- |In the ordering, xis come before yjs come before zks, but within the xis, or yjs, or zks, grevlex ordering is used 
 data Elim -- a term order for elimination
 
 
Math/Algebra/Group/PermutationGroup.hs view
@@ -45,6 +45,7 @@     where fromCycle xs = zip xs (rotateL xs)
 
 -- |Construct a permutation from a list of cycles
+-- |For example, p [[1,2,3],[4,5]] returns the permutation that sends 1 to 2, 2 to 3, 3 to 1, 4 to 5, 5 to 4
 p :: (Ord a) => [[a]] -> Permutation a
 p cs = fromCycles cs
 -- can't specify in pointfree style because of monomorphism restriction
@@ -82,7 +83,8 @@ instance (Ord a, Show a) => Fractional (Permutation a) where
     recip = inverse
 
--- conjugation
+-- |g ~^ h returns the conjugate of g by h
+(~^) :: (Ord t, Show t) => Permutation t -> Permutation t -> Permutation t
 g ~^ h = h^-1 * g * h
 
 -- commutator
@@ -143,7 +145,8 @@ -- GROUPS
 -- Some standard sequences of groups, and constructions of new groups from old
 
--- |Generators for Cn, the cyclic group of order n
+-- |_C n returns generators for Cn, the cyclic group of order n
+_C :: (Integral a) => a -> [Permutation a]
 _C n | n >= 2 = [p [[1..n]]]
 
 -- D2n, dihedral group of order 2n, symmetry group of n-gon
@@ -155,14 +158,16 @@     b = p [[i,n+1-i] | i <- [1..n `div` 2]]   -- reflection
     -- b = fromPairs $ [(i,n+1-i) | i <- [1..n]] -- reflection
 
--- |Generators for Sn, the symmetric group on [1..n]
+-- |_S n returns generators for Sn, the symmetric group on [1..n]
+_S :: (Integral a) => a -> [Permutation a]
 _S n | n >= 3 = [s,t]
      | n == 2 = [t]
      | n == 1 = []
     where s = p [[1..n]]
           t = p [[1,2]]
 
--- |Generators for An, the alternating group on [1..n]
+-- |_A n returns generators for An, the alternating group on [1..n]
+_A :: (Integral a) => a -> [Permutation a]
 _A n | n > 3 = [s,t]
      | n == 3 = [t]
      | n == 2 = []
@@ -206,12 +211,16 @@ -- Most of these functions will only be efficient for small groups (say |G| < 10000)
 -- For larger groups we will need to use Schreier-Sims and associated algorithms
 
--- |Given generators for a group, return a (sorted) list of all elements of the group
+-- |Given generators for a group, return a (sorted) list of all elements of the group.
+-- |Implemented using a naive closure algorithm, so only suitable for small groups (|G| < 10000)
 elts :: (Num a, Ord a) => [a] -> [a]
 elts gs = closure [1] [ (*g) | g <- gs]
 
 eltsS gs = closureS [1] [ (*g) | g <- gs]
 
+-- |Given generators for a group, return the order of the group (the number of elements).
+-- |Implemented using a naive closure algorithm, so only suitable for small groups (|G| < 10000)
+order :: (Num a, Ord a) => [a] -> Int
 order gs = S.size $ eltsS gs -- length $ elts gs
 
 isMember gs h = h `S.member` eltsS gs -- h `elem` elts gs
@@ -221,15 +230,37 @@ -- The functions graphAuts2 and graphAuts3 return generating sets consisting of successive transversals
 -- In this case, we don't need to run Schreier-Sims to list elements or calculate order
 
+minsupp = head . supp
+
 -- calculate the order of the group, given a "transversal generating set"
 orderTGS tgs =
-    let transversals = map (1:) $ L.groupBy (\g h -> (head . supp) g == (head .supp) h) tgs
+    let transversals = map (1:) $ L.groupBy (\g h -> minsupp g == minsupp h) tgs
     in product $ map L.genericLength transversals
 
 -- list the elts of the group, given a "transversal generating set"
 eltsTGS tgs =
-    let transversals = map (1:) $ L.groupBy (\g h -> (head . supp) g == (head .supp) h) tgs
+    let transversals = map (1:) $ L.groupBy (\g h -> minsupp g == minsupp h) tgs
     in map product $ sequence transversals
+
+-- recover a transversal generating set from a strong generating set
+-- A strong generating set is a generating set gs such that <gs intersect si> = si
+-- ie, its intersection with each successive stabiliser in the chain generates the stabiliser
+tgsFromSgs sgs = concatMap transversal bs where
+    bs = toListSet $ map minsupp sgs
+    transversal b = closure b $ filter ( (b <=) . minsupp ) sgs
+    closure b gs = closure' M.empty (M.fromList [(b, 1)]) where
+        closure' interior boundary
+            | M.null boundary = filter (/=1) $ M.elems interior
+            | otherwise =
+                let interior' = M.union interior boundary
+                    boundary' = M.fromList [(x .^ g, h*g) | (x,h) <- M.toList boundary, g <- gs] M.\\ interior'
+                in closure' interior' boundary'
+-- For example, sgs (_A 5) == [[[1,2,3]],[[2,4,5]],[[3,4,5]]]
+-- So we need all three to generate the first transversal, then the last two to generate the second transversal, etc
+
+orderSGS sgs = product $ map (L.genericLength . fundamentalOrbit) bs where
+    bs = toListSet $ map minsupp sgs
+    fundamentalOrbit b = b .^^ filter ( (b <=) . minsupp ) sgs
 
 
 -- MORE INVESTIGATIONS
Math/Algebra/Group/SchreierSims.hs view
@@ -4,8 +4,10 @@ 
 import qualified Data.List as L
 import Data.Maybe (isNothing, isJust)
+import qualified Data.Set as S
 import qualified Data.Map as M
 import Math.Algebra.Group.PermutationGroup hiding (elts, order, gens, isMember, isSubgp, isNormal, reduceGens, normalClosure, commutatorGp, derivedSubgp)
+import Math.Common.ListSet (toListSet)
 
 
 -- COSET REPRESENTATIVES FOR STABILISER OF A POINT
@@ -68,10 +70,17 @@                      in ss (((b_,t'),s') : bad : bads) (tail goods)
 ss [] goods = goods
 -}
+
+
+-- strong generating set, with implied base from the Ord instance
+sgs gs = toListSet $ concatMap snd $ ss bs gs
+    where bs = toListSet $ concatMap supp gs
+
 -- Find base and strong generating set using Schreier-Sims algorithm
+-- !! This function is poorly named - it actually finds you a base and sets of transversals
 -- This version guarantees to use bases in order
 bsgs gs = bsgs' bs gs
-    where bs = (map head . L.group . L.sort) $ concatMap supp gs
+    where bs = toListSet $ concatMap supp gs
 
 -- This version lets you pass in bases in the order you want them (or [], and it will find its own)
 bsgs' bs gs = map fst $ ss bs gs
@@ -83,7 +92,7 @@ newLevel' b s = ((b,t),s) where t = cosetRepsGx s b
 
 ss bs gs = ss' bs' [level] []
-    where (bs',level) = newLevel bs gs
+    where (bs',level) = newLevel bs $ filter (/=1) gs
 
 ss' bs (bad@((b,t),s):bads) goods =
     let bts = map fst goods
@@ -127,11 +136,16 @@ 
 orderBSGS bts = product (map (toInteger . M.size . snd) bts)
 
-
+-- |Given generators for a group, determine whether a permutation is a member of the group, using Schreier-Sims algorithm
+isMember :: (Ord t, Show t) => [Permutation t] -> Permutation t -> Bool
 isMember gs h = isMemberBSGS (bsgs gs) h
 
+-- |Given generators for a group, return a (sorted) list of all elements of the group, using Schreier-Sims algorithm
+elts :: (Ord t, Show t) => [Permutation t] -> [Permutation t]
 elts gs = eltsBSGS $ bsgs gs
 
+-- |Given generators for a group, return the order of the group (the number of elements), using Schreier-Sims algorithm
+order :: (Ord t, Show t) => [Permutation t] -> Integer
 order [] = 1
 order gs = orderBSGS $ bsgs gs
 
@@ -143,16 +157,6 @@     where hs' = bsgs hs
 
 index gs hs = order gs `div` order hs
-
-
--- strong generating set
--- sgs gs = filter (/=1) $ concatMap (M.elems . snd) $ bsgs gs
--- sgs gs = concatMap snd $ ss [newLevel gs] []
-sgs gs = L.nub $ concatMap snd $ ss bs gs -- bs' [level] []
-    where bs = (map head . L.group . L.sort) $ concatMap supp gs
-          -- (bs',level) = newLevel bs gs
--- !! Note, not properly tested - results not in expected order
--- the sgs calculated during bsgs may be a smaller set (for example, the whole transversal could be powers of a single generator).
 
 
 -- given list of generators, try to find a shorter list
Math/Combinatorics/Graph.hs view
@@ -24,14 +24,19 @@ powerset [] = [[]]
 powerset (x:xs) = let p = powerset xs in p ++ map (x:) p
 
--- subsets of size k (returned in ascending order)
+-- |combinationsOf k xs returns the subsets of xs of size k
+-- |If xs is in ascending order, then the returned list is in ascending order
+combinationsOf :: (Integral t) => t -> [a] -> [[a]]
 combinationsOf 0 _ = [[]]
 combinationsOf _ [] = []
-combinationsOf k (x:xs) = map (x:) (combinationsOf (k-1) xs) ++ combinationsOf k xs
+combinationsOf k (x:xs) | k > 0 = map (x:) (combinationsOf (k-1) xs) ++ combinationsOf k xs
 
 
 -- GRAPH
 
+-- |Datatype for graphs, represented as a list of vertices and a list of edges
+-- |Both the list of vertices and the list of edges, and also the 2-element lists representing the edges,
+-- |are required to be in ascending order, without duplicates
 data Graph a = G [a] [[a]] deriving (Eq,Ord,Show)
 
 -- we require that vs, es, and each individual e are sorted
@@ -39,6 +44,8 @@ 
 isGraph vs es = isSetSystem vs es && all ( (==2) . length) es
 
+-- |Safe constructor for graph from lists of vertices and edges.
+-- |graph (vs,es) checks that vs and es are valid before returning the graph.
 graph (vs,es) | isGraph vs es = G vs es
 -- isValid g = g where g = G vs es
 
@@ -81,27 +88,31 @@ nullGraph :: Graph Int -- type signature needed
 nullGraph = G [] []
 
--- cyclic graph
+-- |The cyclic graph on n vertices
+c :: (Integral t) => t -> Graph t
 c n = graph (vs,es) where
     vs = [1..n]
     es = L.insert [1,n] [[i,i+1] | i <- [1..n-1]]
 -- automorphism group is D2n
 
--- complete graph
+-- |The complete graph on n vertices
+k :: (Integral t) => t -> Graph t
 k n = graph (vs,es) where
     vs = [1..n]
     es = [[i,j] | i <- [1..n-1], j <- [i+1..n]] -- == combinationsOf 2 [1..n]
 -- automorphism group is Sn
 
--- complete bipartite graph
+-- |The complete bipartite graph on m and n vertices
+-- kb :: (Integral t) => t -> t -> Graph t
 kb m n = to1n $ kb' m n
 
+-- |The complete bipartite graph on m left and n right vertices
+-- kb :: (Integral t) => t -> t -> Graph (Either t t)
 kb' m n = graph (vs,es) where
     vs = map Left [1..m] ++ map Right [1..n]
     es = [ [Left i, Right j] | i <- [1..m], j <- [1..n] ]
 -- automorphism group is Sm*Sn (plus a flip if m==n)
 
--- k-cube
 q' k = graph (vs,es) where
     vs = sequence $ replicate k [0,1] -- ptsAn k f2
     es = [ [u,v] | [u,v] <- combinationsOf 2 vs, hammingDistance u v == 1 ]
@@ -158,12 +169,23 @@     vs' = M.elems mapping
     es' = [map (mapping M.!) e | e <- es] -- the edges will already be sorted correctly by construction
 
+-- Given a graph with vertices which are lists of small integers, eg [1,2,3]
+-- return a graph with vertices which are the numbers obtained by interpreting these as digits, eg 123.
+-- The caller is responsible for ensuring that this makes sense (eg that the small integers are all < 10)
+fromDigits :: Integral a => Graph [a] -> Graph a
+fromDigits (G vs es) = graph (vs',es') where
+    vs' = map fromDigits' vs
+    es' = (map . map) fromDigits' es
 
+fromDigits' xs = f (reverse xs) where
+    f (x:xs) = x + 10 * f xs
+    f [] = 0
+
 -- this definition only in versions >0.1.3
 petersen = graph (vs,es) where
     vs = combinationsOf 2 [1..5]
-    es = [ [v1,v2] | v1 <- vs, v2 <- vs, v1 < v2, disjoint v1 v2]
--- == j 5 2 0
+    es = [ [v1,v2] | [v1,v2] <- combinationsOf 2 vs, disjoint v1 v2]
+-- == kneser 5 2 == j 5 2 0
 -- == complement $ lineGraph' $ k 5
 -- == complement $ t' 5
 
@@ -262,12 +284,40 @@ 
 
 -- Generalized Johnson graph, Godsil & Royle p9
+-- Also called generalised Kneser graph, http://en.wikipedia.org/wiki/Kneser_graph
 j v k i | v >= k && k >= i
     = graph (vs,es) where
         vs = combinationsOf k [1..v]
         es = [ [v1,v2] | [v1,v2] <- combinationsOf 2 vs, length (v1 `intersect` v2) == i ]
 -- j v k i is isomorphic to j v (v-k) (v-2k+i), so may as well have v >= 2k
 
-kneser v k | v >= 2*k = j v k 0
+-- kneser v k | v >= 2*k = j v k 0
+kneser n k | 2*k <= n = graph (vs,es) where
+    vs = combinationsOf k [1..n]
+    es = [ [v1,v2] | [v1,v2] <- combinationsOf 2 vs, disjoint v1 v2]
 
 johnson v k | v >= 2*k = j v k (k-1)
+
+
+bipartiteKneser n k | 2*k < n = graph (vs,es) where
+    vs = map Left (combinationsOf k [1..n])
+      ++ map Right (combinationsOf (n-k) [1..n])
+    es = [ [Left u, Right v] | u <- combinationsOf k [1..n], v <- combinationsOf (n-k) [1..n], u `isSubset` v]
+
+desargues1 = bipartiteKneser 5 2
+
+
+-- Generalised Petersen graphs
+-- http://en.wikipedia.org/wiki/Petersen_graph
+gp n k | 2*k < n = toGraph (vs,es) where
+    vs = map Left [0..n-1] ++ map Right [0..n-1]
+    es = (map . map) Left [ [i, (i+1) `mod` n] | i <- [0..n-1] ]
+      ++ [ [Left i, Right i] | i <- [0..n-1] ]
+      ++ (map . map) Right [ [i, (i+k) `mod` n] | i <- [0..n-1] ]
+
+petersen2 = gp 5 2
+prism n = gp n 1
+durer = gp 6 2
+mobiusKantor = gp 8 3
+dodecahedron2 = gp 10 2
+desargues2 = gp 10 3