\import Algebra.Group
\import Algebra.Monoid
\import Algebra.Pointed
\import Algebra.Ring
\import Algebra.Solver
\import Algebra.Solver.CSemiring
\import Algebra.Solver.Ring
\import Algebra.Solver.Semiring
\import Arith.Int
\import Data.Array(Big, map)
\import Data.List(++)
\import Function.Meta
\import Paths
\open RingSolverModel
\open SemiringSolverModel(NF,multiply)
\open CSemiringSolverModel

\func CRingSolverModel (R : CRing) : SolverModel R \cowith
  | Term => Term Int
  | NF => NF Int
  | normalize => normalize
  | interpret env => interpret env
  | interpretNF env nf => ringInterpretNF env (sortMonomials nf)
  | interpretNF-consistent {_} {env} {_} => ringInterpretNF-correct *> (RingData env).interpretNF-correct *> interpretNF_sort {R} {RingData env} *> normalize-consistent
  \where {
    \lemma terms-equality (env : Array R) (t s : Term Int env.len) (p : ringInterpretNF env (sortMonomials (normalize (t :+ :negative s))) = 0) : interpret env t = interpret env s
      => RingSolverModel.terms-equality env t s $ ringInterpretNF-correct *> (RingData env).interpretNF-correct *> inv ((RingData env).interpretNF-correct *> interpretNF_sort {R} {RingData env}) *> inv ringInterpretNF-correct *> p

    \lemma terms-equality-conv (env : Array R) (t s : Term Int env.len) (p : interpret env t = interpret env s) : ringInterpretNF env (sortMonomials (normalize (t :+ :negative s))) = 0
      => ringInterpretNF-correct *> (RingData env).interpretNF-correct *> interpretNF_sort {R} {RingData env} *> inv (RingData env).interpretNF-correct *> inv ringInterpretNF-correct *> RingSolverModel.terms-equality-conv env t s p

    \lemma diffNF (env : Array R) (left right : NF Int env.len) (p : (RingData env).interpretNF' (left ++ Data.List.map (\lam s => (s.1, negative s.2)) right) = 0)
      : (RingData env).interpretNF' left = (RingData env).interpretNF' right
      => AddGroup.fromZero $ inv (inv p *> (RingData env).interpretNF_++ {left} {Data.List.map (\lam s => (s.1, negative s.2)) right} *> pmap ((+) ((RingData env).interpretNF' left)) (interpretNF_negative {_} {_} {right}))

    \lemma apply-axioms (env : Array R) (l : Array (\Sigma (NF Int env.len) (t s : Term Int env.len) (p : interpret env t = interpret env s))) (add : NF Int env.len)
      : ringInterpretNF env (sortMonomials (Big (++) add (map (\lam s => multiply s.1 (normalize (s.2 :+ :negative s.3))) l))) = ringInterpretNF' add
      => ringInterpretNF-correct *> (RingData env).interpretNF-correct *> interpretNF_sort {R} {RingData env} *> inv (RingData env).interpretNF-correct *> inv ringInterpretNF-correct *> RingSolverModel.apply-axioms env l add
  }