{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}
{-# LANGUAGE DefaultSignatures #-}
-----------------------------------------------------------------------------------------
-- |
-- Module      :  Data.VectorSpace
-- Copyright   :  (c) Antony Courtney and Henrik Nilsson, Yale University, 2003
-- License     :  BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  :  ivan.perez@keera.co.uk
-- Stability   :  provisional
-- Portability :  non-portable (GHC extensions)
--
-- Vector space type relation and basic instances.
--
-- There can be other implementations of VectorSpace, for example you could
-- implement it with linear like this:
-- 
-- @
-- {-# LANGUAGE FlexibleInstances     #-}
-- {-# LANGUAGE MultiParamTypeClasses #-}
-- 
-- import FRP.Yampa
-- import Linear    as L
-- 
-- instance (Eq a, Floating a) => VectorSpace (V2 a) a where
--   zeroVector = L.zero
--   (*^) = (L.*^)
--   (^/) = (L.^/)
--   negateVector = L.negated
--   (^+^) = (L.^+^)
--   (^-^) = (L.^-^)
--   dot = L.dot
-- @
-- 
-- Using this you could benefit from more advanced vector operators and the
-- improved performance linear brings while keeping a simple type class
-- interface with few dependencies.
-----------------------------------------------------------------------------------------

module Data.VectorSpace where

infixr *^
infixl ^/
infix 7 `dot`
infixl 6 ^+^, ^-^

-- Maybe norm and normalize should not be class methods, in which case
-- the constraint on the coefficient space (a) should (or, at least, could)
-- be Fractional (roughly a Field) rather than Floating.

-- | Vector space type relation.
--
--   A vector space is a set (type) closed under addition and multiplication by
--   a scalar. The type of the scalar is the /field/ of the vector space, and
--   it is said that @v@ is a vector space over @a@.
--
--   The encoding uses a type class |VectorSpace| @v a@, where @v@ represents
--   the type of the vectors and @a@ represents the types of the scalars.

class VectorSpace v a | v -> a where
    -- | Vector with no magnitude (unit for addition).
    zeroVector :: v

    -- | Multiplication by a scalar.
    (*^) :: a -> v -> v

    -- | Division by a scalar.
    (^/) :: v -> a -> v
    default (^/) :: Fractional a => v -> a -> v
    v
v ^/ a
a = (a
1forall a. Fractional a => a -> a -> a
/a
a) forall v a. VectorSpace v a => a -> v -> v
*^ v
v

    -- | Vector addition
    (^+^) :: v -> v -> v

    -- | Vector subtraction
    (^-^) :: v -> v -> v
    v
v1 ^-^ v
v2 = v
v1 forall v a. VectorSpace v a => v -> v -> v
^+^ forall v a. VectorSpace v a => v -> v
negateVector v
v2

    -- | Vector negation. Addition with a negated vector should be
    --   same as subtraction.
    negateVector :: v -> v
    default negateVector :: Num a => v -> v
    negateVector v
v = (-a
1) forall v a. VectorSpace v a => a -> v -> v
*^ v
v

    -- | Dot product (also known as scalar or inner product).
    --
    -- For two vectors, mathematically represented as @a = a1,a2,...,an@ and @b
    -- = b1,b2,...,bn@, the dot product is @a . b = a1*b1 + a2*b2 + ... +
    -- an*bn@.
    --
    -- Some properties are derived from this. The dot product of a vector with
    -- itself is the square of its magnitude ('norm'), and the dot product of
    -- two orthogonal vectors is zero.
    dot :: v -> v -> a

    -- | Vector's norm (also known as magnitude).
    --
    -- For a vector represented mathematically as @a = a1,a2,...,an@, the norm
    -- is the square root of @a1^2 + a2^2 + ... + an^2@.
    norm :: v -> a
    default norm :: Floating a => v -> a
    norm v
v = forall a. Floating a => a -> a
sqrt (v
v forall v a. VectorSpace v a => v -> v -> a
`dot` v
v)

    -- | Return a vector with the same origin and orientation (angle), but such
    -- that the norm is one (the unit for multiplication by a scalar).
    normalize    :: v -> v
    default normalize :: (Eq a, Floating a) => v -> v
    normalize v
v = if a
nv forall a. Eq a => a -> a -> Bool
/= a
0 then v
v forall v a. VectorSpace v a => v -> a -> v
^/ a
nv else forall a. HasCallStack => [Char] -> a
error [Char]
"normalize: zero vector"
        where nv :: a
nv = forall v a. VectorSpace v a => v -> a
norm v
v

-- | Vector space instance for 'Float's, with 'Float' scalars.
instance VectorSpace Float Float where
    zeroVector :: Float
zeroVector = Float
0

    Float
a *^ :: Float -> Float -> Float
*^ Float
x = Float
a forall a. Num a => a -> a -> a
* Float
x

    Float
x ^/ :: Float -> Float -> Float
^/ Float
a = Float
x forall a. Fractional a => a -> a -> a
/ Float
a

    negateVector :: Float -> Float
negateVector Float
x = (-Float
x)

    Float
x1 ^+^ :: Float -> Float -> Float
^+^ Float
x2 = Float
x1 forall a. Num a => a -> a -> a
+ Float
x2

    Float
x1 ^-^ :: Float -> Float -> Float
^-^ Float
x2 = Float
x1 forall a. Num a => a -> a -> a
- Float
x2

    Float
x1 dot :: Float -> Float -> Float
`dot` Float
x2 = Float
x1 forall a. Num a => a -> a -> a
* Float
x2

-- | Vector space instance for 'Double's, with 'Double' scalars.
instance VectorSpace Double Double where
    zeroVector :: Double
zeroVector = Double
0

    Double
a *^ :: Double -> Double -> Double
*^ Double
x = Double
a forall a. Num a => a -> a -> a
* Double
x

    Double
x ^/ :: Double -> Double -> Double
^/ Double
a = Double
x forall a. Fractional a => a -> a -> a
/ Double
a

    negateVector :: Double -> Double
negateVector Double
x = (-Double
x)

    Double
x1 ^+^ :: Double -> Double -> Double
^+^ Double
x2 = Double
x1 forall a. Num a => a -> a -> a
+ Double
x2

    Double
x1 ^-^ :: Double -> Double -> Double
^-^ Double
x2 = Double
x1 forall a. Num a => a -> a -> a
- Double
x2

    Double
x1 dot :: Double -> Double -> Double
`dot` Double
x2 = Double
x1 forall a. Num a => a -> a -> a
* Double
x2


-- | Vector space instance for pairs of 'Floating' point numbers.
instance (Eq a, Floating a) => VectorSpace (a,a) a where
    zeroVector :: (a, a)
zeroVector = (a
0,a
0)

    a
a *^ :: a -> (a, a) -> (a, a)
*^ (a
x,a
y) = (a
a forall a. Num a => a -> a -> a
* a
x, a
a forall a. Num a => a -> a -> a
* a
y)

    (a
x,a
y) ^/ :: (a, a) -> a -> (a, a)
^/ a
a = (a
x forall a. Fractional a => a -> a -> a
/ a
a, a
y forall a. Fractional a => a -> a -> a
/ a
a)

    negateVector :: (a, a) -> (a, a)
negateVector (a
x,a
y) = (-a
x, -a
y)

    (a
x1,a
y1) ^+^ :: (a, a) -> (a, a) -> (a, a)
^+^ (a
x2,a
y2) = (a
x1 forall a. Num a => a -> a -> a
+ a
x2, a
y1 forall a. Num a => a -> a -> a
+ a
y2)

    (a
x1,a
y1) ^-^ :: (a, a) -> (a, a) -> (a, a)
^-^ (a
x2,a
y2) = (a
x1 forall a. Num a => a -> a -> a
- a
x2, a
y1 forall a. Num a => a -> a -> a
- a
y2)

    (a
x1,a
y1) dot :: (a, a) -> (a, a) -> a
`dot` (a
x2,a
y2) = a
x1 forall a. Num a => a -> a -> a
* a
x2 forall a. Num a => a -> a -> a
+ a
y1 forall a. Num a => a -> a -> a
* a
y2

-- | Vector space instance for triplets of 'Floating' point numbers.
instance (Eq a, Floating a) => VectorSpace (a,a,a) a where
    zeroVector :: (a, a, a)
zeroVector = (a
0,a
0,a
0)

    a
a *^ :: a -> (a, a, a) -> (a, a, a)
*^ (a
x,a
y,a
z) = (a
a forall a. Num a => a -> a -> a
* a
x, a
a forall a. Num a => a -> a -> a
* a
y, a
a forall a. Num a => a -> a -> a
* a
z)

    (a
x,a
y,a
z) ^/ :: (a, a, a) -> a -> (a, a, a)
^/ a
a = (a
x forall a. Fractional a => a -> a -> a
/ a
a, a
y forall a. Fractional a => a -> a -> a
/ a
a, a
z forall a. Fractional a => a -> a -> a
/ a
a)

    negateVector :: (a, a, a) -> (a, a, a)
negateVector (a
x,a
y,a
z) = (-a
x, -a
y, -a
z)

    (a
x1,a
y1,a
z1) ^+^ :: (a, a, a) -> (a, a, a) -> (a, a, a)
^+^ (a
x2,a
y2,a
z2) = (a
x1forall a. Num a => a -> a -> a
+a
x2, a
y1forall a. Num a => a -> a -> a
+a
y2, a
z1forall a. Num a => a -> a -> a
+a
z2)

    (a
x1,a
y1,a
z1) ^-^ :: (a, a, a) -> (a, a, a) -> (a, a, a)
^-^ (a
x2,a
y2,a
z2) = (a
x1forall a. Num a => a -> a -> a
-a
x2, a
y1forall a. Num a => a -> a -> a
-a
y2, a
z1forall a. Num a => a -> a -> a
-a
z2)

    (a
x1,a
y1,a
z1) dot :: (a, a, a) -> (a, a, a) -> a
`dot` (a
x2,a
y2,a
z2) = a
x1 forall a. Num a => a -> a -> a
* a
x2 forall a. Num a => a -> a -> a
+ a
y1 forall a. Num a => a -> a -> a
* a
y2 forall a. Num a => a -> a -> a
+ a
z1 forall a. Num a => a -> a -> a
* a
z2

-- | Vector space instance for tuples with four 'Floating' point numbers.
instance (Eq a, Floating a) => VectorSpace (a,a,a,a) a where
    zeroVector :: (a, a, a, a)
zeroVector = (a
0,a
0,a
0,a
0)

    a
a *^ :: a -> (a, a, a, a) -> (a, a, a, a)
*^ (a
x,a
y,a
z,a
u) = (a
a forall a. Num a => a -> a -> a
* a
x, a
a forall a. Num a => a -> a -> a
* a
y, a
a forall a. Num a => a -> a -> a
* a
z, a
a forall a. Num a => a -> a -> a
* a
u)

    (a
x,a
y,a
z,a
u) ^/ :: (a, a, a, a) -> a -> (a, a, a, a)
^/ a
a = (a
x forall a. Fractional a => a -> a -> a
/ a
a, a
y forall a. Fractional a => a -> a -> a
/ a
a, a
z forall a. Fractional a => a -> a -> a
/ a
a, a
u forall a. Fractional a => a -> a -> a
/ a
a)

    negateVector :: (a, a, a, a) -> (a, a, a, a)
negateVector (a
x,a
y,a
z,a
u) = (-a
x, -a
y, -a
z, -a
u)

    (a
x1,a
y1,a
z1,a
u1) ^+^ :: (a, a, a, a) -> (a, a, a, a) -> (a, a, a, a)
^+^ (a
x2,a
y2,a
z2,a
u2) = (a
x1forall a. Num a => a -> a -> a
+a
x2, a
y1forall a. Num a => a -> a -> a
+a
y2, a
z1forall a. Num a => a -> a -> a
+a
z2, a
u1forall a. Num a => a -> a -> a
+a
u2)

    (a
x1,a
y1,a
z1,a
u1) ^-^ :: (a, a, a, a) -> (a, a, a, a) -> (a, a, a, a)
^-^ (a
x2,a
y2,a
z2,a
u2) = (a
x1forall a. Num a => a -> a -> a
-a
x2, a
y1forall a. Num a => a -> a -> a
-a
y2, a
z1forall a. Num a => a -> a -> a
-a
z2, a
u1forall a. Num a => a -> a -> a
-a
u2)

    (a
x1,a
y1,a
z1,a
u1) dot :: (a, a, a, a) -> (a, a, a, a) -> a
`dot` (a
x2,a
y2,a
z2,a
u2) = a
x1 forall a. Num a => a -> a -> a
* a
x2 forall a. Num a => a -> a -> a
+ a
y1 forall a. Num a => a -> a -> a
* a
y2 forall a. Num a => a -> a -> a
+ a
z1 forall a. Num a => a -> a -> a
* a
z2 forall a. Num a => a -> a -> a
+ a
u1 forall a. Num a => a -> a -> a
* a
u2

-- | Vector space instance for tuples with five 'Floating' point numbers.
instance (Eq a, Floating a) => VectorSpace (a,a,a,a,a) a where
    zeroVector :: (a, a, a, a, a)
zeroVector = (a
0,a
0,a
0,a
0,a
0)

    a
a *^ :: a -> (a, a, a, a, a) -> (a, a, a, a, a)
*^ (a
x,a
y,a
z,a
u,a
v) = (a
a forall a. Num a => a -> a -> a
* a
x, a
a forall a. Num a => a -> a -> a
* a
y, a
a forall a. Num a => a -> a -> a
* a
z, a
a forall a. Num a => a -> a -> a
* a
u, a
a forall a. Num a => a -> a -> a
* a
v)

    (a
x,a
y,a
z,a
u,a
v) ^/ :: (a, a, a, a, a) -> a -> (a, a, a, a, a)
^/ a
a = (a
x forall a. Fractional a => a -> a -> a
/ a
a, a
y forall a. Fractional a => a -> a -> a
/ a
a, a
z forall a. Fractional a => a -> a -> a
/ a
a, a
u forall a. Fractional a => a -> a -> a
/ a
a, a
v forall a. Fractional a => a -> a -> a
/ a
a)

    negateVector :: (a, a, a, a, a) -> (a, a, a, a, a)
negateVector (a
x,a
y,a
z,a
u,a
v) = (-a
x, -a
y, -a
z, -a
u, -a
v)

    (a
x1,a
y1,a
z1,a
u1,a
v1) ^+^ :: (a, a, a, a, a) -> (a, a, a, a, a) -> (a, a, a, a, a)
^+^ (a
x2,a
y2,a
z2,a
u2,a
v2) = (a
x1forall a. Num a => a -> a -> a
+a
x2, a
y1forall a. Num a => a -> a -> a
+a
y2, a
z1forall a. Num a => a -> a -> a
+a
z2, a
u1forall a. Num a => a -> a -> a
+a
u2, a
v1forall a. Num a => a -> a -> a
+a
v2)

    (a
x1,a
y1,a
z1,a
u1,a
v1) ^-^ :: (a, a, a, a, a) -> (a, a, a, a, a) -> (a, a, a, a, a)
^-^ (a
x2,a
y2,a
z2,a
u2,a
v2) = (a
x1forall a. Num a => a -> a -> a
-a
x2, a
y1forall a. Num a => a -> a -> a
-a
y2, a
z1forall a. Num a => a -> a -> a
-a
z2, a
u1forall a. Num a => a -> a -> a
-a
u2, a
v1forall a. Num a => a -> a -> a
-a
v2)

    (a
x1,a
y1,a
z1,a
u1,a
v1) dot :: (a, a, a, a, a) -> (a, a, a, a, a) -> a
`dot` (a
x2,a
y2,a
z2,a
u2,a
v2) =
        a
x1 forall a. Num a => a -> a -> a
* a
x2 forall a. Num a => a -> a -> a
+ a
y1 forall a. Num a => a -> a -> a
* a
y2 forall a. Num a => a -> a -> a
+ a
z1 forall a. Num a => a -> a -> a
* a
z2 forall a. Num a => a -> a -> a
+ a
u1 forall a. Num a => a -> a -> a
* a
u2 forall a. Num a => a -> a -> a
+ a
v1 forall a. Num a => a -> a -> a
* a
v2