{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude, UndecidableInstances                    #-}
module Algebra.Field.Fraction.Test (arbitraryRational) where
import           AlgebraicPrelude
import           Test.QuickCheck        (Arbitrary (..), Gen,
                                         arbitrarySizedIntegral, suchThat)
import           Test.SmallCheck.Series (CoSerial (..), Serial (..))
import qualified Test.SmallCheck.Series as SC

arbitraryRational :: Gen (Fraction Integer)
arbitraryRational :: Gen (Fraction Integer)
arbitraryRational = do
  Integer
a <- Gen Integer
forall a. Integral a => Gen a
arbitrarySizedIntegral
  Integer
b <- Gen Integer
forall a. Integral a => Gen a
arbitrarySizedIntegral Gen Integer -> (Integer -> Bool) -> Gen Integer
forall a. Gen a -> (a -> Bool) -> Gen a
`suchThat` \Integer
b -> Integer -> Integer -> Integer
forall d. GCDDomain d => d -> d -> d
gcd Integer
a Integer
b Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1 Bool -> Bool -> Bool
&& Integer
b Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0
  Fraction Integer -> Gen (Fraction Integer)
forall (m :: * -> *) a. Monad m => a -> m a
return (Fraction Integer -> Gen (Fraction Integer))
-> Fraction Integer -> Gen (Fraction Integer)
forall a b. (a -> b) -> a -> b
$ Integer
a Integer -> Integer -> Fraction Integer
forall d. GCDDomain d => d -> d -> Fraction d
% Integer -> Integer
forall a. Num a => a -> a
abs Integer
b

instance (GCDDomain r, Eq r, Arbitrary r) => Arbitrary (Fraction r) where
  arbitrary :: Gen (Fraction r)
arbitrary = do
    r
a <- Gen r
forall a. Arbitrary a => Gen a
arbitrary
    r
b <- Gen r
forall a. Arbitrary a => Gen a
arbitrary Gen r -> (r -> Bool) -> Gen r
forall a. Gen a -> (a -> Bool) -> Gen a
`suchThat` \r
b -> r -> r -> r
forall d. GCDDomain d => d -> d -> d
gcd r
a r
b r -> r -> Bool
forall a. Eq a => a -> a -> Bool
== r
forall r. Unital r => r
one Bool -> Bool -> Bool
&& Bool -> Bool
not (r -> Bool
forall r. DecidableZero r => r -> Bool
isZero r
b)
    Fraction r -> Gen (Fraction r)
forall (m :: * -> *) a. Monad m => a -> m a
return (Fraction r -> Gen (Fraction r)) -> Fraction r -> Gen (Fraction r)
forall a b. (a -> b) -> a -> b
$ r
a r -> r -> Fraction r
forall d. GCDDomain d => d -> d -> Fraction d
% r
b

instance {-# OVERLAPPING #-} Arbitrary (Fraction Integer) where
  arbitrary :: Gen (Fraction Integer)
arbitrary = Gen (Fraction Integer)
arbitraryRational

instance (Euclidean i, Integral i, Serial m i) => Serial m (Fraction i) where
  series :: Series m (Fraction i)
series = (i, Positive i) -> Fraction i
forall d. GCDDomain d => (d, Positive d) -> Fraction d
pairToRatio ((i, Positive i) -> Fraction i)
-> Series m (i, Positive i) -> Series m (Fraction i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Series m (i, Positive i)
forall (m :: * -> *) a. Serial m a => Series m a
series
    where
      pairToRatio :: (d, Positive d) -> Fraction d
pairToRatio (d
n, SC.Positive d
d) = d
n d -> d -> Fraction d
forall d. GCDDomain d => d -> d -> Fraction d
% d
d

instance (CoSerial m i) => CoSerial m (Fraction i) where
  coseries :: Series m b -> Series m (Fraction i -> b)
coseries Series m b
rs = (((i, i) -> b) -> (Fraction i -> (i, i)) -> Fraction i -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fraction i -> (i, i)
forall b. Fraction b -> (b, b)
ratioToPair) (((i, i) -> b) -> Fraction i -> b)
-> Series m ((i, i) -> b) -> Series m (Fraction i -> b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Series m b -> Series m ((i, i) -> b)
forall (m :: * -> *) a b.
CoSerial m a =>
Series m b -> Series m (a -> b)
coseries Series m b
rs
    where
      ratioToPair :: Fraction b -> (b, b)
ratioToPair Fraction b
r = (Fraction b -> b
forall t. Fraction t -> t
numerator Fraction b
r, Fraction b -> b
forall t. Fraction t -> t
denominator Fraction b
r)