diff --git a/poly.cabal b/poly.cabal index 2925dbd..1e863c3 100644 --- a/poly.cabal +++ b/poly.cabal @@ -60,13 +60,14 @@ library Data.Poly.Internal.Multi.Field Data.Poly.Internal.Multi.GcdDomain Data.Poly.Internal.Multi.Laurent + Data.Poly.Internal.Multi.Monom build-depends: base >= 4.12 && < 5, deepseq >= 1.1 && < 1.6, primitive >= 0.6, semirings >= 0.5.2, - vector >= 0.12.0.2 + vector >= 0.13 if flag(sparse) build-depends: diff --git a/src/Data/Poly/Internal/Convert.hs b/src/Data/Poly/Internal/Convert.hs index c9f16e9..98f33db 100644 --- a/src/Data/Poly/Internal/Convert.hs +++ b/src/Data/Poly/Internal/Convert.hs @@ -34,23 +34,23 @@ import qualified Data.Poly.Internal.Multi as Sparse -- -- @since 0.5.0.0 denseToSparse - :: (Eq a, Num a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => Dense.Poly v a -> Sparse.Poly v a denseToSparse = denseToSparseInternal 0 denseToSparse' - :: (Eq a, Semiring a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => Dense.Poly v a -> Sparse.Poly v a denseToSparse' = denseToSparseInternal zero denseToSparseInternal - :: (Eq a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => a -> Dense.Poly v a -> Sparse.Poly v a -denseToSparseInternal z = Sparse.MultiPoly . G.imapMaybe (\i c -> if c == z then Nothing else Just (fromIntegral i, c)) . Dense.unPoly +denseToSparseInternal z = Sparse.MultiPoly . G.imapMaybe (\i c -> if c == z then Nothing else Just (Sparse.Monom (fromIntegral i) c)) . Dense.unPoly -- | Convert from sparse to dense polynomials. -- @@ -60,31 +60,31 @@ denseToSparseInternal z = Sparse.MultiPoly . G.imapMaybe (\i c -> if c == z then -- -- @since 0.5.0.0 sparseToDense - :: (Num a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Num a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => Sparse.Poly v a -> Dense.Poly v a sparseToDense = sparseToDenseInternal 0 sparseToDense' - :: (Semiring a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Semiring a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => Sparse.Poly v a -> Dense.Poly v a sparseToDense' = sparseToDenseInternal zero sparseToDenseInternal - :: (G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => a -> Sparse.Poly v a -> Dense.Poly v a sparseToDenseInternal z (Sparse.MultiPoly xs) | G.null xs = Dense.Poly G.empty | otherwise = runST $ do - let len = fromIntegral (SU.head (fst (G.unsafeLast xs)) + 1) + let len = fromIntegral (SU.head (Sparse.monomPower (G.unsafeLast xs)) + 1) ys <- MG.unsafeNew len MG.set ys z let go xi yi | xi >= G.length xs = pure () - | (yi', c) <- G.unsafeIndex xs xi + | Sparse.Monom yi' c <- G.unsafeIndex xs xi , yi == fromIntegral (SU.head yi') = MG.unsafeWrite ys yi c >> go (xi + 1) (yi + 1) | otherwise = go xi (yi + 1) diff --git a/src/Data/Poly/Internal/Multi.hs b/src/Data/Poly/Internal/Multi.hs index ea5cc95..17a10b1 100644 --- a/src/Data/Poly/Internal/Multi.hs +++ b/src/Data/Poly/Internal/Multi.hs @@ -58,14 +58,16 @@ module Data.Poly.Internal.Multi -- * Conversions , segregate , unsegregate + -- * Monom + , Monom(..) ) where import Prelude hiding (quot, gcd) -import Data.Bifunctor import Control.DeepSeq import Data.Coerce import Data.Euclidean (Field, quot) import Data.Finite +import Data.Function (on) import Data.Kind import Data.List (intersperse) import Data.Semiring (Semiring(..), Ring()) @@ -106,15 +108,17 @@ import Data.Poly.Internal.Multi.Core -- -- @since 0.5.0.0 newtype MultiPoly (v :: Type -> Type) (n :: Nat) (a :: Type) = MultiPoly - { unMultiPoly :: v (SU.Vector n Word, a) - -- ^ Convert a 'MultiPoly' to a vector of (powers, coefficient) pairs. - -- - -- @since 0.5.0.0 + { unMultiPoly :: v (Monom n a) } -deriving instance Eq (v (SU.Vector n Word, a)) => Eq (MultiPoly v n a) -deriving instance Ord (v (SU.Vector n Word, a)) => Ord (MultiPoly v n a) -deriving instance NFData (v (SU.Vector n Word, a)) => NFData (MultiPoly v n a) +instance (Eq a, G.Vector v (Monom n a)) => Eq (MultiPoly v n a) where + (==) = G.eqBy (\(Monom p c) (Monom p' c') -> c == c' && p == p') `on` unMultiPoly + +instance (Ord a, G.Vector v (Monom n a)) => Ord (MultiPoly v n a) where + compare = G.cmpBy (\(Monom p c) (Monom p' c') -> compare c c' <> compare p p') `on` unMultiPoly + +instance (NFData a, NFData1 v) => NFData (MultiPoly v n a) where + rnf = liftRnf (\(Monom _ a) -> rnf a) . unMultiPoly -- | Multivariate polynomials backed by boxed vectors. -- @@ -163,18 +167,18 @@ type UPoly (a :: Type) = Poly U.Vector a -- -- @since 0.3.0.0 unPoly - :: (G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + :: (G.Vector v (Word, a), G.Vector v (Monom 1 a)) => Poly v a -> v (Word, a) -unPoly = G.map (first SU.head) . unMultiPoly +unPoly = G.map (\(Monom p c) -> (SU.head p, c)) . unMultiPoly -instance (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) => IsList (MultiPoly v n a) where +instance (Eq a, Semiring a, G.Vector v (Monom n a)) => IsList (MultiPoly v n a) where type Item (MultiPoly v n a) = (SU.Vector n Word, a) - fromList = toMultiPoly' . G.fromList - fromListN = (toMultiPoly' .) . G.fromListN - toList = G.toList . unMultiPoly + fromList = toMultiPoly' . G.fromList . map (uncurry Monom) + fromListN = (toMultiPoly' .) . (. map (uncurry Monom)) . G.fromListN + toList = map (\(Monom p c) -> (p, c)) . G.toList . unMultiPoly -instance (Show a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Show (MultiPoly v n a) where +instance (Show a, KnownNat n, G.Vector v (Monom n a)) => Show (MultiPoly v n a) where showsPrec d (MultiPoly xs) | G.null xs = showString "0" @@ -182,7 +186,7 @@ instance (Show a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Show (MultiPo = showParen (d > 0) $ foldl (.) id $ intersperse (showString " + ") - $ G.foldl (\acc (is, c) -> showCoeff is c : acc) [] xs + $ G.foldl (\acc (Monom is c) -> showCoeff is c : acc) [] xs where showCoeff is c = showsPrec 7 c . foldl (.) id @@ -202,43 +206,33 @@ instance (Show a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Show (MultiPo 2 -> "Z" k -> "X" ++ show k --- | Make a 'MultiPoly' from a list of (powers, coefficient) pairs. --- --- >>> :set -XOverloadedLists -XDataKinds --- >>> import Data.Vector.Generic.Sized (fromTuple) --- >>> toMultiPoly [(fromTuple (0,0),1),(fromTuple (0,1),2),(fromTuple (1,0),3)] :: VMultiPoly 2 Integer --- 3 * X + 2 * Y + 1 --- >>> toMultiPoly [(fromTuple (0,0),0),(fromTuple (0,1),0),(fromTuple (1,0),0)] :: UMultiPoly 2 Int --- 0 --- --- @since 0.5.0.0 toMultiPoly - :: (Eq a, Num a, G.Vector v (SU.Vector n Word, a)) - => v (SU.Vector n Word, a) + :: (Eq a, Num a, G.Vector v (Monom n a)) + => v (Monom n a) -> MultiPoly v n a toMultiPoly = MultiPoly . normalize (/= 0) (+) {-# INLINABLE toMultiPoly #-} toMultiPoly' - :: (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) - => v (SU.Vector n Word, a) + :: (Eq a, Semiring a, G.Vector v (Monom n a)) + => v (Monom n a) -> MultiPoly v n a toMultiPoly' = MultiPoly . normalize (/= zero) plus {-# INLINABLE toMultiPoly' #-} -- | Note that 'abs' = 'id' and 'signum' = 'const' 1. -instance (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Num (MultiPoly v n a) where +instance (Eq a, Num a, KnownNat n, G.Vector v (Monom n a)) => Num (MultiPoly v n a) where - (+) = coerce (plusPoly @v @(SU.Vector n Word) @a (/= 0) (+)) - (-) = coerce (minusPoly @v @(SU.Vector n Word) @a (/= 0) negate (-)) - (*) = coerce (convolution @v @(SU.Vector n Word) @a (/= 0) (+) (*)) + (+) = coerce (plusPoly @v @n @a (/= 0) (+)) + (-) = coerce (minusPoly @v @n @a (/= 0) negate (-)) + (*) = coerce (convolution @v @n @a (/= 0) (+) (*)) - negate (MultiPoly xs) = MultiPoly $ G.map (fmap negate) xs + negate (MultiPoly xs) = MultiPoly $ G.map (\(Monom ps c) -> Monom ps (negate c)) xs abs = id signum = const 1 fromInteger n = case fromInteger n of 0 -> MultiPoly G.empty - m -> MultiPoly $ G.singleton (0, m) + m -> MultiPoly $ G.singleton (Monom 0 m) {-# INLINE (+) #-} {-# INLINE (-) #-} @@ -246,28 +240,28 @@ instance (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Num (Mul {-# INLINE fromInteger #-} {-# INLINE (*) #-} -instance (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Semiring (MultiPoly v n a) where +instance (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => Semiring (MultiPoly v n a) where zero = MultiPoly G.empty one | (one :: a) == zero = zero - | otherwise = MultiPoly $ G.singleton (0, one) + | otherwise = MultiPoly $ G.singleton (Monom 0 one) - plus = coerce (plusPoly @v @(SU.Vector n Word) @a (/= zero) plus) - times = coerce (convolution @v @(SU.Vector n Word) @a (/= zero) plus times) + plus = coerce (plusPoly @v @n @a (/= zero) plus) + times = coerce (convolution @v @n @a (/= zero) plus times) {-# INLINE zero #-} {-# INLINE one #-} {-# INLINE plus #-} {-# INLINE times #-} - fromNatural n = if n' == zero then zero else MultiPoly $ G.singleton (0, n') + fromNatural n = if n' == zero then zero else MultiPoly $ G.singleton (Monom 0 n') where n' :: a n' = fromNatural n {-# INLINE fromNatural #-} -instance (Eq a, Ring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Ring (MultiPoly v n a) where - negate (MultiPoly xs) = MultiPoly $ G.map (fmap Semiring.negate) xs +instance (Eq a, Ring a, KnownNat n, G.Vector v (Monom n a)) => Ring (MultiPoly v n a) where + negate (MultiPoly xs) = MultiPoly $ G.map (\(Monom ps c) -> Monom ps (Semiring.negate c)) xs -- | Return the leading power and coefficient of a non-zero polynomial. -- @@ -278,10 +272,12 @@ instance (Eq a, Ring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Ring (M -- Nothing -- -- @since 0.3.0.0 -leading :: G.Vector v (SU.Vector 1 Word, a) => Poly v a -> Maybe (Word, a) +leading :: G.Vector v (Monom 1 a) => Poly v a -> Maybe (Word, a) leading (MultiPoly v) | G.null v = Nothing - | otherwise = Just $ first SU.head $ G.last v + | otherwise = Just (SU.head p, c) + where + Monom p c = G.last v -- | Multiply a polynomial by a monomial, expressed as powers and a coefficient. -- @@ -292,7 +288,7 @@ leading (MultiPoly v) -- -- @since 0.5.0.0 scale - :: (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Num a, KnownNat n, G.Vector v (Monom n a)) => SU.Vector n Word -> a -> MultiPoly v n a @@ -300,7 +296,7 @@ scale scale yp yc = MultiPoly . scaleInternal (/= 0) (*) yp yc . unMultiPoly scale' - :: (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => SU.Vector n Word -> a -> MultiPoly v n a @@ -311,23 +307,23 @@ scale' yp yc = MultiPoly . scaleInternal (/= zero) times yp yc . unMultiPoly -- -- @since 0.5.0.0 monomial - :: (Eq a, Num a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Num a, G.Vector v (Monom n a)) => SU.Vector n Word -> a -> MultiPoly v n a monomial p c | c == 0 = MultiPoly G.empty - | otherwise = MultiPoly $ G.singleton (p, c) + | otherwise = MultiPoly $ G.singleton (Monom p c) {-# INLINABLE monomial #-} monomial' - :: (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom n a)) => SU.Vector n Word -> a -> MultiPoly v n a monomial' p c | c == zero = MultiPoly G.empty - | otherwise = MultiPoly $ G.singleton (p, c) + | otherwise = MultiPoly $ G.singleton (Monom p c) {-# INLINABLE monomial' #-} -- | Evaluate the polynomial at a given point. @@ -339,7 +335,7 @@ monomial' p c -- -- @since 0.5.0.0 eval - :: (Num a, G.Vector v (SU.Vector n Word, a), G.Vector u a) + :: (Num a, G.Vector v (Monom n a), G.Vector u a) => MultiPoly v n a -> SG.Vector u n a -> a @@ -347,7 +343,7 @@ eval = substitute (*) {-# INLINE eval #-} eval' - :: (Semiring a, G.Vector v (SU.Vector n Word, a), G.Vector u a) + :: (Semiring a, G.Vector v (Monom n a), G.Vector u a) => MultiPoly v n a -> SG.Vector u n a -> a @@ -363,7 +359,7 @@ eval' = substitute' times -- -- @since 0.5.0.0 subst - :: (Eq a, Num a, KnownNat m, G.Vector v (SU.Vector n Word, a), G.Vector w (SU.Vector m Word, a)) + :: (Eq a, Num a, KnownNat m, G.Vector v (Monom n a), G.Vector w (Monom m a)) => MultiPoly v n a -> SV.Vector n (MultiPoly w m a) -> MultiPoly w m a @@ -371,7 +367,7 @@ subst = substitute (scale 0) {-# INLINE subst #-} subst' - :: (Eq a, Semiring a, KnownNat m, G.Vector v (SU.Vector n Word, a), G.Vector w (SU.Vector m Word, a)) + :: (Eq a, Semiring a, KnownNat m, G.Vector v (Monom n a), G.Vector w (Monom m a)) => MultiPoly v n a -> SV.Vector n (MultiPoly w m a) -> MultiPoly w m a @@ -380,15 +376,15 @@ subst' = substitute' (scale' 0) substitute :: forall v u n a b. - (G.Vector v (SU.Vector n Word, a), G.Vector u b, Num b) + (G.Vector v (Monom n a), G.Vector u b, Num b) => (a -> b -> b) -> MultiPoly v n a -> SG.Vector u n b -> b substitute f (MultiPoly cs) xs = G.foldl' go 0 cs where - go :: b -> (SU.Vector n Word, a) -> b - go acc (ps, c) = acc + f c (doMonom ps) + go :: b -> (Monom n a) -> b + go acc (Monom ps c) = acc + f c (doMonom ps) doMonom :: SU.Vector n Word -> b doMonom = SU.ifoldl' (\acc i p -> acc * ((xs `SG.index` i) ^ p)) 1 @@ -396,15 +392,15 @@ substitute f (MultiPoly cs) xs = G.foldl' go 0 cs substitute' :: forall v u n a b. - (G.Vector v (SU.Vector n Word, a), G.Vector u b, Semiring b) + (G.Vector v (Monom n a), G.Vector u b, Semiring b) => (a -> b -> b) -> MultiPoly v n a -> SG.Vector u n b -> b substitute' f (MultiPoly cs) xs = G.foldl' go zero cs where - go :: b -> (SU.Vector n Word, a) -> b - go acc (ps, c) = acc `plus` f c (doMonom ps) + go :: b -> (Monom n a) -> b + go acc (Monom ps c) = acc `plus` f c (doMonom ps) doMonom :: SU.Vector n Word -> b doMonom = SU.ifoldl' (\acc i p -> acc `times` ((xs `SG.index` i) Semiring.^ p)) one @@ -420,7 +416,7 @@ substitute' f (MultiPoly cs) xs = G.foldl' go zero cs -- -- @since 0.5.0.0 deriv - :: (Eq a, Num a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Num a, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a -> MultiPoly v n a @@ -432,7 +428,7 @@ deriv i (MultiPoly xs) = MultiPoly $ derivPoly {-# INLINE deriv #-} deriv' - :: (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a -> MultiPoly v n a @@ -455,38 +451,38 @@ deriv' i (MultiPoly xs) = MultiPoly $ derivPoly -- -- @since 0.5.0.0 integral - :: (Fractional a, G.Vector v (SU.Vector n Word, a)) + :: (Fractional a, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a -> MultiPoly v n a integral i (MultiPoly xs) = MultiPoly - $ G.map (\(ps, c) -> let p = ps `SU.index` i in - (ps SU.// [(i, p + 1)], c / fromIntegral (p + 1))) xs + $ G.map (\(Monom ps c) -> let p = ps `SU.index` i in + (Monom (ps SU.// [(i, p + 1)]) (c / fromIntegral (p + 1)))) xs {-# INLINE integral #-} integral' - :: (Field a, G.Vector v (SU.Vector n Word, a)) + :: (Field a, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a -> MultiPoly v n a integral' i (MultiPoly xs) = MultiPoly - $ G.map (\(ps, c) -> let p = ps `SU.index` i in - (ps SU.// [(i, p + 1)], c `quot` Semiring.fromIntegral (p + 1))) xs + $ G.map (\(Monom ps c) -> let p = ps `SU.index` i in + (Monom (ps SU.// [(i, p + 1)]) (c `quot` Semiring.fromIntegral (p + 1)))) xs {-# INLINE integral' #-} -- | Create a polynomial equal to the first variable. -- -- @since 0.5.0.0 pattern X - :: (Eq a, Num a, KnownNat n, 1 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Num a, KnownNat n, 1 <= n, G.Vector v (Monom n a)) => MultiPoly v n a pattern X <- (isVar 0 -> True) where X = var 0 pattern X' - :: (Eq a, Semiring a, KnownNat n, 1 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 1 <= n, G.Vector v (Monom n a)) => MultiPoly v n a pattern X' <- (isVar' 0 -> True) where X' = var' 0 @@ -495,13 +491,13 @@ pattern X' <- (isVar' 0 -> True) -- -- @since 0.5.0.0 pattern Y - :: (Eq a, Num a, KnownNat n, 2 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Num a, KnownNat n, 2 <= n, G.Vector v (Monom n a)) => MultiPoly v n a pattern Y <- (isVar 1 -> True) where Y = var 1 pattern Y' - :: (Eq a, Semiring a, KnownNat n, 2 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 2 <= n, G.Vector v (Monom n a)) => MultiPoly v n a pattern Y' <- (isVar' 1 -> True) where Y' = var' 1 @@ -510,59 +506,67 @@ pattern Y' <- (isVar' 1 -> True) -- -- @since 0.5.0.0 pattern Z - :: (Eq a, Num a, KnownNat n, 3 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Num a, KnownNat n, 3 <= n, G.Vector v (Monom n a)) => MultiPoly v n a pattern Z <- (isVar 2 -> True) where Z = var 2 pattern Z' - :: (Eq a, Semiring a, KnownNat n, 3 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 3 <= n, G.Vector v (Monom n a)) => MultiPoly v n a pattern Z' <- (isVar' 2 -> True) where Z' = var' 2 var :: forall v n a. - (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + (Eq a, Num a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a var i | (1 :: a) == 0 = MultiPoly G.empty | otherwise = MultiPoly $ G.singleton - (SU.generate (\j -> if i == j then 1 else 0), 1) + (Monom (SU.generate (\j -> if i == j then 1 else 0)) 1) {-# INLINE var #-} var' :: forall v n a. - (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a var' i | (one :: a) == zero = MultiPoly G.empty | otherwise = MultiPoly $ G.singleton - (SU.generate (\j -> if i == j then 1 else 0), one) + (Monom (SU.generate (\j -> if i == j then 1 else 0)) one) {-# INLINE var' #-} isVar :: forall v n a. - (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + (Eq a, Num a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a -> Bool isVar i (MultiPoly xs) | (1 :: a) == 0 = G.null xs - | otherwise = G.length xs == 1 && G.unsafeHead xs == (SU.generate (\j -> if i == j then 1 else 0), 1) + | otherwise = G.length xs == 1 && + monomCoeff mon == 1 && + monomPower mon == SU.generate (\j -> if i == j then 1 else 0) + where + mon = G.unsafeHead xs {-# INLINE isVar #-} isVar' :: forall v n a. - (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiPoly v n a -> Bool isVar' i (MultiPoly xs) | (one :: a) == zero = G.null xs - | otherwise = G.length xs == 1 && G.unsafeHead xs == (SU.generate (\j -> if i == j then 1 else 0), one) + | otherwise = G.length xs == 1 && + monomCoeff mon == one && + monomPower mon == SU.generate (\j -> if i == j then 1 else 0) + where + mon = G.unsafeHead xs {-# INLINE isVar' #-} ------------------------------------------------------------------------------- @@ -585,14 +589,14 @@ groupOn f = go -- -- @since 0.5.0.0 segregate - :: (G.Vector v (SU.Vector (1 + m) Word, a), G.Vector v (SU.Vector m Word, a)) + :: (G.Vector v (Monom (1 + m) a), G.Vector v (Monom m a)) => MultiPoly v (1 + m) a -> VPoly (MultiPoly v m a) segregate = MultiPoly . G.fromList - . map (\vs -> (SU.take (fst (G.unsafeHead vs)), MultiPoly $ G.map (first SU.tail) vs)) - . groupOn (SU.head . fst) + . map (\vs -> Monom (let Monom hp _ = G.unsafeHead vs in SU.take hp) (MultiPoly $ G.map (\(Monom p c) -> Monom (SU.tail p) c) vs)) + . groupOn (\(Monom p _) -> SU.head p) . unMultiPoly -- | Interpret a univariate polynomials, whose coefficients are @@ -601,12 +605,12 @@ segregate -- -- @since 0.5.0.0 unsegregate - :: (G.Vector v (SU.Vector (1 + m) Word, a), G.Vector v (SU.Vector m Word, a)) + :: (G.Vector v (Monom (1 + m) a), G.Vector v (Monom m a)) => VPoly (MultiPoly v m a) -> MultiPoly v (1 + m) a unsegregate = MultiPoly . G.concat . G.toList - . G.map (\(v, MultiPoly vs) -> G.map (first (v SU.++)) vs) + . G.map (\(Monom v (MultiPoly vs)) -> G.map (\(Monom p c) -> Monom (v SU.++ p) c) vs) . unMultiPoly diff --git a/src/Data/Poly/Internal/Multi/Core.hs b/src/Data/Poly/Internal/Multi/Core.hs index 2035f02..93c33ea 100644 --- a/src/Data/Poly/Internal/Multi/Core.hs +++ b/src/Data/Poly/Internal/Multi/Core.hs @@ -20,23 +20,27 @@ module Data.Poly.Internal.Multi.Core , convolution , scaleInternal , derivPoly + , Monom(..) ) where import Control.Monad import Control.Monad.ST import Data.Bits import Data.Ord +import Data.Poly.Internal.Multi.Monom import qualified Data.Vector.Algorithms.Tim as Tim import qualified Data.Vector.Generic as G import qualified Data.Vector.Generic.Mutable as MG import qualified Data.Vector.Unboxed as U +import qualified Data.Vector.Unboxed.Sized as SU +import GHC.TypeNats normalize - :: (G.Vector v (t, a), Ord t) + :: G.Vector v (Monom n a) => (a -> Bool) -> (a -> a -> a) - -> v (t, a) - -> v (t, a) + -> v (Monom n a) + -> v (Monom n a) normalize p add vs | G.null vs = vs | otherwise = runST $ do @@ -46,14 +50,14 @@ normalize p add vs {-# INLINABLE normalize #-} normalizeM - :: (G.Vector v (t, a), Ord t) + :: G.Vector v (Monom n a) => (a -> Bool) -> (a -> a -> a) - -> G.Mutable v s (t, a) + -> G.Mutable v s (Monom n a) -> ST s Int normalizeM p add ws = do let l = MG.length ws - let go i j acc@(accP, accC) + let go i j acc@(Monom accP accC) | j >= l = if p accC then do @@ -61,26 +65,26 @@ normalizeM p add ws = do pure $ i + 1 else pure i | otherwise = do - v@(vp, vc) <- MG.unsafeRead ws j + v@(Monom vp vc) <- MG.unsafeRead ws j if vp == accP - then go i (j + 1) (accP, accC `add` vc) + then go i (j + 1) (Monom accP (accC `add` vc)) else if p accC then do MG.write ws i acc go (i + 1) (j + 1) v else go i (j + 1) v - Tim.sortBy (comparing fst) ws + Tim.sortBy (comparing (\(Monom w _) -> w)) ws wsHead <- MG.unsafeRead ws 0 go 0 1 wsHead {-# INLINABLE normalizeM #-} plusPoly - :: (G.Vector v (t, a), Ord t) + :: G.Vector v (Monom n a) => (a -> Bool) -> (a -> a -> a) - -> v (t, a) - -> v (t, a) - -> v (t, a) + -> v (Monom n a) + -> v (Monom n a) + -> v (Monom n a) plusPoly p add = \xs ys -> runST $ do zs <- MG.unsafeNew (G.length xs + G.length ys) lenZs <- plusPolyM p add xs ys zs @@ -88,12 +92,12 @@ plusPoly p add = \xs ys -> runST $ do {-# INLINABLE plusPoly #-} plusPolyM - :: (G.Vector v (t, a), Ord t) + :: G.Vector v (Monom n a) => (a -> Bool) -> (a -> a -> a) - -> v (t, a) - -> v (t, a) - -> G.Mutable v s (t, a) + -> v (Monom n a) + -> v (Monom n a) + -> G.Mutable v s (Monom n a) -> ST s Int plusPolyM p add xs ys zs = go 0 0 0 where @@ -112,32 +116,32 @@ plusPolyM p add xs ys zs = go 0 0 0 (MG.unsafeSlice iz (lenXs - ix) zs) (G.unsafeSlice ix (lenXs - ix) xs) pure $ iz + lenXs - ix - | (xp, xc) <- G.unsafeIndex xs ix - , (yp, yc) <- G.unsafeIndex ys iy + | (Monom xp xc) <- G.unsafeIndex xs ix + , (Monom yp yc) <- G.unsafeIndex ys iy = case xp `compare` yp of LT -> do - MG.unsafeWrite zs iz (xp, xc) + MG.unsafeWrite zs iz (Monom xp xc) go (ix + 1) iy (iz + 1) EQ -> do let zc = xc `add` yc if p zc then do - MG.unsafeWrite zs iz (xp, zc) + MG.unsafeWrite zs iz (Monom xp zc) go (ix + 1) (iy + 1) (iz + 1) else go (ix + 1) (iy + 1) iz GT -> do - MG.unsafeWrite zs iz (yp, yc) + MG.unsafeWrite zs iz (Monom yp yc) go ix (iy + 1) (iz + 1) {-# INLINE plusPolyM #-} minusPoly - :: (G.Vector v (t, a), Ord t) + :: G.Vector v (Monom n a) => (a -> Bool) -> (a -> a) -> (a -> a -> a) - -> v (t, a) - -> v (t, a) - -> v (t, a) + -> v (Monom n a) + -> v (Monom n a) + -> v (Monom n a) minusPoly p neg sub = \xs ys -> runST $ do let lenXs = G.length xs lenYs = G.length ys @@ -147,86 +151,86 @@ minusPoly p neg sub = \xs ys -> runST $ do | ix == lenXs = do forM_ [iy .. lenYs - 1] $ \i -> MG.unsafeWrite zs (iz + i - iy) - (fmap neg (G.unsafeIndex ys i)) + ((\(Monom ps c) -> Monom ps (neg c)) (G.unsafeIndex ys i)) pure $ iz + lenYs - iy | iy == lenYs = do G.unsafeCopy (MG.unsafeSlice iz (lenXs - ix) zs) (G.unsafeSlice ix (lenXs - ix) xs) pure $ iz + lenXs - ix - | (xp, xc) <- G.unsafeIndex xs ix - , (yp, yc) <- G.unsafeIndex ys iy + | (Monom xp xc) <- G.unsafeIndex xs ix + , (Monom yp yc) <- G.unsafeIndex ys iy = case xp `compare` yp of LT -> do - MG.unsafeWrite zs iz (xp, xc) + MG.unsafeWrite zs iz (Monom xp xc) go (ix + 1) iy (iz + 1) EQ -> do let zc = xc `sub` yc if p zc then do - MG.unsafeWrite zs iz (xp, zc) + MG.unsafeWrite zs iz (Monom xp zc) go (ix + 1) (iy + 1) (iz + 1) else go (ix + 1) (iy + 1) iz GT -> do - MG.unsafeWrite zs iz (yp, neg yc) + MG.unsafeWrite zs iz (Monom yp (neg yc)) go ix (iy + 1) (iz + 1) lenZs <- go 0 0 0 G.unsafeFreeze $ MG.unsafeSlice 0 lenZs zs {-# INLINABLE minusPoly #-} scaleM - :: (G.Vector v (t, a), Num t) + :: (KnownNat n, G.Vector v (Monom n a)) => (a -> Bool) -> (a -> a -> a) - -> v (t, a) - -> (t, a) - -> G.Mutable v s (t, a) + -> v (Monom n a) + -> (Monom n a) + -> G.Mutable v s (Monom n a) -> ST s Int -scaleM p mul xs (yp, yc) zs = go 0 0 +scaleM p mul xs (Monom yp yc) zs = go 0 0 where lenXs = G.length xs go ix iz | ix == lenXs = pure iz - | (xp, xc) <- G.unsafeIndex xs ix + | (Monom xp xc) <- G.unsafeIndex xs ix = do let zc = xc `mul` yc if p zc then do - MG.unsafeWrite zs iz (xp + yp, zc) + MG.unsafeWrite zs iz (Monom (xp + yp) zc) go (ix + 1) (iz + 1) else go (ix + 1) iz {-# INLINABLE scaleM #-} scaleInternal - :: (G.Vector v (t, a), Num t) + :: (KnownNat n, G.Vector v (Monom n a)) => (a -> Bool) -> (a -> a -> a) - -> t + -> SU.Vector n Word -> a - -> v (t, a) - -> v (t, a) + -> v (Monom n a) + -> v (Monom n a) scaleInternal p mul yp yc xs = runST $ do zs <- MG.unsafeNew (G.length xs) - len <- scaleM p (flip mul) xs (yp, yc) zs + len <- scaleM p (flip mul) xs (Monom yp yc) zs G.unsafeFreeze $ MG.unsafeSlice 0 len zs {-# INLINABLE scaleInternal #-} convolution - :: forall v t a. - (G.Vector v (t, a), Ord t, Num t) + :: forall v n a. + (KnownNat n, G.Vector v (Monom n a)) => (a -> Bool) -> (a -> a -> a) -> (a -> a -> a) - -> v (t, a) - -> v (t, a) - -> v (t, a) + -> v (Monom n a) + -> v (Monom n a) + -> v (Monom n a) convolution p add mult = \xs ys -> if G.length xs >= G.length ys then go mult xs ys else go (flip mult) ys xs where - go :: (a -> a -> a) -> v (t, a) -> v (t, a) -> v (t, a) + go :: (a -> a -> a) -> v (Monom n a) -> v (Monom n a) -> v (Monom n a) go mul long short = runST $ do let lenLong = G.length long lenShort = G.length short @@ -235,10 +239,10 @@ convolution p add mult = \xs ys -> buffer <- MG.unsafeNew lenBuffer forM_ [0 .. lenShort - 1] $ \iShort -> do - let (pShort, cShort) = G.unsafeIndex short iShort + let (Monom pShort cShort) = G.unsafeIndex short iShort from = iShort * lenLong bufferSlice = MG.unsafeSlice from lenLong buffer - len <- scaleM p mul long (pShort, cShort) bufferSlice + len <- scaleM p mul long (Monom pShort cShort) bufferSlice MG.unsafeWrite slices iShort (from, len) slices' <- G.unsafeFreeze slices @@ -248,9 +252,9 @@ convolution p add mult = \xs ys -> gogo :: U.Vector (Int, Int) - -> v (t, a) - -> G.Mutable v s (t, a) - -> ST s (v (t, a)) + -> v (Monom n a) + -> G.Mutable v s (Monom n a) + -> ST s (v (Monom n a)) gogo slices buffer bufferNew | G.length slices == 0 = pure G.empty @@ -283,12 +287,15 @@ convolution p add mult = \xs ys -> {-# INLINABLE convolution #-} derivPoly - :: (G.Vector v (t, a)) - => (a -> Bool) -- ^ is coefficient non-zero? - -> (t -> t) -- ^ how to modify powers? - -> (t -> a -> a) -- ^ how to modify coefficient? - -> v (t, a) - -> v (t, a) + :: G.Vector v (Monom n a) + => (a -> Bool) + -- ^ is coefficient non-zero? + -> (SU.Vector n Word -> SU.Vector n Word) + -- ^ how to modify powers? + -> (SU.Vector n Word -> a -> a) + -- ^ how to modify coefficient? + -> v (Monom n a) + -> v (Monom n a) derivPoly p dec mul xs | G.null xs = G.empty | otherwise = runST $ do @@ -296,11 +303,11 @@ derivPoly p dec mul xs zs <- MG.unsafeNew lenXs let go ix iz | ix == lenXs = pure iz - | (xp, xc) <- G.unsafeIndex xs ix + | (Monom xp xc) <- G.unsafeIndex xs ix = do let zc = xp `mul` xc if p zc then do - MG.unsafeWrite zs iz (dec xp, zc) + MG.unsafeWrite zs iz (Monom (dec xp) zc) go (ix + 1) (iz + 1) else go (ix + 1) iz diff --git a/src/Data/Poly/Internal/Multi/Field.hs b/src/Data/Poly/Internal/Multi/Field.hs index 37d2444..5e54908 100644 --- a/src/Data/Poly/Internal/Multi/Field.hs +++ b/src/Data/Poly/Internal/Multi/Field.hs @@ -33,10 +33,10 @@ import Data.Poly.Internal.Multi import Data.Poly.Internal.Multi.GcdDomain () -- | Note that 'degree' 0 = 0. -instance (Eq a, Field a, G.Vector v (SU.Vector 1 Word, a)) => Euclidean (Poly v a) where +instance (Eq a, Field a, G.Vector v (Monom 1 a)) => Euclidean (Poly v a) where degree (MultiPoly xs) | G.null xs = 0 - | otherwise = fromIntegral (SU.head (fst (G.unsafeLast xs))) + | otherwise = fromIntegral (SU.head (monomPower (G.unsafeLast xs))) quotRem = quotientRemainder zero plus minus times quot @@ -46,12 +46,12 @@ instance (Eq a, Field a, G.Vector v (SU.Vector 1 Word, a)) => Euclidean (Poly v -- (1.0 * X,1.0 * X + 2.0) -- -- @since 0.5.0.0 -quotRemFractional :: (Eq a, Fractional a, G.Vector v (SU.Vector 1 Word, a)) => Poly v a -> Poly v a -> (Poly v a, Poly v a) +quotRemFractional :: (Eq a, Fractional a, G.Vector v (Monom 1 a)) => Poly v a -> Poly v a -> (Poly v a, Poly v a) quotRemFractional = quotientRemainder 0 (+) (-) (*) (/) {-# INLINE quotRemFractional #-} quotientRemainder - :: G.Vector v (SU.Vector 1 Word, a) + :: G.Vector v (Monom 1 a) => Poly v a -- ^ zero -> (Poly v a -> Poly v a -> Poly v a) -- ^ add -> (Poly v a -> Poly v a -> Poly v a) -- ^ subtract @@ -71,5 +71,5 @@ quotientRemainder zer add sub mul div ts ys = case leading ys of EQ -> (zs, xs') GT -> first (`add` zs) $ go xs' where - zs = MultiPoly $ G.singleton (SU.singleton (xp - yp), xc `div` yc) + zs = MultiPoly $ G.singleton (Monom (SU.singleton (xp - yp)) (xc `div` yc)) xs' = xs `sub` (zs `mul` ys) diff --git a/src/Data/Poly/Internal/Multi/GcdDomain.hs b/src/Data/Poly/Internal/Multi/GcdDomain.hs index a5166a2..39a1693 100644 --- a/src/Data/Poly/Internal/Multi/GcdDomain.hs +++ b/src/Data/Poly/Internal/Multi/GcdDomain.hs @@ -37,7 +37,7 @@ import Unsafe.Coerce import Data.Poly.Internal.Multi -instance {-# OVERLAPPING #-} (Eq a, Ring a, GcdDomain a, G.Vector v (SU.Vector 1 Word, a)) => GcdDomain (Poly v a) where +instance {-# OVERLAPPING #-} (Eq a, Ring a, GcdDomain a, G.Vector v (Monom 1 a)) => GcdDomain (Poly v a) where divide xs ys | G.null (unMultiPoly ys) = throw DivideByZero | G.length (unMultiPoly ys) == 1 = divideSingleton xs (G.unsafeHead (unMultiPoly ys)) @@ -64,7 +64,7 @@ isSucc :: forall n. KnownNat n => IsSucc n isSucc = case someNatVal (natVal (Proxy :: Proxy n) - 1) of SomeNat (_ :: Proxy m) -> IsSucc (unsafeCoerce Refl :: n :~: 1 + m) -instance (Eq a, Ring a, GcdDomain a, KnownNat n, forall m. KnownNat m => G.Vector v (SU.Vector m Word, a), forall m. KnownNat m => Eq (v (SU.Vector m Word, a))) => GcdDomain (MultiPoly v n a) where +instance (Eq a, Ring a, GcdDomain a, KnownNat n, forall m. KnownNat m => G.Vector v (Monom m a)) => GcdDomain (MultiPoly v n a) where divide xs ys | G.null (unMultiPoly ys) = throw DivideByZero | G.length (unMultiPoly ys) == 1 = divideSingleton xs (G.unsafeHead (unMultiPoly ys)) @@ -87,29 +87,29 @@ instance (Eq a, Ring a, GcdDomain a, KnownNat n, forall m. KnownNat m => G.Vecto IsSucc Refl -> unsegregate $ segregate xs `gcd` segregate ys divideSingleton - :: (GcdDomain a, G.Vector v (SU.Vector n Word, a)) + :: (GcdDomain a, G.Vector v (Monom n a)) => MultiPoly v n a - -> (SU.Vector n Word, a) + -> (Monom n a) -> Maybe (MultiPoly v n a) -divideSingleton (MultiPoly pcs) (p, c) = MultiPoly <$> G.mapM divideMonomial pcs +divideSingleton (MultiPoly pcs) (Monom p c) = MultiPoly <$> G.mapM divideMonomial pcs where - divideMonomial (p', c') + divideMonomial (Monom p' c') | SU.and (SU.zipWith (>=) p' p) , Just c'' <- c' `divide` c - = Just (SU.zipWith (-) p' p, c'') + = Just (Monom (SU.zipWith (-) p' p) c'') | otherwise = Nothing gcdSingleton - :: (Eq a, GcdDomain a, G.Vector v (SU.Vector n Word, a)) - => (SU.Vector n Word, a) + :: (Eq a, GcdDomain a, G.Vector v (Monom n a)) + => (Monom n a) -> MultiPoly v n a -> MultiPoly v n a -gcdSingleton pc (MultiPoly pcs) = uncurry monomial' $ - G.foldl' (\(accP, accC) (p, c) -> (SU.zipWith min accP p, gcd accC c)) pc pcs +gcdSingleton pc (MultiPoly pcs) = (\(Monom p c) -> monomial' p c) $ + G.foldl' (\(Monom accP accC) (Monom p c) -> Monom (SU.zipWith min accP p) (gcd accC c)) pc pcs divide1 - :: (Eq a, GcdDomain a, Ring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, GcdDomain a, Ring a, G.Vector v (Monom 1 a)) => Poly v a -> Poly v a -> Maybe (Poly v a) @@ -121,12 +121,12 @@ divide1 xs ys = case leading ys of | xp < yp -> Nothing | otherwise -> do zc <- divide xc yc - let z = MultiPoly $ G.singleton (SU.singleton (xp - yp), zc) + let z = MultiPoly $ G.singleton (Monom (SU.singleton (xp - yp)) zc) rest <- divide1 (xs `minus` z `times` ys) ys pure $ rest `plus` z gcd1 - :: (Eq a, GcdDomain a, Ring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, GcdDomain a, Ring a, G.Vector v (Monom 1 a)) => Poly v a -> Poly v a -> Poly v a @@ -137,11 +137,11 @@ gcd1 x@(MultiPoly xs) y@(MultiPoly ys) = xy = monomial' 0 (gcd (content xs) (content ys)) divide1' = (fromMaybe (error "gcd: violated internal invariant") .) . divide1 -content :: (GcdDomain a, G.Vector v (t, a)) => v (t, a) -> a -content = G.foldl' (\acc (_, t) -> gcd acc t) zero +content :: (GcdDomain a, G.Vector v (Monom n a)) => v (Monom n a) -> a +content = G.foldl' (\acc (Monom _ t) -> gcd acc t) zero gcdHelper - :: (Eq a, Ring a, GcdDomain a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Ring a, GcdDomain a, G.Vector v (Monom 1 a)) => Poly v a -> Poly v a -> Poly v a diff --git a/src/Data/Poly/Internal/Multi/Laurent.hs b/src/Data/Poly/Internal/Multi/Laurent.hs index acd96c9..9b3d3d7 100644 --- a/src/Data/Poly/Internal/Multi/Laurent.hs +++ b/src/Data/Poly/Internal/Multi/Laurent.hs @@ -26,6 +26,7 @@ module Data.Poly.Internal.Multi.Laurent ( MultiLaurent , VMultiLaurent , UMultiLaurent + , Multi.Monom , unMultiLaurent , toMultiLaurent , leading @@ -51,7 +52,7 @@ module Data.Poly.Internal.Multi.Laurent import Prelude hiding (quotRem, quot, rem, gcd, lcm) import Data.Bifunctor (first) -import Control.DeepSeq (NFData(..)) +import Control.DeepSeq (NFData(..), NFData1) import Control.Exception import Data.Euclidean (GcdDomain(..), Euclidean(..), Field) import Data.Finite @@ -73,6 +74,7 @@ import Data.Poly.Internal.Multi (Poly, MultiPoly(..)) import qualified Data.Poly.Internal.Multi as Multi import Data.Poly.Internal.Multi.Field () import Data.Poly.Internal.Multi.GcdDomain () +import Data.Poly.Internal.Multi.Monom -- | Sparse -- @@ -100,8 +102,11 @@ import Data.Poly.Internal.Multi.GcdDomain () data MultiLaurent (v :: Type -> Type) (n :: Nat) (a :: Type) = MultiLaurent !(SU.Vector n Int) !(MultiPoly v n a) -deriving instance Eq (v (SU.Vector n Word, a)) => Eq (MultiLaurent v n a) -deriving instance Ord (v (SU.Vector n Word, a)) => Ord (MultiLaurent v n a) +deriving instance (Eq a, G.Vector v (Monom n a)) => Eq (MultiLaurent v n a) +deriving instance (Ord a, G.Vector v (Monom n a)) => Ord (MultiLaurent v n a) + +instance (NFData a, NFData1 v) => NFData (MultiLaurent v n a) where + rnf (MultiLaurent off poly) = rnf off `seq` rnf poly -- | Multivariate Laurent polynomials backed by boxed vectors. -- @@ -147,17 +152,17 @@ type VLaurent (a :: Type) = Laurent V.Vector a -- @since 0.4.0.0 type ULaurent (a :: Type) = Laurent U.Vector a -instance (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Int, a), G.Vector v (SU.Vector n Word, a)) => IsList (MultiLaurent v n a) where +instance (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => IsList (MultiLaurent v n a) where type Item (MultiLaurent v n a) = (SU.Vector n Int, a) fromList [] = MultiLaurent 0 zero fromList xs = toMultiLaurent minPow (fromList ys) where minPow = foldl1' (SU.zipWith min) (map fst xs) - ys = map (first (SU.map fromIntegral . subtract minPow)) xs + ys = map (\(p, c) -> (SU.map fromIntegral (p - minPow), c)) xs toList (MultiLaurent off (MultiPoly poly)) = - map (first ((+ off) . SU.map fromIntegral)) $ G.toList poly + map (\(Monom p c) -> (off + SU.map fromIntegral p, c)) $ G.toList poly -- | Deconstruct a 'MultiLaurent' polynomial into an offset (largest possible) -- and a regular polynomial. @@ -201,7 +206,7 @@ unLaurent = first SU.head . unMultiLaurent -- >>> toMultiLaurent (fromTuple (0, -2)) (2 * Data.Poly.Multi.X + 1) :: UMultiLaurent 2 Int -- 2 * X * Y^-2 + 1 * Y^-2 toMultiLaurent - :: (KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (KnownNat n, G.Vector v (Monom n a)) => SU.Vector n Int -> MultiPoly v n a -> MultiLaurent v n a @@ -209,10 +214,10 @@ toMultiLaurent off (MultiPoly xs) | G.null xs = MultiLaurent 0 (MultiPoly G.empty) | otherwise = MultiLaurent (SU.zipWith (\o m -> o + fromIntegral m) off minPow) (MultiPoly ys) where - minPow = G.foldl'(\acc (x, _) -> SU.zipWith min acc x) (SU.replicate maxBound) xs + minPow = G.foldl' (\acc (Monom x _) -> SU.zipWith min acc x) (SU.replicate maxBound) xs ys | SU.all (== 0) minPow = xs - | otherwise = G.map (first (SU.zipWith subtract minPow)) xs + | otherwise = G.map (\(Monom p c) -> Monom (SU.zipWith subtract minPow p) c) xs {-# INLINE toMultiLaurent #-} -- | Construct a 'Laurent' polynomial from an offset and a regular polynomial. @@ -225,17 +230,14 @@ toMultiLaurent off (MultiPoly xs) -- -- @since 0.4.0.0 toLaurent - :: G.Vector v (SU.Vector 1 Word, a) + :: G.Vector v (Monom 1 a) => Int -> Poly v a -> Laurent v a toLaurent = toMultiLaurent . SU.singleton {-# INLINABLE toLaurent #-} -instance NFData (v (SU.Vector n Word, a)) => NFData (MultiLaurent v n a) where - rnf (MultiLaurent off poly) = rnf off `seq` rnf poly - -instance (Show a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Show (MultiLaurent v n a) where +instance (Show a, KnownNat n, G.Vector v (Monom n a)) => Show (MultiLaurent v n a) where showsPrec d (MultiLaurent off (MultiPoly xs)) | G.null xs = showString "0" @@ -243,7 +245,7 @@ instance (Show a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Show (MultiLa = showParen (d > 0) $ foldl (.) id $ intersperse (showString " + ") - $ G.foldl (\acc (is, c) -> showCoeff (SU.map fromIntegral is + off) c : acc) [] xs + $ G.foldl (\acc (Monom is c) -> showCoeff (SU.map fromIntegral is + off) c : acc) [] xs where showCoeff is c = showsPrec 7 c . foldl (.) id @@ -271,11 +273,11 @@ instance (Show a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Show (MultiLa -- Nothing -- -- @since 0.4.0.0 -leading :: G.Vector v (SU.Vector 1 Word, a) => Laurent v a -> Maybe (Int, a) +leading :: G.Vector v (Monom 1 a) => Laurent v a -> Maybe (Int, a) leading (MultiLaurent off poly) = first ((+ SU.head off) . fromIntegral) <$> Multi.leading poly -- | Note that 'abs' = 'id' and 'signum' = 'const' 1. -instance (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Num (MultiLaurent v n a) where +instance (Eq a, Num a, KnownNat n, G.Vector v (Monom n a)) => Num (MultiLaurent v n a) where MultiLaurent off1 poly1 * MultiLaurent off2 poly2 = toMultiLaurent (off1 + off2) (poly1 * poly2) MultiLaurent off1 poly1 + MultiLaurent off2 poly2 = toMultiLaurent off (poly1' + poly2') where @@ -297,7 +299,7 @@ instance (Eq a, Num a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Num (Mul {-# INLINE fromInteger #-} {-# INLINE (*) #-} -instance (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Semiring (MultiLaurent v n a) where +instance (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => Semiring (MultiLaurent v n a) where zero = MultiLaurent 0 zero one = MultiLaurent 0 one MultiLaurent off1 poly1 `times` MultiLaurent off2 poly2 = @@ -314,14 +316,14 @@ instance (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Sem {-# INLINE times #-} {-# INLINE fromNatural #-} -instance (Eq a, Ring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Ring (MultiLaurent v n a) where +instance (Eq a, Ring a, KnownNat n, G.Vector v (Monom n a)) => Ring (MultiLaurent v n a) where negate (MultiLaurent off poly) = MultiLaurent off (Semiring.negate poly) -- | Create a monomial from a power and a coefficient. -- -- @since 0.5.0.0 monomial - :: (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => SU.Vector n Int -> a -> MultiLaurent v n a @@ -339,7 +341,7 @@ monomial p c -- -- @since 0.5.0.0 scale - :: (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => SU.Vector n Int -> a -> MultiLaurent v n a @@ -355,7 +357,7 @@ scale yp yc (MultiLaurent off poly) = toMultiLaurent (off + yp) (Multi.scale' 0 -- -- @since 0.5.0.0 eval - :: (Field a, G.Vector v (SU.Vector n Word, a), G.Vector u a) + :: (Field a, G.Vector v (Monom n a), G.Vector u a) => MultiLaurent v n a -> SG.Vector u n a -> a @@ -373,7 +375,7 @@ eval (MultiLaurent off poly) xs = Multi.eval' poly xs `times` -- -- @since 0.5.0.0 subst - :: (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a), G.Vector w (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a), G.Vector w (Monom n a)) => MultiPoly v n a -> SV.Vector n (MultiLaurent w n a) -> MultiLaurent w n a @@ -390,7 +392,7 @@ subst = Multi.substitute' (scale 0) -- -- @since 0.5.0.0 deriv - :: (Eq a, Ring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Ring a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiLaurent v n a -> MultiLaurent v n a @@ -406,7 +408,7 @@ deriv i (MultiLaurent off (MultiPoly xs)) = -- -- @since 0.5.0.0 pattern X - :: (Eq a, Semiring a, KnownNat n, 1 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 1 <= n, G.Vector v (Monom n a)) => MultiLaurent v n a pattern X <- (isVar 0 -> True) where X = var 0 @@ -415,7 +417,7 @@ pattern X <- (isVar 0 -> True) -- -- @since 0.5.0.0 pattern Y - :: (Eq a, Semiring a, KnownNat n, 2 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 2 <= n, G.Vector v (Monom n a)) => MultiLaurent v n a pattern Y <- (isVar 1 -> True) where Y = var 1 @@ -424,14 +426,14 @@ pattern Y <- (isVar 1 -> True) -- -- @since 0.5.0.0 pattern Z - :: (Eq a, Semiring a, KnownNat n, 3 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 3 <= n, G.Vector v (Monom n a)) => MultiLaurent v n a pattern Z <- (isVar 2 -> True) where Z = var 2 var :: forall v n a. - (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiLaurent v n a var i @@ -442,7 +444,7 @@ var i isVar :: forall v n a. - (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => Finite n -> MultiLaurent v n a -> Bool @@ -451,7 +453,11 @@ isVar i (MultiLaurent off (MultiPoly xs)) = off == 0 && G.null xs | otherwise = off == SU.generate (\j -> if i == j then 1 else 0) - && G.length xs == 1 && G.unsafeHead xs == (0, one) + && G.length xs == 1 + && monomCoeff mon == one + && monomPower mon == 0 + where + mon = G.unsafeHead xs {-# INLINE isVar #-} -- | Used to construct monomials with negative powers. @@ -467,17 +473,20 @@ isVar i (MultiLaurent off (MultiPoly xs)) -- -- @since 0.5.0.0 (^-) - :: (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, G.Vector v (Monom n a)) => MultiLaurent v n a -> Int -> MultiLaurent v n a MultiLaurent off (MultiPoly xs) ^- n - | G.length xs == 1, G.unsafeHead xs == (0, one) + | G.length xs == 1 + , mon <- G.unsafeHead xs + , monomCoeff mon == one + , monomPower mon == 0 = MultiLaurent (SU.map (* (-n)) off) (MultiPoly xs) | otherwise = throw $ PatternMatchFail "(^-) can be applied only to a monom with unit coefficient" -instance {-# OVERLAPPING #-} (Eq a, Ring a, GcdDomain a, G.Vector v (SU.Vector 1 Word, a)) => GcdDomain (Laurent v a) where +instance {-# OVERLAPPING #-} (Eq a, Ring a, GcdDomain a, G.Vector v (Monom 1 a)) => GcdDomain (Laurent v a) where divide (MultiLaurent off1 poly1) (MultiLaurent off2 poly2) = toMultiLaurent (off1 - off2) <$> divide poly1 poly2 {-# INLINE divide #-} @@ -494,7 +503,7 @@ instance {-# OVERLAPPING #-} (Eq a, Ring a, GcdDomain a, G.Vector v (SU.Vector 1 coprime poly1 poly2 {-# INLINE coprime #-} -instance (Eq a, Ring a, GcdDomain a, KnownNat n, forall m. KnownNat m => G.Vector v (SU.Vector m Word, a), forall m. KnownNat m => Eq (v (SU.Vector m Word, a))) => GcdDomain (MultiLaurent v n a) where +instance (Eq a, Ring a, GcdDomain a, KnownNat n, forall m. KnownNat m => G.Vector v (Monom m a)) => GcdDomain (MultiLaurent v n a) where divide (MultiLaurent off1 poly1) (MultiLaurent off2 poly2) = toMultiLaurent (off1 - off2) <$> divide poly1 poly2 {-# INLINE divide #-} @@ -519,13 +528,13 @@ instance (Eq a, Ring a, GcdDomain a, KnownNat n, forall m. KnownNat m => G.Vecto -- -- @since 0.5.0.0 segregate - :: (KnownNat m, G.Vector v (SU.Vector (1 + m) Word, a), G.Vector v (SU.Vector m Word, a)) + :: (KnownNat m, G.Vector v (Monom (1 + m) a), G.Vector v (Monom m a)) => MultiLaurent v (1 + m) a -> VLaurent (MultiLaurent v m a) segregate (MultiLaurent off poly) = toMultiLaurent (SU.take off) $ MultiPoly - $ G.map (fmap (toMultiLaurent (SU.tail off))) + $ G.map (\(Monom p c) -> Monom p (toMultiLaurent (SU.tail off) c)) $ Multi.unMultiPoly $ Multi.segregate poly @@ -536,7 +545,7 @@ segregate (MultiLaurent off poly) -- @since 0.5.0.0 unsegregate :: forall v m a. - (KnownNat m, KnownNat (1 + m), G.Vector v (SU.Vector (1 + m) Word, a), G.Vector v (SU.Vector m Word, a)) + (KnownNat m, KnownNat (1 + m), G.Vector v (Monom (1 + m) a), G.Vector v (Monom m a)) => VLaurent (MultiLaurent v m a) -> MultiLaurent v (1 + m) a unsegregate (MultiLaurent off poly) @@ -545,9 +554,9 @@ unsegregate (MultiLaurent off poly) | otherwise = toMultiLaurent (off SU.++ offs) (MultiPoly (G.concat (G.toList ys))) where - xs :: V.Vector (SU.Vector 1 Word, (SU.Vector m Int, MultiPoly v m a)) - xs = G.map (fmap unMultiLaurent) $ Multi.unMultiPoly poly + xs :: V.Vector (Monom 1 (SU.Vector m Int, MultiPoly v m a)) + xs = G.map (\(Monom p c) -> Monom p (unMultiLaurent c)) $ Multi.unMultiPoly poly offs :: SU.Vector m Int - offs = G.foldl' (\acc (_, (v, _)) -> SU.zipWith min acc v) (SU.replicate maxBound) xs - ys :: V.Vector (v (SU.Vector (1 + m) Word, a)) - ys = G.map (\(v, (vs, p)) -> G.map (first ((v SU.++) . SU.zipWith3 (\a b c -> c + fromIntegral (b - a)) offs vs)) (unMultiPoly p)) xs + offs = G.foldl' (\acc (Monom _ (v, _)) -> SU.zipWith min acc v) (SU.replicate maxBound) xs + ys :: V.Vector (v (Monom (1 + m) a)) + ys = G.map (\(Monom v (vs, p)) -> G.map (\(Monom r s) -> Monom (v SU.++ SU.zipWith3 (\a b c -> c + fromIntegral (b - a)) offs vs r) s) (unMultiPoly p)) xs diff --git a/src/Data/Poly/Internal/Multi/Monom.hs b/src/Data/Poly/Internal/Multi/Monom.hs new file mode 100644 index 0000000..0cc6471 --- /dev/null +++ b/src/Data/Poly/Internal/Multi/Monom.hs @@ -0,0 +1,46 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Data.Poly.Internal.Multi.Monom + ( Monom(..) + ) where + +-- import Control.DeepSeq +import qualified Data.Vector.Generic as G +import qualified Data.Vector.Generic.Mutable as MG +import qualified Data.Vector.Unboxed as U +import qualified Data.Vector.Unboxed.Mutable as MU +import qualified Data.Vector.Unboxed.Sized as SU +import GHC.Generics (Generic) +import GHC.TypeNats (KnownNat) + +-- | A strict tuple of a vector of unsigned powers and a coefficient. +-- Basic building block for sparse polynomials. +-- +-- In the current API 'Monom' rarely appears as an argument, +-- only in constraints. +data Monom n a = Monom + { monomPower :: !(SU.Vector n Word) + , monomCoeff :: !a + } deriving (Generic) + +instance U.IsoUnbox (Monom n a) (SU.Vector n Word, a) + +newtype instance MU.MVector s (Monom n a) = + MV_Monom (MU.MVector s (SU.Vector n Word, a)) + +newtype instance U.Vector (Monom n a) = + V_Monom (U.Vector (SU.Vector n Word, a)) + +deriving via (Monom n a `U.As` (SU.Vector n Word, a)) + instance (KnownNat n, U.Unbox a) => MG.MVector U.MVector (Monom n a) + +deriving via (Monom n a `U.As` (SU.Vector n Word, a)) + instance (KnownNat n, U.Unbox a) => G.Vector U.Vector (Monom n a) + +instance (KnownNat n, U.Unbox a) => U.Unbox (Monom n a) diff --git a/src/Data/Poly/Multi.hs b/src/Data/Poly/Multi.hs index 7d3afb2..ed707f3 100644 --- a/src/Data/Poly/Multi.hs +++ b/src/Data/Poly/Multi.hs @@ -16,6 +16,7 @@ module Data.Poly.Multi ( MultiPoly , VMultiPoly , UMultiPoly + , Monom , unMultiPoly , toMultiPoly , monomial @@ -31,6 +32,35 @@ module Data.Poly.Multi , unsegregate ) where -import Data.Poly.Internal.Multi +import qualified Data.Vector.Generic as G +import qualified Data.Vector.Unboxed.Sized as SU + +import Data.Poly.Internal.Multi hiding (unMultiPoly, toMultiPoly) +import qualified Data.Poly.Internal.Multi as Multi import Data.Poly.Internal.Multi.Field () import Data.Poly.Internal.Multi.GcdDomain () + +-- | Make a 'MultiPoly' from a list of (powers, coefficient) pairs. +-- +-- >>> :set -XOverloadedLists -XDataKinds +-- >>> import Data.Vector.Generic.Sized (fromTuple) +-- >>> toMultiPoly [(fromTuple (0,0),1),(fromTuple (0,1),2),(fromTuple (1,0),3)] :: VMultiPoly 2 Integer +-- 3 * X + 2 * Y + 1 +-- >>> toMultiPoly [(fromTuple (0,0),0),(fromTuple (0,1),0),(fromTuple (1,0),0)] :: UMultiPoly 2 Int +-- 0 +-- +-- @since 0.5.0.0 +toMultiPoly + :: (Eq a, Num a, G.Vector v (Monom n a), G.Vector v (SU.Vector n Word, a)) + => v (SU.Vector n Word, a) + -> MultiPoly v n a +toMultiPoly = Multi.toMultiPoly . G.map (uncurry Monom) + +-- | Convert a 'MultiPoly' to a vector of (powers, coefficient) pairs. +-- +-- @since 0.5.0.0 +unMultiPoly + :: (G.Vector v (Monom n a), G.Vector v (SU.Vector n Word, a)) + => MultiPoly v n a + -> v (SU.Vector n Word, a) +unMultiPoly = G.map (\(Monom p c) -> (p, c)) . Multi.unMultiPoly diff --git a/src/Data/Poly/Multi/Laurent.hs b/src/Data/Poly/Multi/Laurent.hs index 9f9b95b..6bf13e9 100644 --- a/src/Data/Poly/Multi/Laurent.hs +++ b/src/Data/Poly/Multi/Laurent.hs @@ -14,6 +14,7 @@ module Data.Poly.Multi.Laurent ( MultiLaurent , VMultiLaurent , UMultiLaurent + , Monom , unMultiLaurent , toMultiLaurent , monomial diff --git a/src/Data/Poly/Multi/Semiring.hs b/src/Data/Poly/Multi/Semiring.hs index 9dc95ef..0dbe3d6 100644 --- a/src/Data/Poly/Multi/Semiring.hs +++ b/src/Data/Poly/Multi/Semiring.hs @@ -18,6 +18,7 @@ module Data.Poly.Multi.Semiring ( MultiPoly , VMultiPoly , UMultiPoly + , Multi.Monom , unMultiPoly , toMultiPoly , monomial @@ -42,7 +43,7 @@ import qualified Data.Vector.Sized as SV import qualified Data.Vector.Unboxed.Sized as SU import GHC.TypeNats (KnownNat, type (<=)) -import Data.Poly.Internal.Multi (MultiPoly, VMultiPoly, UMultiPoly, unMultiPoly, segregate, unsegregate) +import Data.Poly.Internal.Multi (MultiPoly, VMultiPoly, UMultiPoly, segregate, unsegregate) import qualified Data.Poly.Internal.Multi as Multi import Data.Poly.Internal.Multi.Field () import Data.Poly.Internal.Multi.GcdDomain () @@ -58,16 +59,25 @@ import Data.Poly.Internal.Multi.GcdDomain () -- -- @since 0.5.0.0 toMultiPoly - :: (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom n a), G.Vector v (SU.Vector n Word, a)) => v (SU.Vector n Word, a) -> MultiPoly v n a -toMultiPoly = Multi.toMultiPoly' +toMultiPoly = Multi.toMultiPoly' . G.map (uncurry Multi.Monom) + +-- | Convert a 'MultiPoly' to a vector of (powers, coefficient) pairs. +-- +-- @since 0.5.0.0 +unMultiPoly + :: (G.Vector v (Multi.Monom n a), G.Vector v (SU.Vector n Word, a)) + => MultiPoly v n a + -> v (SU.Vector n Word, a) +unMultiPoly = G.map (\(Multi.Monom p c) -> (p, c)) . Multi.unMultiPoly -- | Create a monomial from powers and a coefficient. -- -- @since 0.5.0.0 monomial - :: (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom n a)) => SU.Vector n Word -> a -> MultiPoly v n a @@ -82,7 +92,7 @@ monomial = Multi.monomial' -- -- @since 0.5.0.0 scale - :: (Eq a, Semiring a, KnownNat n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, G.Vector v (Multi.Monom n a)) => SU.Vector n Word -> a -> MultiPoly v n a @@ -93,7 +103,7 @@ scale = Multi.scale' -- -- @since 0.5.0.0 pattern X - :: (Eq a, Semiring a, KnownNat n, 1 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 1 <= n, G.Vector v (Multi.Monom n a)) => MultiPoly v n a pattern X = Multi.X' @@ -101,7 +111,7 @@ pattern X = Multi.X' -- -- @since 0.5.0.0 pattern Y - :: (Eq a, Semiring a, KnownNat n, 2 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 2 <= n, G.Vector v (Multi.Monom n a)) => MultiPoly v n a pattern Y = Multi.Y' @@ -109,7 +119,7 @@ pattern Y = Multi.Y' -- -- @since 0.5.0.0 pattern Z - :: (Eq a, Semiring a, KnownNat n, 3 <= n, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, KnownNat n, 3 <= n, G.Vector v (Multi.Monom n a)) => MultiPoly v n a pattern Z = Multi.Z' @@ -122,7 +132,7 @@ pattern Z = Multi.Z' -- -- @since 0.5.0.0 eval - :: (Semiring a, G.Vector v (SU.Vector n Word, a), G.Vector u a) + :: (Semiring a, G.Vector v (Multi.Monom n a), G.Vector u a) => MultiPoly v n a -> SG.Vector u n a -> a @@ -137,7 +147,7 @@ eval = Multi.eval' -- -- @since 0.5.0.0 subst - :: (Eq a, Semiring a, KnownNat m, G.Vector v (SU.Vector n Word, a), G.Vector w (SU.Vector m Word, a)) + :: (Eq a, Semiring a, KnownNat m, G.Vector v (Multi.Monom n a), G.Vector w (Multi.Monom m a)) => MultiPoly v n a -> SV.Vector n (MultiPoly w m a) -> MultiPoly w m a @@ -153,7 +163,7 @@ subst = Multi.subst' -- -- @since 0.5.0.0 deriv - :: (Eq a, Semiring a, G.Vector v (SU.Vector n Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom n a)) => Finite n -> MultiPoly v n a -> MultiPoly v n a @@ -171,7 +181,7 @@ deriv = Multi.deriv' -- -- @since 0.5.0.0 integral - :: (Field a, G.Vector v (SU.Vector n Word, a)) + :: (Field a, G.Vector v (Multi.Monom n a)) => Finite n -> MultiPoly v n a -> MultiPoly v n a diff --git a/src/Data/Poly/Semiring.hs b/src/Data/Poly/Semiring.hs index b665c14..e9f656f 100644 --- a/src/Data/Poly/Semiring.hs +++ b/src/Data/Poly/Semiring.hs @@ -49,7 +49,6 @@ import Data.Poly.Internal.Dense.DFT import Data.Poly.Internal.Dense.GcdDomain () #ifdef SupportSparse -import qualified Data.Vector.Unboxed.Sized as SU import qualified Data.Poly.Internal.Multi as Sparse import qualified Data.Poly.Internal.Convert as Convert #endif @@ -163,7 +162,7 @@ dftMult getPrimRoot (Poly xs) (Poly ys) = -- 1 * X^2 + 1 -- -- @since 0.5.0.0 -denseToSparse :: (Eq a, Semiring a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) => Dense.Poly v a -> Sparse.Poly v a +denseToSparse :: (Eq a, Semiring a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => Dense.Poly v a -> Sparse.Poly v a denseToSparse = Convert.denseToSparse' -- | Convert from sparse to dense polynomials. @@ -173,6 +172,6 @@ denseToSparse = Convert.denseToSparse' -- 1 * X^2 + 0 * X + 1 -- -- @since 0.5.0.0 -sparseToDense :: (Semiring a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) => Sparse.Poly v a -> Dense.Poly v a +sparseToDense :: (Semiring a, G.Vector v a, G.Vector v (Sparse.Monom 1 a)) => Sparse.Poly v a -> Dense.Poly v a sparseToDense = Convert.sparseToDense' #endif diff --git a/src/Data/Poly/Sparse.hs b/src/Data/Poly/Sparse.hs index 391bc33..904c7e2 100644 --- a/src/Data/Poly/Sparse.hs +++ b/src/Data/Poly/Sparse.hs @@ -32,7 +32,6 @@ module Data.Poly.Sparse , sparseToDense ) where -import Data.Bifunctor import qualified Data.Vector.Generic as G import qualified Data.Vector.Unboxed.Sized as SU import qualified Data.Vector.Sized as SV @@ -53,17 +52,17 @@ import Data.Poly.Internal.Multi.GcdDomain () -- -- @since 0.3.0.0 toPoly - :: (Eq a, Num a, G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v (Word, a), G.Vector v (Multi.Monom 1 a)) => v (Word, a) -> Poly v a -toPoly = Multi.toMultiPoly . G.map (first SU.singleton) +toPoly = Multi.toMultiPoly . G.map (\(p, c) -> Multi.Monom (SU.singleton p) c) {-# INLINABLE toPoly #-} -- | Create a monomial from a power and a coefficient. -- -- @since 0.3.0.0 monomial - :: (Eq a, Num a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v (Multi.Monom 1 a)) => Word -> a -> Poly v a @@ -77,7 +76,7 @@ monomial = Multi.monomial . SU.singleton -- -- @since 0.3.0.0 scale - :: (Eq a, Num a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v (Multi.Monom 1 a)) => Word -> a -> Poly v a @@ -91,7 +90,7 @@ scale = Multi.scale . SU.singleton -- -- @since 0.3.0.0 pattern X - :: (Eq a, Num a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v (Multi.Monom 1 a)) => Poly v a pattern X = Multi.X @@ -102,7 +101,7 @@ pattern X = Multi.X -- -- @since 0.3.0.0 eval - :: (Num a, G.Vector v (SU.Vector 1 Word, a)) + :: (Num a, G.Vector v (Multi.Monom 1 a)) => Poly v a -> a -> a @@ -116,7 +115,7 @@ eval p = Multi.eval p . SV.singleton -- -- @since 0.3.3.0 subst - :: (Eq a, Num a, G.Vector v (SU.Vector 1 Word, a), G.Vector w (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v (Multi.Monom 1 a), G.Vector w (Multi.Monom 1 a)) => Poly v a -> Poly w a -> Poly w a @@ -130,7 +129,7 @@ subst p = Multi.subst p . SV.singleton -- -- @since 0.3.0.0 deriv - :: (Eq a, Num a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Num a, G.Vector v (Multi.Monom 1 a)) => Poly v a -> Poly v a deriv = Multi.deriv 0 @@ -144,7 +143,7 @@ deriv = Multi.deriv 0 -- -- @since 0.3.0.0 integral - :: (Fractional a, G.Vector v (SU.Vector 1 Word, a)) + :: (Fractional a, G.Vector v (Multi.Monom 1 a)) => Poly v a -> Poly v a integral = Multi.integral 0 diff --git a/src/Data/Poly/Sparse/Laurent.hs b/src/Data/Poly/Sparse/Laurent.hs index 15efc7d..51d8db1 100644 --- a/src/Data/Poly/Sparse/Laurent.hs +++ b/src/Data/Poly/Sparse/Laurent.hs @@ -43,7 +43,7 @@ import Data.Poly.Internal.Multi (Poly) -- -- @since 0.4.0.0 monomial - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom 1 a)) => Int -> a -> Laurent v a @@ -57,7 +57,7 @@ monomial = Multi.monomial . SU.singleton -- -- @since 0.4.0.0 scale - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom 1 a)) => Int -> a -> Laurent v a @@ -71,7 +71,7 @@ scale = Multi.scale . SU.singleton -- -- @since 0.4.0.0 pattern X - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom 1 a)) => Laurent v a pattern X = Multi.X @@ -88,7 +88,7 @@ pattern X = Multi.X -- -- @since 0.4.0.0 (^-) - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom 1 a)) => Laurent v a -> Int -> Laurent v a @@ -101,7 +101,7 @@ pattern X = Multi.X -- -- @since 0.4.0.0 eval - :: (Field a, G.Vector v (SU.Vector 1 Word, a)) + :: (Field a, G.Vector v (Monom 1 a)) => Laurent v a -> a -> a @@ -116,7 +116,7 @@ eval p = Multi.eval p . SV.singleton -- -- @since 0.4.0.0 subst - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a), G.Vector w (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Monom 1 a), G.Vector w (Monom 1 a)) => Poly v a -> Laurent w a -> Laurent w a @@ -130,7 +130,7 @@ subst p = Multi.subst p . SV.singleton -- -- @since 0.4.0.0 deriv - :: (Eq a, Ring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Ring a, G.Vector v (Monom 1 a)) => Laurent v a -> Laurent v a deriv = Multi.deriv 0 diff --git a/src/Data/Poly/Sparse/Semiring.hs b/src/Data/Poly/Sparse/Semiring.hs index 52b80ae..858f524 100644 --- a/src/Data/Poly/Sparse/Semiring.hs +++ b/src/Data/Poly/Sparse/Semiring.hs @@ -31,7 +31,6 @@ module Data.Poly.Sparse.Semiring , sparseToDense ) where -import Data.Bifunctor import Data.Euclidean (Field) import Data.Semiring (Semiring(..)) import qualified Data.Vector.Generic as G @@ -55,17 +54,17 @@ import Data.Poly.Internal.Multi.GcdDomain () -- -- @since 0.3.0.0 toPoly - :: (Eq a, Semiring a, G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Word, a), G.Vector v (Multi.Monom 1 a)) => v (Word, a) -> Poly v a -toPoly = Multi.toMultiPoly' . G.map (first SU.singleton) +toPoly = Multi.toMultiPoly' . G.map (\(p, c) -> Multi.Monom (SU.singleton p) c) {-# INLINABLE toPoly #-} -- | Create a monomial from a power and a coefficient. -- -- @since 0.3.0.0 monomial - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom 1 a)) => Word -> a -> Poly v a @@ -79,7 +78,7 @@ monomial = Multi.monomial' . SU.singleton -- -- @since 0.3.0.0 scale - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom 1 a)) => Word -> a -> Poly v a @@ -93,7 +92,7 @@ scale = Multi.scale' . SU.singleton -- -- @since 0.3.0.0 pattern X - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom 1 a)) => Poly v a pattern X = Multi.X' @@ -104,7 +103,7 @@ pattern X = Multi.X' -- -- @since 0.3.0.0 eval - :: (Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Semiring a, G.Vector v (Multi.Monom 1 a)) => Poly v a -> a -> a @@ -118,7 +117,7 @@ eval p = Multi.eval' p . SV.singleton -- -- @since 0.3.3.0 subst - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a), G.Vector w (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom 1 a), G.Vector w (Multi.Monom 1 a)) => Poly v a -> Poly w a -> Poly w a @@ -132,7 +131,7 @@ subst p = Multi.subst' p . SV.singleton -- -- @since 0.3.0.0 deriv - :: (Eq a, Semiring a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v (Multi.Monom 1 a)) => Poly v a -> Poly v a deriv = Multi.deriv' 0 @@ -146,7 +145,7 @@ deriv = Multi.deriv' 0 -- -- @since 0.3.2.0 integral - :: (Field a, G.Vector v (SU.Vector 1 Word, a)) + :: (Field a, G.Vector v (Multi.Monom 1 a)) => Poly v a -> Poly v a integral = Multi.integral' 0 @@ -160,7 +159,7 @@ integral = Multi.integral' 0 -- -- @since 0.5.0.0 denseToSparse - :: (Eq a, Semiring a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Eq a, Semiring a, G.Vector v a, G.Vector v (Multi.Monom 1 a)) => Dense.Poly v a -> Multi.Poly v a denseToSparse = Convert.denseToSparse' @@ -174,7 +173,7 @@ denseToSparse = Convert.denseToSparse' -- -- @since 0.5.0.0 sparseToDense - :: (Semiring a, G.Vector v a, G.Vector v (SU.Vector 1 Word, a)) + :: (Semiring a, G.Vector v a, G.Vector v (Multi.Monom 1 a)) => Multi.Poly v a -> Dense.Poly v a sparseToDense = Convert.sparseToDense' diff --git a/test/Multi.hs b/test/Multi.hs index 150277d..4a43de0 100644 --- a/test/Multi.hs +++ b/test/Multi.hs @@ -194,7 +194,7 @@ evalTests = testGroup "eval" $ concat evalTestGroup :: forall v a. - (Eq a, Num a, Semiring a, Arbitrary a, Show a, Eq (v (SU.Vector 3 Word, a)), Show (v (SU.Vector 3 Word, a)), G.Vector v (SU.Vector 3 Word, a)) + (Eq a, Num a, Semiring a, Arbitrary a, Show a, G.Vector v (SU.Vector 3 Word, a), G.Vector v (Monom 3 a)) => Proxy (MultiPoly v 3 a) -> [TestTree] evalTestGroup _ = @@ -224,7 +224,7 @@ evalTestGroup _ = substTestGroup :: forall v a. - (Eq a, Num a, Semiring a, Arbitrary a, Show a, Eq (v (SU.Vector 3 Word, a)), Show (v (SU.Vector 3 Word, a)), G.Vector v (SU.Vector 3 Word, a)) + (Eq a, Num a, Semiring a, Arbitrary a, Show a, G.Vector v (SU.Vector 3 Word, a), G.Vector v (Monom 3 a)) => Proxy (MultiPoly v 3 a) -> [TestTree] substTestGroup _ = diff --git a/test/MultiLaurent.hs b/test/MultiLaurent.hs index 65294a8..1cc0d0f 100644 --- a/test/MultiLaurent.hs +++ b/test/MultiLaurent.hs @@ -139,7 +139,7 @@ evalTests = testGroup "eval" $ concat evalTestGroup :: forall v a. - (Eq a, Field a, Arbitrary a, Show a, Eq (v (Word, a)), Show (v (Word, a)), G.Vector v (Word, a), Eq (v (SU.Vector 3 Word, a)), Show (v (SU.Vector 3 Word, a)), G.Vector v (SU.Vector 3 Word, a)) + (Eq a, Field a, Arbitrary a, Show a, G.Vector v (Word, a), G.Vector v (SU.Vector 3 Word, a), G.Vector v (Data.Poly.Multi.Monom 3 a)) => Proxy (MultiLaurent v 3 a) -> [TestTree] evalTestGroup _ = @@ -158,7 +158,7 @@ evalTestGroup _ = substTestGroup :: forall v a. - (Eq a, Num a, Semiring a, Arbitrary a, Show a, Eq (v (SU.Vector 3 Word, a)), Show (v (Word, a)), G.Vector v (Word, a), G.Vector v (SU.Vector 3 Word, a)) + (Eq a, Num a, Semiring a, Arbitrary a, Show a,G.Vector v (Word, a), G.Vector v (SU.Vector 3 Word, a), G.Vector v (Data.Poly.Multi.Monom 3 a)) => Proxy (MultiLaurent v 3 a) -> [TestTree] substTestGroup _ = diff --git a/test/Sparse.hs b/test/Sparse.hs index bad76ed..846197e 100644 --- a/test/Sparse.hs +++ b/test/Sparse.hs @@ -18,6 +18,7 @@ import Data.Int import Data.List (sortOn) import qualified Data.List.NonEmpty as NE import Data.Mod.Word +import Data.Poly.Multi (Monom) import Data.Poly.Sparse import qualified Data.Poly.Sparse.Semiring as S import Data.Proxy @@ -213,7 +214,7 @@ evalTests = testGroup "eval" $ concat evalTestGroup :: forall v a. - (Eq a, Num a, Semiring a, Arbitrary a, Show a, Eq (v (Word, a)), Show (v (Word, a)), G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + (Eq a, Num a, Semiring a, Arbitrary a, Show a, G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a), G.Vector v (Monom 1 a)) => Proxy (Poly v a) -> [TestTree] evalTestGroup _ = @@ -244,7 +245,7 @@ evalTestGroup _ = substTestGroup :: forall v a. - (Eq a, Num a, Semiring a, Arbitrary a, Show a, Eq (v (SU.Vector 1 Word, a)), Show (v (SU.Vector 1 Word, a)), G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + (Eq a, Num a, Semiring a, Arbitrary a, Show a, G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a), G.Vector v (Monom 1 a)) => Proxy (Poly v a) -> [TestTree] substTestGroup _ = diff --git a/test/SparseLaurent.hs b/test/SparseLaurent.hs index 0f5379b..d047f57 100644 --- a/test/SparseLaurent.hs +++ b/test/SparseLaurent.hs @@ -13,6 +13,7 @@ import Prelude hiding (gcd, quotRem, quot, rem) import Control.Exception import Data.Euclidean (GcdDomain(..), Field) import Data.Int +import Data.Poly.Multi (Monom) import qualified Data.Poly.Sparse import Data.Poly.Sparse.Laurent import Data.Proxy @@ -141,7 +142,7 @@ evalTests = testGroup "eval" $ concat evalTestGroup :: forall v a. - (Eq a, Field a, Arbitrary a, Show a, Eq (v (Word, a)), Show (v (Word, a)), G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + (Eq a, Field a, Arbitrary a, Show a, G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a), G.Vector v (Monom 1 a)) => Proxy (Laurent v a) -> [TestTree] evalTestGroup _ = @@ -160,7 +161,7 @@ evalTestGroup _ = substTestGroup :: forall v a. - (Eq a, Num a, Semiring a, Arbitrary a, Show a, Eq (v (SU.Vector 1 Word, a)), Show (v (Word, a)), G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a)) + (Eq a, Num a, Semiring a, Arbitrary a, Show a, G.Vector v (Word, a), G.Vector v (SU.Vector 1 Word, a), G.Vector v (Monom 1 a)) => Proxy (Laurent v a) -> [TestTree] substTestGroup _ = diff --git a/test/TestUtils.hs b/test/TestUtils.hs index a524a2f..2ad6904 100644 --- a/test/TestUtils.hs +++ b/test/TestUtils.hs @@ -82,19 +82,19 @@ instance (Arbitrary a, KnownNat n, G.Vector v a) => Arbitrary (SG.Vector v n a) arbitrary = SG.replicateM arbitrary shrink vs = [ vs SG.// [(i, x)] | i <- finites, x <- shrink (SG.index vs i) ] -instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Arbitrary (MultiPoly v n a) where +instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (Monom n a), G.Vector v (SU.Vector n Word, a)) => Arbitrary (MultiPoly v n a) where arbitrary = toMultiPoly . G.fromList <$> arbitrary shrink = fmap (toMultiPoly . G.fromList) . shrink . G.toList . unMultiPoly -instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (SU.Vector n Word, a)) => Arbitrary (ShortPoly (MultiPoly v n a)) where +instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (Monom n a), G.Vector v (SU.Vector n Word, a)) => Arbitrary (ShortPoly (MultiPoly v n a)) where arbitrary = ShortPoly . toMultiPoly . G.fromList . (\xs -> take (length xs `mod` 4) (map (first (SU.map (`mod` 3))) xs)) <$> arbitrary shrink = fmap (ShortPoly . toMultiPoly . G.fromList) . shrink . G.toList . unMultiPoly . unShortPoly -instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (Word, a), G.Vector v (SU.Vector n Word, a)) => Arbitrary (MultiLaurent.MultiLaurent v n a) where +instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (Word, a), G.Vector v (Monom n a), G.Vector v (SU.Vector n Word, a)) => Arbitrary (MultiLaurent.MultiLaurent v n a) where arbitrary = MultiLaurent.toMultiLaurent <$> (SU.map (`rem` 10) <$> arbitrary) <*> arbitrary shrink = fmap (uncurry MultiLaurent.toMultiLaurent) . shrink . MultiLaurent.unMultiLaurent -instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (Word, a), G.Vector v (SU.Vector n Word, a)) => Arbitrary (ShortPoly (MultiLaurent.MultiLaurent v n a)) where +instance (Eq a, Semiring a, Arbitrary a, KnownNat n, G.Vector v (Word, a), G.Vector v (Monom n a), G.Vector v (SU.Vector n Word, a)) => Arbitrary (ShortPoly (MultiLaurent.MultiLaurent v n a)) where arbitrary = (ShortPoly .) . MultiLaurent.toMultiLaurent <$> (SU.map (`rem` 10) <$> arbitrary) <*> (unShortPoly <$> arbitrary) shrink = fmap (ShortPoly . uncurry MultiLaurent.toMultiLaurent . fmap unShortPoly) . shrink . fmap ShortPoly . MultiLaurent.unMultiLaurent . unShortPoly