HaskellForMaths 0.2.0 → 0.2.1
raw patch · 9 files changed
+365/−27 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- HaskellForMaths.cabal +4/−2
- Math/Algebra/Group/RandomSchreierSims.hs +5/−12
- Math/Algebra/Group/SchreierSims.hs +12/−9
- Math/Algebra/Group/Subquotients.hs +196/−0
- Math/Combinatorics/LatinSquares.hs +1/−1
- Math/Projects/MiniquaternionGeometry.hs +1/−1
- Math/Projects/Rubik.hs +88/−2
- Math/Test/TSubquotients.hs +56/−0
- Math/Test/TestAll.hs +2/−0
HaskellForMaths.cabal view
@@ -1,5 +1,5 @@ Name: HaskellForMaths - Version: 0.2.0 + Version: 0.2.1 Category: Math Description: A library of maths code in the areas of combinatorics, group theory, commutative algebra, and non-commutative algebra. The library is mainly intended for educational purposes, but does have efficient implementations of several fundamental algorithms. Synopsis: Combinatorics, group theory, commutative algebra, non-commutative algebra @@ -19,6 +19,7 @@ Math/Test/TGraph.hs, Math/Test/TNonCommutativeAlgebra.hs, Math/Test/TPermutationGroup.hs, + Math/Test/TSubquotients.hs, Math/Test/TestAll.hs Library @@ -29,7 +30,8 @@ Math.Algebra.Commutative.MPoly, Math.Algebra.Commutative.GBasis, Math.Algebra.Field.Base, Math.Algebra.Field.Extension, Math.Algebra.Group.PermutationGroup, Math.Algebra.Group.SchreierSims, - Math.Algebra.Group.RandomSchreierSims, Math.Algebra.Group.StringRewriting, + Math.Algebra.Group.RandomSchreierSims, Math.Algebra.Group.Subquotients, + Math.Algebra.Group.StringRewriting, Math.Algebra.NonCommutative.NCPoly, Math.Algebra.NonCommutative.GSBasis, Math.Algebra.NonCommutative.TensorAlgebra, Math.Combinatorics.Graph, Math.Combinatorics.GraphAuts, Math.Combinatorics.StronglyRegularGraph, Math.Combinatorics.Design, Math.Combinatorics.FiniteGeometry, Math.Combinatorics.Hypergraph,
Math/Algebra/Group/RandomSchreierSims.hs view
@@ -1,4 +1,4 @@-+-- Copyright (c) David Amos, 2009. All rights reserved. module Math.Algebra.Group.RandomSchreierSims where @@ -16,16 +16,7 @@ import Math.Algebra.Group.PermutationGroup import Math.Algebra.Group.SchreierSims (sift, cosetRepsGx, ss') -{---- all the imports below used only for testing-import Math.Algebra.Field.Base-import Math.Algebra.Field.Extension -import Math.Projects.ChevalleyGroup.Classical-import Math.Projects.ChevalleyGroup.Exceptional--}-- testProdRepl = do (r,xs) <- initProdRepl $ _D 10 hs <- replicateM 20 $ nextProdRepl (r,xs) mapM_ print hs@@ -114,8 +105,10 @@ -- recover the base tranversals from the sgs. gs must be an sgs-baseTransversalsSGS gs = [let hs = [h | h <- gs, b <= minsupp h] in (b, cosetRepsGx hs b) | b <- bs]- where bs = toListSet $ concatMap supp gs+-- baseTransversalsSGS gs = [let hs = [h | h <- gs, b <= minsupp h] in (b, cosetRepsGx hs b) | b <- bs]+baseTransversalsSGS gs = [let hs = filter ( (b <=) . minsupp ) gs in (b, cosetRepsGx hs b) | b <- bs]+ where bs = toListSet $ map minsupp gs+ -- where bs = toListSet $ concatMap supp gs -- |Given a strong generating set gs, isMemberSGS gs is a membership test for the group isMemberSGS :: (Ord a, Show a) => [Permutation a] -> Permutation a -> Bool
Math/Algebra/Group/SchreierSims.hs view
@@ -12,7 +12,7 @@ -- COSET REPRESENTATIVES FOR STABILISER OF A POINT --- Given a group G = <gs>, and a point x, find coset representatives for Gx (stabiliser of x) in G +-- Given a group G = <gs>, and a point x, find (right) coset representatives for Gx (stabiliser of x) in G -- In other words, for each x' in the orbit of x under G, we find a g <- G taking x to x' -- The code is similar to the code for calculating orbits, but modified to keep track of the group elements that we used to get there cosetRepsGx gs x = cosetRepsGx' gs M.empty (M.singleton x 1) where @@ -40,15 +40,18 @@ -- SCHREIER-SIMS ALGORITHM -sift bts g = sift' bts g where - sift' _ 1 = Nothing - sift' ((b,t):bts) g = case M.lookup (b .^ g) t of - Nothing -> Just g - -- Nothing -> sift' bts g -- if we allow empty levels - Just h -> sift' bts (g * inverse h) - sift' [] g = if g == 1 then Nothing else Just g +-- Given a list of right transversals for a stabiliser chain, sift a group element through it +-- Note, this version assumes the base is non-redundant +sift _ 1 = Nothing +sift ((b,t):bts) g = case M.lookup (b .^ g) t of + Nothing -> Just g + -- Nothing -> sift bts g -- if we allow redundant levels + Just h -> sift bts (g * inverse h) +sift [] g = Just g -- g == 1 case already caught above -findBase gs = minimum $ concatMap supp gs + +-- findBase gs = minimum $ concatMap supp gs +findBase gs = minimum $ map minsupp gs {- -- Find base and strong generating set using Schreier-Sims algorithm bsgs gs | all (/= 1) gs = map fst $ ss [newLevel gs] []
+ Math/Algebra/Group/Subquotients.hs view
@@ -0,0 +1,196 @@+-- Copyright (c) David Amos, 2009. All rights reserved.++{-# LANGUAGE NoMonomorphismRestriction #-}+-- Because unRight defined point-free++module Math.Algebra.Group.Subquotients where++import qualified Data.List as L+import qualified Data.Map as M++import Math.Common.ListSet+import Math.Algebra.Group.PermutationGroup hiding (ptStab, normalClosure)+import Math.Algebra.Group.SchreierSims (cosetRepsGx)+import Math.Algebra.Group.RandomSchreierSims+++-- Source: Seress, Permutation Group Algorithms+++isLeft (Left _) = True+isLeft (Right _) = False++isRight (Right _) = True+isRight (Left _) = False+++unRight = fromPairs . map (\(Right a, Right b) -> (a,b)) . toPairs++restrictLeft g = fromPairs [(a,b) | (Left a, Left b) <- toPairs g]+-- note that this is doing a filter - taking only the left part of the action - and a map, unLefting+++-- pointwise stabiliser of xs+ptStab gs delta = map unRight $ dropWhile (isLeft . minsupp) $ sgs gs' where+ gs' = [ (fromPairs . map (\(a,b) -> (lr a, lr b)) . toPairs) g | g <- gs]+ lr x = if x `elem` delta then Left x else Right x+++{-+-- !! NEXT TWO FUNCTIONS NOT TESTED+-- Need some meaningful examples of homomorphisms+-- eg Sn -> Sym(k-subsets of n)+-- restrict to a transitive constituent+-- blocks++-- Given generators gs for a group G, and f : G -> H a homomorphism,+-- return the "semi-diagonal" subgroup [(f g, g) | g <- gs] of f(G) * G+homomorphismConstruction :: (Ord a, Ord b) => [Permutation a] -> (Permutation a -> Permutation b) -> [Permutation (Either b a)]+homomorphismConstruction gs f = [lift g | g <- gs] where+ lift g = fromPairs $ [(Right x, Right y) | (x,y) <- toPairs g] ++ [(Left x', Left y') | (x',y') <- toPairs (f g)] ++ker gs f = ks where+ gbar = homomorphismConstruction gs f+ gs' = sgs gbar+ ks' = dropWhile (\h -> isLeft $ minsupp h) gs' -- !! should filter isRight - sgs might not be in order+ ks = map unRight ks'+ unRight = fromPairs . map (\(Right a, Right b) -> (a,b)) . toPairs+-}+++isTransitive gs = length (orbits gs) == 1+++-- TRANSITIVE CONSTITUENTS++{-+-- find largest composition factor of a group which is not transitive+-- we do this by taking the smallest orbit delta,+-- then constructing the homomorphism G -> Sym(delta)+-- and returning the kernel and the image+factorNotTransitive gs = transitiveConstituentHomomorphism' gs delta where+ delta = smallest $ orbits gs+ sizeSorted lists = map snd $ L.sort $ [(length l, l) | l <- lists]+ smallest = head . sizeSorted+-}++-- Seress p81+-- A transitive constituent homomorphism is the restriction of G <= Sym(omega) to an orbit delta <= omega+-- This function returns the kernel and the image+transitiveConstituentHomomorphism gs delta+ | delta == closure delta [(.^ g) | g <- gs] -- delta is closed under action of gs, hence a union of orbits+ = transitiveConstituentHomomorphism' gs delta++transitiveConstituentHomomorphism' gs delta = (ker, im) where+ gs' = sgs $ map (fromPairs . map (\(a,b) -> (lr a, lr b)) . toPairs) gs+ -- as delta is a transitive constituent, we will always have a and b either both Left or both Right+ lr x = if x `elem` delta then Left x else Right x+ ker = map unRight $ dropWhile (isLeft . minsupp) gs' -- pointwise stabiliser of delta+ im = map restrictLeft $ takeWhile (isLeft . minsupp) gs' -- restriction of the action to delta+++-- BLOCKS OF IMPRIMITIVITY++-- Holt p83ff (and also Seress p107ff)+-- Find a minimal block containing ys. ys are assumed to be sorted.+minimalBlock gs ys@(y1:yt) = minimalBlock' p yt gs where+ xs = foldl union [] $ map supp gs+ p = M.fromList $ [(yi,y1) | yi <- ys] ++ [(x,x) | x <- xs \\ ys]+ minimalBlock' p (q:qs) (h:hs) =+ let r = p M.! q -- representative of class containing q+ k = p M.! (q .^ h) -- rep of class (q^h)+ l = p M.! (r .^ h) -- rep of class (r^h)+ in if k /= l -- then we need to merge the classes+ then let p' = M.map (\x -> if x == l then k else x) p+ qs' = qs ++ [l]+ in minimalBlock' p' (q:qs') hs+ else minimalBlock' p (q:qs) hs+ minimalBlock' p (q:qs) [] = minimalBlock' p qs gs+ minimalBlock' p [] _ =+ let reps = toListSet $ M.elems p+ in L.sort [ filter (\x -> p M.! x == r) xs | r <- reps ]+-- Because the support of the permutations is not constrained to be [1..n], we have to use a map instead of an array+-- This probably affects the complexity, but isn't a problem in practice++-- Find all block systems+blockSystems gs+ | isTransitive gs = toListSet $ filter (/= [x:xs]) $ map (minimalBlock gs) [ [x,x'] | x' <- xs ]+ | otherwise = error "blockSystems: not transitive"+ where x:xs = foldl union [] $ map supp gs+++-- More efficient version if we have an sgs+blockSystemsSGS gs = toListSet $ filter (/= [x:xs]) $ map (minimalBlock gs) [ [x,x'] | x' <- rs ]+ where x:xs = foldl union [] $ map supp gs+ hs = filter (\g -> x < minsupp g) gs -- sgs for stabiliser Gx+ os = orbits hs+ rs = map head os ++ (xs \\ L.sort (concat os)) -- orbit representatives, including singleton cycles+-- Perhaps we could have a function which just returns orbit reps for stabiliser++-- eg for D 10, the stabiliser of 1 is [[2,6],[3,5]] - we need to make sure we don't forget 4++-- If we didn't have an SGS, we could try to randomly generate a few elts of stabiliser Gx, as that would still be better than nothing+-- see Holt RandomStab function+++isPrimitive gs = null (blockSystems gs)++isPrimitiveSGS gs = null (blockSystemsSGS gs)++-- There are other optimisations we haven't done+-- see Holt p86+++blockHomomorphism gs bs+ | bs == closure bs [(-^ g) | g <- gs] -- bs is closed under action of gs+ = blockHomomorphism' gs bs++blockHomomorphism' gs bs = (ker,im) where+ gs' = sgs $ map lr gs+ lr g = fromPairs $ [(Left b, Left $ b -^ g) | b <- bs] ++ [(Right x, Right y) | (x,y) <- toPairs g]+ ker = map unRight $ dropWhile (isLeft . minsupp) gs' -- stabiliser of the blocks+ im = map restrictLeft $ takeWhile (isLeft . minsupp) gs' -- restriction to the action on blocks++-- Note that there is a slightly more efficient way to calculate block homomorphism,+-- but requires change of base algorithm which we haven't implemented yet+++-- NORMAL CLOSURE++-- Seress 115+-- Given G, H < Sym(Omega) return <H^G> (the normal closure)+normalClosure gs hs = map unRight $ dropWhile (isLeft . minsupp) $ sgs ks where+ xs = foldl union [] $ map supp $ gs ++ hs+ ds = map diag gs -- {(g,g) | g <- G}+ diag g = fromPairs $ concat [ [(Left x, Left y) , (Right x, Right y)] | (x,y) <- toPairs g]+ hsR = map inR hs -- {(1,h) | h <- H}+ inR h = fromPairs [(Right x, Right y) | (x,y) <- toPairs h]+ ks = ds ++ hsR++-- Seress 116+-- Given G, H < Sym(Omega) return <H^G> `intersection` G+intersectionNormalClosure gs hs = map unRight $ dropWhile (isLeft . minsupp) $ sgs ks where+ xs = foldl union [] $ map supp $ gs ++ hs+ ds = map diag gs -- {(g,g) | g <- G}+ diag g = fromPairs $ concat [ [(Left x, Left y) , (Right x, Right y)] | (x,y) <- toPairs g]+ hsL = map inL hs -- {(h,1) | h <- H}+ inL h = fromPairs [(Left x, Left y) | (x,y) <- toPairs h]+ ks = ds ++ hsL+++-- CENTRALISER IN THE SYMMETRIC GROUP++-- Centralizer of G in Sym(X) - transitive case+centralizerSymTrans gs = filter (/= 1) $ centralizerSymTrans' [] fix_g_a where+ xs@(a:_) = foldl union [] $ map supp gs+ ss = sgs gs+ g_a = dropWhile ( (==a) . minsupp ) ss -- pt stabiliser of a+ fix_g_a = xs \\ (foldl union [] $ map supp g_a) -- the pts fixed by stabiliser of a+ reps_a = cosetRepsGx gs a+ -- xs = M.keys reps_a+ centralizingElt b = fromPairs [ let g = reps_a M.! x in (x, b .^ g) | x <- xs ]+ centralizerSymTrans' ls (r:rs) =+ let c = centralizingElt r+ in c : centralizerSymTrans' (c:ls) (rs \\ orbitP (c:ls) a)+ centralizerSymTrans' _ [] = []+
Math/Combinatorics/LatinSquares.hs view
@@ -1,4 +1,4 @@-+-- Copyright (c) David Amos, 2009. All rights reserved. module Math.Combinatorics.LatinSquares where
Math/Projects/MiniquaternionGeometry.hs view
@@ -1,4 +1,4 @@-+-- Copyright (c) David Amos, 2009. All rights reserved. module Math.Projects.MiniquaternionGeometry where
Math/Projects/Rubik.hs view
@@ -2,11 +2,14 @@ module Math.Projects.Rubik where -import Math.Algebra.Group.PermutationGroup +import Math.Algebra.Group.PermutationGroup hiding (_D) import Math.Algebra.Group.SchreierSims as SS import Math.Algebra.Group.RandomSchreierSims as RSS +import Math.Algebra.Group.Subquotients +-- Rubik's cube + -- 11 12 13 -- 14 U 16 -- 17 18 19 @@ -25,5 +28,88 @@ d = p [[31,33,39,37],[32,36,38,34],[ 7,47,57,27],[ 8,48,58,28],[ 9,49,59,29]] rubikCube = [f,b,l,r,u,d] +-- In Singmaster notation these would be capital letters. --- In Singmaster notation these would be capital letters.+[cornerFaces,edgeFaces] = orbits rubikCube + +(kerCornerFaces,imCornerFaces) = transitiveConstituentHomomorphism rubikCube cornerFaces +-- kernel is the elts which fix all corner faces +-- image is the action restricted to the corner faces + +(kerEdgeFaces,imEdgeFaces) = transitiveConstituentHomomorphism rubikCube edgeFaces +-- kernel is the elts which fix all edge faces +-- image is the action restricted to the edge faces + +[cornerBlocks] = blockSystems imCornerFaces +[edgeBlocks] = blockSystems imEdgeFaces + +(kerCornerBlocks,imCornerBlocks) = blockHomomorphism imCornerFaces cornerBlocks +-- kernel is elts which fix all the corners as blocks, with order 3^7 +-- (Whenever you twist one corner you must untwist another +-- - so the action on 7 corners determines the 8th) +-- image is the action on the corners as blocks, which is S8 of order 20160 + +(kerEdgeBlocks,imEdgeBlocks) = blockHomomorphism imEdgeFaces edgeBlocks +-- kernel is elts which fix all the edges as blocks, with order 2^11 +-- (Whenever you flip one edge, you must flip another edge +-- - so the action on 11 edges determines the 12th) +-- image is the action on the edges as blocks, which is S12 of order 479001600 + +-- Note that orderSGS imCornerFaces * orderSGS imEdgeFaces == 2 * orderSGS (sgs rubikCube) +-- This is because you can't operate on corners and edges totally independently +-- If you swap two corners, you must also swap two edges + +-- See also +-- http://www.gap-system.org/Doc/Examples/rubik.html + +-- (Note that the kernel of the corner constituent homomorphism /= image of edge constituent homomorphism +-- For example, [[36,38],[48,58]] is in the latter, but not the former because it's not in the Rubik group +-- ie there is an elt in the Rubik group which does just that to the edges, but may do some things to the corners) + + +-- Rubik's revenge (4*4*4 cube) + +-- 1 2 3 4 +-- 5 6 7 8 +-- 9 10 11 12 +-- 13 14 15 16 +-- 101 102 103 104 201 202 203 204 301 302 303 304 401 402 403 404 +-- 105 106 107 108 205 206 207 208 305 306 307 308 405 406 407 408 +-- 109 110 111 112 209 210 211 212 309 310 311 312 409 410 411 412 +-- 113 114 115 116 213 214 215 216 313 314 315 316 413 414 415 416 +-- 501 502 503 504 +-- 505 506 507 508 +-- 509 510 511 512 +-- 513 514 515 516 + +_U = p [[1,13,16,4],[2,9,15,8],[3,5,14,12],[6,10,11,7], + [101,201,301,401],[102,202,302,402],[103,203,303,403],[104,204,304,404]] +_u = p [[105,205,305,405],[106,206,306,406],[107,207,307,407],[108,208,308,408]] +_d = p [[109,209,309,409],[110,210,310,410],[111,211,311,411],[112,212,312,412]] +_D = p [[113,213,313,413],[114,214,314,414],[115,215,315,415],[116,216,316,416], + [501,504,516,513],[502,508,515,509],[503,512,514,505],[506,507,511,510]] + +bf = p [[1,304,516,113],[2,308,515,109],[3,312,514,105],[4,316,513,101], + [5,303,512,114],[6,307,511,110],[7,311,510,106],[8,315,509,102], + [9,302,508,115],[10,306,507,111],[11,310,506,107],[12,314,505,103], + [13,301,504,116],[14,305,503,112],[15,309,502,108],[16,313,501,104], + [201,204,216,213],[202,208,215,209],[203,212,214,205],[206,207,211,210], + [401,413,416,404],[402,409,415,408],[403,405,414,412],[406,410,411,407]] + +_R = _U ~^ bf +_r = _u ~^ bf +_l = _d ~^ bf +_L = _D ~^ bf + +ud = _U * _u * _d * _D + +_B = _R ~^ ud +_b = _r ~^ ud +_f = _l ~^ ud +_F = _L ~^ ud + +-- Note that orderSGS $ sgs [_U,_u,_d,_D,bf] comes out much too large, +-- because it includes rotations of the whole cube (24) +-- and exchanges of indistinguishable centre faces (24 for each of 6 colours) +-- So we have to divide by 24^7 / 2. +-- (The /2 is because we can only have even permutations when exchanging indistinguishable centres)
+ Math/Test/TSubquotients.hs view
@@ -0,0 +1,56 @@+-- Copyright (c) David Amos, 2009. All rights reserved.++module Math.Test.TSubquotients where++import Math.Algebra.Group.PermutationGroup hiding (ptStab, normalClosure)+-- import Math.Algebra.Group.SchreierSims (cosetRepsGx)+-- import Math.Algebra.Group.RandomSchreierSims++import Math.Algebra.Group.Subquotients++import qualified Math.Algebra.Group.PermutationGroup as P -- for testing+++test = and [testPtStab, testTransitiveConstituentHomomorphism, testBlockSystems, testBlockHomomorphism,+ testNormalClosure, testCentralizerSymTrans]++-- TESTS++testPtStab =+ let gs = [p [[1..5],[6,7]], p [[1,2],[6..10]] ] -- S 5 * S 5+ gs16 = ptStab gs [1,6]+ in orderSGS gs16 == 24*24 && orbitP gs16 1 == [1] && orbitP gs16 6 == [6]++testTransitiveConstituentHomomorphism =+ let gs1 = [p [[1..5],[6,7]], p [[1,2],[6..10]] ] -- S 5 * S 5+ (ker1,im1) = transitiveConstituentHomomorphism gs1 [1..5]+ gs2 = [p [[1,2,3],[4,5,6]], p [[1,2],[4,5]]] -- note that the two halves don't move independently+ (ker2,im2) = transitiveConstituentHomomorphism gs2 [1,2,3]+ in orderSGS ker1 == 120 && orderSGS im1 == 120 &&+ null ker2 && orderSGS im2 == 6+++testBlockSystems =+ blockSystems [p [[1..3]], p [[4..6]], p [[1,4],[2,5],[3,6]]] == [ [[1,2,3],[4,5,6]] ] &&+ blockSystems (_D 10) == [] &&+ blockSystems (_D 12) == [ [[1,3,5],[2,4,6]], [[1,4],[2,5],[3,6]] ]++testBlockHomomorphism =+ let (ker14,im14) = blockHomomorphism (_D 12) [[1,4],[2,5],[3,6]]+ (ker135,im135) = blockHomomorphism (_D 12) [[1,3,5],[2,4,6]]+ in (orderSGS ker14, orderSGS im14) == (2,6) &&+ (orderSGS ker135, orderSGS im135) == (6,2)++-- !! Need to improve this test+testNormalClosure =+ let gs = [p [[1,4]]]+ hs = [p [[1,2,3]]]+ in elts (P.normalClosure gs hs) == elts (normalClosure gs hs)+-- == _A 4+++testCentralizerSymTrans =+ let gs = [ p [[1..5]] ]+ hs = [ p [[1,2],[3,4]], p [[1,3],[2,4]] ]+ in centralizerSymTrans gs == gs+ && centralizerSymTrans hs == hs
Math/Test/TestAll.hs view
@@ -3,6 +3,7 @@ import Math.Test.TGraph import Math.Test.TDesign import Math.Test.TPermutationGroup +import Math.Test.TSubquotients import Math.Test.TFiniteGeometry import Math.Test.TCommutativeAlgebra import Math.Test.TNonCommutativeAlgebra @@ -14,6 +15,7 @@ [Math.Test.TGraph.test ,Math.Test.TDesign.test ,Math.Test.TPermutationGroup.test + ,Math.Test.TSubquotients.test ,Math.Test.TFiniteGeometry.test ,Math.Test.TCommutativeAlgebra.test ,Math.Test.TField.test