{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, TypeFamilies #-}
{-# LANGUAGE Trustworthy #-}

{- | 
Module      :  Physics.Learn.StateSpace
Copyright   :  (c) Scott N. Walck 2014
License     :  BSD3 (see LICENSE)
Maintainer  :  Scott N. Walck <walck@lvc.edu>
Stability   :  experimental

A 'StateSpace' is an affine space where the associated vector space
has scalars that are instances of 'Fractional'.
If p is an instance of 'StateSpace', then the associated vectorspace
'Diff' p is intended to represent the space of time derivatives
of paths in p.

'StateSpace' is very similar to Conal Elliott's 'AffineSpace'.
-}

module Physics.Learn.StateSpace
    ( StateSpace(..)
    , (.-^)
    , Time
    )
    where

import Data.VectorSpace
    ( VectorSpace
    , Scalar
    , negateV
    )
import Physics.Learn.Position
    ( Position
    , shiftPosition
    , displacement
    )
import Physics.Learn.CarrotVec
    ( Vec
    , (^+^)
    , (^-^)
    )

infixl 6 .+^, .-^
infix  6 .-.

-- | A 'StateSpace' has an associated vector space, the vectors of which
--   can be multiplied or divided by scalars.
--   An example would be the set of positions of a particle.
--   Position is not a vector, but displacement (difference in position) is a vector.
class (VectorSpace (Diff p), Fractional (Scalar (Diff p))) => StateSpace p where
  -- | Associated vector space
  type Diff p
  -- | Subtract points
  (.-.)  :: p -> p -> Diff p
  -- | Point plus vector
  (.+^)  :: p -> Diff p -> p

-- | The scalars of the associated vector space can be thought of as time intervals.
type Time p = Scalar (Diff p)

-- | Point minus vector
(.-^) :: StateSpace p => p -> Diff p -> p
p .-^ v = p .+^ negateV v

instance StateSpace Double where
    type Diff Double = Double
    (.-.) = (-)
    (.+^) = (+)

instance StateSpace Vec where
    type Diff Vec = Vec
    (.-.) = (^-^)
    (.+^) = (^+^)

instance StateSpace Position where
    type Diff Position = Vec
    (.-.) = flip displacement
    (.+^) = flip shiftPosition

instance (StateSpace p, StateSpace q, Time p ~ Time q) => StateSpace (p,q) where
  type Diff (p,q)   = (Diff p, Diff q)
  (p,q) .-. (p',q') = (p .-. p', q .-. q')
  (p,q) .+^ (u,v)   = (p .+^ u, q .+^ v)

instance (StateSpace p, StateSpace q, StateSpace r, Time p ~ Time q
         ,Time q ~ Time r) => StateSpace (p,q,r) where
  type Diff (p,q,r)      = (Diff p, Diff q, Diff r)
  (p,q,r) .-. (p',q',r') = (p .-. p', q .-. q', r .-. r')
  (p,q,r) .+^ (u,v,w)    = (p .+^ u, q .+^ v, r .+^ w)