packages feed

padic-0.1.0.0: test/Test/Rational.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Test.Rational (testSuite) where


import Math.NumberTheory.Padic
import Test.Base
import GHC.TypeLits hiding (Mod)
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Test.Tasty.ExpectedFailure
import Test.QuickCheck
import Data.Mod
import Data.Ratio


------------------------------------------------------------
digitsTestQ :: (Show n, Eq n, PadicNum n) => n -> n -> Property
digitsTestQ t n = valuation n == 0 ==> fromDigits (digits n) === n

digitsTests = testGroup "Conversion to and from digits"
  [ testProperty "Q 2" $ digitsTestQ (0 :: Q 2)
  , testProperty "Q 13" $ digitsTestQ (0 :: Q 13)
  , testProperty "Q 257" $ digitsTestQ (0 :: Q 257)
  , testCase "1" $ firstDigit (1 :: Q 3) @?= 1
  , testCase "-1" $ firstDigit (-1 :: Q 3) @?= 2
  , testCase "2" $ firstDigit (0 :: Q 3) @?= 0
  , testCase "3" $ firstDigit (9 :: Q 3) @?= 0
  , testCase "4" $ firstDigit (9 :: Q 10) @?= 9
  ]
  
------------------------------------------------------------
equivTest :: TestTree
equivTest = testGroup "Equivalence tests"
  [ testCase "5" $ (432100000 :: Q' 10 5) @?= 0
  , testCase "6" $ (0 :: Q' 10 5) @/= 543210000
  , testCase "7" $ (1/7 :: Q' 10 5) @?= 57143
  , testCase "8" $ (1/7 :: Q' 10 5) @?= 657143
  , testCase "9" $ (1/7 :: Q' 10 5) @/= 67143
  ]

------------------------------------------------------------
showTests = testGroup "String representation"
  [ testCase "0" $ show (0 :: Q 3) @?= "0.0"
  , testCase "3" $ show (3 :: Q 3) @?= "10.0"
  , testCase "-3" $ show (-3 :: Q 3) @?= "(2)0.0"
  , testCase "123" $ show (123 :: Q 10) @?= "123.0"
  , testCase "123" $ show (123 :: Q 2) @?= "1111011.0"
  , testCase "-123" $ show (-123 :: Q 10) @?= "(9)877.0"
  , testCase "1/2" $ show (1/2 :: Q 2) @?= "0.1"
  , testCase "-1/2" $ show (-1/2 :: Q 2) @?= "(1).1"
  , testCase "1/15" $ show (1/15 :: Q 3) @?= "(1210).2"
  , testCase "1/700" $ show (1/700 :: Q 10) @?= "(428571).43"
  , testCase "100/7" $ show (100/7 :: Q 10) @?= "(285714)300.0"
  , testCase "0.1" $ show (0.1 :: Q 10) @?= "0.1"
  , testCase "0.01" $ show (0.01 :: Q 10) @?= "0.01"
  , testCase "1/23" $ show (1/23 :: Q 10) @?= "…565217391304347826087.0"
  , testCase "1/23" $ show (1/23 :: Q' 17 5) @?= "… 8 14 13 5 3 . 0"
  , testCase "123456" $ show (123456 :: Q' 257 4) @?= "1 223 96 . 0"
  , testCase "123456" $ show (-123456 :: Q' 257 6) @?= "… 256 256 256 255 33 161 . 0"
  ]

ringIsoQ ::
     ( KnownRadix m
     , Fractional n
     , Real n
     , PadicNum n
     , Digit n ~ Mod m
     , Arbitrary n
     , Show n
     )
  => TestName -> n -> TestTree
ringIsoQ s t = testGroup s 
  [ testProperty "Q <-> Qp" $ homo0 phi psi t
  , testProperty "add Q -> Qp" $ homo1 phi (+) (+) t
  , testProperty "add Qp -> Q" $ homo2 phi psi (+) (+) t
  , testProperty "mul Q -> Qp" $ homo1 phi (*) (*) t
  , testProperty "mul Qp -> Q" $ homo2 phi psi (*) (*) t
  , testProperty "negation Qp" $ invOp phi (+) negate (const True) t
  , testProperty "inversion Qp" $ invOp phi (*) (1 /) isInvertible t
  , ringLaws t
  ]

phi :: (Fractional n, Real n) => SmallRational -> n
phi (SmallRational r) = fromRational r
psi :: (Fractional n, Real n) => n -> SmallRational
psi = SmallRational . toRational 

ringIsoQTests = testGroup "Ring isomorphism"
  [ ringIsoQ "Q 2" (0 :: Q' 2 68)
  , ringIsoQ "Q 3" (0 :: Q' 3 45)
  , ringIsoQ "Q 5" (0 :: Q' 5 29)
  , ringIsoQ "Q 7" (0 :: Q' 7 26)
  , ringIsoQ "Q 13" (0 :: Q 13)
  , ringIsoQ "Q 257" (0 :: Q 257)
  ]

------------------------------------------------------------
 
pAdicUnitTests :: TestTree
pAdicUnitTests = testGroup "p-adic units."
  [ testCase "8" $ splitUnit (0 :: Q' 2 13) @?= (0, 13)
  , testCase "9" $ splitUnit (1 :: Q 2) @?= (1, 0)
  , testCase "10" $ splitUnit (100 :: Q 2) @?= (25, 2)
  , testCase "11" $ splitUnit (1/96 :: Q 2) @?= (1 `div` 3, -5)
  , testCase "12" $ splitUnit (-1/96 :: Q 2) @?= (-1 `div` 3, -5)
  ]


------------------------------------------------------------
testSuite :: TestTree
testSuite = testGroup "Rational"
  [
    showTests
  , digitsTests 
  , equivTest
  , ringIsoQTests
  , pAdicUnitTests
  ]

test = defaultMain testSuite