numeric-prelude-0.2: test/Test/MathObj/PartialFraction.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Test.MathObj.PartialFraction where
import qualified MathObj.PartialFraction as PartialFraction
import qualified MathObj.Polynomial as Poly
import qualified Number.Ratio as Ratio
import qualified Algebra.PrincipalIdealDomain as PID
import qualified Algebra.Ring as Ring
import qualified Algebra.Indexable as Indexable
import qualified Algebra.Vector as Vector
-- import Algebra.Vector((*>))
import qualified Algebra.Laws as Laws
import qualified Test.QuickCheck as QC
import Control.Monad.HT as M
import Test.NumericPrelude.Utility (testUnit)
import Test.QuickCheck (quickCheck)
import qualified Test.HUnit as HUnit
import NumericPrelude.Base as P
import NumericPrelude.Numeric as NP
{- * Properties for generic types -}
fractionConv :: (PID.C a, Indexable.C a) => [a] -> a -> Bool
fractionConv xs y =
PartialFraction.toFraction (PartialFraction.fromFactoredFraction xs y) ==
y % product xs
fractionConvAlt :: (PID.C a, Indexable.C a) => [a] -> a -> Bool
fractionConvAlt xs y =
PartialFraction.fromFactoredFraction xs y ==
PartialFraction.fromFactoredFractionAlt xs y
scaleInt :: (PID.C a, Indexable.C a) => a -> PartialFraction.T a -> Bool
scaleInt k a =
PartialFraction.toFraction (PartialFraction.scaleInt k a) ==
Ratio.scale k (PartialFraction.toFraction a)
add :: (PID.C a, Indexable.C a) => PartialFraction.T a -> PartialFraction.T a -> Bool
add = Laws.homomorphism PartialFraction.toFraction (+) (+)
sub :: (PID.C a, Indexable.C a) => PartialFraction.T a -> PartialFraction.T a -> Bool
sub = Laws.homomorphism PartialFraction.toFraction (-) (-)
mul :: (PID.C a, Indexable.C a) => PartialFraction.T a -> PartialFraction.T a -> Bool
mul = Laws.homomorphism PartialFraction.toFraction (*) (*)
{- * Properties for Integers -}
{- |
Arbitrary instance of that type generates irreducible elements for tests.
Choosing from a list of examples is a simple yet effective design.
If we would construct irreducible elements by a clever algorithm
we might obtain multiple primes only rarely.
-}
newtype SmallPrime = SmallPrime {intFromSmallPrime :: Integer}
type IntFraction = ([SmallPrime],Integer)
instance QC.Arbitrary SmallPrime where
arbitrary =
let primes = [2,3,5,7,11,13]
in fmap SmallPrime $ QC.elements (primes ++ map negate primes)
instance Show SmallPrime where
show = show . intFromSmallPrime
fractionConvInt :: [SmallPrime] -> Integer -> Bool
fractionConvInt =
fractionConv . map intFromSmallPrime
fractionConvAltInt :: [SmallPrime] -> Integer -> Bool
fractionConvAltInt =
fractionConvAlt . map intFromSmallPrime
fromSmallPrimes :: IntFraction -> PartialFraction.T Integer
fromSmallPrimes (xs,y) =
PartialFraction.fromFactoredFraction (map intFromSmallPrime xs) y
scaleIntInt :: Integer -> IntFraction -> Bool
scaleIntInt k a =
scaleInt k (fromSmallPrimes a)
addInt :: IntFraction -> IntFraction -> Bool
addInt q0 q1 =
add
(fromSmallPrimes q0)
(fromSmallPrimes q1)
subInt :: IntFraction -> IntFraction -> Bool
subInt q0 q1 =
sub
(fromSmallPrimes q0)
(fromSmallPrimes q1)
mulInt :: IntFraction -> IntFraction -> Bool
mulInt q0 q1 =
mul
(fromSmallPrimes q0)
(fromSmallPrimes q1)
intTests :: HUnit.Test
intTests =
HUnit.TestLabel "integer" $
HUnit.TestList $
map testUnit $
("conversion between partial and ordinary fraction", quickCheck fractionConvInt) :
("two conversion routines from factored fractions", quickCheck fractionConvAltInt) :
("integer scaling", quickCheck scaleIntInt) :
("addition", quickCheck addInt) :
("subtraction", quickCheck subInt) :
("multiplication", quickCheck mulInt) :
[]
{- * Properties for Polynomials -}
newtype IrredPoly = IrredPoly {polyFromIrredPoly :: Poly.T Rational}
type RatPolynomial = Poly.T Rational
type PolyFraction = ([IrredPoly],RatPolynomial)
instance QC.Arbitrary IrredPoly where
arbitrary =
do poly <- QC.elements (map Poly.fromCoeffs [[2,3],[2,0,1],[3,0,1],[1,-3,0,1]])
unit <- M.until (not. isZero) QC.arbitrary
return (IrredPoly (unit Vector.*> poly))
instance Show IrredPoly where
show = show . polyFromIrredPoly
fractionConvPoly :: [IrredPoly] -> RatPolynomial -> Bool
fractionConvPoly =
fractionConv . map polyFromIrredPoly
fractionConvAltPoly :: [IrredPoly] -> RatPolynomial -> Bool
fractionConvAltPoly =
fractionConvAlt . map polyFromIrredPoly
fromIrredPolys :: PolyFraction -> PartialFraction.T RatPolynomial
fromIrredPolys (xs,y) =
PartialFraction.fromFactoredFraction (map polyFromIrredPoly xs) y
scaleIntPoly :: RatPolynomial -> PolyFraction -> Bool
scaleIntPoly k a =
scaleInt k (fromIrredPolys a)
addPoly :: PolyFraction -> PolyFraction -> Bool
addPoly q0 q1 =
add
(fromIrredPolys q0)
(fromIrredPolys q1)
subPoly :: PolyFraction -> PolyFraction -> Bool
subPoly q0 q1 =
sub
(fromIrredPolys q0)
(fromIrredPolys q1)
mulPoly :: PolyFraction -> PolyFraction -> Bool
mulPoly q0 q1 =
mul
(fromIrredPolys q0)
(fromIrredPolys q1)
polyTests :: HUnit.Test
polyTests =
HUnit.TestLabel "polynomial" $
HUnit.TestList $
map testUnit $
{- this test fails, because addition may result in leading zero coefficients,
that is, polynomial addition does not contain a normalization
if it would contain one, we would exclude computable reals -}
-- wrong ("conversion between partial and ordinary fraction", quickCheck fractionConvPoly) :
-- wrong ("two conversion routines from factored fractions", quickCheck fractionConvAltPoly) :
-- too slow ("integer scaling", quickCheck scaleIntPoly) :
-- too slow ("addition", quickCheck addPoly) :
-- too slow ("subtraction", quickCheck subPoly) :
-- too slow ("multiplication", quickCheck mulPoly) :
[]
tests :: HUnit.Test
tests =
HUnit.TestLabel "partial fraction" $
HUnit.TestList $
intTests :
-- polyTests :
[]