lattest-lib-0.1.0.0: src/Lattest/Model/Symbolic/Internal/Product.hs
{-
This is a modified version of:
TorXakis - Model Based Testing
See LICENSE in the parent Symbolic folder.
-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Lattest.Model.Symbolic.Internal.Product (
-- * Product type
FreeProduct
, ProductTerm (..)
-- * Filter
, fraction
-- * Product of Term and Products
, multiply
, divide
, product
, products
-- * Power
, power
) where
import Control.Arrow ((***))
import Data.Data
import Data.Foldable hiding (product)
import qualified Data.Map.Strict as Map
import Data.Monoid hiding ((<>))
import Data.Semigroup
import GHC.Generics (Generic)
import Prelude hiding (product)
import Lattest.Model.Symbolic.Internal.FreeMonoidX (FreeMonoidX (..), IntMultipliable,
TermWrapper, (<.>))
import qualified Lattest.Model.Symbolic.Internal.FreeMonoidX as FMX
{--------------------------------------------------------------------
The data types
--------------------------------------------------------------------}
-- |
-- `FreeProduct` represents a symbolic product of terms of the type parameter `a`.
-- The same term can occur multiple times.
type FreeProduct a = FreeMonoidX (ProductTerm a)
-- | Terms of a free-monoids of the form:
--
-- > a0 <> a1 <> ... <> an-1
--
-- where `<>` will be interpreted as the arithmetic multiplication of terms:
--
-- > a0 * a1 * ... * an-1
--
newtype ProductTerm a = ProductTerm { factor :: a }
deriving (Eq, Ord, Read, Generic, Functor, Data)
instance Show a => Show (ProductTerm a) where
show = show . factor
instance Applicative ProductTerm where
pure = ProductTerm
fa <*> a = ProductTerm $ factor fa (factor a)
instance Num a => Semigroup (ProductTerm a) where
pt0 <> pt1 = (*) <$> pt0 <*> pt1
instance Num a => Monoid (ProductTerm a) where
mempty = pure 1
instance TermWrapper ProductTerm where
wrap = ProductTerm
unwrap = factor
instance Num a => IntMultipliable (ProductTerm a) where
n <.> pt = (^ toInteger n) <$> pt
instance Foldable ProductTerm where
--foldr :: (a -> b -> b) -> b -> t a -> b
foldr f e (ProductTerm x) = f x e
{--------------------------------------------------------------------
Products and multiplications
--------------------------------------------------------------------}
-- | /O(log n)/. Multiply a product with a term.
multiply :: Ord a => a -> FreeProduct a -> FreeProduct a
multiply = FMX.append . ProductTerm
-- | /O(log n)/. Divide a product by a term.
divide :: Ord a => a -> FreeProduct a -> FreeProduct a
divide = FMX.remove . ProductTerm
-- | The product of a list of products.
products :: Ord a => [FreeProduct a] -> FreeProduct a
products = fold
-- | /O(n+m)/. The product of two products.
--
product :: Ord a => FreeProduct a -> FreeProduct a -> FreeProduct a
product = (<>)
-- | /O(n)/. Take the product /ms/ to the power with the constant /x/.
power :: Ord a => Integer -> FreeProduct a -> FreeProduct a
power = (<.>)
{--------------------------------------------------------------------
Partition
--------------------------------------------------------------------}
-- | /O(n)/. Partition the product into the dividend and divisor.
fraction :: Ord a => FreeProduct a -> (FreeProduct a, FreeProduct a)
fraction =
(FMX *** (power (-1). FMX) ) . Map.partition (>= 0) . asMap