    -- Copyright (c) 2010-2015, David Amos. All rights reserved.

    {-# LANGUAGE  MultiParamTypeClasses, FlexibleInstances #-}

    module Math.Algebras.Matrix where

    import Prelude hiding ( (*>) )

    import Math.Algebra.Field.Base
    import Math.Algebras.VectorSpace
    import Math.Algebras.TensorProduct
    import Math.Algebras.Structures

    -- Mat2

    {-
    -- defined in Math.Algebras.TensorProduct
    delta i j | i == j    = 1
              | otherwise = 0
    -}

    data Mat2 = E2 Int Int deriving (Eq,Ord,Show)
    -- E i j represents the elementary matrix with a 1 at the (i,j) position, and 0s elsewhere

    instance (Eq k, Num k) => Algebra k Mat2 where
        unit x = x *> V [(E2 i i, 1) | i <- [1..2] ]
        mult = linear mult' where
            mult' (E2 i j, E2 k l) = delta j k *> return (E2 i l)

    -- In other words
    -- unit x = x (1 0)
    --            (0 1)
    -- mult (a1 b1) `te` (a2 b2) = (a1 b1) * (a2 b2) = (a b)
    --      (c1 d1)      (c2 d2)   (c1 d1)   (c2 d2)   (c d)

    instance (Eq k, Num k) => Module k Mat2 EBasis where
        -- action ax = nf $ ax >>= action' where
        action = linear action' where
            action' (E2 i j, E k) = delta j k `smultL` return (E i)

    -- In other words
    -- action (a b) `te` (x) = (ax+by)
    --        (c d)      (y)   (cx+dy)

    toMat2 [[a,b],[c,d]] = sum $ zipWith (\x e -> unit x * return e) [a,b,c,d] [E2 1 1, E2 1 2, E2 2 1, E2 2 2]
    -- fromMat2

    toEB2 [x,y] = foldl add zerov $ zipWith (\x e -> x `smultL` return e) [x,y] [E 1, E 2]

    toEB xs = foldl add zerov $ zipWith (\x e -> x `smultL` return e) xs (map E [1..])

    data Mat2' = E2' Int Int deriving (Eq,Ord,Show)
    -- E2' i j represents the dual basis element corresponding to E i j

    -- Kassel p42
    instance (Eq k, Num k) => Coalgebra k Mat2' where
        counit (V ts) = sum [xij * delta i j | (E2' i j, xij) <- ts]
        -- comult (V ts) = V $ concatMap (\(E2' i j,xij) -> [(T (E2' i k) (E2' k j), xij) | k <- [1..2]]) ts
        comult = linear (\(E2' i j) -> foldl (<+>) zerov [return (E2' i k, E2' k j) | k <- [1..2]])
    -- In other words
    -- counit (a b) = (1 0)
    --        (c d)   (0 1)
    -- comult (a b) = (a1 b1) `te` (a2 b2)
    --        (c d)   (c1 d1)      (c2 d2)
    -- ??
    -- ?? How does this act on Mat2?
    -- ?? What is the relationship between this and SL2 ABCD, which it seems to resemble

    data M3 = E3 Int Int deriving (Eq,Ord,Show)
    -- E i j represents the elementary matrix with a 1 at the (i,j) position, and 0s elsewhere

    instance (Eq k, Num k) => Algebra k M3 where
        unit 0 = zerov -- V []
        unit x = V [(E3 i i, x) | i <- [1..3] ]
        -- mult (V ts) = nf $ V $ map (\((E3 i j, E3 k l), x) -> (E3 i l, delta j k * x)) ts
        mult = linear mult' where
            mult' (E3 i j, E3 k l) = delta j k *> return (E3 i l)

    {-
    -- Kassel p42
    -- In this coalgebra instance, the E3 i j are to be interpreted as the dual basis, not the original basis
    instance Num k => Coalgebra k M3 where
        counit (V ts) = sum [xij * delta i j | (E3 i j, xij) <- ts]
        comult (V ts) = V $ concatMap (\(E3 i j,xij) -> [((E3 i k, E3 k j), xij) | k <- [1..3]]) ts
    -- (is this order preserving?)
    -}