\import Algebra.Monoid
\import Algebra.Semiring
\import Algebra.Solver
\import Algebra.Solver.CMonoid
\import Algebra.Solver.Semiring
\import Arith.Nat
\import Arith.Fin.Order
\import Data.List
\import Function.Meta
\import Paths
\open SemiringSolverModel \hiding (natCoef)

\func CSemiringSolverModel (R : CSemiring) : SolverModel R \cowith
  | Term => Term Nat
  | NF => NF Nat
  | normalize => normalize
  | interpret env => (SemiringData env).interpret
  | interpretNF env nf => (SemiringData env).interpretNF (sortMonomials nf)
  | interpretNF-consistent {_} {env} {_} =>
    \have d => SemiringData env
    \in d.interpretNF-correct *> interpretNF_sort *> d.normalize-consistent
  \where {
    \func sortMonomials {n : Nat} {C : \Set} (l : NF C n) => map (\lam s => (Sort.RedBlack.sort s.1, s.2)) l

    \lemma interpretNF_sort {R : CSemiring} {d : Data R} {l : NF} : interpretNF' (sortMonomials l) = interpretNF' l \elim l
      | nil => idp
      | a :: l => interpretNF_:: *> pmap2 (_ * __ + __) CMonoidSolverModel.sort-consistent interpretNF_sort *> inv interpretNF_::
      \where \open SemiringSolverModel.Data

    \lemma apply-axiom (env : Array R) (t s : Term Nat env.len) (p : (SemiringData env).interpret t = (SemiringData env).interpret s) (mul add : NF Nat env.len)
      => apply-axiom' {R} {SemiringData env} t s p mul add
      \where {
        \private \lemma apply-axiom' {R : CSemiring} {d : Data R} (t s : Term C env.len) (p : interpret t = interpret s) (mul add : NF)
          : interpretNF (sortMonomials (multiply mul (normalize t)) ++ add) = interpretNF (sortMonomials (multiply mul (normalize s)) ++ add)
          => interpretNF-correct *> interpretNF_++ *> pmap (`+ _) (interpretNF_sort *> interpretNF_multiply *> pmap (_ *) (normalize-consistent *> p *> inv normalize-consistent) *> inv interpretNF_multiply *> inv interpretNF_sort) *> inv (interpretNF-correct *> interpretNF_++)
          \where \open SemiringSolverModel.Data
      }
  }