module Math.Algebra.Commutative.GBasis where
import Data.List
import qualified Data.Map as M
import Math.Algebra.Commutative.Monomial
import Math.Algebra.Commutative.MPoly
sPoly f g = let h = lcmT (lt f) (lt g)
in h `divT` lt f .* f h `divT` lt g .* g
isGB fs = all (\h -> h %% fs == 0) (pairWith sPoly fs)
gb1 fs = gb' fs (pairWith sPoly fs) where
gb' gs (h:hs) = let h' = h %% gs in
if h' == 0 then gb' gs hs else gb' (h':gs) (hs ++ map (sPoly h') gs)
gb' gs [] = gs
pairWith f (x:xs) = map (f x) xs ++ pairWith f xs
pairWith _ [] = []
reduce gs = reduce' [] gs where
reduce' gs' (g:gs) | g' == 0 = reduce' gs' gs
| otherwise = reduce' (g':gs') gs
where g' = g %% (gs'++gs)
reduce' gs' [] = reverse $ sort $ map toMonic gs'
gb2 fs = reduce $ gb' fs (pairs [1..s]) s where
s = length fs
gb' gs ((i,j):ps) t =
let fi = gs!i; fj = gs!j in
if coprimeM (lm fi) (lm fj) || criterion fi fj
then gb' gs ps t
else let h = sPoly fi fj %% gs in
if h == 0 then gb' gs ps t else gb' (gs++[h]) (ps ++ [ (i,t+1) | i <- [1..t] ]) (t+1)
where
criterion fi fj = let l = lcmM (lm fi) (lm fj) in any (test l) [1..t]
test l k = k `notElem` [i,j]
&& ordpair i k `notElem` ps
&& ordpair j k `notElem` ps
&& lm (gs!k) `dividesM` l
gb' gs [] _ = gs
pairs (x:xs) = map (\y->(x,y)) xs ++ pairs xs
pairs [] = []
xs ! i = xs !! (i1)
ordpair x y | x < y = (x,y)
| otherwise = (y,x)
gb2b fs = reduce $ gb1' [] fs [] 0 where
gb1' gs (f:fs) ps t = gb1' (gs ++ [f]) fs ps' (t+1) where
ps' = updatePairs gs ps f t
gb1' ls [] ps t = gb2' ls ps t
gb2' gs ((i,j):ps) t =
let h = sPoly (gs!i) (gs!j) %% gs in
if h == 0
then gb2' gs ps t
else let ps' = updatePairs gs ((i,j):ps) h t in gb2' (gs++[h]) ps' (t+1)
gb2' gs [] _ = gs
updatePairs gs ps f t =
[p | p@(i,j) <- ps,
not (lm f `dividesM` lcmM (lm (gs!i)) (lm (gs!j)))]
++ [ (i,t+1) | (gi,i) <- zip gs [1..t],
not (coprimeM (lm gi) (lm f)),
not (criterion (lcmM (lm gi) (lm f)) i) ]
where criterion l i = any (`dividesM` l) [lm gk | (gk,k) <- zip gs [1..t], k /= i, ordpair i k `notElem` ps]
gb3b fs =
let fs' = sort $ filter (/=0) fs
in reduce $ gb1' [] fs' [] 0 where
gb1' gs (f:fs) ps t = gb1' (gs ++ [f]) fs ps' (t+1) where
ps' = updatePairs gs ps f t
gb1' ls [] ps t = gb2' ls ps t
gb2' gs ((l,(i,j)):ps) t =
let h = sPoly (gs!i) (gs!j) %% gs in
if h == 0
then gb2' gs ps t
else let ps' = updatePairs gs ((l,(i,j)):ps) h t in gb2' (gs++[h]) ps' (t+1)
gb2' gs [] _ = gs
updatePairs :: (Ord (Monomial ord), Fractional r) => [MPoly ord r] -> [(Monomial ord, (Int,Int))] -> (MPoly ord r) -> Int -> [(Monomial ord, (Int,Int))]
updatePairs gs ps f t =
mergeBy cmpFst
[p | p@(l,(i,j)) <- ps,
not (lm f `dividesM` l)]
$ sortBy cmpFst
[ (l,(i,t+1)) | (gi,i) <- zip gs [1..t], l <- [lcmM (lm gi) (lm f)],
not (coprimeM (lm gi) (lm f)),
not (criterion l i) ]
where criterion l i = any (`dividesM` l) [lm gk | (gk,k) <- zip gs [1..t], k /= i, ordpair i k `notElem` map snd ps]
cmpFst (a,_) (b,_) = compare a b
mergeBy cmp (t:ts) (u:us) =
case cmp t u of
LT -> t : mergeBy cmp ts (u:us)
EQ -> t : mergeBy cmp ts (u:us)
GT -> u : mergeBy cmp (t:ts) us
mergeBy _ ts us = ts ++ us
gb4b fs =
let fs' = sort $ filter (/=0) fs
in reduce $ gb1' [] fs' [] 0 where
gb1' gs (f:fs) ps t = gb1' (gs ++ [f]) fs ps' (t+1) where
ps' = updatePairs gs ps f t
gb1' ls [] ps t = gb2' ls ps t
gb2' gs ((sl,(i,j)):ps) t =
let h = sPoly (gs!i) (gs!j) %% gs in
if h == 0
then gb2' gs ps t
else let ps' = updatePairs gs ((sl,(i,j)):ps) h t in gb2' (gs++[h]) ps' (t+1)
gb2' gs [] _ = gs
updatePairs :: (Ord (Monomial ord), Fractional r) =>
[MPoly ord r] -> [((Int,Monomial ord), (Int,Int))] -> (MPoly ord r) -> Int -> [((Int,Monomial ord), (Int,Int))]
updatePairs gs ps f t =
mergeBy cmpFst
[p | p@((s,l),(i,j)) <- ps,
not (lm f `dividesM` l)]
$ sortBy cmpFst
[ ((s,l),(i,t+1)) | (gi,i) <- zip gs [1..t], l <- [lcmM (lm gi) (lm f)], s <- [sugar gi f l],
not (coprimeM (lm gi) (lm f)),
not (criterion l i) ]
where criterion l i = any (`dividesM` l) [lm gk | (gk,k) <- zip gs [1..t], k /= i, ordpair i k `notElem` map snd ps]
gb :: (Ord (Monomial ord), Fractional k, Ord k) =>
[MPoly ord k] -> [MPoly ord k]
gb fs =
let fs' = sort $ map toMonic $ filter (/=0) fs
in reduce $ gb1' [] fs' [] 0 where
gb1' gs (f:fs) ps t = gb1' (gs ++ [f]) fs ps' (t+1)
where ps' = updatePairs gs ps f (t+1)
gb1' ls [] ps t = gb2' ls ps t
gb2' gs (p@(_,(i,j)):ps) t =
if h == 0
then gb2' gs ps t
else gb2' (gs++[h]) ps' (t+1)
where h = toMonic $ sPoly (gs!i) (gs!j) %% gs
ps' = updatePairs gs (p:ps) h (t+1)
gb2' gs [] _ = gs
updatePairs :: (Ord (Monomial ord), Fractional r) =>
[MPoly ord r] -> [((Int,Monomial ord), (Int,Int))] -> (MPoly ord r) -> Int -> [((Int,Monomial ord), (Int,Int))]
updatePairs gs ps gk k =
let newps = [let l = lcmM (lm gi) (lm gk) in ((sugar gi gk l, l), (i,k)) | (gi,i) <- zip gs [1..k1] ]
ps' = [p | p@((sij,tij),(i,j)) <- ps, ((sik,tik),_) <- [newps ! i], ((sjk,tjk),_) <- [newps ! j],
not ( (tik `properlyDividesM` tij) && (tjk `properlyDividesM` tij) ) ]
newps' = discard1 [] newps
newps'' = sortBy cmpSug $ discard2 [] $ sortBy cmpNormal newps'
in mergeBy cmpSug ps' newps''
where
discard1 ls (r@((_sik,tik),(i,_k)):rs) =
if lm (gs!i) `coprimeM` lm gk
then discard1 (filter (\((_,tjk),_) -> tjk /= tik) ls) (filter (\((_,tjk),_) -> tjk /= tik) rs)
else discard1 (r:ls) rs
discard1 ls [] = ls
discard2 ls (r@((_sik,tik),(i,k)):rs) = discard2 (r:ls) $ filter (\((_sjk,tjk),(j,k')) -> not (k == k' && tik `dividesM` tjk)) rs
discard2 ls [] = ls
sugar f g h = degM h + max (deg f degM (lm f)) (deg g degM (lm g))
cmpNormal ((s1,t1),(i1,j1)) ((s2,t2),(i2,j2)) = compare (t1,j1) (t2,j2)
cmpSug ((s1,t1),(i1,j1)) ((s2,t2),(i2,j2)) = compare (s1,t1,j1) (s2,t2,j2)
gb3 fs =
let gs = sort $ filter (/=0) fs
ps = sortBy cmpFst $ pairWith (\(i,fi) (j,fj) -> (lcmM (lm fi) (lm fj), (i,j)) ) $ zip [1..] gs
in reduce $ gb' gs ps s
where
s = length fs
gb' :: (Ord (Monomial ord), Fractional r) => [MPoly ord r] -> [(Monomial ord, (Int,Int))] -> Int -> [MPoly ord r]
gb' gs ((l,(i,j)):ps) t =
let fi = gs!i; fj = gs!j in
if coprimeM (lm fi) (lm fj) || any (test l) [1..t]
then gb' gs ps t
else let h = sPoly fi fj %% gs in
if h == 0
then gb' gs ps t
else let ps' = mergeBy cmpFst ps $ sortBy cmpFst $ zip [lcmM (lm h) (lm fi) | fi <- gs] [(i,t+1) | i <- [1..t]]
in gb' (gs++[h]) ps' (t+1)
where
test l k = k `notElem` [i,j]
&& ordpair i k `notElem` map snd ps
&& ordpair j k `notElem` map snd ps
&& lm (gs!k) `dividesM` l
gb' gs [] _ = gs
gb4 fs =
let gs = sort $ filter (/=0) fs
ps = sortBy cmpFst $ pairWith (\(i,fi) (j,fj) -> let l = lcmM (lm fi) (lm fj) in ((sugar fi fj l, l), (i,j)) ) $ zip [1..] gs
in reduce $ gb' gs ps s
where
s = length fs
gb' :: (Ord (Monomial ord), Fractional r) => [MPoly ord r] -> [((Int,Monomial ord), (Int,Int))] -> Int -> [MPoly ord r]
gb' gs (((s,l),(i,j)):ps) t =
let fi = gs!i; fj = gs!j in
if coprimeM (lm fi) (lm fj) || any (test l) [1..t]
then gb' gs ps t
else let h = sPoly fi fj %% gs in
if h == 0
then gb' gs ps t
else let ps' = mergeBy cmpFst ps $ sortBy cmpFst $ zip [let l = lcmM (lm fi) (lm h) in (sugar fi h l, l) | fi <- gs] [(i,t+1) | i <- [1..t]]
in gb' (gs++[h]) ps' (t+1)
where
test l k = k `notElem` [i,j]
&& ordpair i k `notElem` map snd ps
&& ordpair j k `notElem` map snd ps
&& lm (gs!k) `dividesM` l
gb' gs [] _ = gs