packages feed

numeric-prelude-0.4.1: test/Test/MathObj/PowerSeries.hs

{-# LANGUAGE NoImplicitPrelude #-}
module Test.MathObj.PowerSeries where

import qualified MathObj.PowerSeries         as PST
import qualified MathObj.PowerSeries.Core    as PS
import qualified MathObj.PowerSeries.Example as PSE

import qualified Test.QuickCheck.Modifiers as Mod
import Test.NumericPrelude.Utility (equalInfLists, testUnit)
import Test.QuickCheck (quickCheck)
-- import Test.QuickCheck (Property, quickCheck, (==>))
import qualified Test.HUnit as HUnit


import NumericPrelude.Base as P
import NumericPrelude.Numeric as NP


identitiesExplODE, identitiesSeriesFunction, identitiesInverses ::
   [(String, Int, [Rational],[Rational])]

identitiesExplODE =
   ("exp",   500, PSE.expExpl,   PSE.expODE) :
   ("sin",   500, PSE.sinExpl,   PSE.sinODE) :
   ("cos",   500, PSE.cosExpl,   PSE.cosODE) :
   ("tan",    50, PSE.tanExpl,   PSE.tanODE) :
   ("tan",    50, PSE.tanExpl,   PSE.tanExplSieve) :
   ("tan",    50, PSE.tanODE,    PSE.tanODESieve) :
   ("log",   500, PSE.logExpl,   PSE.logODE) :
   ("asin",   50, PSE.asinODE,   snd (PS.inv PSE.sinODE)) :
   ("atan",  500, PSE.atanExpl,  PSE.atanODE) :
   ("sinh",  500, PSE.sinhExpl,  PSE.sinhODE) :
   ("cosh",  500, PSE.coshExpl,  PSE.coshODE) :
   ("atanh", 500, PSE.atanhExpl, PSE.atanhODE) :
   ("sqrt",  100, PSE.sqrtExpl,  PSE.sqrtODE) :
   []

identitiesSeriesFunction =
   ("exp",   500, PSE.expExpl,  PS.exp (\0 -> 1) [0,1]) :
   ("sin",   500, PSE.sinExpl,  PS.sin (\0 -> (0,1)) [0,1]) :
   ("cos",   500, PSE.cosExpl,  PS.cos (\0 -> (0,1)) [0,1]) :
   ("tan",    50, PSE.tanExpl,  PS.tan (\0 -> (0,1)) [0,1]) :
   ("sqrt",   50, PSE.sqrtExpl, PS.sqrt (\1 -> 1) [1,1]) :
   ("power", 500, PSE.powExpl (-1/3), PS.pow (\1 -> 1) (-1/3) [1,1]) :
   ("power",  50, PSE.powExpl (-1/3), PS.exp (\0 -> 1) (PS.scale (-1/3) PSE.log)) :
   ("log",   500, PSE.logExpl, PS.log (\1 -> 0) [1,1]) :
   ("asin",   50, PSE.asin, PS.asin (\1 -> 1) (\0 -> 0) [0,1]) :
 --  ("acos",  50, PSE.acos, PS.acos (\1 -> 1) (\0 -> pi/2) [0,1]) :
   ("atan",  500, PSE.atan, PS.atan (\0 -> 0) [0,1]) :
   []

identitiesInverses =
   ("exp",   100, 1:1:repeat 0, PS.exp  (\0 -> 1) PSE.log) :
   ("log",   100, 0:1:repeat 0, PS.log  (\1 -> 0) PSE.exp) :
   ("tan",    50, 0:1:repeat 0, PS.tan  (\0 -> (0,1)) PSE.atan) :
   ("atan",   50, 0:1:repeat 0, PS.atan (\0 -> 0) PSE.tan) :
   ("sin",    50, 0:1:repeat 0, PS.sin  (\0 -> (0,1)) PSE.asin) :
   ("asin",  100, 0:1:repeat 0, PS.asin (\1 -> 1) (\0 -> 0) PSE.sin) :
   ("sqrt",  500, 1:1:repeat 0, PS.sqrt (\1 -> 1) (PS.mul [1,1] [1,1])) :
   []

identitiesHoles :: [(String, Int, [Rational] -> [Rational], Rational)]
identitiesHoles =
   ("exp",    30, PS.exp  (\0 -> 1), 0) :
   ("log",    30, PS.log  (\1 -> 0), 1) :
   ("tan",    20, PS.tan  (\0 -> (0,1)), 0) :
   ("atan",   20, PS.atan (\0 -> 0), 0) :
   ("sin",    20, PS.sin  (\0 -> (0,1)), 0) :
   ("cos",    20, PS.cos  (\0 -> (0,1)), 0) :
   ("asin",   30, PS.asin (\1 -> 1) (\0 -> 0), 0) :
   ("sqrt",   50, PS.sqrt (\1 -> 1), 1) :
   ("pow13",  30, PS.pow  (\1 -> 1) (1/3), 1) :
   ("pow25",  30, PS.pow  (\1 -> 1) (2/5), 1) :
   []

testSeriesIdentity :: (String, Int, [Rational], [Rational]) -> HUnit.Test
testSeriesIdentity (label, len, x, y) =
   HUnit.test (HUnit.assertBool label (equalInfLists len [x,y]))

testSeriesIdentities ::
   String -> [(String, Int, [Rational], [Rational])] -> HUnit.Test
testSeriesIdentities label ids =
   HUnit.TestLabel label $
     HUnit.TestList $ map testSeriesIdentity ids

_checkSeriesIdentities ::
   [(String, Int, [Rational], [Rational])] -> [(String,Bool)]
_checkSeriesIdentities =
   map (\(label, len, x, y) -> (label, equalInfLists len [x,y]))


holesMultiplicative :: Int -> Int -> Int -> [Rational] -> Bool
holesMultiplicative trunc expon0 expon1 xs =
   let n0 = 1 + mod expon0 10
       n1 = 1 + mod expon1 10
   in  equalInfLists trunc
          [PS.insertHoles n0 $ PS.insertHoles n1 xs,
           PS.insertHoles n1 $ PS.insertHoles n0 xs,
           PS.insertHoles (n0*n1) xs]

testHolesIdentity ::
   (String, Int, [Rational] -> [Rational], Rational) -> HUnit.Test
testHolesIdentity (label, len, f, x0) =
   HUnit.test $ testUnit $ (,) ("holes in " ++ label) $
   quickCheck $ \expon0 xs -> checkHoles len expon0 f x0 xs


checkHoles ::
   Int -> Int -> ([Rational] -> [Rational]) ->
   Rational -> [Rational] -> Bool
checkHoles trunc expon0 f x xs =
   let expon = 1 + mod expon0 10
   in  equalInfLists trunc
          [(f $ PS.insertHoles expon (x:xs)) ++ repeat zero,
           (PS.insertHoles expon $ f $ x:xs) ++ repeat zero]


powerMultSeries :: Int -> Integer -> Mod.Positive Rational -> [Rational] -> Bool
powerMultSeries trunc expon0 xp xs =
   let expon = 1 + mod expon0 10
       x = Mod.getPositive xp
       xt = x:xs
   in  equalInfLists trunc
          [PS.pow
              (const x) (1 % expon)
              (PST.coeffs (PST.fromCoeffs xt ^ expon))
            ++ repeat zero,
           xt ++ repeat zero]

powerMult :: Int -> Rational -> Rational -> Bool
powerMult trunc exp0 exp1 =
   equalInfLists trunc
      [PS.mul (PSE.pow exp0) (PSE.pow exp1), PSE.pow (exp0+exp1)]

powerExplODE :: Int -> Rational -> Bool
powerExplODE trunc expon =
   equalInfLists trunc [PSE.powODE expon, PSE.powExpl expon]

invDiff :: Int -> Rational -> Mod.NonZero Rational -> [Rational] -> Bool
invDiff trunc x0 x1 xs_ =
   let xs = x0 : Mod.getNonZero x1 : xs_
       (y,ys) = PS.inv xs
       (z,zs) = PS.invDiff xs
   in  y==z && equalInfLists trunc [ys, zs]


tests :: HUnit.Test
tests =
   HUnit.TestLabel "power series" $
   HUnit.TestList [
      testSeriesIdentities "explicit vs. ODE solution" identitiesExplODE,
      testSeriesIdentities "transcendent functions of series" identitiesSeriesFunction,
      testSeriesIdentities "inverses of some series" identitiesInverses,
      HUnit.TestLabel "laws" $
      HUnit.TestList $
         map testHolesIdentity identitiesHoles
         ++
         (map testUnit $
            ("multiplicative holes",   quickCheck (holesMultiplicative 100)) :
            ("powers of series",       quickCheck (powerMultSeries 15)) :
            ("products of powers",     quickCheck (powerMult 30)) :
            ("power explicit vs. ODE", quickCheck (powerExplODE 50)) :
            ("inv vs. invDiff",        quickCheck (invDiff 15)) :
            [])
    ]