packages feed

ideas-math-1.0: src/Domain/Math/Numeric/Tests.hs

-----------------------------------------------------------------------------
-- Copyright 2013, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Domain.Math.Numeric.Tests (main) where

import Control.Monad
import Data.Maybe
import Data.Monoid
import Domain.Math.Expr
import Domain.Math.Numeric.Generators
import Domain.Math.Numeric.Strategies
import Domain.Math.Numeric.Views
import Ideas.Common.Classes
import Ideas.Common.Context
import Ideas.Common.Utils.TestSuite
import Ideas.Common.View
import Test.QuickCheck

main :: TestSuite
main = suite "Numeric tests" $ do

   suite "Correctness numeric views" $ do
      let f s v = forM_ numGenerators $ \g -> do
             addProperty ("idempotence " ++ s) $ propIdempotence g v
             addProperty ("soundness " ++ s)   $ propSoundness semEqDouble g v
      f "integer view"          integerView
      f "rational view"         rationalView
      f "integer normal form"   integerNF
      f "rational normal form"  rationalNF
      f "rational relaxed form" rationalRelaxedForm

   suite "Normal forms" $ do
      let f s v = forM_ numGenerators $ \g ->
             addProperty s $ propNormalForm g v
      f "integer normal form" integerNF
    -- f rationalNF -- no longer a normal form

   suite "Correctness generators" $ do
      let f s g v = addProperty s $ forAll (sized g) (`belongsTo` v)
      f "integer" integerGenerator integerView
      f "rational" rationalGenerator rationalView
      f "ratio expr" ratioExprGen rationalNF
      f "ratio expr nonzero" ratioExprGenNonZero rationalNF

   suite "View relations" $ do
      let va .>. vb = forM_ numGenerators $ \g ->
             addProperty "" $ forAll g $ \a ->
                not (a `belongsTo` va) || a `belongsTo` vb
      integerNF .>. integerView
      rationalNF .>. rationalRelaxedForm
      rationalRelaxedForm .>. rationalView
      integerNF .>. rationalNF
      integerView .>. rationalView

   suite "Pre/post conditions strategies" $ do
      let f l s pre post = forM_ numGenerators $ \g ->
             addProperty l $ forAll g $ \a ->
                let run = fromMaybe a . fromContext . applyD s
                        . newContext mempty . termNavigator
                in not (a `belongsTo` pre) || run a `belongsTo` post
      f "natural"  naturalStrategy  integerView  integerNF
      f "integer"  integerStrategy  integerView  integerNF
      f "rational" rationalStrategy rationalView rationalNF
      f "fraction" fractionStrategy rationalView rationalNF

numGenerators :: [Gen Expr]
numGenerators = map sized
   [ integerGenerator, rationalGenerator
   , ratioExprGen, ratioExprGenNonZero, numGenerator
   ]

semEqDouble :: Expr -> Expr -> Bool
semEqDouble a b =
   case (match doubleView a, match doubleView b) of
      (Just x, Just y)   -> x ~= y
      (Nothing, Nothing) -> True
      _                  -> False
 where
   delta = 0.0001

   (~=) :: Double -> Double -> Bool
   x ~= y = abs x < delta || abs y < delta || abs (1 - (x/y)) < delta