packages feed

padic-0.1.0.0: test/Test/Base.hs

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

module Test.Base where

import Math.NumberTheory.Padic

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.Word
import Data.Ratio
import Data.Maybe

instance KnownRadix m => Arbitrary (Mod m) where
  arbitrary = fromInteger <$> arbitrary

instance Radix p prec => Arbitrary (Z' p prec) where
  arbitrary = oneof [integerZ, rationalZ, arbitraryZ]
    where
      integerZ = fromInteger <$> arbitrary
      arbitraryZ = fromDigits . take 20 <$> infiniteList
      rationalZ = do
        a <- integerZ
        b <- suchThat integerZ isInvertible
        return $ a `div` b
      shrink _ = []

instance Radix p prec => Arbitrary (Q' p prec) where
  arbitrary = oneof [integerQ, rationalQ, arbitraryQ]
    where
      integerQ = fromInteger <$> arbitrary
      arbitraryQ = fromDigits . take 20 <$> infiniteList
      rationalQ = do
        SmallRational r <- arbitrary
        return $ fromRational r
  shrink _ = []

newtype SmallRational = SmallRational (Rational)
  deriving (Show, Eq, Num, Fractional)

instance Arbitrary SmallRational where
  arbitrary = do
    let m = fromIntegral (maxBound :: Word32)
    n <- chooseInteger (-m, m)
    d <- chooseInteger (1,m)
    return $ SmallRational (n % d)
  shrink (SmallRational r) = SmallRational <$> shrink r
 
a @/= b = assertBool "" (a /= b)

homo0 :: (Show a, Eq a) => (a -> t) -> (t -> a) -> t -> a -> Property
homo0 phi psi w a =
  let [x, _] = [phi a, w] in psi x === a

homo1 :: (Show t , Eq t) => (a -> t)
      -> (a -> a -> a)
      -> (t -> t -> t)
      -> t -> a -> a -> Property
homo1 phi opa opt w a b =
  let [x, y, _] = [phi a, phi b, w]
  in x `opt` y === phi (a `opa` b)

homo2 :: (Show a, Eq a) => (a -> t) -> (t -> a)
      -> (a -> a -> a)
      -> (t -> t -> t)
      -> t -> a -> a -> Property
homo2 phi psi opa opt w a b =
  let [x, y, _] = [phi a, phi b, w]
  in psi (x `opt` y) === a `opa` b

invOp :: (Show t, Eq t) => (a -> t) 
      -> (t -> t -> t) 
      -> (t -> t)
      -> (t -> Bool)
      -> t -> a -> a -> Property
invOp phi op inv p w a b =
  let [x, y, _] = [phi a, phi b, w]
  in p y ==> (x `op` y) `op` inv y === x 
  
addComm :: (Show a, Eq a, Num a) => a -> a -> a -> Bool
addComm t a b = a + b == b + a

addAssoc :: (Show a, Eq a, Num a) => a -> a -> a -> a -> Bool
addAssoc t a b c = a + (b + c) == (a + b) + c

negInvol :: (Show a, Eq a, Num a) => a -> a -> Bool
negInvol t a = - (- a) == a

negInvers :: (Eq a, Num a) => a -> a -> Bool
negInvers t a = a - a == 0

negScale :: (Eq a, Num a) => a -> a -> Bool
negScale t a = (-1) * a == - a

mulZero :: (Eq a, Num a) => a -> a -> Bool
mulZero t a = 0 * a == 0

mulOne :: (Eq a, Num a) => a -> a -> Bool
mulOne t a = 1 * a == a

mulComm :: (Eq a, Num a) => a -> a -> a -> Bool
mulComm t a b = a * b == b * a

mulAssoc :: (Eq a, Num a) => a -> a -> a -> a -> Bool
mulAssoc t a b c = a * (b * c) == (a * b) * c

mulDistr :: (Eq a, Num a) => a -> a -> a -> a -> Bool
mulDistr t a b c = a * (b + c) == a * b + a * c
  
divDistr :: (Eq a, Fractional a) => a -> a -> a -> a -> Property
divDistr t a b c = a /= 0 ==> (b + c) / a == b / a + c / a
  
divMul :: (Eq a, Fractional a) => a -> a -> a -> Property
divMul t a b = b /= 0 ==> (a / b) * b == a

mulSign :: (Eq a, Num a) => a -> a -> a -> Bool
mulSign t a b = and [a * (- b) == - (a * b), (- a) * (- b) == a * b]

ringLaws t = testGroup "Ring laws" $
  [ testProperty "Addition commutativity" $ addComm t
  , testProperty "Addition associativity" $ addAssoc t
  , testProperty "Negation involution" $ negInvol t
  , testProperty "Addition inverse" $ negInvers t
  , testProperty "Negative scaling" $ negScale t
  , testProperty "Multiplicative zero" $ mulZero t
  , testProperty "Multiplicative one" $ mulOne t
  , testProperty "Multiplication commutativity" $ mulComm t
  , testProperty "Multiplication associativity" $ mulAssoc t
  , testProperty "Multiplication distributivity" $ mulDistr t
  , testProperty "Multiplication signs" $ mulSign t
  ]