packages feed

poly-0.5.1.0: test/Orthogonal.hs

{-# LANGUAGE OverloadedLists #-}

module Orthogonal
  ( testSuite
  ) where

import Test.Tasty

import Data.List (foldl', tails)
import Data.Poly (VPoly, deriv, eval, integral)
import Data.Poly.Orthogonal
import Test.Tasty.QuickCheck

testSuite :: TestTree
testSuite = testGroup "Orthogonal"
  [ testGroup "differential equations"
    [ testProperty "jacobi"      prop_jacobi_de
    , testProperty "gegenbauer"  prop_gegenbauer_de
    , testProperty "legendre"    prop_legendre_de
    , testProperty "chebyshev1"  prop_chebyshev1_de
    , testProperty "chebyshev2"  prop_chebyshev2_de
    , testProperty "hermitePhys" prop_hermitePhys_de
    , testProperty "laguerre"    prop_laguerre_de
    , testProperty "laguerreGen" prop_laguerreGen_de
    ]
  , testGroup "normalization"
    [ testProperty "jacobi"     prop_jacobi_norm
    , testProperty "gegenbauer" prop_gegenbauer_norm
    , testProperty "legendre"   prop_legendre_norm
    , testProperty "chebyshev1" prop_chebyshev1_norm
    , testProperty "chebyshev2" prop_chebyshev2_norm
    ]
  , testGroup "orthogonality"
    [ testProperty "legendre"   prop_legendre_orth
    ]
  , testGroup "Hermite"
    [ testProperty "hermiteProb" prop_hermiteProb
    , testProperty "hermitePhys" prop_hermitePhys
    ]
  ]

prop_jacobi_de :: Rational -> Rational -> Property
prop_jacobi_de a b = foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] (jacobi a b)
  where
    de :: Rational -> VPoly Rational -> VPoly Rational
    de n y = [1, 0, -1] * deriv (deriv y)
           + [b - a, - (a + b + 2)] * deriv y
           + [n * (n + a + b + 1)] * y

prop_gegenbauer_de :: Rational -> Property
prop_gegenbauer_de g = foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] (gegenbauer g)
  where
    de :: Rational -> VPoly Rational -> VPoly Rational
    de n y = [1, 0, -1] * deriv (deriv y)
           + [0, - (2 * g + 1)] * deriv y
           + [n * (n + 2 * g)] * y

prop_legendre_de :: Property
prop_legendre_de = once $ foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] legendre
  where
    de :: Rational -> VPoly Rational -> VPoly Rational
    de n y = deriv ([1, 0, -1] * deriv y) + [n * (n + 1)] * y

prop_chebyshev1_de :: Property
prop_chebyshev1_de = once $ foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] chebyshev1
  where
    de :: Integer -> VPoly Integer -> VPoly Integer
    de n y = [1, 0, -1] * deriv (deriv y) + [0, -1] * deriv y + [n * n] * y

prop_chebyshev2_de :: Property
prop_chebyshev2_de = once $ foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] chebyshev2
  where
    de :: Integer -> VPoly Integer -> VPoly Integer
    de n y = [1, 0, -1] * deriv (deriv y) + [0, -3] * deriv y + [n * (n + 2)] * y

prop_hermitePhys_de :: Property
prop_hermitePhys_de = once $ foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] hermitePhys
  where
    de :: Integer -> VPoly Integer -> VPoly Integer
    de n y = deriv (deriv y) + [0, -2] * deriv y + [2 * n] * y

prop_laguerre_de :: Property
prop_laguerre_de = once $ foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] laguerre
  where
    de :: Rational -> VPoly Rational -> VPoly Rational
    de n y = [0, 1] * deriv (deriv y) + [1, -1] * deriv y + [n] * y

prop_laguerreGen_de :: Rational -> Property
prop_laguerreGen_de a  = foldl' (.&&.) (property True) $
  zipWith (((=== 0) .) . de) [0..limit] (laguerreGen a)
  where
    de :: Rational -> VPoly Rational -> VPoly Rational
    de n y = [0, 1] * deriv (deriv y) + [1 + a, -1] * deriv y + [n] * y

prop_jacobi_norm :: Rational -> Rational -> Property
prop_jacobi_norm a b = foldl' (.&&.) (property True) $
  zipWith (\n y -> norm n === eval y 1) [0..limit] (jacobi a b :: [VPoly Rational])
  where
    prod n x = product $ take n $ iterate (subtract 1) (fromIntegral n + x)
    norm n = prod n a / prod n 0

prop_gegenbauer_norm :: Rational -> Property
prop_gegenbauer_norm a = foldl' (.&&.) (property True) $
  zipWith (\n y -> norm n === eval y 1) [0..limit] (gegenbauer a :: [VPoly Rational])
  where
    prod n x = product $ take n $ iterate (subtract 1) (fromIntegral n + x)
    norm n = prod n (a - 1 / 2) / prod n 0

prop_legendre_norm :: Property
prop_legendre_norm = once $ foldl' (.&&.) (property True) $
  map ((=== 1) . flip eval 1) (take limit legendre :: [VPoly Rational])

prop_chebyshev1_norm :: Property
prop_chebyshev1_norm = once $ foldl' (.&&.) (property True) $
  map ((=== 1) . flip eval 1) (take limit chebyshev1 :: [VPoly Integer])

prop_chebyshev2_norm :: Property
prop_chebyshev2_norm = once $ foldl' (.&&.) (property True) $
  zipWith (\n y -> n + 1 === eval y 1) [0..limit] (chebyshev2 :: [VPoly Integer])

prop_legendre_orth :: Property
prop_legendre_orth = once $ foldl' (.&&.) (property True) $
  [ integral11 (x * y) === 0 | (x : xs) <- tails polys, y <- xs ]
  where
    polys :: [VPoly Rational]
    polys = take limit legendre

hermiteProbRef :: [VPoly Integer]
hermiteProbRef = iterate (\he -> [0, 1] * he - deriv he) 1

hermitePhysRef :: [VPoly Integer]
hermitePhysRef = iterate (\h -> [0, 2] * h - deriv h) 1

prop_hermiteProb :: Property
prop_hermiteProb = once $ foldl' (.&&.) (property True) $
  take limit $ zipWith (===) hermiteProb hermiteProbRef

prop_hermitePhys :: Property
prop_hermitePhys = once $ foldl' (.&&.) (property True) $
  take limit $ zipWith (===) hermitePhys hermitePhysRef

integral11 :: VPoly Rational -> Rational
integral11 x = eval y 1 - eval y (-1)
  where
    y = integral x

limit :: Num a => a
limit = 10