math-programming-0.5.0: test/Math/Programming/LinExprSpec.hs
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Math.Programming.LinExprSpec where
import Control.Monad
import Data.Ratio
import Math.Programming
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
spec :: Spec
spec = do
describe "algebraic properties" $ do
prop "satisfies addititive commutivity" commutativityProp
prop "satisfies addititive associativity" additiveAssociativityProp
prop "satisfies coefficient commutativity" coefficientCommutativityProp
describe "simplification" $ do
simplifyRegressions
prop "simplification preserves value" simplifyProp
type ExactExpr = LinExpr (Ratio Integer) (Ratio Integer)
instance Arbitrary ExactExpr where
arbitrary = LinExpr <$> arbitrary <*> arbitrary
-- | A pair of linear expressions, differing only by the ordering of
-- the summands.
newtype ShuffledAndUnshuffled
= ShuffledAndUnshuffled (ExactExpr, ExactExpr)
deriving
( Show
)
instance Arbitrary ShuffledAndUnshuffled where
arbitrary = do
unshuffled@(LinExpr terms constant) <- arbitrary
shuffledTerms <- shuffle terms
let shuffled = LinExpr shuffledTerms constant
return $ ShuffledAndUnshuffled (unshuffled, shuffled)
-- | Addition should be commutative.
commutativityProp :: ShuffledAndUnshuffled -> Bool
commutativityProp (ShuffledAndUnshuffled (shuffled, unshuffled)) =
eval shuffled == eval unshuffled
-- | A pair of linear expressions, differing only by the ordering of
-- the coefficients of the summands.
newtype ShuffledCoefficients
= ShuffledCoefficients (ExactExpr, ExactExpr)
deriving
( Show
)
instance Arbitrary ShuffledCoefficients where
arbitrary = do
unshuffled@(LinExpr terms constant) <- arbitrary
terms' <- forM terms $ \(x, y) -> do
flipped <- arbitrary
return $
if flipped
then (y, x)
else (x, y)
let shuffled = LinExpr terms' constant
return $ ShuffledCoefficients (shuffled, unshuffled)
coefficientCommutativityProp :: ShuffledCoefficients -> Bool
coefficientCommutativityProp (ShuffledCoefficients (shuffled, unshuffled)) =
eval shuffled == eval unshuffled
additiveAssociativityProp :: ExactExpr -> ExactExpr -> ExactExpr -> Bool
additiveAssociativityProp x y z =
eval ((x .+. y) .+. z) == eval (x .+. (y .+. z))
simplifyProp :: ExactExpr -> Bool
simplifyProp x = eval x == eval (simplify x)
simplifyRegressions :: Spec
simplifyRegressions = do
it "simplifies x + x - x" $
let terms :: [(Int, Int)]
coef :: Int
(LinExpr terms coef) = simplify $ LinExpr [(1, 0), (1, 0), (-1, 0)] 0
in do
coef `shouldBe` 0
terms `shouldBe` [(1, 0)]