{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{- |
See "Algebra.DimensionTerm".
-}

module Number.DimensionTerm where

import qualified Algebra.DimensionTerm as Dim

import qualified Algebra.OccasionallyScalar as OccScalar
import qualified Algebra.Module        as Module
import qualified Algebra.Algebraic     as Algebraic
import qualified Algebra.Field         as Field
import qualified Algebra.Absolute      as Absolute
import qualified Algebra.Ring          as Ring
import qualified Algebra.Additive      as Additive

import Algebra.Field    ((/), fromRational', )
import Algebra.Ring     ((*), one, fromInteger, )
import Algebra.Additive ((+), (-), zero, negate, )
import Algebra.Module   ((*>), )

import System.Random (Random, randomR, random)

import Control.DeepSeq (NFData(rnf), )

import Data.Tuple.HT (mapFst, )
import NumericPrelude.Base
import Prelude ()


{- * Number type -}

newtype T u a = Cons a
   deriving (T u a -> T u a -> Bool
(T u a -> T u a -> Bool) -> (T u a -> T u a -> Bool) -> Eq (T u a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall u a. Eq a => T u a -> T u a -> Bool
/= :: T u a -> T u a -> Bool
$c/= :: forall u a. Eq a => T u a -> T u a -> Bool
== :: T u a -> T u a -> Bool
$c== :: forall u a. Eq a => T u a -> T u a -> Bool
Eq, Eq (T u a)
Eq (T u a)
-> (T u a -> T u a -> Ordering)
-> (T u a -> T u a -> Bool)
-> (T u a -> T u a -> Bool)
-> (T u a -> T u a -> Bool)
-> (T u a -> T u a -> Bool)
-> (T u a -> T u a -> T u a)
-> (T u a -> T u a -> T u a)
-> Ord (T u a)
T u a -> T u a -> Bool
T u a -> T u a -> Ordering
T u a -> T u a -> T u a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall u a. Ord a => Eq (T u a)
forall u a. Ord a => T u a -> T u a -> Bool
forall u a. Ord a => T u a -> T u a -> Ordering
forall u a. Ord a => T u a -> T u a -> T u a
min :: T u a -> T u a -> T u a
$cmin :: forall u a. Ord a => T u a -> T u a -> T u a
max :: T u a -> T u a -> T u a
$cmax :: forall u a. Ord a => T u a -> T u a -> T u a
>= :: T u a -> T u a -> Bool
$c>= :: forall u a. Ord a => T u a -> T u a -> Bool
> :: T u a -> T u a -> Bool
$c> :: forall u a. Ord a => T u a -> T u a -> Bool
<= :: T u a -> T u a -> Bool
$c<= :: forall u a. Ord a => T u a -> T u a -> Bool
< :: T u a -> T u a -> Bool
$c< :: forall u a. Ord a => T u a -> T u a -> Bool
compare :: T u a -> T u a -> Ordering
$ccompare :: forall u a. Ord a => T u a -> T u a -> Ordering
$cp1Ord :: forall u a. Ord a => Eq (T u a)
Ord)


instance (Dim.C u, Show a) => Show (T u a) where
   showsPrec :: Int -> T u a -> ShowS
showsPrec Int
p T u a
x =
      let disect :: T u a -> (u,a)
          disect :: T u a -> (u, a)
disect (Cons a
y) = (u
forall a. HasCallStack => a
undefined, a
y)
          (u
u,a
z) = T u a -> (u, a)
forall u a. T u a -> (u, a)
disect T u a
x
      in  Bool -> ShowS -> ShowS
showParen (Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
Dim.appPrec)
            (String -> ShowS
showString String
"DimensionNumber.fromNumberWithDimension " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> u -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
Dim.appPrec u
u ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
             String -> ShowS
showString String
" " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> a -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
Dim.appPrec a
z)

instance NFData a => NFData (T u a) where
   rnf :: T u a -> ()
rnf (Cons a
x) = a -> ()
forall a. NFData a => a -> ()
rnf a
x


fromNumber :: a -> Scalar a
fromNumber :: a -> Scalar a
fromNumber = a -> Scalar a
forall u a. a -> T u a
Cons

toNumber :: Scalar a -> a
toNumber :: Scalar a -> a
toNumber (Cons a
x) = a
x

fromNumberWithDimension :: Dim.C u => u -> a -> T u a
fromNumberWithDimension :: u -> a -> T u a
fromNumberWithDimension u
_ = a -> T u a
forall u a. a -> T u a
Cons

toNumberWithDimension :: Dim.C u => u -> T u a -> a
toNumberWithDimension :: u -> T u a -> a
toNumberWithDimension u
_ (Cons a
x) = a
x


instance (Dim.C u, Additive.C a) => Additive.C (T u a) where
   zero :: T u a
zero                = a -> T u a
forall u a. a -> T u a
Cons a
forall a. C a => a
zero
   (Cons a
a) + :: T u a -> T u a -> T u a
+ (Cons a
b) = a -> T u a
forall u a. a -> T u a
Cons (a
aa -> a -> a
forall a. C a => a -> a -> a
+a
b)
   (Cons a
a) - :: T u a -> T u a -> T u a
- (Cons a
b) = a -> T u a
forall u a. a -> T u a
Cons (a
aa -> a -> a
forall a. C a => a -> a -> a
-a
b)
   negate :: T u a -> T u a
negate (Cons a
a)     = a -> T u a
forall u a. a -> T u a
Cons (a -> a
forall a. C a => a -> a
negate a
a)

instance (Dim.C u, Module.C a b) => Module.C a (T u b) where
   a
a *> :: a -> T u b -> T u b
*> (Cons b
b) = b -> T u b
forall u a. a -> T u a
Cons (a
a a -> b -> b
forall a v. C a v => a -> v -> v
*> b
b)

instance (Dim.IsScalar u, Ring.C a) => Ring.C (T u a) where
   one :: T u a
one                 = a -> T u a
forall u a. a -> T u a
Cons a
forall a. C a => a
one
   (Cons a
a) * :: T u a -> T u a -> T u a
* (Cons a
b) = a -> T u a
forall u a. a -> T u a
Cons (a
aa -> a -> a
forall a. C a => a -> a -> a
*a
b)
   fromInteger :: Integer -> T u a
fromInteger Integer
a       = a -> T u a
forall u a. a -> T u a
Cons (Integer -> a
forall a. C a => Integer -> a
fromInteger Integer
a)

instance (Dim.IsScalar u, Field.C a) => Field.C (T u a) where
   (Cons a
a) / :: T u a -> T u a -> T u a
/ (Cons a
b) = a -> T u a
forall u a. a -> T u a
Cons (a
aa -> a -> a
forall a. C a => a -> a -> a
/a
b)
   recip :: T u a -> T u a
recip (Cons a
a)      = a -> T u a
forall u a. a -> T u a
Cons (a -> a
forall a. C a => a -> a
Field.recip a
a)
   fromRational' :: Rational -> T u a
fromRational' Rational
a     = a -> T u a
forall u a. a -> T u a
Cons (Rational -> a
forall a. C a => Rational -> a
fromRational' Rational
a)

instance (Dim.IsScalar u, OccScalar.C a b) => OccScalar.C a (T u b) where
   toScalar :: T u b -> a
toScalar =
      b -> a
forall a v. C a v => v -> a
OccScalar.toScalar (b -> a) -> (T u b -> b) -> T u b -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scalar b -> b
forall a. Scalar a -> a
toNumber (Scalar b -> b) -> (T u b -> Scalar b) -> T u b -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (u -> Scalar) -> T u b -> Scalar b
forall u v a. (C u, C v) => (u -> v) -> T u a -> T v a
rewriteDimension u -> Scalar
forall dim. IsScalar dim => dim -> Scalar
Dim.toScalar
   toMaybeScalar :: T u b -> Maybe a
toMaybeScalar =
      b -> Maybe a
forall a v. C a v => v -> Maybe a
OccScalar.toMaybeScalar (b -> Maybe a) -> (T u b -> b) -> T u b -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scalar b -> b
forall a. Scalar a -> a
toNumber (Scalar b -> b) -> (T u b -> Scalar b) -> T u b -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (u -> Scalar) -> T u b -> Scalar b
forall u v a. (C u, C v) => (u -> v) -> T u a -> T v a
rewriteDimension u -> Scalar
forall dim. IsScalar dim => dim -> Scalar
Dim.toScalar
   fromScalar :: a -> T u b
fromScalar =
      (Scalar -> u) -> Scalar b -> T u b
forall u v a. (C u, C v) => (u -> v) -> T u a -> T v a
rewriteDimension Scalar -> u
forall dim. IsScalar dim => Scalar -> dim
Dim.fromScalar (Scalar b -> T u b) -> (a -> Scalar b) -> a -> T u b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Scalar b
forall a. a -> Scalar a
fromNumber (b -> Scalar b) -> (a -> b) -> a -> Scalar b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
forall a v. C a v => a -> v
OccScalar.fromScalar

instance (Dim.C u, Random a) => Random (T u a) where
  randomR :: (T u a, T u a) -> g -> (T u a, g)
randomR (Cons a
l, Cons a
u) = (a -> T u a) -> (a, g) -> (T u a, g)
forall a c b. (a -> c) -> (a, b) -> (c, b)
mapFst a -> T u a
forall u a. a -> T u a
Cons ((a, g) -> (T u a, g)) -> (g -> (a, g)) -> g -> (T u a, g)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, a) -> g -> (a, g)
forall a g. (Random a, RandomGen g) => (a, a) -> g -> (a, g)
randomR (a
l,a
u)
  random :: g -> (T u a, g)
random = (a -> T u a) -> (a, g) -> (T u a, g)
forall a c b. (a -> c) -> (a, b) -> (c, b)
mapFst a -> T u a
forall u a. a -> T u a
Cons ((a, g) -> (T u a, g)) -> (g -> (a, g)) -> g -> (T u a, g)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. g -> (a, g)
forall a g. (Random a, RandomGen g) => g -> (a, g)
random


infixl 7 &*&, *&
infixl 7 &/&

(&*&) :: (Dim.C u, Dim.C v, Ring.C a) =>
   T u a -> T v a -> T (Dim.Mul u v) a
&*& :: T u a -> T v a -> T (Mul u v) a
(&*&) (Cons a
x) (Cons a
y) = a -> T (Mul u v) a
forall u a. a -> T u a
Cons (a
x a -> a -> a
forall a. C a => a -> a -> a
Ring.* a
y)

(&/&) :: (Dim.C u, Dim.C v, Field.C a) =>
   T u a -> T v a -> T (Dim.Mul u (Dim.Recip v)) a
&/& :: T u a -> T v a -> T (Mul u (Recip v)) a
(&/&) (Cons a
x) (Cons a
y) = a -> T (Mul u (Recip v)) a
forall u a. a -> T u a
Cons (a
x a -> a -> a
forall a. C a => a -> a -> a
Field./ a
y)

mulToScalar :: (Dim.C u, Ring.C a) =>
   T u a -> T (Dim.Recip u) a -> a
mulToScalar :: T u a -> T (Recip u) a -> a
mulToScalar T u a
x T (Recip u) a
y = T (Mul u (Recip u)) a -> a
forall u a. C u => T (Mul u (Recip u)) a -> a
cancelToScalar (T u a
x T u a -> T (Recip u) a -> T (Mul u (Recip u)) a
forall u v a. (C u, C v, C a) => T u a -> T v a -> T (Mul u v) a
&*& T (Recip u) a
y)

divToScalar :: (Dim.C u, Field.C a) =>
   T u a -> T u a -> a
divToScalar :: T u a -> T u a -> a
divToScalar T u a
x T u a
y = T (Mul u (Recip u)) a -> a
forall u a. C u => T (Mul u (Recip u)) a -> a
cancelToScalar (T u a
x T u a -> T u a -> T (Mul u (Recip u)) a
forall u v a.
(C u, C v, C a) =>
T u a -> T v a -> T (Mul u (Recip v)) a
&/& T u a
y)

cancelToScalar :: (Dim.C u) =>
   T (Dim.Mul u (Dim.Recip u)) a -> a
cancelToScalar :: T (Mul u (Recip u)) a -> a
cancelToScalar =
   Scalar a -> a
forall a. Scalar a -> a
toNumber (Scalar a -> a)
-> (T (Mul u (Recip u)) a -> Scalar a)
-> T (Mul u (Recip u)) a
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Mul u (Recip u) -> Scalar) -> T (Mul u (Recip u)) a -> Scalar a
forall u v a. (C u, C v) => (u -> v) -> T u a -> T v a
rewriteDimension Mul u (Recip u) -> Scalar
forall u. C u => Mul u (Recip u) -> Scalar
Dim.cancelRight


recip :: (Dim.C u, Field.C a) =>
   T u a -> T (Dim.Recip u) a
recip :: T u a -> T (Recip u) a
recip (Cons a
x) = a -> T (Recip u) a
forall u a. a -> T u a
Cons (a -> a
forall a. C a => a -> a
Field.recip a
x)

unrecip :: (Dim.C u, Field.C a) =>
   T (Dim.Recip u) a -> T u a
unrecip :: T (Recip u) a -> T u a
unrecip (Cons a
x) = a -> T u a
forall u a. a -> T u a
Cons (a -> a
forall a. C a => a -> a
Field.recip a
x)

sqr :: (Dim.C u, Ring.C a) =>
   T u a -> T (Dim.Sqr u) a
sqr :: T u a -> T (Sqr u) a
sqr T u a
x = T u a
x T u a -> T u a -> T (Sqr u) a
forall u v a. (C u, C v, C a) => T u a -> T v a -> T (Mul u v) a
&*& T u a
x

sqrt :: (Dim.C u, Algebraic.C a) =>
   T (Dim.Sqr u) a -> T u a
sqrt :: T (Sqr u) a -> T u a
sqrt (Cons a
x) = a -> T u a
forall u a. a -> T u a
Cons (a -> a
forall a. C a => a -> a
Algebraic.sqrt a
x)


abs :: (Dim.C u, Absolute.C a) => T u a -> T u a
abs :: T u a -> T u a
abs (Cons a
x) = a -> T u a
forall u a. a -> T u a
Cons (a -> a
forall a. C a => a -> a
Absolute.abs a
x)

absSignum :: (Dim.C u, Absolute.C a) => T u a -> (T u a, a)
absSignum :: T u a -> (T u a, a)
absSignum x0 :: T u a
x0@(Cons a
x) = (T u a -> T u a
forall u a. (C u, C a) => T u a -> T u a
abs T u a
x0, a -> a
forall a. C a => a -> a
Absolute.signum a
x)

scale, (*&) :: (Dim.C u, Ring.C a) =>
   a -> T u a -> T u a
scale :: a -> T u a -> T u a
scale a
x (Cons a
y) = a -> T u a
forall u a. a -> T u a
Cons (a
x a -> a -> a
forall a. C a => a -> a -> a
Ring.* a
y)

*& :: a -> T u a -> T u a
(*&) = a -> T u a -> T u a
forall u a. (C u, C a) => a -> T u a -> T u a
scale


rewriteDimension :: (Dim.C u, Dim.C v) => (u -> v) -> T u a -> T v a
rewriteDimension :: (u -> v) -> T u a -> T v a
rewriteDimension u -> v
_ (Cons a
x) = a -> T v a
forall u a. a -> T u a
Cons a
x


{-
type class for converting Dim types to Dim value is straight-forward
   class SIDimensionType u where
      dynamic :: DimensionNumber u a -> SIValue a

   instance SIDimensionType Scalar where
      dynamic (DimensionNumber.Cons x) = SIValue.scalar x

   instance SIDimensionType Length where
      dynamic (DimensionNumber.Cons x) = SIValue.meter * dynamic x
-}


{- * Example constructors -}

type Scalar      a = T Dim.Scalar a
type Length      a = T Dim.Length a
type Time        a = T Dim.Time a
type Mass        a = T Dim.Mass a
type Charge      a = T Dim.Charge a
type Angle       a = T Dim.Angle a
type Temperature a = T Dim.Temperature a
type Information a = T Dim.Information a

type Frequency   a = T Dim.Frequency a
type Voltage     a = T Dim.Voltage a


scalar :: a -> Scalar a
scalar :: a -> Scalar a
scalar = a -> Scalar a
forall a. a -> Scalar a
fromNumber

length :: a -> Length a
length :: a -> Length a
length = a -> Length a
forall u a. a -> T u a
Cons

time :: a -> Time a
time :: a -> Time a
time = a -> Time a
forall u a. a -> T u a
Cons

mass :: a -> Mass a
mass :: a -> Mass a
mass = a -> Mass a
forall u a. a -> T u a
Cons

charge :: a -> Charge a
charge :: a -> Charge a
charge = a -> Charge a
forall u a. a -> T u a
Cons

frequency :: a -> Frequency a
frequency :: a -> Frequency a
frequency = a -> Frequency a
forall u a. a -> T u a
Cons

angle :: a -> Angle a
angle :: a -> Angle a
angle = a -> Angle a
forall u a. a -> T u a
Cons

temperature :: a -> Temperature a
temperature :: a -> Temperature a
temperature = a -> Temperature a
forall u a. a -> T u a
Cons

information :: a -> Information a
information :: a -> Information a
information = a -> Information a
forall u a. a -> T u a
Cons


voltage :: a -> Voltage a
voltage :: a -> Voltage a
voltage = a -> Voltage a
forall u a. a -> T u a
Cons