packages feed

exp-pairs-0.2.0.0: 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 (testProperty, QuickCheckTests(..))
import Test.Tasty.HUnit

import Debug.Trace

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'

testZetaReverse1 :: Ratio01 Rational -> Bool
testZetaReverse1 (Ratio01 s') = if t <= s + 2.1e-2 && s <= t + 2e-3 then True else trace (show $ fromRational $ s-t) False where
  s = fromHalfToOne s'
  zs = zetaOnS s
  t = toRational $ optimalValue $ reverseZetaOnS $ toRational $ optimalValue zs

testZetaReverse2 :: Ratio01 Rational -> Bool
testZetaReverse2 (Ratio01 s') = if t <= s + 1e-10 && s <= t + 4e-3 then True else trace (show $ fromRational $ s-t) False where
  s = s' * 32 / 205
  zs = reverseZetaOnS s
  t = toRational $ optimalValue $ zetaOnS $ toRational $ optimalValue zs

testMOnSReverse1 :: Ratio01 Rational -> Bool
testMOnSReverse1 (Ratio01 s') =
  if t <= s + 4e-2 && s <= t + 1e-3 then True else trace (show $ fromRational $ s-t) False
  where
    s = fromHalfToOne s'
    zs = mOnS s
    t = toRational $ reverseMOnS 1e-3 $ optimalValue zs

testMOnSReverse2 :: Ratio01 Rational -> Bool
testMOnSReverse2 (Ratio01 s')
  =  s' == 0
  || t' == InfPlus || t' == InfMinus
  || if recip t <= recip s + 1e-3 && recip s <= recip t + 1e-3 then True else trace (show $ fromRational $ recip s - recip t) False
    where
      s  = 4 * recip s'
      zs = reverseMOnS 1e-3 (Finite s)
      t' = optimalValue $ mOnS $ toRational zs
      t  = toRational t'

testMBigOnHalfReverse1 :: Positive Rational -> Bool
testMBigOnHalfReverse1 (Positive s') = if recip t <= recip s + 2e-3 && recip s <= recip t + 1e-10 then True else trace (show $ fromRational $ recip s - recip t) False where
  s = s' + 4
  zs = mBigOnHalf s
  t = toRational $ optimalValue $ reverseMBigOnHalf $ toRational $ optimalValue zs

testMBigOnHalfReverse2 :: Positive Rational -> Bool
testMBigOnHalfReverse2 (Positive s') = if recip t <= recip s + 2e-3 && recip s <= recip t + 1e-10 then True else trace (show $ fromRational $ recip s - recip t) False where
  s = s' + 1
  zs = reverseMBigOnHalf s
  t = toRational $ optimalValue $ mBigOnHalf $ toRational $ optimalValue zs


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 "reverseZetaOnS . zetaOnS == id" testZetaReverse1
  , QC.testProperty "reverseZetaOnS . zetaOnS == id" testZetaReverse1
  , SC.testProperty "zetaOnS . reverseZetaOnS == id" testZetaReverse2
  , QC.testProperty "zetaOnS . reverseZetaOnS == id" testZetaReverse2

  , SC.testProperty "reverseMOnS . mOnS == id" testMOnSReverse1
  , adjustOption (\(QC.QuickCheckTests n) -> QC.QuickCheckTests (n `min` 100)) $
      QC.testProperty "reverseMOnS . mOnS == id" testMOnSReverse1
  , SC.testProperty "mOnS . reverseMOnS == id" testMOnSReverse2
  , adjustOption (\(QC.QuickCheckTests n) -> QC.QuickCheckTests (n `min` 100)) $
      QC.testProperty "mOnS . reverseMOnS == id" testMOnSReverse2

  , SC.testProperty "reverseMBigOnHalf . mBigOnHalf == id" testMBigOnHalfReverse1
  , QC.testProperty "reverseMBigOnHalf . mBigOnHalf == id" testMBigOnHalfReverse1
  , SC.testProperty "mBigOnHalf . reverseMBigOnHalf == id" testMBigOnHalfReverse2
  , QC.testProperty "mBigOnHalf . reverseMBigOnHalf == id" testMBigOnHalfReverse2

  , 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
  ]