{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Polynomial.Polynomial
(
Poly(..),
class',
ld,
prem,
varDegree,
lt,
lv,
initOfv,
initOfv',
max',
spoly,
basicSpoly,
lcmP,
withoutFactor,
lcmT,
factor,
simP,
listElimination,
p,
orden,
tsum,
totalDeg,
numTerms
) where
import Polynomial.Terms
import Polynomial.Monomial
import Prelude as P
import Data.Massiv.Array as A
import Control.Scheduler
import Numeric.Algebra as N
import Data.Function
import Data.Char.SScript
import Data.List as L
import Control.DeepSeq
import GHC.Generics (Generic, Generic1)
newtype Poly t ord = Poly (Array N Ix1 (Term t ord)) deriving (Generic, NFData, Eq)
p :: (NFData k ) => [Term k Revlex] -> Poly k Revlex
p xs = Poly $ A.fromList (Seq) xs
class' ::(NFData t ) => Poly t ord -> Int
class' (Poly p) = A.maximum' $ A.map (f) p
where
g (Mon m) = m
f (Term k mon) = A.elemsCount (g mon)
max' :: [Int] -> Int
max' [] = error "There is no max in a empty list"
max' [x] = x
max' (x:x':xs) =
max'
((if x >= x'
then x
else x') :
xs)
lv :: (NFData t ) => Poly t Revlex -> Int
lv = class'
ld :: (NFData t ) => Poly t Revlex -> Int
ld p@(Poly xp) = A.maximum' . findingLast $ A.computeAs N predicate
where
g (Mon m) = m
f (Term k mon) = A.elemsCount (g mon)
predicate = A.filterS (\x -> (f x) == class' p) xp
k (Term k mon) = if elemsCount (g mon) /= 0 then g mon ! ((elemsCount (g mon)) P.-1) else 0
findingLast = A.map k
lt :: (NFData t, Eq t) => Poly t Revlex -> Term t Revlex
lt poly@(Poly terms)= h . i . computeAs N $ fil terms
where
fil = A.filterS (\x -> f x == ld poly)
g (Mon m) = m
f (Term k mon) = if elemsCount (g mon) /= 0 then g mon ! (elemsCount (g mon) P.-1) else 0
i = A.quicksort
h = head . A.toList
varDegree :: (NFData t, Eq t) => Poly t Revlex -> Int -> Int
varDegree (Poly terms ) n = maxel . A.map takeEl . computeAs N $ fil terms
where
fil = A.filterS (\x -> f x >= n)
g (Mon m) = m
f (Term k mon) = if elemsCount (g mon) /= 0 then elemsCount (g mon) else 0
maxel = N.sum
takeEl (Term k mon) = g mon ! (n P.- 1)
initOfv :: (NFData t, Eq t) => Poly t Revlex -> Poly t Revlex
initOfv p@(Poly xp) = Poly $ A.computeAs N (A.map takeInit (A.computeAs N predicate))
where
predicate = A.filterS (\x -> f x == class' p && h x == ld p) xp
f (Term k mon) = A.elemsCount (g mon)
g (Mon m) = m
h (Term k mon) = g mon ! (A.elemsCount (g mon) P.- 1 )
takeInit :: Term t ord -> Term t ord
takeInit (Term k mod)
| A.elemsCount (g mod) == 1 = Term k $ m[]
| otherwise = Term k $ Mon ( A.computeAs P ( A.takeS (Sz (A.elemsCount (g mod)) P.- 1 ) (g mod) ))
where
g (Mon m) = m
initOfv' :: (NFData t, Eq t) => Poly t Revlex -> Poly t Revlex
initOfv' p@(Poly xp) = Poly $ (A.computeAs N predicate)
where
predicate = A.filterS (\x -> f x == class' p && h x == ld p) xp
f (Term k mon) = A.elemsCount (g mon)
g (Mon m) = m
h (Term k mon) = g mon ! (A.elemsCount (g mon) P.- 1 )
lcmP :: (NFData t, Num t, Ord t)=> Poly t Revlex -> Poly t Revlex -> [Poly t Revlex]
lcmP a@(Poly poly) b@(Poly poly')
| A.elemsCount poly == 1 && A.elemsCount poly' == 1 = (p $ on lcmT (head . A.toList) poly poly' : []) :[]
| A.elemsCount poly' == 1 = withoutFactor a N.* (p $ lcmT (head . A.toList $ poly') (factor a) : []) :[]
| A.elemsCount poly == 1 = withoutFactor b N.* (p $ lcmT (head . A.toList $ poly) (factor b) : []) :[]
| otherwise = [p $ [on lcmT factor a b],withoutFactor a, withoutFactor b]
factor :: (NFData t, Num t) => Poly t Revlex -> Term t Revlex
factor (Poly poly) = Term 1 $ m commList
where
f (Term k mon) = g mon
g (Mon m) = A.toList m
commList = L.foldl1' (P.zipWith min) (A.toList $ A.map f poly)
withoutFactor ::(NFData t, Num t) => Poly t Revlex -> Poly t Revlex
withoutFactor (Poly poly) = Poly $ A.computeAs N ( A.map f poly)
where
f m = quit m m'
m' = factor $ Poly poly
quit :: Term k ord -> Term k ord -> Term k ord
quit (Term k mon) (Term k' mon')
| mon' == zero = Term k mon
| otherwise = Term k $ m (on quit' f mon mon')
where
f (Mon m) = A.toList m
quit' :: [Int]->[Int]->[Int]
quit' as [] = as
quit' (a:as) (b:bs) = a P.- b : quit' as bs
lcmT :: (Ord t, Num t) => Term t Revlex -> Term t Revlex -> Term t Revlex
lcmT (Term k mon)(Term k' mon')= lcm' mon mon'
lcm' :: (Ord t, Num t )=> Mon Revlex -> Mon Revlex -> Term t Revlex
lcm' (Mon m)(Mon m') = Term 1 $ Mon (A.computeAs P (A.zipWith max m m' ))
basicSpoly ::(NFData t, Fractional t, Num t, Eq t, Ord t ) => Poly t Revlex -> Poly t Revlex -> Poly t Revlex
basicSpoly f g = simP x' (initOfv' f) f N.- simP x' (initOfv' g) g
where
x' = on lcmP initOfv' f g
simP :: (NFData t, Fractional t, Num t, Eq t ) => [Poly t Revlex]->Poly t Revlex->Poly t Revlex->Poly t Revlex
simP f1 f2 f3
| length f1 == 3 = listElimination f1 f2 f3
| (orden . head $ f1) == orden f2 = f3
| orden f3 == orden f2 = head f1
| (f . head $ f1) == 1 && (f f2) == 1 = p[h f1 N./ g f2] N.* f3
| f f2 == 1 = b N.* p [a N./ g f2] N.* f3
| orden b == orden b' = p[a N./ a'] N.* f3
| otherwise = error "Option not consider in simP"
where
(a,b) = (factor . head $ f1, (withoutFactor . head) f1)
(a',b') = (factor f2, withoutFactor f2)
f (Poly poly) = A.elemsCount poly
g (Poly poly) = head . A.toList $ poly
h [f1] = g f1
orden :: (NFData t)=> Poly t Revlex -> Poly t Revlex
orden (Poly poly) = p $ P.map h ( sortBy (\( k, mon) ( k', mon') -> compare mon mon') (A.toList $ A.map f poly ))
where
h (k, xs)= Term k $ m xs
g (Mon m) = m
f (Term k mon) = (k, A.toList (g mon))
listElimination :: (NFData t, Fractional t, Eq t, Num t) => [Poly t Revlex] -> Poly t Revlex -> Poly t Revlex -> Poly t Revlex
listElimination [a,b,c] f2 f3
| orden b == orden e = f3 N.* p[ (head . A.toList $ f a) N./ d] N.* c
| orden c == orden e = f3 N.* p[ (head . A.toList $ f a) N./ d] N.* b
| orden f3 == orden f2 = a N.* b N.* c
| otherwise = error "Option not consider list Elimination"
where
(d,e) = (factor f2, withoutFactor f2)
f (Poly poly) = poly
spoly :: (NFData t, Fractional t, Ord t) => Poly t Revlex -> Poly t Revlex -> Poly t Revlex
spoly f g
| f == zero = f
| ld f >= ld g && class' g == class' f = spoly (basicSpoly f g) g
| otherwise = f
prem :: (NFData t, Eq t, Num t) => Poly t Revlex -> Poly t Revlex -> Poly t Revlex
prem g f
| g /= zero && class' g == class' f && ld g >= m = prem calc f
| otherwise = g
where
m = ld f
calc = (initOfv f N.* g) N.- (initOfv g N.* f N.* p [Term 1 $ mp[lv f][ld g P.- m] ])
instance (NFData t, Ord t, Num t, Show t) => Show (Poly t ord) where
show (Poly p) = showPoly p
showPoly :: (NFData t, Ord t, Num t, Show t) => Array N Ix1 (Term t ord) -> String
showPoly terms = (concat . A.toList) $ A.map f terms
where
f (Term k mon)
| k P.> 0 = " + " ++ show k ++ show mon
| k P.< 0 = " - " ++ show (abs k) ++ show mon
| otherwise = error "term with empty coefficient k"
instance (NFData t, Num t, Eq t) => Additive (Poly t Revlex) where
(+) (Poly poly)(Poly poly') =
p $
P.filter removeZero $
P.map tsum $
groupBy (\( k, mon) ( k', mon') -> (==) mon mon') $
sortBy (\( k, mon) ( k', mon') -> compare mon mon') (A.toList $ A.map f (computeAs N concatp ))
where
g (Mon m) = m
f (Term k mon) = (k, A.toList (g mon))
concatp = A.append' 1 poly poly'
tsum :: (Num k) => [(k, [Int])] -> Term k ord
tsum [(k,x)] = Term k (m x)
tsum ((k, x):xs) = (Term k $ m x) N.+ tsum xs
removeZero :: (Num k, Eq k) => Term k ord -> Bool
removeZero (Term k mon)
| k /= 0 = True
| otherwise = False
instance (NFData t, Num t, Eq t) => Semiring (Poly t Revlex)
instance (NFData t, Num t, Eq t) => Abelian (Poly t Revlex)
instance (NFData t, Num t, Eq t) => Multiplicative (Poly t Revlex) where
(*) (Poly poly)(Poly poly') = simp $ p [ x N.* y | x <- A.toList poly, y <- A.toList poly' ]
simp :: (NFData t, Num t, Eq t) => Poly t Revlex -> Poly t Revlex
simp (Poly poly) =
p $
P.filter removeZero $
P.map tsum $
groupBy (\( k, mon) ( k', mon') -> (==) mon mon') $
sortBy (\( k, mon) ( k', mon') -> compare mon mon') (A.toList $ A.map f poly )
where
g (Mon m) = m
f (Term k mon) = (k, A.toList (g mon))
instance (NFData t, Num t, Eq t) => Group (Poly t Revlex) where
(-) (Poly poly)(Poly poly') =
p $
P.filter removeZero $
P.map tsum $
groupBy (\( k, mon) ( k', mon') -> (==) mon mon') $
sortBy (\( k, mon) ( k', mon') -> compare mon mon') (A.toList $ A.map f (computeAs N concatp ))
where
g (Mon m) = m
f (Term k mon) = (k, A.toList (g mon))
h (Term k mon) = Term (- k) mon
concatp = A.append' 1 poly (A.map h poly')
instance (NFData t, Num t, Eq t) => LeftModule Integer (Poly t Revlex) where
(.*) = undefined
instance (NFData t, Num t, Eq t) => RightModule Integer (Poly t Revlex) where
(*.) = undefined
instance (NFData t, Num t, Eq t) => LeftModule Natural (Poly t Revlex) where
(.*) = undefined
instance (NFData t, Num t, Eq t) => RightModule Natural (Poly t Revlex) where
(*.) = undefined
instance (NFData t, Num t, Eq t) => Monoidal (Poly t Revlex) where
zero = p[]
last' :: [Int] -> Int
last' [] = 0
last' xs = last xs
totalDeg :: (NFData t) => Poly t Revlex -> Int
totalDeg (Poly p) = A.maximum' $ A.map (f) p
where
g (Mon m) = m
f (Term k mon) = A.sum (g mon)
numTerms :: (NFData t) => Poly t Revlex -> Int
numTerms (Poly p) = A.elemsCount p