packages feed

gasp-1.4.0.0: Algebra/Classes.hs

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses, ConstraintKinds, FlexibleContexts, FlexibleInstances, DeriveGeneric #-}
module Algebra.Classes where

import Prelude (Integer,Float,Double, (==), Monoid(..), Ord(..), Ordering(..), Foldable,
                foldMap, (||), (&&), ($),
                 Enum(..), snd, Rational, Functor(..), Eq(..), Bool(..), Semigroup(..), Show(..), uncurry, otherwise,String)

import qualified Prelude
import qualified Data.Ratio
import qualified Data.Map.Strict as M
import Data.Map (Map)
import Foreign.C
import Data.Word
import Data.Binary
import Data.Complex
import GHC.Generics
import GHC.Int
import Test.QuickCheck
import Control.Applicative

-- import Data.Functor.Utils ((#.))

infixl 6 -
infixl 6 +

infixr 7 *^
infixr 7 *<

infixl 7 *
infixl 7 /
infixl 7 `div`
infixl 7 `mod`
infixl 7 `quot`
infixl 7 `rem`

infixr 8 ^
infixr 8 ^+
infixr 8 ^/
infixr 8 **
infixr 8 ^?

type Natural = Integer

timesDefault :: (Additive a1, Additive a2, Prelude.Integral a1) => a1 -> a2 -> a2
timesDefault n0 = if n0 < zero then Prelude.error "Algebra.Classes.times: negative number of times" else go n0
    where go 0 _ = zero
          go n x = if r == 0 then y + y else x + y + y
            where (m,r) = n `Prelude.divMod` 2
                  y = go m x

-- | Additive monoid
class Additive a where
  (+) :: a -> a -> a
  zero :: a
  times :: Natural -> a -> a
  times = timesDefault

class (Show a) => TestEqual a where
  (=.=) :: a -> a -> Property

law_refl :: TestEqual a => a -> Property
law_refl x = nameLaw "=.=-reflexive" (x =.= x)

laws_testEqual :: forall a. Arbitrary a => TestEqual a => Property
laws_testEqual = property (law_refl @a)

infix 0 =.=

instance Multiplicative Property where
  one = property True
  (*) = (.&&.)

nameLaw :: Testable prop => Prelude.String -> prop -> Property
nameLaw x p = label x (counterexample x p)

law_assoc :: forall a. (TestEqual a) => String -> (a -> a -> a) -> a -> a -> a -> Property
law_assoc opName (⊕) m n o = nameLaw (opName <> "-assoc") (n ⊕ (m ⊕ o) =.= (n ⊕ m) ⊕ o)

law_left_id :: forall a. (TestEqual a) => String -> (a -> a -> a) -> a -> a ->  Property
law_left_id opName (⊕) z n = nameLaw (opName <> "-leftId") (z ⊕ n =.= n)

law_right_id :: forall a. (TestEqual a) => String -> (a -> a -> a) -> a -> a ->  Property
law_right_id opName (⊕) z n = nameLaw (opName <> "-rightId") (n ⊕ z =.= n)

laws_monoid :: forall a. (Arbitrary a, TestEqual a) => String -> (a -> a -> a) -> a -> Property
laws_monoid opName (⊕) z = product
   [property (law_left_id @a opName (⊕) z)
   ,property (law_right_id @a opName (⊕) z)
   ,property (law_assoc @a opName (⊕))]

law_commutative :: (TestEqual a) => String -> (a -> a -> a) -> a -> a -> Property
law_commutative opName (⊕) m n = nameLaw (opName <> "-comm") (m ⊕ n =.= n ⊕ m)

laws_comm_monoid :: forall a. (Arbitrary a, TestEqual a) => String -> (a -> a -> a) -> a -> Property
laws_comm_monoid opName (⊕) z = laws_monoid opName (⊕) z * property (law_commutative opName (⊕)) 
                                          

law_times :: (TestEqual a, Additive a) => Positive Integer -> a -> Property
law_times (Positive m) n = nameLaw "times" (times m n =.= timesDefault m n)

laws_additive :: forall a. Arbitrary a => (Additive a, TestEqual a) => Property
laws_additive = product [property (laws_monoid @a "plus" (+) zero)
                        ,property (law_times @a)]

law_exp_pos :: (TestEqual a, Multiplicative a) => a -> Property
law_exp_pos n = nameLaw "positive exponent" $ do
  m <- choose (0,5) -- for dense polynomials, elevating to a large power can be very expensive.
  pure (n ^+ m =.= positiveExponentDefault n m)

laws_multiplicative :: forall a. Arbitrary a => (Multiplicative a, TestEqual a) => Property
laws_multiplicative = product [property (laws_monoid @a "mul" (*) one)
                              ,property (law_exp_pos @a)]

law_fromInteger :: forall a. (TestEqual a, Ring a) => Integer -> Property
law_fromInteger m = nameLaw "fromInteger" (fromInteger @a m =.= fromIntegerDefault m)

laws_ring :: forall a. Arbitrary a => (Ring a, TestEqual a) => Property
laws_ring = product [property (law_fromInteger @a)
                    ,laws_group @a
                    ,laws_module @a @a
                    ,laws_multiplicative @a]

instance TestEqual Int where (=.=) = (===)
instance TestEqual Double where
  x =.= y = counterexample (show x <> interpret res <> show y) res
   where
    res = (Prelude.abs (x-y) < 0.01)
    interpret True  = " == "  
    interpret False = " /= "

sum :: (Foldable t, Additive a) => t a -> a
sum xs = fromSum (foldMap Sum xs)

instance Additive Integer where
  (+) = (Prelude.+)
  zero = 0
  times n x = n * x

instance Additive Word32 where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive Word16 where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive Word8 where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive Int32 where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x
instance Additive Int16 where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x
instance Additive Int8 where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive CInt where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive Int where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive Double where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance Additive Bool where
  (+) = (Prelude.||)
  zero = False

instance Additive Float where
  (+) = (Prelude.+)
  zero = 0
  times n x = Prelude.fromIntegral n * x

instance (Ord k,AbelianAdditive v) => Additive (Map k v) where
  (+) = M.unionWith (+)
  zero = M.empty
  times n = fmap (times n)

instance (Additive v) => Additive (k -> v) where
  (+) = liftA2 (+)
  zero = pure zero
  times n = fmap (times n)

class Additive r => DecidableZero r where
  isZero :: r -> Bool

law_decidable_zero :: forall a. (DecidableZero a, TestEqual a) => Property
law_decidable_zero = property (isZero (zero @a))


instance DecidableZero Integer where
  isZero = (== 0)
instance DecidableZero CInt where
  isZero = (== 0)
instance DecidableZero Word32 where
  isZero = (== 0)
instance DecidableZero Word16 where
  isZero = (== 0)
instance DecidableZero Word8 where
  isZero = (== 0)
instance DecidableZero Int where
  isZero = (== 0)
instance DecidableZero Double where
  isZero = (== 0)
instance DecidableZero Float where
  isZero = (== 0)
instance (Prelude.Integral x, DecidableZero x) => DecidableZero (Data.Ratio.Ratio x) where
  isZero x = isZero (Data.Ratio.numerator x)
instance (Ord k,DecidableZero v,AbelianAdditive v) => DecidableZero (Map k v) where
  isZero = Prelude.all isZero
instance DecidableZero x => DecidableZero (Complex x) where
  isZero (x :+ y) = isZero x && isZero y

class Additive a => AbelianAdditive a
  -- just a law.

laws_abelian_additive :: forall a. (Arbitrary a, AbelianAdditive a, TestEqual a) => Property
laws_abelian_additive = laws_comm_monoid @a "plus" (+) zero

instance AbelianAdditive Integer
instance AbelianAdditive CInt
instance AbelianAdditive Int
instance AbelianAdditive Int8
instance AbelianAdditive Int16
instance AbelianAdditive Int32
instance AbelianAdditive Word8
instance AbelianAdditive Word16
instance AbelianAdditive Word32
instance AbelianAdditive Bool
instance AbelianAdditive Double
instance AbelianAdditive Float
instance (Ord k,AbelianAdditive v) => AbelianAdditive (Map k v)
instance (AbelianAdditive v) => AbelianAdditive (k -> v)

multDefault :: Group a => Natural -> a -> a
multDefault n x = if n < 0 then negate (times (negate n) x) else times n x

class Additive a => Group a where
  {-# MINIMAL (negate | (-) | subtract) #-}
  (-) :: a -> a -> a
  a - b = a + negate b
  subtract :: a -> a -> a
  subtract b a = a - b
  negate :: a -> a
  negate b = zero - b
  mult :: Integer -> a -> a
  mult = multDefault

law_negate_minus :: (TestEqual a, Group a) => a -> a -> Property
law_negate_minus m n = nameLaw "minus/negate" (m + negate n =.= m - n)

law_mult :: (TestEqual a, Group a) => Integer -> a -> Property
law_mult m n = nameLaw "mult" (mult m n =.= multDefault m n)


laws_group :: forall a. Arbitrary a => (Group a, TestEqual a) => Property
laws_group = laws_additive @a .&&. product [property (law_negate_minus @a)
                                           ,property (law_mult @a)]

laws_abelian_group :: forall a. Arbitrary a => (Group a, TestEqual a) => Property
laws_abelian_group = laws_group @a * product [property (law_commutative @a "plus" (+))]

instance Group Integer where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance Group Int where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance Group CInt where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance Group Int32 where
  (-) = (Prelude.-)
  negate = Prelude.negate
instance Group Int16 where
  (-) = (Prelude.-)
  negate = Prelude.negate
instance Group Int8 where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance Group Word32 where
  (-) = (Prelude.-)
  negate = Prelude.negate
instance Group Word16 where
  (-) = (Prelude.-)
  negate = Prelude.negate
instance Group Word8 where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance Group Double where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance Group Float where
  (-) = (Prelude.-)
  negate = Prelude.negate

instance (Ord k,Group v,AbelianAdditive v) => Group (Map k v) where
  -- This definition does not work:
  -- (-) = M.unionWith (-)
  -- because if a key is not present on the lhs. then the rhs won't be negated.
  negate = fmap negate

instance (Group v) => Group (k -> v) where
  negate = fmap negate
  (-) = liftA2 (-)

-- | Functorial scaling. Compared to (*^) this operator disambiguates
-- the scalar type, by using the functor structure and using the
-- multiplicative instance for scalars.
(*<) :: (Functor f, Multiplicative a) => a -> f a -> f a
s *< v = (s*) <$> v

-- | Any instance must preserve the following invariants: 1. if
-- Multiplicative a and Scalable a a, then (*) = (*^) for a.
-- 2. Scalable must define a partial order relation, in particular,
-- instances of the form (Scalable s a) => Scalable s (T ... a ...)
-- are acceptable, and should be declared overlappable.

class Scalable s a where
  (*^) :: s -> a -> a

instance {-# Overlappable #-} Scalable s a => Scalable s (Map k a) where
  s *^ x = fmap (s *^) x

instance {-# Overlappable #-} Scalable s a => Scalable s (k -> a) where
  s *^ x = fmap (s *^) x

-- | "Most natural" scaling. Also disambiguates the scalar type, but using a fundep.
class Scalable' a where
  type Scalar a
  (!*^) :: Scalar a -> a -> a

  
-- | A prefix variant of (*^), useful when using type applications.
-- scale :: forall s a. Scalable s a => s -> a -> a
-- scale = (*^)

type SemiModule s a = (AbelianAdditive a, SemiRing s, Scalable s a)

type Module s a = (SemiModule s a, Group s, Group a)

law_module_zero :: forall s a. (Module s a, TestEqual a) => s -> Property
law_module_zero s = nameLaw "module/zero" (s *^ zero =.= zero @a)

law_module_one :: forall s a. (Module s a, TestEqual a) => a -> Property
law_module_one x = nameLaw "module/one" ((one @s) *^ x =.= x)

law_module_sum :: forall s a. (Module s a, TestEqual a) => s -> a -> a -> Property
law_module_sum s x y = nameLaw "module/distr/left" (s *^ (x + y) =.= s*^x + s *^ y)

law_module_sum_left :: forall s a. (Module s a, TestEqual a) => s -> s -> a -> Property
law_module_sum_left s t x = nameLaw "module/distr/right" ((s + t) *^ x =.= s*^x + t *^ x)

law_module_mul :: forall s a. (Module s a, TestEqual a) => s -> s -> a -> Property
law_module_mul s t x = nameLaw "module/mul/assoc" ((s * t) *^ x =.= s *^ t *^ x)

laws_module :: forall s a. Arbitrary a => (Module s a, TestEqual a, Arbitrary s, Show s) => Property
laws_module = laws_additive @a .&&. product [property (law_module_zero @s @a)
                                            ,property (law_module_one @s @a)
                                            ,property (law_module_sum @s @a)
                                            ,property (law_module_sum_left @s @a)
                                            ,property (law_module_mul @s @a)
                                            ]

-- Comparision of maps with absence of a key equivalent to zero value.
instance (Ord x, Show x, Arbitrary x,TestEqual a,Additive a) => TestEqual (Map x a) where
  x =.= y = product (uncurry (=.=) <$> M.unionWith collapse ((,zero) <$> x) ((zero,) <$> y))
    where collapse :: (a,b) -> (c,d) -> (a,d)
          collapse (a,_) (_,b) = (a,b)


instance Scalable Integer Integer where
  (*^) = (*)

instance Scalable Int Int where (*^) = (*)

instance Scalable Int8 Int8 where (*^) = (*)
instance Scalable Int16 Int16 where (*^) = (*)
instance Scalable Int32 Int32 where (*^) = (*)

instance Scalable Word8 Word8 where (*^) = (*)
instance Scalable Word16 Word16 where (*^) = (*)
instance Scalable Word32 Word32 where (*^) = (*)

instance Scalable CInt CInt where
  (*^) = (*)

instance Scalable Double Double where
  (*^) = (*)

instance Scalable Float Float where
  (*^) = (*)

-- | Multiplicative monoid
class Multiplicative a where
  (*) :: a -> a -> a
  one :: a
  (^+) :: a -> Natural -> a
  (^+) = positiveExponentDefault

positiveExponentDefault :: Multiplicative a => a -> Natural -> a
positiveExponentDefault x0 n0 = if n0 < 0 then Prelude.error "Algebra.Classes.^+: negative exponent" else go x0 n0
    where go _ 0 = one
          go x n = if r == 0 then y * y else x * y * y
            where (m,r) = n `Prelude.divMod` 2
                  y = go x m

product :: (Multiplicative a, Foldable f) => f a -> a
product xs = fromProduct (foldMap Product xs)

instance Multiplicative Integer where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative CInt where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Word32 where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Word16 where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Word8 where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Int32 where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Int16 where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Int8 where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Int where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Double where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Float where
  (*) = (Prelude.*)
  one = 1
  (^+) = (Prelude.^)

instance Multiplicative Bool where
  (*) = (Prelude.&&)
  one = True


type SemiRing a = (Multiplicative a, AbelianAdditive a)
type PreRing a = (SemiRing a, Group a)

fromIntegerDefault :: PreRing a => Integer -> a
fromIntegerDefault n = mult n one

class (Module a a, PreRing a) => Ring a where
  fromInteger :: Integer -> a
  fromInteger = fromIntegerDefault

instance Ring Integer where
  fromInteger = Prelude.fromInteger

instance Ring Int8 where fromInteger = Prelude.fromInteger
instance Ring Int16 where fromInteger = Prelude.fromInteger
instance Ring Int32 where fromInteger = Prelude.fromInteger

instance Ring Word8 where fromInteger = Prelude.fromInteger
instance Ring Word16 where fromInteger = Prelude.fromInteger
instance Ring Word32 where fromInteger = Prelude.fromInteger

instance Ring CInt where
  fromInteger = Prelude.fromInteger

instance Ring Int where
  fromInteger = Prelude.fromInteger

instance Ring Double where
  fromInteger = Prelude.fromInteger

instance Ring Float where
  fromInteger = Prelude.fromInteger

class Multiplicative a => Division a where
  {-# MINIMAL (recip | (/)) #-}
  recip :: a -> a
  recip x         =  one / x

  (/) :: a -> a -> a
  x / y           =  x * recip y

  (^) :: a -> Integer -> a
  b ^ n | n < 0 = recip b ^+ negate n
        | True  = b ^+ n

instance Division Double where
  (/) = (Prelude./)
  recip = Prelude.recip
  (^) = (Prelude.^^)

instance Division Float where
  (/) = (Prelude./)
  recip = Prelude.recip
  (^) = (Prelude.^^)

class (Ring a, Division a) => Field a where
  fromRational :: Rational -> a
  fromRational x  =  fromInteger (Data.Ratio.numerator x) /
                     fromInteger (Data.Ratio.denominator x)

instance Field Double where
  fromRational = Prelude.fromRational

instance Field Float where
  fromRational = Prelude.fromRational


class (Ring a, DecidableZero a) => EuclideanDomain a where
    {-# MINIMAL (stdUnit | normalize) , (quotRem | (quot , rem)) #-}
    stdAssociate    :: a -> a
    stdUnit         :: a -> a
    normalize       :: a -> (a, a)

    quot, rem        :: a -> a -> a
    quotRem          :: a -> a -> (a,a)

    stdAssociate x  =  x `quot` stdUnit x
    stdUnit x       =  snd (normalize x)
    normalize x     =  (stdAssociate x, stdUnit x)

    n `quotRem` d    =  (n `quot` d, n `rem` d)
    n `quot` d       =  q  where (q,_) = quotRem n d
    n `rem` d       =  r  where (_,r) = quotRem n d

gcd             :: EuclideanDomain a => a -> a -> a
{-# NOINLINE [1] gcd #-}
gcd x y         =  gcd' (stdAssociate x) (stdAssociate y)
 where
   gcd'             :: (EuclideanDomain a) => a -> a -> a
   gcd' a b | isZero b  =  a
            | otherwise  =  gcd' b (a `rem` b)

-- | @'lcm' x y@ is the smallest positive integer that both @x@ and @y@ divide.
lcm :: (EuclideanDomain a) => a -> a -> a
{-# SPECIALISE lcm :: Int -> Int -> Int #-}
{-# NOINLINE [1] lcm #-}
lcm x y | isZero x || isZero y = zero
        | otherwise =  stdAssociate ((x `quot` (gcd x y)) * y)

instance  EuclideanDomain Integer  where
    quot             =  Prelude.quot
    rem             =  Prelude.rem
    stdAssociate x  =  Prelude.abs x
    stdUnit x       =  if x < 0 then -1 else 1

instance  EuclideanDomain CInt  where
    quot             =  Prelude.quot
    rem             =  Prelude.rem
    stdAssociate x  =  Prelude.abs x
    stdUnit x       =  if x < 0 then -1 else 1

instance  EuclideanDomain Int  where
    quot             =  Prelude.quot
    rem             =  Prelude.rem
    stdAssociate x  =  Prelude.abs x
    stdUnit x       =  if x < 0 then -1 else 1


-- Note: base.Integral has "Real", superclass, which also defines "toRational"
class (Ord a, Ring a, Enum a, EuclideanDomain a) => Integral a  where
    div, mod       :: a -> a -> a
    divMod         :: a -> a -> (a,a)
    toInteger       :: a -> Integer

    n `div` d      =  q  where (q,_) = divMod n d
    n `mod` d       =  r  where (_,r) = divMod n d
    divMod n d     =  if stdUnit r == negate (stdUnit d) then (q+one, r-d) else qr
      where qr@(q,r) = quotRem n d

instance  Integral Integer  where
    div      =  Prelude.div
    mod       =  Prelude.mod
    toInteger = Prelude.toInteger

instance  Integral Int  where
    div      =  Prelude.div
    mod       =  Prelude.mod
    toInteger = Prelude.toInteger

---------------------------------------
-- Data.Ratio.Ratio instances
instance Prelude.Integral a => Additive (Data.Ratio.Ratio a) where
  zero = Prelude.fromInteger 0
  (+) = (Prelude.+)

instance Prelude.Integral a => AbelianAdditive (Data.Ratio.Ratio a) where

instance Prelude.Integral a => Group (Data.Ratio.Ratio a) where
  negate = Prelude.negate
  (-) = (Prelude.-)

instance Prelude.Integral a => Multiplicative (Data.Ratio.Ratio a) where
  one = Prelude.fromInteger 1
  (*) = (Prelude.*)
  (^+) = (Prelude.^)

instance Prelude.Integral a => Division (Data.Ratio.Ratio a) where
  recip = Prelude.recip
  (/) = (Prelude./)
  (^) = (Prelude.^^)
instance Prelude.Integral a => Scalable (Data.Ratio.Ratio a) (Data.Ratio.Ratio a) where
  (*^) = (*)
instance Prelude.Integral a => Ring (Data.Ratio.Ratio a) where
  fromInteger = Prelude.fromInteger
instance Prelude.Integral a => Field (Data.Ratio.Ratio a) where
  fromRational = Prelude.fromRational

instance Scalable Rational Double where
    r *^ d = fromRational r * d

----------------------
-- Complex instances
instance Additive a => Additive (Complex a) where
    (x:+y) + (x':+y')   =  (x+x') :+ (y+y')
    zero = zero :+ zero
instance Ring a => Multiplicative (Complex a) where
    (x:+y) * (x':+y')   =  (x*x'-y*y') :+ (x*y'+y*x')
    one = one :+ zero
instance Group a => Group  (Complex a) where
    (x:+y) - (x':+y')   =  (x-x') :+ (y-y')
    negate (x:+y)       =  negate x :+ negate y
instance AbelianAdditive a => AbelianAdditive (Complex a)
instance Ring a => Scalable (Complex a) (Complex a) where
  (*^) = (*)
instance {-# Overlappable #-} Scalable s a => Scalable s (Complex a) where
  s *^ x = fmap (s *^) x
instance Ring a => Ring (Complex a) where
    fromInteger n  =  fromInteger n :+ zero

instance  Field a => Division (Complex a)  where
    {-# SPECIALISE instance Division (Complex Double) #-}
    (x:+y) / (x':+y')   =  (x*x'+y*y') / d :+ (y*x'-x*y') / d
      where d   = x'*x' + y'*y'

instance Field a => Field (Complex a) where
    fromRational a =  fromRational a :+ zero

-- Syntax

ifThenElse :: Bool -> t -> t -> t
ifThenElse True a _ = a
ifThenElse False _ a = a


class Division a => Roots a where
  {-# MINIMAL root | (^/) #-}
  sqrt :: a -> a
  sqrt = root 2
  {-# INLINE sqrt #-}

  root :: Integer -> a -> a
  root n x = x ^/ (1 Data.Ratio.% n)

  (^/) :: a -> Rational -> a
  x ^/ y = root (Data.Ratio.denominator y) (x ^ Data.Ratio.numerator y)

type Algebraic a = (Roots a, Field a)

instance Roots Float where
  sqrt = Prelude.sqrt
  x ^/ y = x ** fromRational y

instance Roots Double where
  sqrt = Prelude.sqrt
  x ^/ y = x ** fromRational y

-- | Class providing transcendental functions
class Algebraic a => Transcendental a where 
    pi                  :: a
    exp, log            :: a -> a
    (**), logBase       :: a -> a -> a
    sin, cos, tan       :: a -> a
    asin, acos, atan    :: a -> a
    sinh, cosh, tanh    :: a -> a
    asinh, acosh, atanh :: a -> a

    -- | @'log1p' x@ computes @'log' (1 + x)@, but provides more precise
    -- results for small (absolute) values of @x@ if possible.
    --
    -- @since 4.9.0.0
    log1p               :: a -> a

    -- | @'expm1' x@ computes @'exp' x - 1@, but provides more precise
    -- results for small (absolute) values of @x@ if possible.
    --
    -- @since 4.9.0.0
    expm1               :: a -> a

    -- | @'log1pexp' x@ computes @'log' (1 + 'exp' x)@, but provides more
    -- precise results if possible.
    --
    -- Examples:
    --
    -- * if @x@ is a large negative number, @'log' (1 + 'exp' x)@ will be
    --   imprecise for the reasons given in 'log1p'.
    --
    -- * if @'exp' x@ is close to @-1@, @'log' (1 + 'exp' x)@ will be
    --   imprecise for the reasons given in 'expm1'.
    --
    -- @since 4.9.0.0
    log1pexp            :: a -> a

    -- | @'log1mexp' x@ computes @'log' (1 - 'exp' x)@, but provides more
    -- precise results if possible.
    --
    -- Examples:
    --
    -- * if @x@ is a large negative number, @'log' (1 - 'exp' x)@ will be
    --   imprecise for the reasons given in 'log1p'.
    --
    -- * if @'exp' x@ is close to @1@, @'log' (1 - 'exp' x)@ will be
    --   imprecise for the reasons given in 'expm1'.
    --
    -- @since 4.9.0.0
    log1mexp            :: a -> a

    {-# INLINE (**) #-}
    {-# INLINE logBase #-}
    {-# INLINE tan #-}
    {-# INLINE tanh #-}
    x ** y              =  exp (log x * y)
    logBase x y         =  log y / log x
    tan  x              =  sin  x / cos  x
    tanh x              =  sinh x / cosh x

    {-# INLINE log1p #-}
    {-# INLINE expm1 #-}
    {-# INLINE log1pexp #-}
    {-# INLINE log1mexp #-}
    log1p x = log (one + x)
    expm1 x = exp x - one
    log1pexp x = log1p (exp x)
    log1mexp x = log1p (negate (exp x))

(^?) :: Transcendental a => a -> a -> a
(^?) = (**)

instance Transcendental Double where
  pi = Prelude.pi
  exp = Prelude.exp
  log = Prelude.log
  (**) = (Prelude.**)
  logBase = Prelude.logBase
  sin = Prelude.sin
  cos = Prelude.cos
  tan = Prelude.tan
  asin = Prelude.asin
  acos = Prelude.acos
  atan = Prelude.atan
  sinh = Prelude.sinh
  cosh = Prelude.cosh
  tanh = Prelude.tanh
  asinh = Prelude.asinh
  acosh = Prelude.acosh
  atanh = Prelude.atanh

instance Transcendental Float where
  pi = Prelude.pi
  exp = Prelude.exp
  log = Prelude.log
  (**) = (Prelude.**)
  logBase = Prelude.logBase
  sin = Prelude.sin
  cos = Prelude.cos
  tan = Prelude.tan
  asin = Prelude.asin
  acos = Prelude.acos
  atan = Prelude.atan
  sinh = Prelude.sinh
  cosh = Prelude.cosh
  tanh = Prelude.tanh
  asinh = Prelude.asinh
  acosh = Prelude.acosh
  atanh = Prelude.atanh



instance (Prelude.RealFloat a, Ord a, Algebraic a) => Roots (Complex a) where
    root n x = mkPolar (root n ρ) (θ / fromInteger n)
      where (ρ,θ) = polar x
    sqrt z@(x:+y)
      | z == zero = zero
      | otherwise 
                     =  u :+ (if y < 0 then -v else v)
                      where (u,v) = if x < 0 then (v',u') else (u',v')
                            v'    = Prelude.abs y / (u'*2)
                            u'    = sqrt ((magnitude z + Prelude.abs x) / 2)


instance  (Prelude.RealFloat a, Transcendental a) => AlgebraicallyClosed (Complex a) where
  imaginaryUnit = 0 :+ 1
  rootOfUnity n i = exp (0 :+ 2*pi*fromInteger i/fromInteger n)
  

instance  (Prelude.RealFloat a, Transcendental a) => Transcendental (Complex a) where
    {-# SPECIALISE instance Transcendental (Complex Float) #-}
    {-# SPECIALISE instance Transcendental (Complex Double) #-}
    pi             =  pi :+ 0
    exp (x:+y)     =  expx * cos y :+ expx * sin y
                      where expx = exp x
    log z          =  log (magnitude z) :+ phase z

    x ** y = case (x,y) of
      (_ , (0:+0))  -> 1 :+ 0
      ((0:+0), (exp_re:+_)) -> case compare exp_re 0 of
                 GT -> 0 :+ 0
                 LT -> inf :+ 0
                 EQ -> nan :+ nan
      ((re:+im), (exp_re:+_))
        | (Prelude.isInfinite re || Prelude.isInfinite im) -> case compare exp_re 0 of
                 GT -> inf :+ 0
                 LT -> 0 :+ 0
                 EQ -> nan :+ nan
        | otherwise -> exp (log x * y)
      where
        inf = 1/0
        nan = 0/0

    sin (x:+y)     =  sin x * cosh y :+ cos x * sinh y
    cos (x:+y)     =  cos x * cosh y :+ (- sin x * sinh y)
    tan (x:+y)     =  (sinx*coshy:+cosx*sinhy)/(cosx*coshy:+(-sinx*sinhy))
                      where sinx  = sin x
                            cosx  = cos x
                            sinhy = sinh y
                            coshy = cosh y

    sinh (x:+y)    =  cos y * sinh x :+ sin  y * cosh x
    cosh (x:+y)    =  cos y * cosh x :+ sin y * sinh x
    tanh (x:+y)    =  (cosy*sinhx:+siny*coshx)/(cosy*coshx:+siny*sinhx)
                      where siny  = sin y
                            cosy  = cos y
                            sinhx = sinh x
                            coshx = cosh x

    asin z@(x:+y)  =  y':+(-x')
                      where  (x':+y') = log (((-y):+x) + sqrt (1 - z*z))
    acos z         =  y'':+(-x'')
                      where (x'':+y'') = log (z + ((-y'):+x'))
                            (x':+y')   = sqrt (1 - z*z)
    atan z@(x:+y)  =  y':+(-x')
                      where (x':+y') = log (((1-y):+x) / sqrt (1+z*z))

    asinh z        =  log (z + sqrt (1+z*z))
    -- Take care to allow (-1)::Complex, fixing #8532
    acosh z        =  log (z + (sqrt (z+1)) * (sqrt (z-1)))
    atanh z        =  0.5 * log ((1.0+z) / (1.0-z))


class Algebraic a => AlgebraicallyClosed a where
  imaginaryUnit :: a
  imaginaryUnit = rootOfUnity 2 1
  -- | rootOfUnity n give the nth roots of unity. The 2nd argument specifies which one is demanded
  rootOfUnity :: Integer -> Integer -> a

----------------
-- The following should go in Morphism.Monoids but sum/product depend on it.

newtype Sum a = Sum {fromSum :: a} deriving (Generic,Ord,Eq,Show)

instance Binary a => Binary (Sum a)

instance Additive a => Monoid (Sum a) where
  mempty = Sum zero
  mappend = (<>)

instance Additive a => Semigroup (Sum a) where
  (<>) (Sum x) (Sum y) = Sum (x + y)


newtype Product a = Product {fromProduct :: a} deriving (Generic,Ord,Eq,Show)

instance Multiplicative a => Semigroup (Product a) where
  (<>) (Product x) (Product y) = Product (x * y)

instance Multiplicative a => Monoid (Product a) where
  mempty = Product one
  mappend = (<>)

---------------------
-- Functor application, useful for "deriving via".

newtype App f x = App (f x) deriving (Functor, Applicative) -- should be somewhere in base but can't find it.

instance (Applicative f, AbelianAdditive a) => AbelianAdditive (App f a) where
instance (Applicative f, Additive a) => Additive (App f a) where
  (+) = liftA2 (+)
  zero = pure zero
instance (Applicative f, Group a) => Group (App f a) where
  (-) = liftA2 (-)
  negate = fmap negate

instance (Applicative f, Multiplicative a) => Multiplicative (App f a) where
  (*) = liftA2 (*)
  one = pure one

instance (Applicative f, Scalable s a) =>  Scalable (App f s) (App f a) where
  (*^) = liftA2 (*^)

instance (Applicative f, Division s) => Division (App f s) where
  recip = fmap recip
  (/) = liftA2 (/)

instance (Applicative f, Roots s) => Roots (App f s) where
  x ^/ r = (^/ r) <$> x
  root i = fmap (root i)

instance (Applicative f, Field s) => Field (App f s) where
  fromRational x = pure (fromRational x)
  
instance (Applicative f, Transcendental s) => Transcendental (App f s) where
  pi = pure pi
  exp = fmap exp
  log = fmap log 
  sin = fmap sin 
  cos = fmap cos 
  asin = fmap asin 
  acos = fmap acos 
  atan = fmap atan 
  sinh = fmap sinh 
  cosh = fmap cosh 
  asinh = fmap asinh 
  acosh = fmap acosh 
  atanh = fmap atanh 
  
instance (Applicative f, Ring a) => Ring (App f a) where
  fromInteger x = pure (fromInteger x)