{-# LANGUAGE RebindableSyntax #-}
module Algebra.Field (
    {- * Class -}
    C,

    (/),
    recip,
    fromRational',
    fromRational,
    (^-),

    {- * Properties -}
    propDivision,
    propReciprocal,
  ) where

import Number.Ratio (T((:%)), Rational, (%), numerator, denominator, )
import qualified Number.Ratio as Ratio
import qualified Data.Complex as Complex98
import qualified Data.Ratio as Ratio98
import qualified Algebra.PrincipalIdealDomain as PID

import qualified Algebra.Ring         as Ring
import qualified Algebra.ZeroTestable as ZeroTestable

import Algebra.Ring ((*), (^), one, fromInteger)
import Algebra.Additive (zero, negate)
import Algebra.ZeroTestable (isZero)

import NumericPrelude.Base
import Prelude (Integer, Float, Double)
import qualified Prelude as P
import Test.QuickCheck ((==>), Property)


infixr 8 ^-
infixl 7 /


{- |
Field again corresponds to a commutative ring.
Division is partially defined and satisfies

>    not (isZero b)  ==>  (a * b) / b === a
>    not (isZero a)  ==>  a * recip a === one

when it is defined. 
To safely call division,
the program must take type-specific action;
e.g., the following is appropriate in many cases:

> safeRecip :: (Integral a, Eq a, Field.C a) => a -> Maybe a
> safeRecip x =
>     let (q,r) = one `divMod` x
>     in  toMaybe (isZero r) q

Typical examples include rationals, the real numbers,
and rational functions (ratios of polynomial functions).
An instance should be typically declared
only if most elements are invertible.

Actually, we have also used this type class for non-fields
containing lots of units,
e.g. residue classes with respect to non-primes and power series.
So the restriction @not (isZero a)@ must be better @isUnit a@.

Minimal definition: 'recip' or ('/')
-}

class (Ring.C a) => C a where
    {-# MINIMAL recip | (/) #-}
    (/)           :: a -> a -> a
    recip         :: a -> a
    fromRational' :: Rational -> a
    (^-)          :: a -> Integer -> a

    {-# INLINE recip #-}
    recip a
a = a
forall a. C a => a
one a -> a -> a
forall a. C a => a -> a -> a
/ a
a
    {-# INLINE (/) #-}
    a
a / a
b = a
a a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
recip a
b
    {-# INLINE fromRational' #-}
    fromRational' Rational
r = Integer -> a
forall a. C a => Integer -> a
fromInteger (Rational -> Integer
forall a. T a -> a
numerator Rational
r) a -> a -> a
forall a. C a => a -> a -> a
/ Integer -> a
forall a. C a => Integer -> a
fromInteger (Rational -> Integer
forall a. T a -> a
denominator Rational
r)
    {-# INLINE (^-) #-}
    a
a ^- Integer
n = if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
forall a. C a => a
zero
               then a -> a
forall a. C a => a -> a
recip (a
aa -> Integer -> a
forall a. C a => a -> Integer -> a
^(-Integer
n))
               else a
aa -> Integer -> a
forall a. C a => a -> Integer -> a
^Integer
n
 -- a ^ n | n < 0 = reduceRepeated (^) one (recip a) (negate (toInteger n))
 --       | True  = reduceRepeated (^) one a (toInteger n)



-- | Needed to work around shortcomings in GHC.

{-# INLINE fromRational #-}
fromRational :: (C a) => P.Rational -> a
fromRational :: Rational -> a
fromRational Rational
x = Rational -> a
forall a. C a => Rational -> a
fromRational' (Rational -> Integer
forall a. Ratio a -> a
Ratio98.numerator Rational
x Integer -> Integer -> Rational
forall a. a -> a -> T a
:% Rational -> Integer
forall a. Ratio a -> a
Ratio98.denominator Rational
x)


{- * Instances for atomic types -}

{-
fromRational must be implemented explicitly for Float and Double!
It may be that numerator or denominator cannot be represented as Float
due to size constraints, but the fraction can.
-}

instance C Float where
    {-# INLINE (/) #-}
    {-# INLINE recip #-}
    / :: Float -> Float -> Float
(/)    = Float -> Float -> Float
forall a. Fractional a => a -> a -> a
(P./)
    recip :: Float -> Float
recip  = (Float -> Float
forall a. Fractional a => a -> a
P.recip)
    -- using Ratio98.:% would be more efficient but it is not exported.
    fromRational' :: Rational -> Float
fromRational' Rational
x =
       Rational -> Float
forall a. Fractional a => Rational -> a
P.fromRational (Rational -> Integer
forall a. T a -> a
numerator Rational
x Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
Ratio98.% Rational -> Integer
forall a. T a -> a
denominator Rational
x)

instance C Double where
    {-# INLINE (/) #-}
    {-# INLINE recip #-}
    / :: Double -> Double -> Double
(/)    = Double -> Double -> Double
forall a. Fractional a => a -> a -> a
(P./)
    recip :: Double -> Double
recip  = (Double -> Double
forall a. Fractional a => a -> a
P.recip)
    fromRational' :: Rational -> Double
fromRational' Rational
x =
       Rational -> Double
forall a. Fractional a => Rational -> a
P.fromRational (Rational -> Integer
forall a. T a -> a
numerator Rational
x Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
Ratio98.% Rational -> Integer
forall a. T a -> a
denominator Rational
x)

instance (PID.C a) => C (Ratio.T a) where
    {-# INLINE (/) #-}
    {-# INLINE recip #-}
    {-# INLINE fromRational' #-}
--    (/)                  =  Ratio.liftOrd (%)
    T a
x / :: T a -> T a -> T a
/ T a
y                =  T a
x T a -> T a -> T a
forall a. C a => a -> a -> a
* T a -> T a
forall a. C a => a -> a
recip T a
y
{-
This is efficient and almost correct in the sense,
that all admissible cases yield a correct result.
However it will hide division by zero and thus may hide bugs.
Unfortunately 'x' might not be a standard associate,
thus (y:%x) may deviate from the canonical representation.

    recip (x:%y)         =  (y:%x)
-}
    recip :: T a -> T a
recip = T a -> T a
forall a. (C a, C a) => T a -> T a
Ratio.recip
    fromRational' :: Rational -> T a
fromRational' (Integer
x:%Integer
y) =  Integer -> a
forall a. C a => Integer -> a
fromInteger Integer
x a -> a -> T a
forall a. C a => a -> a -> T a
% Integer -> a
forall a. C a => Integer -> a
fromInteger Integer
y


-- | the restriction on the divisor should be @isUnit a@ instead of @not (isZero a)@
propDivision   :: (Eq a, ZeroTestable.C a, C a) => a -> a -> Property
propReciprocal :: (Eq a, ZeroTestable.C a, C a) => a -> Property

propDivision :: a -> a -> Property
propDivision   a
a a
b   =   Bool -> Bool
not (a -> Bool
forall a. C a => a -> Bool
isZero a
b)  Bool -> Bool -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>  (a
a a -> a -> a
forall a. C a => a -> a -> a
* a
b) a -> a -> a
forall a. C a => a -> a -> a
/ a
b a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
a
propReciprocal :: a -> Property
propReciprocal a
a     =   Bool -> Bool
not (a -> Bool
forall a. C a => a -> Bool
isZero a
a)  Bool -> Bool -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>  a
a a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
recip a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. C a => a
one



-- legacy

instance (P.Integral a) => C (Ratio98.Ratio a) where
    {-# INLINE (/) #-}
    {-# INLINE recip #-}
    / :: Ratio a -> Ratio a -> Ratio a
(/)    = Ratio a -> Ratio a -> Ratio a
forall a. Fractional a => a -> a -> a
(P./)
    recip :: Ratio a -> Ratio a
recip  = (Ratio a -> Ratio a
forall a. Fractional a => a -> a
P.recip)

instance (P.RealFloat a) => C (Complex98.Complex a) where
    {-# INLINE (/) #-}
    {-# INLINE recip #-}
    / :: Complex a -> Complex a -> Complex a
(/)    = Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
(P./)
    recip :: Complex a -> Complex a
recip  = (Complex a -> Complex a
forall a. Fractional a => a -> a
P.recip)