```{-# 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

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

```