packages feed

exp-pairs-0.1.4.1: tests/Ivic.hs

module Ivic where

import Data.Ratio
import Math.ExpPairs
import Math.ExpPairs.Ivic

import Test.Tasty
import Test.Tasty.SmallCheck as SC
import Test.Tasty.QuickCheck as QC
import Test.Tasty.HUnit

import Instances
import Etalon (testEtalon)

fromMinus3To3 :: Rational -> Rational
fromMinus3To3 n = (n - 1 % 2) * 6

fromHalfToOne :: Rational -> Rational
fromHalfToOne n = n / 2 + 1 % 2

testZetaOnS1 :: Sorted (Ratio01 Rational, Ratio01 Rational) -> Bool
testZetaOnS1 (Sorted (Ratio01 a', Ratio01 b')) = a == b || za >= zb where
  [ a,  b] = map fromMinus3To3 [a', b']
  [za, zb] = map (optimalValue . zetaOnS) [a, b]

-- Strict comparison without 3e-4 may fail due to the granularity of 'sect'.
testZetaOnS2 :: Sorted (Ratio01 Rational, Ratio01 Rational) -> Bool
testZetaOnS2 (Sorted (Ratio01 a, Ratio01 b)) = a == b || za + 5e-4 > zb where
  [za, zb] = map (optimalValue . zetaOnS) [a, b]

testZetaOnSsym :: Ratio01 Rational -> Bool
testZetaOnSsym (Ratio01 a') = (toRational . abs) (za - za') == abs (a - 1 % 2) where
  a   = fromMinus3To3 a'
  za  = optimalValue $ zetaOnS a
  za' = optimalValue $ zetaOnS (1 - a)

testZetaOnSZero :: Ratio01 Rational -> Bool
testZetaOnSZero (Ratio01 a') = a < 1 || optimalValue (zetaOnS a) == 0 where
  a = fromMinus3To3 a'

testMOnS1 :: Sorted (Ratio01 Rational, Ratio01 Rational) -> Bool
testMOnS1 (Sorted (Ratio01 a', Ratio01 b')) = a == b || za <= zb where
  [ a,  b] = map fromMinus3To3 [a', b']
  [za, zb] = map (optimalValue . mOnS) [a, b]

testMOnS2 :: Sorted (Ratio01 Rational, Ratio01 Rational) -> Bool
testMOnS2 (Sorted (Ratio01 a', Ratio01 b')) = a == b || za < zb where
  [ a,  b] = map fromHalfToOne [a', b']
  [za, zb] = map (optimalValue . mOnS) [a, b]

testMOnSZero :: Ratio01 Rational -> Bool
testMOnSZero (Ratio01 a') = a >= 1%2 || (optimalValue . mOnS) a == 0 where
  a = fromMinus3To3 a'

testMOnSInf :: Ratio01 Rational -> Bool
testMOnSInf (Ratio01 a') = a < 1 || (optimalValue . mOnS) a == InfPlus where
  a = fromMinus3To3 a'

testZetaReverse :: Ratio01 Rational -> Bool
testZetaReverse (Ratio01 s') = abs (s - t) <= 5 % 1000 where
  s = s' / 2
  zs = zetaOnS s
  t = toRational $ optimalValue $ reverseZetaOnS $ toRational $ optimalValue zs

-- Convexity tests - they fail and it is OK
testZetaConvex :: Sorted (Ratio01 Rational, Ratio01 Rational, Ratio01 Rational) -> Bool
testZetaConvex (Sorted (Ratio01 a, Ratio01 b, Ratio01 c)) = a == b || b == c || zb <= k * Finite b + l where
  [za, zb, zc] = map (optimalValue . zetaOnS) [a, b, c]
  k = (za - zc) / Finite (a - c)
  l = za - k * Finite a

-- Ivic, Th. 8.1, p. 205
testMConvex :: Sorted (Ratio01 Rational, Ratio01 Rational, Ratio01 Rational) -> Bool
testMConvex (Sorted (Ratio01 a', Ratio01 b', Ratio01 c')) = a==b || b==c || za==InfPlus || zc==InfPlus
  || zb>= za*zc*Finite(c-a)/(zc*Finite(c-b) + za*Finite(b-a)) where
    [a,b,c] = map fromHalfToOne [a', b', c']
    [za, zb, zc] = map (optimalValue . mOnS) [a,b,c] :: [RationalInf]

etalonZetaOnS :: Integer -> Integer -> Integer -> Integer -> Bool
etalonZetaOnS a b c d = Finite (c%d) >= optimalValue (zetaOnS $ a%b)

etalonMOnS :: Integer -> Integer -> Integer -> Integer -> Bool
etalonMOnS a b c d = Finite (c%d) <= (optimalValue . mOnS) (a%b)

testSuite :: TestTree
testSuite = testGroup "Ivic"
  [ testCase "etalon zetaOnS"
    (testEtalon 100 (\(a:b:c:d:_) -> etalonZetaOnS a b c d) "tests/etalon-zetaOnS.txt")
  , testCase "etalon mOnS"
    (testEtalon 100 (\(a:b:c:d:_) -> etalonMOnS a b c d) "tests/etalon-mOnS.txt")
  , adjustOption (\(SC.SmallCheckDepth n) -> SC.SmallCheckDepth (n `div` 2)) $
      SC.testProperty "zetaOnS monotonic" testZetaOnS1
  , QC.testProperty "zetaOnS monotonic" testZetaOnS1
  , adjustOption (\(SC.SmallCheckDepth n) -> SC.SmallCheckDepth (n `div` 2)) $
      SC.testProperty "zetaOnS strict monotonic" testZetaOnS2
  , QC.testProperty "zetaOnS strict monotonic" testZetaOnS2
  , adjustOption (\(SC.SmallCheckDepth n) -> SC.SmallCheckDepth (n `div` 2)) $
      SC.testProperty "mOnS monotonic" testMOnS1
  , QC.testProperty "mOnS monotonic" testMOnS1
  , adjustOption (\(SC.SmallCheckDepth n) -> SC.SmallCheckDepth (n `div` 2)) $
      SC.testProperty "mOnS strict monotonic" testMOnS2
  , QC.testProperty "mOnS strict monotonic" testMOnS2
  , SC.testProperty "zetaOnS reverse" testZetaReverse
  , QC.testProperty "zetaOnS reverse" testZetaReverse
  , SC.testProperty "zetaOnS symmetry" testZetaOnSsym
  , QC.testProperty "zetaOnS symmetry" testZetaOnSsym
  , SC.testProperty "zetaOnS above s=1" testZetaOnSZero
  , QC.testProperty "zetaOnS above s=1" testZetaOnSZero
  , SC.testProperty "mOnS below s=1/2" testMOnSZero
  , QC.testProperty "mOnS below s=1/2" testMOnSZero
  , SC.testProperty "mOnS above s=1" testMOnSInf
  , QC.testProperty "mOnS above s=1" testMOnSInf
  ]