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

{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleInstances, EmptyDataDecls #-}

-- |A module defining the category of tangles, and representations into the category of vector spaces
-- (specifically, knot invariants).
module Math.QuantumAlgebra.Tangle where

import Prelude hiding ( (*>) )

-- import qualified Data.List as L

import Math.Algebras.VectorSpace
import Math.Algebras.TensorProduct
import Math.Algebras.Structures

import Math.Algebra.Field.Base
import Math.Algebras.LaurentPoly

import Math.QuantumAlgebra.TensorCategory hiding (Vect)


instance Mon [a] where
    munit = []
    mmult = (++)

-- type TensorAlgebra k a = Vect k [a]

instance (Eq k, Num k, Ord a) => Algebra k [a] where
    unit 0 = zerov -- V []
    unit x = V [(munit,x)]
    mult = nf . fmap (\(a,b) -> a `mmult` b)

-- Could make TensorAlgebra k a into an instance of Category, TensorCategory


-- TANGLE CATEGORY
-- (Unoriented)

data Tangle

instance MCategory Tangle where
    data Ob Tangle = OT Int deriving (Eq,Ord,Show)
    data Ar Tangle = IdT Int
                   | CapT
                   | CupT
                   | OverT
                   | UnderT
--                   | SeqT (Ar Tangle) (Ar Tangle)
                   | SeqT [Ar Tangle]
--                   | ParT (Ar Tangle) (Ar Tangle)
                   | ParT [Ar Tangle]
                   deriving (Eq,Ord,Show)
    id_ (OT n) = IdT n
    source (IdT n) = OT n
    source CapT = OT 0
    source CupT = OT 2
    source OverT = OT 2
    source UnderT = OT 2
--    source (ParT a b) = OT (sa + sb) where OT sa = source a; OT sb = source b
    source (ParT as) = OT $ sum [sa | a <- as, let OT sa = source a]
--    source (SeqT a b) = source a
    source (SeqT as) = source (head as)
    target (IdT n) = OT n
    target CapT = OT 2
    target CupT = OT 0
    target OverT = OT 2
    target UnderT = OT 2
--    target (ParT a b) = OT (ta + tb) where OT ta = target a; OT tb = target b
    target (ParT as) = OT $ sum [ta | a <- as, let OT ta = target a]
--    target (SeqT a b) = target b
    target (SeqT as) = target (last as)
--    a >>> b | target a == source b = SeqT a b
    a >>> b | target a == source b = SeqT [a,b]

instance Monoidal Tangle where
    tunit = OT 0
    tob (OT a) (OT b) = OT (a+b)
--    tar a b = ParT a b
    tar a b = ParT [a,b]



-- KAUFFMAN BRACKET

data Oriented = Plus | Minus deriving (Eq,Ord,Show)

type TangleRep b = Vect (LaurentPoly Q) b


-- adapted from http://blog.sigfpe.com/2008/10/untangling-with-continued-fractions.html
cap :: [Oriented] -> TangleRep [Oriented]
cap [] = return [Plus, Minus] <+> (-q^2) *> return [Minus, Plus]

cup :: [Oriented] -> TangleRep [Oriented]
cup [Plus, Minus] = (-q'^2) *> return []
cup [Minus, Plus] = return []
cup _ = zerov

-- also called xminus
over :: [Oriented] -> TangleRep [Oriented]
over [u, v] = q  *> do {_ <- cup [u, v]; cap []}
          <+> q' *> return [u, v]

{-
-- if you expand "over" into terms, you find that it equals the following,
-- which strongly resembles c' below
over' (T i j) = case compare i j of
                EQ -> q' *> return (T i i)                                       -- ++ -> q' ++, -- -> q' -- 
                LT -> q  *> return (T j i)                                       -- +- -> q -+
                GT -> q  *> (return (T j i) <+> (q'^2 - q^2) *> return (T i j))  -- -+ -> q +- + (q'-q^3) -+
-}
-- also called xplus
under :: [Oriented] -> TangleRep [Oriented]
under [u, v] = q' *> do {_ <- cup [u, v]; cap []}
           <+> q  *> return [u, v]

{-
-- if you expand "under" into terms, you find that it equals the following,
-- which strongly resembles c below
under' (T i j) = case compare i j of
                 EQ -> q  *> return (T i i)                                       -- ++ -> q ++, -- -> q -- 
                 LT -> q' *> (return (T j i) <+> (q^2 - q'^2) *> return (T i j))  -- +- -> q' -+ + (q-q^-3) -+
                 GT -> q' *> return (T j i)                                       -- -+ -> q' +-
-}
loop = nf $ do {ij <- cap []; cup ij}

{-
-- The following doesn't work, because the pattern matches can fail, but Vect has no MonadFail instance.
-- Commented out for now, pending figuring out the best fix
trefoil = nf $ do
    [i, j] <- cap []
    [k, l] <- cap []
    [m, n] <- under [j, k]
    [p, q] <- over [i, m]
    [r, s] <- over [n, l]
    cup [p, s]
    cup [q, r]
-}


-- KAUFFMAN BRACKET AS A REPRESENTATION FROM TANGLE TO VECT

-- But this isn't quite the Kauffman bracket - we still need to divide by (-q^2-q^-2)
kauffman :: Ar Tangle -> TangleRep [Oriented] -> TangleRep [Oriented]
kauffman (IdT n) = id -- could be tf of n ids
kauffman CapT = linear cap
kauffman CupT = linear cup
kauffman OverT = linear over
kauffman UnderT = linear under
kauffman (SeqT fs) = foldl (>>>) id $ map kauffman fs
    where g >>> h = h . g
kauffman (ParT [f]) = kauffman f
kauffman (ParT (f:fs)) = tf m (kauffman f) (kauffman (ParT fs))
    where OT m = source f
          tf m f' fs' = linear (\xs -> let (ls,rs) = splitAt m xs in f' (return ls) * fs' (return rs) )
{-
kauffman (ParT f g) = tf m n (kauffman f) (kauffman g)
    where OT m = source f
          OT n = source g
          tf m n f' g' = linear (\xs -> let (ls,rs) = splitAt m xs in f' (return ls) * g' (return rs) )
-}

-- loopT = SeqT CapT CupT
loopT = SeqT [CapT, CupT]

{-
trefoilT = (ParT CapT CapT) `SeqT` (ParT (IdT 1) (ParT UnderT (IdT 1)))
    `SeqT` (ParT OverT OverT) `SeqT` (ParT (IdT 1) (ParT CupT (IdT 1))) `SeqT` CupT

trefoilT = ParT [CapT, CapT]
    `SeqT` ParT [IdT 1, UnderT, IdT 1]
    `SeqT` ParT [OverT, OverT]
    `SeqT` ParT [IdT 1, CupT, IdT 1]
    `SeqT` CupT
-}
trefoilT = SeqT [
    ParT [CapT, CapT],
    ParT [IdT 1, UnderT, IdT 1],
    ParT [OverT, OverT],
    ParT [IdT 1, CupT, IdT 1],
    CupT]
-- eg kauffman (trefoilT) (return [])