module Satchmo.PolynomialN
( Coefficient, Exponents, PolynomialN (), NumPolynomialN
, fromMonomials, add, equals)
where
import Control.Monad (forM,foldM)
import Data.List (partition,sortBy)
import qualified Satchmo.Binary.Op.Fixed as F
import Satchmo.Code (Decode (..),decode)
import Satchmo.MonadSAT (MonadSAT)
import Satchmo.Boolean (Boolean)
import qualified Satchmo.Boolean as B
type Coefficient a = a
type Exponents = [Integer]
data Monomial a = Monomial (Coefficient a, Exponents) deriving (Show)
type NumMonomial = Monomial F.Number
data PolynomialN a = PolynomialN [Monomial a] deriving (Show)
type NumPolynomialN = PolynomialN F.Number
instance Decode m a Integer => Decode m (Monomial a) (Monomial Integer) where
decode (Monomial (coeff,vars)) = do
decodedCoeff <- decode coeff
return $ Monomial (decodedCoeff,vars)
instance Decode m a Integer => Decode m (PolynomialN a) (PolynomialN Integer) where
decode (PolynomialN monomials) = do
decodedMonomials <- forM monomials decode
return $ PolynomialN decodedMonomials
fromMonomials :: MonadSAT m
=> Int
-> [(Coefficient Integer,Exponents)]
-> m NumPolynomialN
fromMonomials bits monomials = do
monomials' <- forM monomials $ \(c,es) -> do
coefficient <- F.constantWidth bits c
return $ Monomial (coefficient,es)
reduce $ PolynomialN monomials'
coefficient :: Monomial a -> Coefficient a
coefficient (Monomial (c,_)) = c
exponents :: Monomial a -> Exponents
exponents (Monomial (_,e)) = e
monomials :: PolynomialN a -> [Monomial a]
monomials (PolynomialN xs) = xs
sameExponents :: Monomial a -> Monomial a -> Bool
sameExponents m1 m2 = exponents m1 == exponents m2
add :: MonadSAT m => NumPolynomialN -> NumPolynomialN -> m NumPolynomialN
add (PolynomialN xs) (PolynomialN ys) =
reduce $ PolynomialN $ xs ++ ys
addMonomial :: MonadSAT m => NumMonomial -> NumMonomial -> m NumMonomial
addMonomial m1 m2 =
if sameExponents m1 m2 then
do c <- F.add (coefficient m1) (coefficient m2)
return $ Monomial (c, exponents m1)
else
error "PolynomialN.addMonomial"
strictOrdering :: Monomial a -> Monomial a -> Ordering
strictOrdering (Monomial (_,xs)) (Monomial (_,ys)) = compare xs ys
reduce :: MonadSAT m => NumPolynomialN -> m NumPolynomialN
reduce (PolynomialN []) = return $ PolynomialN []
reduce (PolynomialN (x:xs)) =
let (reducable,notReducable) = partition (sameExponents x) xs
strictOrd (Monomial (_,xs)) (Monomial (_,ys)) = compare xs ys
in do
newMonomial <- foldM addMonomial x reducable
PolynomialN rest <- reduce $ PolynomialN notReducable
return $ PolynomialN $ sortBy strictOrd $ newMonomial : rest
equalsMonomial :: MonadSAT m => NumMonomial -> NumMonomial -> m Boolean
equalsMonomial m1 m2 = do
equalsCoefficient <- F.equals (coefficient m1) (coefficient m2)
equalsExponents <- B.constant $ (exponents m1) == (exponents m2)
B.and [equalsCoefficient,equalsExponents]
equals :: MonadSAT m => NumPolynomialN -> NumPolynomialN -> m Boolean
equals (PolynomialN []) (PolynomialN []) = B.constant True
equals (PolynomialN (x:xs)) (PolynomialN (y:ys)) = do
e <- equalsMonomial x y
es <- equals (PolynomialN xs) (PolynomialN ys)
B.and [e,es]