{-# LANGUAGE CPP #-}
#define Flt Double
#define VECT_Double

-- | 'Eq', 'Num' and 'Fractional' instances for vectors and matrices.
-- These make writing code much more convenient, but also much more 
-- dangerous; thus you have to import this module explicitely.
--
-- In the case of Vector instances, all operations are pointwise
-- (including multiplication and division), and scalars are implicitly
-- converted to vectors so that all components of the resulting vectors
-- are the equal to the given scalar. This gives a set of consistent
-- instances.
--
-- In the case of Matrices, multiplication is usual matrix multiplication,
-- division is not implemented, and scalars are converted to diagonal 
-- matrices.
--
-- 'abs' and 'signum' are implemented to be 'normalize' and 'norm'
-- (in the case of matrices, Frobenius norm).

module Data.Vect.Flt.Instances where

--------------------------------------------------------------------------------  
  
import Data.Vect.Flt.Base 

--------------------------------------------------------------------------------  
-- * Vectors

instance Eq Vec2 where
  Vec2 x y == Vec2 a b = (x==a && y==b)

instance Num Vec2 where
  (+) = (&+)
  (-) = (&-)
  negate = neg
  (*) = pointwise 
  fromInteger a = let x = fromInteger a in Vec2 x x
  abs = normalize
  signum v = let x = norm v in Vec2 x x
  
instance Fractional Vec2 where
  (Vec2 x y) / (Vec2 a b) = Vec2 (x/a) (y/b) 
  fromRational a = let x = fromRational a in Vec2 x x 

--------------------------------------------------------------------------------  

instance Eq Vec3 where
  Vec3 x y z == Vec3 a b c = (x==a && y==b && z==c)

instance Num Vec3 where
  (+) = (&+)
  (-) = (&-)
  negate = neg
  (*) = pointwise 
  fromInteger a = let x = fromInteger a in Vec3 x x x
  abs = normalize
  signum v = let x = norm v in Vec3 x x x
  
instance Fractional Vec3 where
  (Vec3 x y z) / (Vec3 a b c) = Vec3 (x/a) (y/b) (z/c)
  fromRational a = let x = fromRational a in Vec3 x x x  
  
--------------------------------------------------------------------------------  

instance Eq Vec4 where
  Vec4 x y z w == Vec4 a b c d = (x==a && y==b && z==c && w==d)

instance Num Vec4 where
  (+) = (&+)
  (-) = (&-)
  negate = neg
  (*) = pointwise 
  fromInteger a = let x = fromInteger a in Vec4 x x x x
  abs = normalize
  signum v = let x = norm v in Vec4 x x x x
  
instance Fractional Vec4 where
  (Vec4 x y z w) / (Vec4 a b c d) = Vec4 (x/a) (y/b) (z/c) (w/d)
  fromRational a = let x = fromRational a in Vec4 x x x x  

--------------------------------------------------------------------------------  
-- * Matrices  

instance Eq Mat2 where
  Mat2 x y == Mat2 a b = (x==a && y==b)

instance Num Mat2 where
  (+) = (&+)
  (-) = (&-)
  negate = neg
  
  (*) = (.*.)
  fromInteger = diag . fromInteger
  abs m = m &* (1.0 / frobeniusNorm m)
  signum = diag . (\x -> Vec2 x x) . frobeniusNorm
  
  -- (*) = pointwise 
  -- fromInteger a = let x = fromInteger a in Mat2 x x
  -- abs m = m &* (1.0 / frobeniusNorm m)
  -- signum m = Mat2 v v where
  --   x = frobeniusNorm m 
  --   v = Vec2 x x
    
instance Fractional Mat2 where
  -- (Mat2 x y) / (Mat2 a b) = Mat2 (x/a) (y/b) 
  -- fromRational a = let x = fromRational a in Mat2 x x  
  (/) = error "Mat2/division: not implemented"
  fromRational = diag . fromRational
  
--------------------------------------------------------------------------------  
    
instance Eq Mat3 where
  Mat3 x y z == Mat3 a b c = (x==a && y==b && z==c)

instance Num Mat3 where
  (+) = (&+)
  (-) = (&-)
  negate = neg

  (*) = (.*.)
  fromInteger = diag . fromInteger
  abs m = m &* (1.0 / frobeniusNorm m)
  signum = diag . (\x -> Vec3 x x x) . frobeniusNorm

  -- (*) = pointwise 
  -- fromInteger a = let x = fromInteger a in Mat3 x x x
  -- abs m = m &* (1.0 / frobeniusNorm m)
  -- signum m = Mat3 v v v where
  --   x = frobeniusNorm m 
  --   v = Vec3 x x x
    
instance Fractional Mat3 where
  -- (Mat3 x y z) / (Mat3 a b c) = Mat3 (x/a) (y/b) (z/c)
  -- fromRational a = let x = fromRational a in Mat3 x x x  
  (/) = error "Mat3/division: not implemented"
  fromRational = diag . fromRational
    
--------------------------------------------------------------------------------  
  
instance Eq Mat4 where
  Mat4 x y z w == Mat4 a b c d = (x==a && y==b && z==c && w==d)

instance Num Mat4 where
  (+) = (&+)
  (-) = (&-)
  negate = neg

  (*) = (.*.)
  fromInteger = diag . fromInteger
  abs m = m &* (1.0 / frobeniusNorm m)
  signum = diag . (\x -> Vec4 x x x x) . frobeniusNorm

  -- (*) = pointwise 
  -- fromInteger a = let x = fromInteger a in Mat4 x x x x
  -- abs m = m &* (1.0 / frobeniusNorm m)
  -- signum m = Mat4 v v v v where
  --   x = frobeniusNorm m 
  --   v = Vec4 x x x x
    
instance Fractional Mat4 where
  -- (Mat4 x y z w) / (Mat4 a b c d) = Mat4 (x/a) (y/b) (z/c) (w/d)
  -- fromRational a = let x = fromRational a in Mat4 x x x x
  (/) = error "Mat4/division: not implemented"
  fromRational = diag . fromRational

--------------------------------------------------------------------------------