{-# OPTIONS --type-in-type #-}

module DecMatrices where

open import NeilPrelude
open import RealTime
open import Decoupled
open import SVDesc
open import Nat hiding (_*_)
open import Vector

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

import VectorMaths
open VectorMaths Dec dec cau _∧_ _∨_ renaming (mat*mat to _*_ ; mat+mat to _+m_)

-- Note: we choose dec to be 0 so as to allow the identity matrix to match "identity"
-- Note: multiplication has to match sequential composition of two basic dec values

-- dec = 0
-- cau = 1
-- ∧ = +
-- ∨ = *

-- An m × n matrix has m rows and n columns

-- m is the number of input signals
-- n is the number of output signals

-- each row corresponds to one input signal
-- each column corresponds to one output signal

-- A matrix built of vectors is a vector of columns
--  _ _
-- |1|4|
-- |2|5|
-- |3|6|
--  - -
-- Thus, +v+ appends two matrices horizontally.

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

_++v_ : {l m n : }  matrix l n  matrix m n  matrix (l + m) n 
_++v_ = _+m+_

_++h_ : {l m n : }  matrix l m  matrix l n  matrix l (m + n)
_++h_ = _+v+_

postulate extend : {m n : }  matrix m 1  matrix m n

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

svlength : SVDesc  
svlength (C A)     = 1
svlength (E A)     = 1
svlength (S A)     = 1
svlength (as , bs) = svlength as + svlength bs

SVMatrix : SVDesc  SVDesc  Set
SVMatrix as bs = matrix (svlength as) (svlength bs)

Mdec : {m n : }  matrix m n
Mdec = mat dec

Mcau : {m n : }  matrix m n
Mcau = mat cau

I : {n : }  matrix n n
I = matId

postulate SF : (as bs : SVDesc)  SVMatrix as bs  Set

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

postulate identity : {as : SVDesc}  SF as as I

postulate sfFst : {as bs : SVDesc}  SF (as , bs) as (I ++v Mdec)

postulate sfSnd : {as bs : SVDesc}  SF (as , bs) bs (Mdec {svlength as} {svlength bs} ++v I)

postulate _>>>_ : {as bs cs : SVDesc}  {m₁ : SVMatrix as bs}  {m₂ : SVMatrix bs cs}
                 SF as bs m₁  SF bs cs m₂  SF as cs (m₁ * m₂)

postulate _&&&_ : {as bs cs : SVDesc}  {m₁ : SVMatrix as bs}  {m₂ : SVMatrix as cs}
                 SF as bs m₁  SF as cs m₂  SF as (bs , cs) (m₁ ++h m₂)

postulate freeze : {as bs : SVDesc}  {m : SVMatrix as bs}
                  SF as bs m  SF as (bs , C (SF as bs m)) (m ++h Mdec)

postulate switch : {as bs : SVDesc}  {A : Set}  {m₁ m₂ : SVMatrix as bs}  (me : SVMatrix as (E A))
                  SF as (bs , E A) (m₁ ++h me)  (A  SF as bs m₂)  SF as bs ((m₁ +m m₂) +m extend me)

postulate dswitch : {as bs : SVDesc}  {A : Set}  {m₁ m₂ : SVMatrix as bs}  (me : SVMatrix as (E A))
                   SF as (bs , E A) (m₁ ++h me)  (A  SF as bs m₂)  SF as bs (m₁ +m m₂)

postulate loop : {as bs cs : SVDesc}  {m₁ : SVMatrix as bs}  {m₂ : SVMatrix cs bs}
                   SF (as , cs) bs (m₁ ++v m₂)  SF cs bs Mdec  SF as bs m₁

postulate arrowLoop : {as bs cs : SVDesc}  {m₁₁ : SVMatrix as bs}  {m₁₂ : SVMatrix as cs}  {m₂₁ : SVMatrix cs bs}
                     SF (as , cs) (bs , cs) ((m₁₁ ++v m₂₁) ++h (m₁₂ ++v Mdec))  SF as bs (m₁₁ +m (m₁₂ * m₂₁))

postulate loop' : {as bs cs : SVDesc}  {m : SVMatrix bs cs}  SF (as , cs) bs Mdec  SF bs cs m  SF as bs Mdec
-- loop' sff sfb = loop (sfSecond (forkFirst sfb) >>> sfAssocL) (sfFst >>> sff) >>> {!sfSnd!}

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

postulate now : {as : SVDesc}  SF as (E Unit) Mdec
postulate delayE : {A : Set}  Time⁺  SF (E A) (E A) Mdec

postulate toFst : {as bs cs : SVDesc}  {m : SVMatrix as cs}  SF as cs m  SF (as , bs) cs (m ++v Mdec) 
-- toFst sf = sfFst >>> sf

postulate toSnd : {as bs cs : SVDesc}  {m : SVMatrix bs cs}  SF bs cs m   SF (as , bs) cs (Mdec {svlength as} {svlength cs} ++v m)
-- toSnd sf = sfSnd >>> sf

_***_ : {as bs cs ds : SVDesc}  {m₁ : SVMatrix as bs}  {m₂ : SVMatrix cs ds}  SF as bs m₁  SF cs ds m₂  SF (as , cs) (bs , ds) ((m₁ ++v Mdec) ++h (Mdec {svlength as} {svlength ds} ++v m₂))
sf₁ *** sf₂ = toFst sf₁ &&& toSnd sf₂

inaccurate : {A : Set}  SF (E A) (E A , E Unit) Mdec
inaccurate = (identity &&& now) >>> (delayE ı⁺ *** identity)

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