Definition: index-min
index-min(zs) ==
  rec-case(zs) of
  [] => <0, 0>
  z::more =>
   p.if more = Ax then <0, z> otherwise let i,x = p 
                      in if (z) < (x)  then <0, z>  else eval j = i + 1 in <j, x>
Lemma: index-min_wf
∀[zs:ℤ List+]. (index-min(zs) ∈ i:ℕ||zs|| × {x:ℤ| (x = zs[i] ∈ ℤ) ∧ (∀z:ℤ. ((z ∈ zs) 
⇒ (x ≤ z)))} )
Definition: index-of-min
index-of-min(zs) ==  fst(index-min(zs))
Lemma: index-of-min_wf
∀[zs:ℤ List+]. (index-of-min(zs) ∈ {i:ℕ||zs||| ∀x:ℤ. ((x ∈ zs) 
⇒ (zs[i] ≤ x))} )
Lemma: rev-append-property
∀[as,bs:Top].  (rev(as) + bs ~ rev(as) + [] @ bs)
Lemma: rev-append-as-reverse
∀[as,bs:Top].  (rev(as) + bs ~ rev(as) @ bs)
Lemma: member-rev-append
∀[T:Type]. ∀x:T. ∀as,bs:T List.  ((x ∈ rev(as) + bs) 
⇐⇒ (x ∈ as) ∨ (x ∈ bs))
Lemma: eager_product_map_nil_lemma
∀bs,f:Top.  (eager-product-map(f;[];bs) ~ [])
Lemma: eager_product_map_cons_lemma
∀L,as,a,f:Top.  (eager-product-map(f;[a / as];L) ~ eager-map-append(f a;L;eager-product-map(f;as;L)))
Lemma: eager-product-map-nil
∀[f:Top]. ∀[as:Top List].  (eager-product-map(f;as;[]) ~ [])
Lemma: l_all_eager_product-map
∀T:Type
  ∀A,B:Type. ∀Pa:A ⟶ ℙ. ∀Pb:B ⟶ ℙ. ∀Pt:T ⟶ ℙ. ∀f:A ⟶ B ⟶ T.
    ((∀a:A. ∀b:B.  (Pa[a] 
⇒ Pb[b] 
⇒ Pt[f a b]))
    
⇒ (∀as:A List. ∀bs:B List.  ((∀a∈as.Pa[a]) 
⇒ (∀b∈bs.Pb[b]) 
⇒ (∀t∈eager-product-map(f;as;bs).Pt[t])))) 
  supposing value-type(T)
Lemma: map-map2
∀[as,f,g:Top].  (map(g;map(f;as)) ~ map(g o f;as))
Lemma: map-id-map
∀[as,f:Top].  (map(λx.x;map(f;as)) ~ map(f;as))
Definition: accumulate_abort
accumulate_abort(x,sofar.F[x; sofar];s;L) ==  eager-accum(r,x.case r of inl(sofar) => F[x; sofar] | inr(_) => r;s;L)
Lemma: accumulate_abort_wf
∀[A,B:Type]. ∀[s:B?]. ∀[F:A ⟶ B ⟶ (B?)]. ∀[L:A List].
  accumulate_abort(x,sofar.F[x;sofar];s;L) ∈ B? supposing valueall-type(B)
Lemma: accumulate_abort_nil_lemma
∀s,F:Top.  (accumulate_abort(x,y.F[x;y];s;[]) ~ s)
Lemma: accumulate_abort_cons_lemma
∀v,u,s,F:Top.
  (accumulate_abort(x,y.F[x;y];s;[u / v]) ~ let s' ⟵ case s of inl(y) => F[u;y] | inr(_) => s
                                            in accumulate_abort(x,y.F[x;y];s';v))
Lemma: accumulate_abort-aborted
∀[z:Unit]. ∀[F:Top]. ∀[L:Top List].  (accumulate_abort(x,sofar.F[x;sofar];inr z L) ~ inr z )
Lemma: assert-list-deq
∀[A:Type]. ∀[eq:EqDecider(A)]. ∀[as,bs:A List].  uiff(↑(list-deq(eq) as bs);as = bs ∈ (A List))
Definition: integer-dot-product
as ⋅ bs
==r if as = Ax then 0 otherwise if bs = Ax then 0 otherwise let a,as2 = as 
                                                            in let b,bs2 = bs 
                                                               in (a * b) + as2 ⋅ bs2
Lemma: int_dot_nil_left_lemma
∀bs:Top. ([] ⋅ bs ~ 0)
Lemma: int_dot_cons_nil_lemma
∀as,a:Top.  ([a / as] ⋅ [] ~ 0)
Lemma: int_dot_cons_lemma
∀bs,b,as,a:Top.  ([a / as] ⋅ [b / bs] ~ (a * b) + as ⋅ bs)
Lemma: integer-dot-product_wf
∀[as,bs:ℤ List].  (as ⋅ bs ∈ ℤ)
Lemma: integer-dot-product-comm
∀[as,bs:ℤ List].  (as ⋅ bs ~ bs ⋅ as)
Definition: satisfies-integer-equality
xs ⋅ as =0 ==  (||xs|| = ||as|| ∈ ℤ) ∧ 0 < ||xs|| ∧ (hd(xs) = 1 ∈ ℤ) ∧ (as ⋅ xs = 0 ∈ ℤ)
Lemma: satisfies-integer-equality_wf
∀[xs,as:ℤ List].  (xs ⋅ as =0 ∈ ℙ)
Definition: satisfies-integer-inequality
xs ⋅ as ≥0 ==  (||xs|| = ||as|| ∈ ℤ) ∧ 0 < ||xs|| ∧ (hd(xs) = 1 ∈ ℤ) ∧ (as ⋅ xs ≥ 0 )
Lemma: satisfies-integer-inequality_wf
∀[xs,as:ℤ List].  (xs ⋅ as ≥0 ∈ ℙ)
Lemma: trivial-unsat-integer-inequality
∀[xs:ℤ List]. (¬xs ⋅ [-1] ≥0)
Definition: list-delete
as\i==r if as = Ax then as otherwise let a,as2 = as in if (i) < (1)  then as2  else [a / as2\i - 1]
Lemma: list-delete_wf
∀[T:Type]. ∀[as:T List]. ∀[i:ℤ].  (as\i ∈ T List)
Lemma: length-list-delete
∀[T:Type]. ∀[as:T List]. ∀[i:ℕ].  ||as\i|| = (||as|| - 1) ∈ ℤ supposing i < ||as||
Definition: int-vec-mul
a * as ==  map(λx.(a * x);as)
Lemma: int-vec-mul_wf
∀[a:ℤ]. ∀[as:ℤ List].  (a * as ∈ ℤ List)
Lemma: int-vec-mul-mul
∀[a,b:ℤ]. ∀[as:ℤ List].  (a * b * as ~ a * b * as)
Lemma: length-int-vec-mul
∀[a,as:Top].  (||a * as|| ~ ||as||)
Definition: int-vec-add
as + bs
==r if as = Ax then as otherwise if bs = Ax then bs otherwise let a,as2 = as 
                                                              in let b,bs2 = bs 
                                                                 in [a + b / as2 + bs2]
Lemma: int-vec-add_wf
∀[as,bs:ℤ List].  (as + bs ∈ ℤ List)
Lemma: length-int-vec-add
∀[as,bs:ℤ List].  ||as + bs|| = ||bs|| ∈ ℤ supposing ||as|| = ||bs|| ∈ ℤ
Lemma: select-int-vec-add
∀[as,bs:ℤ List]. ∀[i:ℕ].  as + bs[i] ~ as[i] + bs[i] supposing i < ||as|| ∧ i < ||bs||
Lemma: select-int-vec-mul
∀[x:ℤ]. ∀[as:ℤ List]. ∀[i:ℕ||as||].  (x * as[i] ~ x * as[i])
Lemma: int-dot-mul-left
∀[x:ℤ]. ∀[as,bs:ℤ List].  (x * as ⋅ bs ~ x * as ⋅ bs)
Lemma: int-dot-mul-right
∀[x:ℤ]. ∀[as,bs:ℤ List].  (as ⋅ x * bs ~ x * as ⋅ bs)
Lemma: int-dot-add-left
∀[as,bs,cs:ℤ List].  as + bs ⋅ cs ~ as ⋅ cs + bs ⋅ cs supposing ||as|| = ||bs|| ∈ ℤ
Lemma: int-dot-add-right
∀[cs,as,bs:ℤ List].  cs ⋅ as + bs ~ cs ⋅ as + cs ⋅ bs supposing ||as|| = ||bs|| ∈ ℤ
Lemma: int-dot-select
∀[as,bs:ℤ List]. ∀[i:ℕ].  as ⋅ bs ~ (as[i] * bs[i]) + as\i ⋅ bs\i supposing i < ||as|| ∧ i < ||bs||
Lemma: int-dot-reduce-dim
∀[as,bs:ℤ List]. ∀[i:ℕ].
  ∀[cs:ℤ List]. (as ⋅ bs ~ as[i] * cs + as\i ⋅ bs\i) supposing ((bs[i] = cs ⋅ bs\i ∈ ℤ) and (||cs|| = (||as|| - 1) ∈ ℤ))\000C 
  supposing i < ||as|| ∧ i < ||bs||
Lemma: int-eq-constraint-factor
∀[a:ℤ]. ∀[g:ℤ-o]. ∀[xs,L:ℤ List].
  uiff([1 / xs] ⋅ [a / g * L] = 0 ∈ ℤ;((a rem g) = 0 ∈ ℤ) ∧ ([1 / xs] ⋅ [a ÷ g / L] = 0 ∈ ℤ))
Lemma: int-eq-constraint-factor-sym
∀[a:ℤ]. ∀[g:ℤ-o]. ∀[xs,L:ℤ List].
  uiff([a / g * L] ⋅ [1 / xs] = 0 ∈ ℤ;((a rem g) = 0 ∈ ℤ) ∧ ([a ÷ g / L] ⋅ [1 / xs] = 0 ∈ ℤ))
Lemma: int-ineq-constraint-factor
∀[a:ℤ]. ∀[g:ℕ+]. ∀[xs,L:ℤ List].  uiff(0 ≤ [1 / xs] ⋅ [a / g * L];0 ≤ [1 / xs] ⋅ [a ÷↓ g / L])
Lemma: int-ineq-constraint-factor-sym
∀[a:ℤ]. ∀[g:ℕ+]. ∀[xs,L:ℤ List].  uiff(0 ≤ [a / g * L] ⋅ [1 / xs];0 ≤ [a ÷↓ g / L] ⋅ [1 / xs])
Lemma: gcd-list-property
∀L:ℤ List+
  ((∃R:ℤ List. (L = gcd-list(L) * R ∈ (ℤ List))) ∧ (∃S:ℤ List. ((||S|| = ||L|| ∈ ℤ) ∧ (gcd-list(L) = S ⋅ L ∈ ℤ))))
Definition: shadow-vec
shadow-vec(i;as;bs) ==
  eval bs' = evalall(as[i] * bs) in
  eval as' = evalall(-bs[i] * as) in
  eval L = evalall(bs' + as') in
    evalall(L\i)
Lemma: shadow-vec_wf
∀[as,bs:ℤ List]. ∀[i:ℕ||as||].  shadow-vec(i;as;bs) ∈ ℤ List supposing ||as|| = ||bs|| ∈ ℤ
Lemma: length-shadow-vec
∀[as,bs:ℤ List]. ∀[i:ℕ||as||].  ||shadow-vec(i;as;bs)|| = (||as|| - 1) ∈ ℤ supposing ||as|| = ||bs|| ∈ ℤ
Lemma: shadow-vec-property
∀[as,bs:ℤ List]. ∀[i:ℕ||as||].
  (∀[xs:ℤ List]
     0 ≤ shadow-vec(i;as;bs) ⋅ xs\i supposing (||xs|| = ||as|| ∈ ℤ) ∧ (0 ≤ as ⋅ xs) ∧ (0 ≤ bs ⋅ xs)) supposing 
     ((bs[i] ≤ 0) and 
     (0 ≤ as[i]) and 
     (||as|| = ||bs|| ∈ ℤ))
Definition: int_termco
int_termco() ==
  corec(X.lbl:Atom × if lbl =a "Constant" then ℤ
                     if lbl =a "Var" then ℤ
                     if lbl =a "Add" then left:X × X
                     if lbl =a "Subtract" then left:X × X
                     if lbl =a "Multiply" then left:X × X
                     if lbl =a "Minus" then X
                     else Void
                     fi )
Lemma: int_termco_wf
int_termco() ∈ Type
Lemma: int_termco-ext
int_termco() ≡ lbl:Atom × if lbl =a "Constant" then ℤ
                          if lbl =a "Var" then ℤ
                          if lbl =a "Add" then left:int_termco() × int_termco()
                          if lbl =a "Subtract" then left:int_termco() × int_termco()
                          if lbl =a "Multiply" then left:int_termco() × int_termco()
                          if lbl =a "Minus" then int_termco()
                          else Void
                          fi 
Definition: int_termco_size
int_termco_size(p) ==
  fix((λsize,p. let lbl,x = p 
                in if lbl =a "Constant" then 0
                   if lbl =a "Var" then 0
                   if lbl =a "Add" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "Subtract" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "Multiply" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "Minus" then 1 + (size x)
                   else 0
                   fi )) 
  p
Lemma: int_termco_size_wf
∀[p:int_termco()]. (int_termco_size(p) ∈ partial(ℕ))
Definition: int_term
int_term() ==  {p:int_termco()| (int_termco_size(p))↓} 
Lemma: int_term_wf
int_term() ∈ Type
Definition: int_term_size
int_term_size(p) ==
  fix((λsize,p. let lbl,x = p 
                in if lbl =a "Constant" then 0
                   if lbl =a "Var" then 0
                   if lbl =a "Add" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "Subtract" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "Multiply" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "Minus" then 1 + (size x)
                   else 0
                   fi )) 
  p
Lemma: int_term_size_wf
∀[p:int_term()]. (int_term_size(p) ∈ ℕ)
Lemma: int_term-ext
int_term() ≡ lbl:Atom × if lbl =a "Constant" then ℤ
                        if lbl =a "Var" then ℤ
                        if lbl =a "Add" then left:int_term() × int_term()
                        if lbl =a "Subtract" then left:int_term() × int_term()
                        if lbl =a "Multiply" then left:int_term() × int_term()
                        if lbl =a "Minus" then int_term()
                        else Void
                        fi 
Definition: itermConstant
"const" ==  <"Constant", const>
Lemma: itermConstant_wf
∀[const:ℤ]. ("const" ∈ int_term())
Definition: itermVar
vvar ==  <"Var", var>
Lemma: itermVar_wf
∀[var:ℤ]. (vvar ∈ int_term())
Definition: itermAdd
left (+) right ==  <"Add", left, right>
Lemma: itermAdd_wf
∀[left,right:int_term()].  (left (+) right ∈ int_term())
Definition: itermSubtract
left (-) right ==  <"Subtract", left, right>
Lemma: itermSubtract_wf
∀[left,right:int_term()].  (left (-) right ∈ int_term())
Definition: itermMultiply
left (*) right ==  <"Multiply", left, right>
Lemma: itermMultiply_wf
∀[left,right:int_term()].  (left (*) right ∈ int_term())
Definition: itermMinus
"-"num ==  <"Minus", num>
Lemma: itermMinus_wf
∀[num:int_term()]. ("-"num ∈ int_term())
Definition: itermConstant?
itermConstant?(v) ==  fst(v) =a "Constant"
Lemma: itermConstant?_wf
∀[v:int_term()]. (itermConstant?(v) ∈ 𝔹)
Definition: itermConstant-const
itermConstant-const(v) ==  snd(v)
Lemma: itermConstant-const_wf
∀[v:int_term()]. itermConstant-const(v) ∈ ℤ supposing ↑itermConstant?(v)
Definition: itermVar?
itermVar?(v) ==  fst(v) =a "Var"
Lemma: itermVar?_wf
∀[v:int_term()]. (itermVar?(v) ∈ 𝔹)
Definition: itermVar-var
itermVar-var(v) ==  snd(v)
Lemma: itermVar-var_wf
∀[v:int_term()]. itermVar-var(v) ∈ ℤ supposing ↑itermVar?(v)
Definition: itermAdd?
itermAdd?(v) ==  fst(v) =a "Add"
Lemma: itermAdd?_wf
∀[v:int_term()]. (itermAdd?(v) ∈ 𝔹)
Definition: itermAdd-left
itermAdd-left(v) ==  fst(snd(v))
Lemma: itermAdd-left_wf
∀[v:int_term()]. itermAdd-left(v) ∈ int_term() supposing ↑itermAdd?(v)
Definition: itermAdd-right
itermAdd-right(v) ==  snd(snd(v))
Lemma: itermAdd-right_wf
∀[v:int_term()]. itermAdd-right(v) ∈ int_term() supposing ↑itermAdd?(v)
Definition: itermSubtract?
itermSubtract?(v) ==  fst(v) =a "Subtract"
Lemma: itermSubtract?_wf
∀[v:int_term()]. (itermSubtract?(v) ∈ 𝔹)
Definition: itermSubtract-left
itermSubtract-left(v) ==  fst(snd(v))
Lemma: itermSubtract-left_wf
∀[v:int_term()]. itermSubtract-left(v) ∈ int_term() supposing ↑itermSubtract?(v)
Definition: itermSubtract-right
itermSubtract-right(v) ==  snd(snd(v))
Lemma: itermSubtract-right_wf
∀[v:int_term()]. itermSubtract-right(v) ∈ int_term() supposing ↑itermSubtract?(v)
Definition: itermMultiply?
itermMultiply?(v) ==  fst(v) =a "Multiply"
Lemma: itermMultiply?_wf
∀[v:int_term()]. (itermMultiply?(v) ∈ 𝔹)
Definition: itermMultiply-left
itermMultiply-left(v) ==  fst(snd(v))
Lemma: itermMultiply-left_wf
∀[v:int_term()]. itermMultiply-left(v) ∈ int_term() supposing ↑itermMultiply?(v)
Definition: itermMultiply-right
itermMultiply-right(v) ==  snd(snd(v))
Lemma: itermMultiply-right_wf
∀[v:int_term()]. itermMultiply-right(v) ∈ int_term() supposing ↑itermMultiply?(v)
Definition: itermMinus?
itermMinus?(v) ==  fst(v) =a "Minus"
Lemma: itermMinus?_wf
∀[v:int_term()]. (itermMinus?(v) ∈ 𝔹)
Definition: itermMinus-num
itermMinus-num(v) ==  snd(v)
Lemma: itermMinus-num_wf
∀[v:int_term()]. itermMinus-num(v) ∈ int_term() supposing ↑itermMinus?(v)
Lemma: int_term-induction
∀[P:int_term() ⟶ ℙ]
  ((∀const:ℤ. P["const"])
  
⇒ (∀var:ℤ. P[vvar])
  
⇒ (∀left,right:int_term().  (P[left] 
⇒ P[right] 
⇒ P[left (+) right]))
  
⇒ (∀left,right:int_term().  (P[left] 
⇒ P[right] 
⇒ P[left (-) right]))
  
⇒ (∀left,right:int_term().  (P[left] 
⇒ P[right] 
⇒ P[left (*) right]))
  
⇒ (∀num:int_term(). (P[num] 
⇒ P["-"num]))
  
⇒ {∀v:int_term(). P[v]})
Lemma: int_term-definition
∀[A:Type]. ∀[R:A ⟶ int_term() ⟶ ℙ].
  ((∀const:ℤ. {x:A| R[x;"const"]} )
  
⇒ (∀var:ℤ. {x:A| R[x;vvar]} )
  
⇒ (∀left,right:int_term().  ({x:A| R[x;left]}  
⇒ {x:A| R[x;right]}  
⇒ {x:A| R[x;left (+) right]} ))
  
⇒ (∀left,right:int_term().  ({x:A| R[x;left]}  
⇒ {x:A| R[x;right]}  
⇒ {x:A| R[x;left (-) right]} ))
  
⇒ (∀left,right:int_term().  ({x:A| R[x;left]}  
⇒ {x:A| R[x;right]}  
⇒ {x:A| R[x;left (*) right]} ))
  
⇒ (∀num:int_term(). ({x:A| R[x;num]}  
⇒ {x:A| R[x;"-"num]} ))
  
⇒ {∀v:int_term(). {x:A| R[x;v]} })
Definition: int_term_ind
int_term_ind(v;
             itermConstant(const)
⇒ Constant[const];
             itermVar(var)
⇒ Var[var];
             itermAdd(left,right)
⇒ rec1,rec2.Add[left;
                                                  right;
                                                  rec1;
                                                  rec2];
             itermSubtract(left,right)
⇒ rec3,rec4.Subtract[left;
                                                            right;
                                                            rec3;
                                                            rec4];
             itermMultiply(left,right)
⇒ rec5,rec6.Multiply[left;
                                                            right;
                                                            rec5;
                                                            rec6];
             itermMinus(num)
⇒ rec7.Minus[num; rec7])  ==
  fix((λint_term_ind,v. let lbl,v1 = v 
                        in if lbl="Constant" then Constant[v1]
                           if lbl="Var" then Var[v1]
                           if lbl="Add"
                             then let left,v2 = v1 
                                  in Add[left;
                                         v2;
                                         int_term_ind left;
                                         int_term_ind v2]
                           if lbl="Subtract"
                             then let left,v2 = v1 
                                  in Subtract[left;
                                              v2;
                                              int_term_ind left;
                                              int_term_ind v2]
                           if lbl="Multiply"
                             then let left,v2 = v1 
                                  in Multiply[left;
                                              v2;
                                              int_term_ind left;
                                              int_term_ind v2]
                           if lbl="Minus" then Minus[v1; int_term_ind v1]
                           else Ax
                           fi )) 
  v
Lemma: int_term_ind_wf
∀[A:Type]. ∀[R:A ⟶ int_term() ⟶ ℙ]. ∀[v:int_term()]. ∀[Constant:const:ℤ ⟶ {x:A| R[x;"const"]} ].
∀[Var:var:ℤ ⟶ {x:A| R[x;vvar]} ]. ∀[Add:left:int_term()
                                        ⟶ right:int_term()
                                        ⟶ {x:A| R[x;left]} 
                                        ⟶ {x:A| R[x;right]} 
                                        ⟶ {x:A| R[x;left (+) right]} ]. ∀[Subtract:left:int_term()
                                                                                   ⟶ right:int_term()
                                                                                   ⟶ {x:A| R[x;left]} 
                                                                                   ⟶ {x:A| R[x;right]} 
                                                                                   ⟶ {x:A| R[x;left (-) right]} ].
∀[Multiply:left:int_term() ⟶ right:int_term() ⟶ {x:A| R[x;left]}  ⟶ {x:A| R[x;right]}  ⟶ {x:A| R[x;left (*) right]} \000C].
∀[Minus:num:int_term() ⟶ {x:A| R[x;num]}  ⟶ {x:A| R[x;"-"num]} ].
  (int_term_ind(v;
                itermConstant(const)
⇒ Constant[const];
                itermVar(var)
⇒ Var[var];
                itermAdd(left,right)
⇒ rec1,rec2.Add[left;right;rec1;rec2];
                itermSubtract(left,right)
⇒ rec3,rec4.Subtract[left;right;rec3;rec4];
                itermMultiply(left,right)
⇒ rec5,rec6.Multiply[left;right;rec5;rec6];
                itermMinus(num)
⇒ rec7.Minus[num;rec7])  ∈ {x:A| R[x;v]} )
Lemma: int_term_ind_wf_simple
∀[A:Type]. ∀[v:int_term()]. ∀[Constant,Var:var:ℤ ⟶ A]. ∀[Add,Subtract,Multiply:left:int_term()
                                                                                ⟶ right:int_term()
                                                                                ⟶ A
                                                                                ⟶ A
                                                                                ⟶ A].
∀[Minus:num:int_term() ⟶ A ⟶ A].
  (int_term_ind(v;
                itermConstant(const)
⇒ Constant[const];
                itermVar(var)
⇒ Var[var];
                itermAdd(left,right)
⇒ rec1,rec2.Add[left;right;rec1;rec2];
                itermSubtract(left,right)
⇒ rec3,rec4.Subtract[left;right;rec3;rec4];
                itermMultiply(left,right)
⇒ rec5,rec6.Multiply[left;right;rec5;rec6];
                itermMinus(num)
⇒ rec7.Minus[num;rec7])  ∈ A)
Lemma: int_term_subtype_base
int_term() ⊆r Base
Definition: int-term-ind-fun
int-term-ind-fun(c.C[c];
                 v.V[v];
                 l,r,rl,rr.A[l;
                             r;
                             rl;
                             rr];
                 l,r,rl,rr.S[l;
                             r;
                             rl;
                             rr];
                 l,r,rl,rr.M[l;
                             r;
                             rl;
                             rr];
                 x,rx.MN[x; rx]) ==
  λt.int_term_ind(t;
                  itermConstant(c)
⇒ C[c];
                  itermVar(v)
⇒ V[v];
                  itermAdd(l,r)
⇒ rl,rr.A[l;
                                          r;
                                          rl;
                                          rr];
                  itermSubtract(l,r)
⇒ rl,rr.S[l;
                                               r;
                                               rl;
                                               rr];
                  itermMultiply(l,r)
⇒ rl,rr.M[l;
                                               r;
                                               rl;
                                               rr];
                  itermMinus(x)
⇒ rx.MN[x; rx]) 
Lemma: int-term-ind-fun_wf
∀[A:Type]. ∀[v:int_term()]. ∀[Constant,Var:var:ℤ ⟶ A]. ∀[Add,Subtract,Multiply:left:int_term()
                                                                                ⟶ right:int_term()
                                                                                ⟶ A
                                                                                ⟶ A
                                                                                ⟶ A].
∀[Minus:num:int_term() ⟶ A ⟶ A].
  (int-term-ind-fun(c.Constant[c];
                    v.Var[v];
                    l,r,rl,rr.Add[l;r;rl;rr];
                    l,r,rl,rr.Subtract[l;r;rl;rr];
                    l,r,rl,rr.Multiply[l;r;rl;rr];
                    x,rx.Minus[x;rx]) ∈ int_term() ⟶ A)
Lemma: int_term_ind-var
∀[C,V,A,S,M,MN,k:Top].
  (int-term-ind-fun(c.C[c];
                    v.V[v];
                    l,r,rl,rr.A[l;r;rl;rr];
                    l,r,rl,rr.S[l;r;rl;rr];
                    l,r,rl,rr.M[l;r;rl;rr];
                    x,rx.MN[x;rx]) 
   vk ~ V[k])
Lemma: int_term_ind-const
∀[C,V,A,S,M,MN,c:Top].
  (int-term-ind-fun(c.C[c];
                    v.V[v];
                    l,r,rl,rr.A[l;r;rl;rr];
                    l,r,rl,rr.S[l;r;rl;rr];
                    l,r,rl,rr.M[l;r;rl;rr];
                    x,rx.MN[x;rx]) 
   "c" ~ C[c])
Lemma: int_term_ind-add
∀[C,V,A,S,M,MN,a,b:Top].
  (int-term-ind-fun(c.C[c];
                    v.V[v];
                    l,r,rl,rr.A[l;r;rl;rr];
                    l,r,rl,rr.S[l;r;rl;rr];
                    l,r,rl,rr.M[l;r;rl;rr];
                    x,rx.MN[x;rx]) 
   (a (+) b) ~ A[a;b;int-term-ind-fun(c.C[c];
                                      v.V[v];
                                      l,r,rl,rr.A[l;r;rl;rr];
                                      l,r,rl,rr.S[l;r;rl;rr];
                                      l,r,rl,rr.M[l;r;rl;rr];
                                      x,rx.MN[x;rx]) 
                     a;int-term-ind-fun(c.C[c];
                                        v.V[v];
                                        l,r,rl,rr.A[l;r;rl;rr];
                                        l,r,rl,rr.S[l;r;rl;rr];
                                        l,r,rl,rr.M[l;r;rl;rr];
                                        x,rx.MN[x;rx]) 
                       b])
Lemma: int_term_ind-sub
∀[C,V,A,S,M,MN,a,b:Top].
  (int-term-ind-fun(c.C[c];
                    v.V[v];
                    l,r,rl,rr.A[l;r;rl;rr];
                    l,r,rl,rr.S[l;r;rl;rr];
                    l,r,rl,rr.M[l;r;rl;rr];
                    x,rx.MN[x;rx]) 
   (a (-) b) ~ S[a;b;int-term-ind-fun(c.C[c];
                                      v.V[v];
                                      l,r,rl,rr.A[l;r;rl;rr];
                                      l,r,rl,rr.S[l;r;rl;rr];
                                      l,r,rl,rr.M[l;r;rl;rr];
                                      x,rx.MN[x;rx]) 
                     a;int-term-ind-fun(c.C[c];
                                        v.V[v];
                                        l,r,rl,rr.A[l;r;rl;rr];
                                        l,r,rl,rr.S[l;r;rl;rr];
                                        l,r,rl,rr.M[l;r;rl;rr];
                                        x,rx.MN[x;rx]) 
                       b])
Lemma: int_term_ind-mul
∀[C,V,A,S,M,MN,a,b:Top].
  (int-term-ind-fun(c.C[c];
                    v.V[v];
                    l,r,rl,rr.A[l;r;rl;rr];
                    l,r,rl,rr.S[l;r;rl;rr];
                    l,r,rl,rr.M[l;r;rl;rr];
                    x,rx.MN[x;rx]) 
   (a (*) b) ~ M[a;b;int-term-ind-fun(c.C[c];
                                      v.V[v];
                                      l,r,rl,rr.A[l;r;rl;rr];
                                      l,r,rl,rr.S[l;r;rl;rr];
                                      l,r,rl,rr.M[l;r;rl;rr];
                                      x,rx.MN[x;rx]) 
                     a;int-term-ind-fun(c.C[c];
                                        v.V[v];
                                        l,r,rl,rr.A[l;r;rl;rr];
                                        l,r,rl,rr.S[l;r;rl;rr];
                                        l,r,rl,rr.M[l;r;rl;rr];
                                        x,rx.MN[x;rx]) 
                       b])
Lemma: int_term_ind-minus
∀[C,V,A,S,M,MN,x:Top].
  (int-term-ind-fun(c.C[c];
                    v.V[v];
                    l,r,rl,rr.A[l;r;rl;rr];
                    l,r,rl,rr.S[l;r;rl;rr];
                    l,r,rl,rr.M[l;r;rl;rr];
                    x,rx.MN[x;rx]) 
   "-"x ~ MN[x;int-term-ind-fun(c.C[c];
                                v.V[v];
                                l,r,rl,rr.A[l;r;rl;rr];
                                l,r,rl,rr.S[l;r;rl;rr];
                                l,r,rl,rr.M[l;r;rl;rr];
                                x,rx.MN[x;rx]) 
               x])
Definition: int_term_value
int_term_value(f;t) ==
  int_term_ind(t;
               itermConstant(n)
⇒ n;
               itermVar(v)
⇒ f v;
               itermAdd(l,r)
⇒ rl,rr.rl + rr;
               itermSubtract(l,r)
⇒ rl,rr.rl - rr;
               itermMultiply(l,r)
⇒ rl,rr.rl * rr;
               itermMinus(x)
⇒ r.-r) 
Lemma: int_term_value_wf
∀[f:ℤ ⟶ ℤ]. ∀[t:int_term()].  (int_term_value(f;t) ∈ ℤ)
Lemma: int_term_value_add_lemma
∀y,x,f:Top.  (int_term_value(f;x (+) y) ~ int_term_value(f;x) + int_term_value(f;y))
Lemma: int_term_value_mul_lemma
∀y,x,f:Top.  (int_term_value(f;x (*) y) ~ int_term_value(f;x) * int_term_value(f;y))
Lemma: int_term_value_subtract_lemma
∀y,x,f:Top.  (int_term_value(f;x (-) y) ~ int_term_value(f;x) - int_term_value(f;y))
Lemma: int_term_value_minus_lemma
∀x,f:Top.  (int_term_value(f;"-"x) ~ -int_term_value(f;x))
Lemma: int_term_value_constant_lemma
∀x,f:Top.  (int_term_value(f;"x") ~ x)
Lemma: int_term_value_var_lemma
∀x,f:Top.  (int_term_value(f;vx) ~ f x)
Definition: equiv_int_terms
t1 ≡ t2 ==  ∀f:ℤ ⟶ ℤ. (int_term_value(f;t1) = int_term_value(f;t2) ∈ ℤ)
Lemma: equiv_int_terms_wf
∀[t1,t2:int_term()].  (t1 ≡ t2 ∈ ℙ)
Lemma: equiv_int_terms_weakening
∀[t1,t2:int_term()].  t1 ≡ t2 supposing t1 = t2 ∈ int_term()
Lemma: equiv_int_terms_transitivity
∀[t1,t2,t3:int_term()].  (t1 ≡ t3) supposing (t2 ≡ t3 and t1 ≡ t2)
Lemma: equiv_int_terms_inversion
∀[t1,t2:int_term()].  t1 ≡ t2 supposing t2 ≡ t1
Lemma: equiv_int_terms_functionality
∀[x1,x2,y1,y2:int_term()].  (uiff(x1 ≡ y1;x2 ≡ y2)) supposing (y1 ≡ y2 and x1 ≡ x2)
Lemma: int_term_value_functionality
∀[f:ℤ ⟶ ℤ]. ∀[t1,t2:int_term()].  int_term_value(f;t1) = int_term_value(f;t2) ∈ ℤ supposing t1 ≡ t2
Lemma: itermAdd_functionality
∀[a,b,c,d:int_term()].  (a (+) c ≡ b (+) d) supposing (a ≡ b and c ≡ d)
Lemma: itermSubtract_functionality
∀[a,b,c,d:int_term()].  (a (-) c ≡ b (-) d) supposing (a ≡ b and c ≡ d)
Lemma: itermMultiply_functionality
∀[a,b,c,d:int_term()].  (a (*) c ≡ b (*) d) supposing (a ≡ b and c ≡ d)
Lemma: itermMinus_functionality
∀[a,b:int_term()].  "-"a ≡ "-"b supposing a ≡ b
Definition: iMonomial
iMonomial() ==  ℤ-o × {vs:ℤ List| sorted(vs)} 
Lemma: iMonomial_wf
iMonomial() ∈ Type
Definition: isMonomialOne
isMonomialOne(m) ==  let a,vs = m in null(vs) ∧b (a =z 1)
Lemma: isMonomialOne_wf
∀[m:iMonomial()]. (isMonomialOne(m) ∈ 𝔹)
Lemma: iMonomial-value-type
value-type(iMonomial())
Definition: imonomial-le
imonomial-le(m1;m2) ==  snd(m1) ≤_lex snd(m2)
Lemma: imonomial-le_wf
∀[m1,m2:iMonomial()].  (imonomial-le(m1;m2) ∈ 𝔹)
Definition: imonomial-less
imonomial-less(m1;m2) ==  (¬((snd(m1)) = (snd(m2)) ∈ (ℤ List))) ∧ (↑imonomial-le(m1;m2))
Lemma: imonomial-less_wf
∀[m1,m2:iMonomial()].  (imonomial-less(m1;m2) ∈ ℙ)
Lemma: imonomial-less-transitive
∀[m1,m2,m3:iMonomial()].  (imonomial-less(m1;m3)) supposing (imonomial-less(m2;m3) and imonomial-less(m1;m2))
Lemma: not-imonomial-le
∀a,b:iMonomial().  ((¬↑imonomial-le(a;b)) 
⇒ imonomial-less(b;a))
Definition: iPolynomial
iPolynomial() ==  {L:iMonomial() List| ∀i:ℕ||L||. ∀j:ℕi.  imonomial-less(L[j];L[i])} 
Lemma: iPolynomial_wf
iPolynomial() ∈ Type
Definition: isPolyOne
isPolyOne(p) ==  if p is a pair then let m,more = p in null(more) ∧b isMonomialOne(m) otherwise ff
Lemma: isPolyOne_wf
∀[p:iPolynomial()]. (isPolyOne(p) ∈ 𝔹)
Definition: imonomial-term
imonomial-term(m) ==
  let c,vs = m 
  in accumulate (with value t and list item v):
      t (*) vv
     over list:
       vs
     with starting value:
      "c")
Lemma: imonomial-term_wf
∀[m:ℤ × (ℤ List)]. (imonomial-term(m) ∈ int_term())
Lemma: imonomial-cons
∀v:ℤ List. ∀u,a:ℤ. ∀f:ℤ ⟶ ℤ.  (int_term_value(f;imonomial-term(<a, [u / v]>)) = int_term_value(f;imonomial-term(<a * (f\000C u), v>)) ∈ ℤ)
Lemma: imonomial-term-linear
∀f:ℤ ⟶ ℤ. ∀ws:ℤ List. ∀c:ℤ.  (int_term_value(f;imonomial-term(<c, ws>)) = (c * int_term_value(f;imonomial-term(<1, ws>)\000C)) ∈ ℤ)
Lemma: imonomial-term-add
∀vs:ℤ List. ∀a,b:ℤ-o. ∀f:ℤ ⟶ ℤ.  ((int_term_value(f;imonomial-term(<a, vs>)) + int_term_value(f;imonomial-term(<b, vs>)\000C)) = int_term_value(f;imonomial-term(<a + b, vs>)) ∈ ℤ)
Definition: ipolynomial-term
ipolynomial-term(p) ==
  if null(p)
  then "0"
  else let m1,ms = p 
       in accumulate (with value t and list item m):
           t (+) imonomial-term(m)
          over list:
            ms
          with starting value:
           imonomial-term(m1))
  fi 
Lemma: ipolynomial-term_wf
∀[p:iMonomial() List]. (ipolynomial-term(p) ∈ int_term())
Lemma: ipolynomial-term-cons
∀[m:iMonomial()]. ∀[p:iMonomial() List].  ipolynomial-term([m / p]) ≡ imonomial-term(m) (+) ipolynomial-term(p)
Lemma: ipolynomial-term-cons-value
∀[m:iMonomial()]. ∀[p:iMonomial() List].
  ∀f:ℤ ⟶ ℤ
    (int_term_value(f;ipolynomial-term([m / p]))
    = (int_term_value(f;imonomial-term(m)) + int_term_value(f;ipolynomial-term(p)))
    ∈ ℤ)
Definition: add-ipoly
add-ipoly(p;q)
==r eval pp = p in
    eval qq = q in
      if null(pp) then qq
      if null(qq) then pp
      else let p1,ps = pp 
           in let q1,qs = qq 
              in if imonomial-le(p1;q1)
                 then if imonomial-le(q1;p1)
                      then let x ⟵ add-ipoly(ps;qs)
                           in let cp,vs = p1 
                              in eval c = cp + (fst(q1)) in
                                 if c=0 then x else [<c, vs> / x]
                      else let x ⟵ add-ipoly(ps;[q1 / qs])
                           in [p1 / x]
                      fi 
                 else let x ⟵ add-ipoly([p1 / ps];qs)
                      in [q1 / x]
                 fi 
      fi 
Lemma: add-ipoly_wf1
∀[p,q:iMonomial() List].  (add-ipoly(p;q) ∈ iMonomial() List)
Definition: add-ipoly1
add-ipoly1(p;q) ==  add-ipoly(p;q)
Lemma: add-poly-lemma1
∀p,q:iMonomial() List. ∀m:iMonomial().
  ((∀i:ℕ||p||. ∀j:ℕi.  imonomial-less(p[j];p[i]))
  
⇒ (∀i:ℕ||q||. ∀j:ℕi.  imonomial-less(q[j];q[i]))
  
⇒ (0 < ||p|| 
⇒ imonomial-less(m;p[0]))
  
⇒ (0 < ||q|| 
⇒ imonomial-less(m;q[0]))
  
⇒ 0 < ||add-ipoly(p;q)||
  
⇒ imonomial-less(m;add-ipoly(p;q)[0]))
Lemma: add-ipoly-equiv
∀p,q:iMonomial() List.  ipolynomial-term(add-ipoly(p;q)) ≡ ipolynomial-term(p) (+) ipolynomial-term(q)
Lemma: add-ipoly_wf
∀[p,q:iPolynomial()].  (add-ipoly(p;q) ∈ iPolynomial())
Definition: add-ipoly-prepend
add-ipoly-prepend(p;q;l)
==r eval pp = p in
    eval qq = q in
      if pp = Ax then rev(l) + qq
      otherwise if qq = Ax then rev(l) + pp otherwise let p1,ps = pp 
                                                      in let q1,qs = qq 
                                                         in if imonomial-le(p1;q1)
                                                            then if imonomial-le(q1;p1)
                                                                 then let cp,vs = p1 
                                                                      in eval c = cp + (fst(q1)) in
                                                                         eval l' = if c=0 then l else [<c, vs> / l] in
                                                                           add-ipoly-prepend(ps;qs;l')
                                                                 else add-ipoly-prepend(ps;[q1 / qs];[p1 / l])
                                                                 fi 
                                                            else add-ipoly-prepend([p1 / ps];qs;[q1 / l])
                                                            fi 
Lemma: add-ipoly-wf1
∀p,q:(ℤ × (ℤ List)) List.  (add-ipoly(p;q) ∈ (ℤ × (ℤ List)) List)
Lemma: add-ipoly1_wf
∀p,q:(ℤ × (ℤ List)) List.  (add-ipoly1(p;q) ∈ (ℤ × (ℤ List)) List)
Lemma: add-poly-prepend-sq1
∀[p,q,l:(ℤ × (ℤ List)) List].  (add-ipoly-prepend(p;q;l) ~ rev(l) + add-ipoly(p;q))
Lemma: add-poly-prepend-sq
∀[p,q,l:iMonomial() List].  (add-ipoly-prepend(p;q;l) ~ rev(l) + add-ipoly(p;q))
Lemma: add-ipoly-prepend_wf
∀[p,q,l:iMonomial() List].  (add-ipoly-prepend(p;q;l) ∈ iMonomial() List)
Definition: add_ipoly
add_ipoly(p;q) ==  add-ipoly-prepend(p;q;[])
Lemma: add_ipoly-sq
∀[p,q:iMonomial() List].  (add_ipoly(p;q) ~ add-ipoly(p;q))
Lemma: add_ipoly_wf
∀[p,q:iPolynomial()].  (add_ipoly(p;q) ∈ iPolynomial())
Definition: minus-monomial
minus-monomial(m) ==  let c,vs = m in <-c, vs>
Lemma: minus-monomial_wf
∀[m:iMonomial()]. (minus-monomial(m) ∈ iMonomial())
Definition: minus-poly
minus-poly(p) ==  map(λm.minus-monomial(m);p)
Lemma: minus-poly_wf
∀[p:iPolynomial()]. (minus-poly(p) ∈ iPolynomial())
Lemma: minus-poly-equiv
∀p:iPolynomial(). ipolynomial-term(minus-poly(p)) ≡ "-"ipolynomial-term(p)
Definition: mul-monomials
mul-monomials(m1;m2) ==  let a,vs = m1 in let b,ws = m2 in eval c = a * b in eval u = merge-int-accum(vs;ws) in   <c, u>
Lemma: mul-monomials_wf
∀[m1,m2:iMonomial()].  (mul-monomials(m1;m2) ∈ iMonomial())
Lemma: mul-monomials-equiv
∀[m1,m2:iMonomial()].  imonomial-term(mul-monomials(m1;m2)) ≡ imonomial-term(m1) (*) imonomial-term(m2)
Definition: even-int-list
even-int-list(L) ==  null(L) ∨b((¬bnull(tl(L))) ∧b (hd(L) =z hd(tl(L))) ∧b even-int-list(tl(tl(L))))
Lemma: even-int-list_wf
∀[L:ℤ List]. (even-int-list(L) ∈ 𝔹)
Definition: nonneg-monomial
nonneg-monomial(m) ==  let c,L = m in 0 ≤z c ∧b even-int-list(L)
Lemma: nonneg-monomial_wf
∀[m:iMonomial()]. (nonneg-monomial(m) ∈ 𝔹)
Lemma: assert-nonneg-monomial
∀m:iMonomial(). ((↑nonneg-monomial(m)) 
⇒ (∃m':iMonomial(). ∃k:ℕ+. (mul-monomials(m';m') = mul-monomials(m;<k, []>) ∈ iM\000Conomial())))
Definition: mul-mono-poly
mul-mono-poly(m;p) ==  rec-case(p) of [] => [] | h::t => r.eval m = mul-monomials(m;h) in eval l = r in   [m / l]
Lemma: mul-mono-poly_wf1
∀[m:iMonomial()]. ∀[p:iMonomial() List].  (mul-mono-poly(m;p) ∈ iMonomial() List)
Lemma: mul-mono-poly_wf
∀[m:iMonomial()]. ∀[p:iPolynomial()].  (mul-mono-poly(m;p) ∈ iPolynomial())
Lemma: mul-mono-poly-equiv
∀[m:iMonomial()]. ∀[p:iMonomial() List].
  ipolynomial-term(mul-mono-poly(m;p)) ≡ imonomial-term(m) (*) ipolynomial-term(p)
Definition: mul-ipoly
mul-ipoly(p;q) ==
  let pp ⟵ p
  in if null(pp)
  then []
  else let p1,ps = pp 
       in let qq ⟵ q
          in if null(qq)
          then []
          else eager-accum(sofar,m.add-ipoly(sofar;mul-mono-poly(m;qq));mul-mono-poly(p1;qq);ps)
          fi 
  fi 
Lemma: mul-ipoly_wf
∀[p,q:iPolynomial()].  (mul-ipoly(p;q) ∈ iPolynomial())
Lemma: mul-ipoly-equiv
∀[p,q:iMonomial() List].  ipolynomial-term(mul-ipoly(p;q)) ≡ ipolynomial-term(p) (*) ipolynomial-term(q)
Definition: cbv_list_accum
cbv_list_accum(x,a.f[x; a];y;L) ==
  fix((λcbv_list_accum,y,L. eval v = L in
                            if v is a pair then let h,t = v 
                                                in eval y' = f[y; h] in
                                                   cbv_list_accum y' t otherwise if v = Ax then y otherwise ⊥)) 
  y 
  L
Lemma: cbv_list_accum_wf
∀[T,T':Type]. ∀[l:T List]. ∀[y:T']. ∀[f:T' ⟶ T ⟶ T'].  cbv_list_accum(x,a.f[x;a];y;l) ∈ T' supposing value-type(T')
Lemma: cbv_list_accum-is-list_accum
∀[T,T':Type]. ∀[l:T List]. ∀[y:T']. ∀[f:T' ⟶ T ⟶ T'].
  cbv_list_accum(x,a.f[x;a];y;l) ~ accumulate (with value x and list item a):
                                    f[x;a]
                                   over list:
                                     l
                                   with starting value:
                                    y) 
  supposing value-type(T')
Definition: mul_ipoly
mul_ipoly(p;q) ==
  eval pp = p in
  if pp = Ax then []
  otherwise let p1,ps = pp 
            in eval qq = q in
               if qq = Ax then []
               otherwise cbv_list_accum(sofar,m.add_ipoly(sofar;mul-mono-poly(m;qq));mul-mono-poly(p1;qq);ps)
Lemma: mul_poly-sq
∀[p,q:iMonomial() List].  (mul_ipoly(p;q) ~ mul-ipoly(p;q))
Lemma: mul_ipoly_wf
∀[p,q:iPolynomial()].  (mul_ipoly(p;q) ∈ iPolynomial())
Definition: int_term_to_ipoly
int_term_to_ipoly(t) ==
  int_term_ind(t;
               itermConstant(c)
⇒ if c=0 then [] else [<c, []>];
               itermVar(v)
⇒ [<1, [v]>];
               itermAdd(l,r)
⇒ rl,rr.add_ipoly(rl;rr);
               itermSubtract(l,r)
⇒ rl,rr.add_ipoly(rl;minus-poly(rr));
               itermMultiply(l,r)
⇒ rl,rr.mul_ipoly(rl;rr);
               itermMinus(x)
⇒ rx.minus-poly(rx)) 
Lemma: int_term_to_ipoly_wf
∀[t:int_term()]. (int_term_to_ipoly(t) ∈ iPolynomial())
Definition: int_term_to_rP
int_term_to_rP(t) ==
  int_term_ind(t;
               itermConstant(c)
⇒ [1; c];
               itermVar(v)
⇒ [2; v];
               itermAdd(l,r)
⇒ rl,rr.eager-append(rl;eager-append(rr;[3]));
               itermSubtract(l,r)
⇒ rl,rr.eager-append(rl;eager-append(rr;[4]));
               itermMultiply(l,r)
⇒ rl,rr.eager-append(rl;eager-append(rr;[5]));
               itermMinus(x)
⇒ rx.eager-append(rx;[6])) 
Lemma: int_term_to_rP_wf
∀[t:int_term()]. (int_term_to_rP(t) ∈ ℤ List)
Definition: rP_to_poly
rP_to_poly(stack;L)
==r if L = Ax then stack otherwise let op,more = L 
                                   in if op=1
                                      then let c,evenmore = more 
                                           in rP_to_poly([if c=0 then [] else [<c, []>] / stack];evenmore)
                                      else if op=2
                                           then let v,evenmore = more 
                                                in rP_to_poly(<[<1, [v]>], stack>evenmore)
                                           else if op=3
                                                then let q,p,s = stack in 
                                                     rP_to_poly([add_ipoly(p;q) / s];more)
                                                else if op=4
                                                     then let q,p,s = stack in 
                                                          rP_to_poly([add_ipoly(p;minus-poly(q)) / s];more)
                                                     else if op=5
                                                          then let q,p,s = stack in 
                                                               rP_to_poly([mul_ipoly(p;q) / s];more)
                                                          else let p,s = stack 
                                                               in rP_to_poly([minus-poly(p) / s];more)
Lemma: rP_to_poly-int_term_to_rP
∀[t:int_term()]. ∀[s:iPolynomial() List].  (rP_to_poly(s;int_term_to_rP(t)) ~ [int_term_to_ipoly(t) / s])
Definition: rP_to_term
rP_to_term(stack;L)
==r if L = Ax then stack otherwise let op,more = L 
                                   in if op=1
                                      then let c,evenmore = more 
                                           in rP_to_term(["c" / stack];evenmore)
                                      else if op=2
                                           then let v,evenmore = more 
                                                in rP_to_term([vv / stack];evenmore)
                                           else if op=3
                                                then let q,p,s = stack in 
                                                     rP_to_term([p (+) q / s];more)
                                                else if op=4
                                                     then let q,p,s = stack in 
                                                          rP_to_term([p (-) q / s];more)
                                                     else if op=5
                                                          then let q,p,s = stack in 
                                                               rP_to_term([p (*) q / s];more)
                                                          else let p,s = stack 
                                                               in rP_to_term(["-"p / s];more)
Lemma: rP_to_term-int_term_to_rP
∀[t:int_term()]. ∀[s:int_term() List].  (rP_to_term(s;int_term_to_rP(t)) ~ [t / s])
Lemma: int_term_to_ipoly-add
∀[a,b:Top].  (int_term_to_ipoly(a (+) b) ~ add_ipoly(int_term_to_ipoly(a);int_term_to_ipoly(b)))
Lemma: int_term_to_ipoly-sub
∀[a,b:Top].  (int_term_to_ipoly(a (-) b) ~ add_ipoly(int_term_to_ipoly(a);minus-poly(int_term_to_ipoly(b))))
Lemma: int_term_to_ipoly-minus
∀[b:Top]. (int_term_to_ipoly("-"b) ~ minus-poly(int_term_to_ipoly(b)))
Lemma: int_term_to_ipoly-mul
∀[a,b:Top].  (int_term_to_ipoly(a (*) b) ~ mul_ipoly(int_term_to_ipoly(a);int_term_to_ipoly(b)))
Lemma: int_term_to_ipoly-const
∀[c:Top]. (int_term_to_ipoly("c") ~ if c=0 then [] else [<c, []>])
Lemma: int_term_to_ipoly-var
∀[c:Top]. (int_term_to_ipoly(vc) ~ [<1, [c]>])
Lemma: int_term_polynomial
∀t:int_term(). ipolynomial-term(int_term_to_ipoly(t)) ≡ t
Definition: const-poly
const-poly(n) ==  [<n, []>]
Lemma: const-poly_wf
∀[n:ℤ-o]. (const-poly(n) ∈ iPolynomial())
Lemma: const-poly-value
∀[n,f:Top].  (int_term_value(f;ipolynomial-term(const-poly(n))) ~ n)
Definition: int_formulaco
int_formulaco() ==
  corec(X.lbl:Atom × if lbl =a "less" then left:int_term() × int_term()
                     if lbl =a "le" then left:int_term() × int_term()
                     if lbl =a "eq" then left:int_term() × int_term()
                     if lbl =a "and" then left:X × X
                     if lbl =a "or" then left:X × X
                     if lbl =a "implies" then left:X × X
                     if lbl =a "not" then X
                     else Void
                     fi )
Lemma: int_formulaco_wf
int_formulaco() ∈ Type
Lemma: int_formulaco-ext
int_formulaco() ≡ lbl:Atom × if lbl =a "less" then left:int_term() × int_term()
                             if lbl =a "le" then left:int_term() × int_term()
                             if lbl =a "eq" then left:int_term() × int_term()
                             if lbl =a "and" then left:int_formulaco() × int_formulaco()
                             if lbl =a "or" then left:int_formulaco() × int_formulaco()
                             if lbl =a "implies" then left:int_formulaco() × int_formulaco()
                             if lbl =a "not" then int_formulaco()
                             else Void
                             fi 
Definition: int_formulaco_size
int_formulaco_size(p) ==
  fix((λsize,p. let lbl,x = p 
                in if lbl =a "less" then 0
                   if lbl =a "le" then 0
                   if lbl =a "eq" then 0
                   if lbl =a "and" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "or" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "implies" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "not" then 1 + (size x)
                   else 0
                   fi )) 
  p
Lemma: int_formulaco_size_wf
∀[p:int_formulaco()]. (int_formulaco_size(p) ∈ partial(ℕ))
Definition: int_formula
int_formula() ==  {p:int_formulaco()| (int_formulaco_size(p))↓} 
Lemma: int_formula_wf
int_formula() ∈ Type
Definition: int_formula_size
int_formula_size(p) ==
  fix((λsize,p. let lbl,x = p 
                in if lbl =a "less" then 0
                   if lbl =a "le" then 0
                   if lbl =a "eq" then 0
                   if lbl =a "and" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "or" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "implies" then 1 + (size (fst(x))) + (size (snd(x)))
                   if lbl =a "not" then 1 + (size x)
                   else 0
                   fi )) 
  p
Lemma: int_formula_size_wf
∀[p:int_formula()]. (int_formula_size(p) ∈ ℕ)
Lemma: int_formula-ext
int_formula() ≡ lbl:Atom × if lbl =a "less" then left:int_term() × int_term()
                           if lbl =a "le" then left:int_term() × int_term()
                           if lbl =a "eq" then left:int_term() × int_term()
                           if lbl =a "and" then left:int_formula() × int_formula()
                           if lbl =a "or" then left:int_formula() × int_formula()
                           if lbl =a "implies" then left:int_formula() × int_formula()
                           if lbl =a "not" then int_formula()
                           else Void
                           fi 
Definition: intformless
(left "<" right) ==  <"less", left, right>
Lemma: intformless_wf
∀[left,right:int_term()].  ((left "<" right) ∈ int_formula())
Definition: intformle
left "≤" right ==  <"le", left, right>
Lemma: intformle_wf
∀[left,right:int_term()].  (left "≤" right ∈ int_formula())
Definition: intformeq
left "=" right ==  <"eq", left, right>
Lemma: intformeq_wf
∀[left,right:int_term()].  (left "=" right ∈ int_formula())
Definition: intformand
left "∧" right ==  <"and", left, right>
Lemma: intformand_wf
∀[left,right:int_formula()].  (left "∧" right ∈ int_formula())
Definition: intformor
left "or" right ==  <"or", left, right>
Lemma: intformor_wf
∀[left,right:int_formula()].  (left "or" right ∈ int_formula())
Definition: intformimplies
left "=>" right ==  <"implies", left, right>
Lemma: intformimplies_wf
∀[left,right:int_formula()].  (left "=>" right ∈ int_formula())
Definition: intformnot
"¬"form ==  <"not", form>
Lemma: intformnot_wf
∀[form:int_formula()]. ("¬"form ∈ int_formula())
Definition: intformless?
intformless?(v) ==  fst(v) =a "less"
Lemma: intformless?_wf
∀[v:int_formula()]. (intformless?(v) ∈ 𝔹)
Definition: intformless-left
intformless-left(v) ==  fst(snd(v))
Lemma: intformless-left_wf
∀[v:int_formula()]. intformless-left(v) ∈ int_term() supposing ↑intformless?(v)
Definition: intformless-right
intformless-right(v) ==  snd(snd(v))
Lemma: intformless-right_wf
∀[v:int_formula()]. intformless-right(v) ∈ int_term() supposing ↑intformless?(v)
Definition: intformle?
intformle?(v) ==  fst(v) =a "le"
Lemma: intformle?_wf
∀[v:int_formula()]. (intformle?(v) ∈ 𝔹)
Definition: intformle-left
intformle-left(v) ==  fst(snd(v))
Lemma: intformle-left_wf
∀[v:int_formula()]. intformle-left(v) ∈ int_term() supposing ↑intformle?(v)
Definition: intformle-right
intformle-right(v) ==  snd(snd(v))
Lemma: intformle-right_wf
∀[v:int_formula()]. intformle-right(v) ∈ int_term() supposing ↑intformle?(v)
Definition: intformeq?
intformeq?(v) ==  fst(v) =a "eq"
Lemma: intformeq?_wf
∀[v:int_formula()]. (intformeq?(v) ∈ 𝔹)
Definition: intformeq-left
intformeq-left(v) ==  fst(snd(v))
Lemma: intformeq-left_wf
∀[v:int_formula()]. intformeq-left(v) ∈ int_term() supposing ↑intformeq?(v)
Definition: intformeq-right
intformeq-right(v) ==  snd(snd(v))
Lemma: intformeq-right_wf
∀[v:int_formula()]. intformeq-right(v) ∈ int_term() supposing ↑intformeq?(v)
Definition: intformand?
intformand?(v) ==  fst(v) =a "and"
Lemma: intformand?_wf
∀[v:int_formula()]. (intformand?(v) ∈ 𝔹)
Definition: intformand-left
intformand-left(v) ==  fst(snd(v))
Lemma: intformand-left_wf
∀[v:int_formula()]. intformand-left(v) ∈ int_formula() supposing ↑intformand?(v)
Definition: intformand-right
intformand-right(v) ==  snd(snd(v))
Lemma: intformand-right_wf
∀[v:int_formula()]. intformand-right(v) ∈ int_formula() supposing ↑intformand?(v)
Definition: intformor?
intformor?(v) ==  fst(v) =a "or"
Lemma: intformor?_wf
∀[v:int_formula()]. (intformor?(v) ∈ 𝔹)
Definition: intformor-left
intformor-left(v) ==  fst(snd(v))
Lemma: intformor-left_wf
∀[v:int_formula()]. intformor-left(v) ∈ int_formula() supposing ↑intformor?(v)
Definition: intformor-right
intformor-right(v) ==  snd(snd(v))
Lemma: intformor-right_wf
∀[v:int_formula()]. intformor-right(v) ∈ int_formula() supposing ↑intformor?(v)
Definition: intformimplies?
intformimplies?(v) ==  fst(v) =a "implies"
Lemma: intformimplies?_wf
∀[v:int_formula()]. (intformimplies?(v) ∈ 𝔹)
Definition: intformimplies-left
intformimplies-left(v) ==  fst(snd(v))
Lemma: intformimplies-left_wf
∀[v:int_formula()]. intformimplies-left(v) ∈ int_formula() supposing ↑intformimplies?(v)
Definition: intformimplies-right
intformimplies-right(v) ==  snd(snd(v))
Lemma: intformimplies-right_wf
∀[v:int_formula()]. intformimplies-right(v) ∈ int_formula() supposing ↑intformimplies?(v)
Definition: intformnot?
intformnot?(v) ==  fst(v) =a "not"
Lemma: intformnot?_wf
∀[v:int_formula()]. (intformnot?(v) ∈ 𝔹)
Definition: intformnot-form
intformnot-form(v) ==  snd(v)
Lemma: intformnot-form_wf
∀[v:int_formula()]. intformnot-form(v) ∈ int_formula() supposing ↑intformnot?(v)
Lemma: int_formula-induction
∀[P:int_formula() ⟶ ℙ]
  ((∀left,right:int_term().  P[(left "<" right)])
  
⇒ (∀left,right:int_term().  P[left "≤" right])
  
⇒ (∀left,right:int_term().  P[left "=" right])
  
⇒ (∀left,right:int_formula().  (P[left] 
⇒ P[right] 
⇒ P[left "∧" right]))
  
⇒ (∀left,right:int_formula().  (P[left] 
⇒ P[right] 
⇒ P[left "or" right]))
  
⇒ (∀left,right:int_formula().  (P[left] 
⇒ P[right] 
⇒ P[left "=>" right]))
  
⇒ (∀form:int_formula(). (P[form] 
⇒ P["¬"form]))
  
⇒ {∀v:int_formula(). P[v]})
Lemma: int_formula-definition
∀[A:Type]. ∀[R:A ⟶ int_formula() ⟶ ℙ].
  ((∀left,right:int_term().  {x:A| R[x;(left "<" right)]} )
  
⇒ (∀left,right:int_term().  {x:A| R[x;left "≤" right]} )
  
⇒ (∀left,right:int_term().  {x:A| R[x;left "=" right]} )
  
⇒ (∀left,right:int_formula().  ({x:A| R[x;left]}  
⇒ {x:A| R[x;right]}  
⇒ {x:A| R[x;left "∧" right]} ))
  
⇒ (∀left,right:int_formula().  ({x:A| R[x;left]}  
⇒ {x:A| R[x;right]}  
⇒ {x:A| R[x;left "or" right]} ))
  
⇒ (∀left,right:int_formula().  ({x:A| R[x;left]}  
⇒ {x:A| R[x;right]}  
⇒ {x:A| R[x;left "=>" right]} ))
  
⇒ (∀form:int_formula(). ({x:A| R[x;form]}  
⇒ {x:A| R[x;"¬"form]} ))
  
⇒ {∀v:int_formula(). {x:A| R[x;v]} })
Definition: int_formula_ind
int_formula_ind(v;
                intformless(left,right)
⇒ less[left; right];
                intformle(left,right)
⇒ le[left; right];
                intformeq(left,right)
⇒ eq[left; right];
                intformand(left,right)
⇒ rec1,rec2.and[left;
                                                       right;
                                                       rec1;
                                                       rec2];
                intformor(left,right)
⇒ rec3,rec4.or[left;
                                                     right;
                                                     rec3;
                                                     rec4];
                intformimplies(left,right)
⇒ rec5,rec6.implies[left;
                                                               right;
                                                               rec5;
                                                               rec6];
                intformnot(form)
⇒ rec7.not[form; rec7])  ==
  fix((λint_formula_ind,v. let lbl,v1 = v 
                           in if lbl="less" then let left,v2 = v1 in less[left; v2]
                              if lbl="le" then let left,v2 = v1 in le[left; v2]
                              if lbl="eq" then let left,v2 = v1 in eq[left; v2]
                              if lbl="and"
                                then let left,v2 = v1 
                                     in and[left;
                                            v2;
                                            int_formula_ind left;
                                            int_formula_ind v2]
                              if lbl="or"
                                then let left,v2 = v1 
                                     in or[left;
                                           v2;
                                           int_formula_ind left;
                                           int_formula_ind v2]
                              if lbl="implies"
                                then let left,v2 = v1 
                                     in implies[left;
                                                v2;
                                                int_formula_ind left;
                                                int_formula_ind v2]
                              if lbl="not" then not[v1; int_formula_ind v1]
                              else Ax
                              fi )) 
  v
Lemma: int_formula_ind_wf
∀[A:Type]. ∀[R:A ⟶ int_formula() ⟶ ℙ]. ∀[v:int_formula()]. ∀[less:left:int_term()
                                                                    ⟶ right:int_term()
                                                                    ⟶ {x:A| R[x;(left "<" right)]} ].
∀[le:left:int_term() ⟶ right:int_term() ⟶ {x:A| R[x;left "≤" right]} ]. ∀[eq:left:int_term()
                                                                              ⟶ right:int_term()
                                                                              ⟶ {x:A| R[x;left "=" right]} ].
∀[and:left:int_formula() ⟶ right:int_formula() ⟶ {x:A| R[x;left]}  ⟶ {x:A| R[x;right]}  ⟶ {x:A| R[x;left "∧" right]}\000C ].
∀[or:left:int_formula() ⟶ right:int_formula() ⟶ {x:A| R[x;left]}  ⟶ {x:A| R[x;right]}  ⟶ {x:A| R[x;left "or" right]}\000C ].
∀[implies:left:int_formula()
          ⟶ right:int_formula()
          ⟶ {x:A| R[x;left]} 
          ⟶ {x:A| R[x;right]} 
          ⟶ {x:A| R[x;left "=>" right]} ]. ∀[not:form:int_formula() ⟶ {x:A| R[x;form]}  ⟶ {x:A| R[x;"¬"form]} ].
  (int_formula_ind(v;
                   intformless(left,right)
⇒ less[left;right];
                   intformle(left,right)
⇒ le[left;right];
                   intformeq(left,right)
⇒ eq[left;right];
                   intformand(left,right)
⇒ rec1,rec2.and[left;right;rec1;rec2];
                   intformor(left,right)
⇒ rec3,rec4.or[left;right;rec3;rec4];
                   intformimplies(left,right)
⇒ rec5,rec6.implies[left;right;rec5;rec6];
                   intformnot(form)
⇒ rec7.not[form;rec7])  ∈ {x:A| R[x;v]} )
Lemma: int_formula_ind_wf_simple
∀[A:Type]. ∀[v:int_formula()]. ∀[less,le,eq:left:int_term() ⟶ right:int_term() ⟶ A].
∀[and,or,implies:left:int_formula() ⟶ right:int_formula() ⟶ A ⟶ A ⟶ A]. ∀[not:form:int_formula() ⟶ A ⟶ A].
  (int_formula_ind(v;
                   intformless(left,right)
⇒ less[left;right];
                   intformle(left,right)
⇒ le[left;right];
                   intformeq(left,right)
⇒ eq[left;right];
                   intformand(left,right)
⇒ rec1,rec2.and[left;right;rec1;rec2];
                   intformor(left,right)
⇒ rec3,rec4.or[left;right;rec3;rec4];
                   intformimplies(left,right)
⇒ rec5,rec6.implies[left;right;rec5;rec6];
                   intformnot(form)
⇒ rec7.not[form;rec7])  ∈ A)
Definition: int_formula_prop
int_formula_prop(f;fmla) ==
  int_formula_ind(fmla;
                  a,b.int_term_value(f;a) < int_term_value(f;b);
                  a,b.int_term_value(f;a) ≤ int_term_value(f;b);
                  a,b.int_term_value(f;a) = int_term_value(f;b) ∈ ℤ;
                  X,Y,PX,PY.PX ∧ PY;
                  X,Y,PX,PY.PX ∨ PY;
                  X,Y,PX,PY.PX 
⇒ PY;
                  X,PX.¬PX)
Lemma: int_formula_prop_wf
∀[f:ℤ ⟶ ℤ]. ∀[fmla:int_formula()].  (int_formula_prop(f;fmla) ∈ ℙ)
Lemma: istype-int_formula_prop
∀[f:ℤ ⟶ ℤ]. ∀[fmla:int_formula()].  istype(int_formula_prop(f;fmla))
Lemma: int_formula_prop_and_lemma
∀y,x,f:Top.  (int_formula_prop(f;x "∧" y) ~ int_formula_prop(f;x) ∧ int_formula_prop(f;y))
Lemma: int_formula_prop_or_lemma
∀y,x,f:Top.  (int_formula_prop(f;x "or" y) ~ int_formula_prop(f;x) ∨ int_formula_prop(f;y))
Lemma: int_formual_prop_imp_lemma
∀y,x,f:Top.  (int_formula_prop(f;x "=>" y) ~ int_formula_prop(f;x) 
⇒ int_formula_prop(f;y))
Lemma: int_formula_prop_not_lemma
∀x,f:Top.  (int_formula_prop(f;"¬"x) ~ ¬int_formula_prop(f;x))
Lemma: int_formula_prop_le_lemma
∀y,x,f:Top.  (int_formula_prop(f;x "≤" y) ~ int_term_value(f;x) ≤ int_term_value(f;y))
Lemma: int_formula_prop_less_lemma
∀y,x,f:Top.  (int_formula_prop(f;(x "<" y)) ~ int_term_value(f;x) < int_term_value(f;y))
Lemma: int_formula_prop_eq_lemma
∀y,x,f:Top.  (int_formula_prop(f;x "=" y) ~ int_term_value(f;x) = int_term_value(f;y) ∈ ℤ)
Lemma: int_formula-subtype-base
int_formula() ⊆r Base
Definition: satisfiable_int_formula
satisfiable_int_formula(fmla) ==  ∃f:ℤ ⟶ ℤ. int_formula_prop(f;fmla)
Lemma: satisfiable_int_formula_wf
∀[fmla:int_formula()]. (satisfiable_int_formula(fmla) ∈ ℙ)
Definition: polynomial-constraints
polynomial-constraints() ==  iPolynomial() List × (iPolynomial() List)
Lemma: polynomial-constraints_wf
polynomial-constraints() ∈ Type
Definition: satisfies-poly-constraints
satisfies-poly-constraints(f;X) ==
  let eqs,ineqs = X 
  in (∀p∈eqs.int_term_value(f;ipolynomial-term(p)) = 0 ∈ ℤ) ∧ (∀p∈ineqs.0 ≤ int_term_value(f;ipolynomial-term(p)))
Lemma: satisfies-poly-constraints_wf
∀[f:ℤ ⟶ ℤ]. ∀[X:polynomial-constraints()].  (satisfies-poly-constraints(f;X) ∈ ℙ)
Definition: satisfiable_polynomial_constraints
satisfiable_polynomial_constraints(X) ==  ∃f:ℤ ⟶ ℤ. satisfies-poly-constraints(f;X)
Lemma: satisfiable_polynomial_constraints_wf
∀[X:polynomial-constraints()]. (satisfiable_polynomial_constraints(X) ∈ ℙ)
Definition: combine-pcs
combine-pcs(X;Y) ==  let eqsX,ineqsX = X in let eqsY,ineqsY = Y in <eqsX @ eqsY, ineqsX @ ineqsY>
Lemma: combine-pcs_wf
∀[X,Y:polynomial-constraints()].  (combine-pcs(X;Y) ∈ polynomial-constraints())
Lemma: satisfies-combine-pcs
∀f:ℤ ⟶ ℤ. ∀A,B:polynomial-constraints().
  (satisfies-poly-constraints(f;combine-pcs(A;B)) 
⇐⇒ satisfies-poly-constraints(f;A) ∧ satisfies-poly-constraints(f;B))
Definition: and-poly-constraints
and-poly-constraints(Xs;Ys) ==
  accumulate (with value sofar and list item Y):
   accumulate (with value sofar' and list item X):
    [combine-pcs(X;Y) / sofar']
   over list:
     Xs
   with starting value:
    sofar)
  over list:
    Ys
  with starting value:
   [])
Lemma: and-poly-constraints_wf
∀[Xs,Ys:polynomial-constraints() List].  (and-poly-constraints(Xs;Ys) ∈ polynomial-constraints() List)
Lemma: member-and-poly-constraints
∀L1,L2:polynomial-constraints() List. ∀X:polynomial-constraints().
  ((X ∈ and-poly-constraints(L1;L2)) 
⇐⇒ (∃A∈L1. (∃B∈L2. X = combine-pcs(A;B) ∈ polynomial-constraints())))
Lemma: satisfies-and-poly-constraints
∀f:ℤ ⟶ ℤ. ∀L2,L1:polynomial-constraints() List.
  ((∃X∈L1. satisfies-poly-constraints(f;X)) ∧ (∃X∈L2. satisfies-poly-constraints(f;X))
  
⇐⇒ (∃X∈and-poly-constraints(L1;L2). satisfies-poly-constraints(f;X)))
Definition: negate-poly-constraint
negate-poly-constraint(X) ==
  let eqs,ineqs = X 
  in accumulate (with value pcs and list item e):
      [<[], [minus-poly(add-ipoly(e;const-poly(1)))]> [<[], [add-ipoly(e;const-poly(-1))]> / pcs]]
     over list:
       eqs
     with starting value:
      map(λineq.<[], [minus-poly(add-ipoly(ineq;const-poly(1)))]>ineqs))
Lemma: negate-poly-constraint_wf
∀[X:polynomial-constraints()]. (negate-poly-constraint(X) ∈ polynomial-constraints() List)
Lemma: satisfies-negate-poly-constraint
∀X:polynomial-constraints(). ∀f:ℤ ⟶ ℤ.
  ((∃Z∈negate-poly-constraint(X). satisfies-poly-constraints(f;Z)) 
⇐⇒ ¬satisfies-poly-constraints(f;X))
Definition: negate-poly-constraints
negate-poly-constraints(Xs) ==
  if null(Xs)
  then [<[], []>]
  else let x,more = Xs 
       in accumulate (with value sofar and list item X):
           and-poly-constraints(sofar;negate-poly-constraint(X))
          over list:
            more
          with starting value:
           negate-poly-constraint(x))
  fi 
Lemma: negate-poly-constraints_wf
∀[Xs:polynomial-constraints() List]. (negate-poly-constraints(Xs) ∈ polynomial-constraints() List)
Lemma: satisfies-negate-poly-constraints
∀f:ℤ ⟶ ℤ. ∀L:polynomial-constraints() List.
  ((∀X∈L.¬satisfies-poly-constraints(f;X)) 
⇐⇒ (∃X∈negate-poly-constraints(L). satisfies-poly-constraints(f;X)))
Definition: int_formula_dnf
int_formula_dnf(fmla) ==
  int_formula_ind(fmla;
                  a,b.[<[], [int_term_to_ipoly(b (-) a (+) "1")]>];
                  a,b.[<[], [int_term_to_ipoly(b (-) a)]>];
                  a,b.[<[int_term_to_ipoly(b (-) a)], []>];
                  X,Y,nfX,nfY.and-poly-constraints(nfX;nfY);
                  X,Y,nfX,nfY.nfX @ nfY;
                  X,Y,nfX,nfY.negate-poly-constraints(nfX) @ nfY;
                  X,nfX.negate-poly-constraints(nfX))
Lemma: int_formula_dnf_wf
∀[fmla:int_formula()]. (int_formula_dnf(fmla) ∈ polynomial-constraints() List)
Lemma: satisfies_int_formula_dnf
∀fmla:int_formula(). ∀f:ℤ ⟶ ℤ.
  (int_formula_prop(f;fmla) 
⇐⇒ (∃X∈int_formula_dnf(fmla). satisfies-poly-constraints(f;X)))
Lemma: satisfiable_int_formula_dnf
∀fmla:int_formula()
  (satisfiable_int_formula(fmla) 
⇐⇒ (∃X∈int_formula_dnf(fmla). satisfiable_polynomial_constraints(X)))
Definition: polynomial-mon-vars
polynomial-mon-vars(init;p) ==
  accumulate (with value vss and list item m):
   let c,vs = m 
   in insert(vs;vss)
  over list:
    p
  with starting value:
   init)
Lemma: polynomial-mon-vars_wf
∀[init:ℤ List List]. ∀[p:(Top × (ℤ List)) List].  (polynomial-mon-vars(init;p) ∈ ℤ List List)
Lemma: member-polynomial-mon-vars
∀p:iMonomial() List. ∀L:ℤ List List. ∀vs:ℤ List.
  ((vs ∈ polynomial-mon-vars(L;p)) 
⇐⇒ (vs ∈ L) ∨ (∃m∈p. vs = (snd(m)) ∈ (ℤ List)))
Lemma: no_repeats-polynomial-mon-vars
∀p:iMonomial() List. ∀L:ℤ List List.  (no_repeats(ℤ List;L) 
⇒ no_repeats(ℤ List;polynomial-mon-vars(L;p)))
Definition: pcs-mon-vars
pcs-mon-vars(X) ==
  let eqs,ineqs = X 
  in accumulate (with value vs and list item p):
      polynomial-mon-vars(vs;p)
     over list:
       ineqs
     with starting value:
      accumulate (with value vs and list item p):
       polynomial-mon-vars(vs;p)
      over list:
        eqs
      with starting value:
       [[]]))
Lemma: pcs-mon-vars_wf
∀[X:polynomial-constraints()]. (pcs-mon-vars(X) ∈ ℤ List List)
Lemma: member-pcs-mon-vars
∀X:polynomial-constraints(). ∀vs:ℤ List.
  ((vs ∈ pcs-mon-vars(X))
  
⇐⇒ (vs = [] ∈ (ℤ List))
      ∨ (∃p∈fst(X). (∃m∈p. vs = (snd(m)) ∈ (ℤ List)))
      ∨ (∃p∈snd(X). (∃m∈p. vs = (snd(m)) ∈ (ℤ List))))
Lemma: no_repeats-pcs-mon-vars
∀X:polynomial-constraints(). no_repeats(ℤ List;pcs-mon-vars(X))
Lemma: hd-rev-pcs-mon-vars
∀X:polynomial-constraints(). (0 < ||rev(pcs-mon-vars(X))|| ∧ (hd(rev(pcs-mon-vars(X))) = [] ∈ (ℤ List)))
Definition: poly-coeff-of
poly-coeff-of(vs;p) ==
  rec-case(p) of
  [] => 0
  m::ps2 =>
   r.let c,ws = m 
     in if ws ≤_lex vs then if vs ≤_lex ws then c else r fi  else 0 fi 
Lemma: poly-coeff-of_wf
∀[vs:ℤ List]. ∀[p:iPolynomial()].  (poly-coeff-of(vs;p) ∈ ℤ)
Definition: linearization
linearization(p;L) ==  map(λvs.poly-coeff-of(vs;p);L)
Lemma: linearization_wf
∀[p:iPolynomial()]. ∀[L:ℤ List List].  (linearization(p;L) ∈ {cs:ℤ List| ||cs|| = ||L|| ∈ ℤ} )
Lemma: linearization-value
∀[L:ℤ List List]. ∀[p:iPolynomial()].
  ∀f:ℤ ⟶ ℤ
    (int_term_value(f;ipolynomial-term(p))
    = linearization(p;L) ⋅ map(λvs.accumulate (with value x and list item v):
                                    x * (f v)
                                   over list:
                                     vs
                                   with starting value:
                                    1);L)
    ∈ ℤ) 
  supposing (∀m∈p.(snd(m) ∈ L)) ∧ no_repeats(ℤ List;L)
Definition: pcs-to-integer-problem
pcs-to-integer-problem(X) ==
  eval L = rev(pcs-mon-vars(X)) in
  let polyeqs,polyineqs = X 
  in eval eqs = evalall(eager-map(λp.linearization(p;L);polyeqs)) in
     eval ineqs = evalall(eager-map(λp.linearization(p;L);polyineqs)) in
       <eqs, ineqs>
Lemma: pcs-to-integer-problem_wf
∀[X:polynomial-constraints()]
  (pcs-to-integer-problem(X) ∈ ⋃n:ℕ.({L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List × ({L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List)))
Definition: satisfies-integer-problem
satisfies-integer-problem(eqs;ineqs;xs) ==  (∀as∈eqs.xs ⋅ as =0) ∧ (∀bs∈ineqs.xs ⋅ bs ≥0)
Lemma: satisfies-integer-problem_wf
∀[eqs,ineqs:ℤ List List]. ∀[xs:ℤ List].  (satisfies-integer-problem(eqs;ineqs;xs) ∈ ℙ)
Definition: satisfiable-integer-problem
satisfiable(eqs;ineqs) ==  ∃xs:ℤ List. satisfies-integer-problem(eqs;ineqs;xs)
Lemma: satisfiable-integer-problem_wf
∀[eqs,ineqs:ℤ List List].  (satisfiable(eqs;ineqs) ∈ ℙ)
Lemma: satisfiable-pcs-to-integer-problem
∀X:polynomial-constraints()
  (satisfiable_polynomial_constraints(X) 
⇒ satisfiable(fst(pcs-to-integer-problem(X));snd(pcs-to-integer-problem(X))))
Lemma: satisfies-integer-problem-length
∀[eqs,ineqs:ℤ List List]. ∀[xs:ℤ List].
  {(∀e∈eqs.||e|| = ||xs|| ∈ ℤ) ∧ (∀e∈ineqs.||e|| = ||xs|| ∈ ℤ)} supposing satisfies-integer-problem(eqs;ineqs;xs)
Definition: exact-eq-constraint
exact-eq-constraint(eqs;i;j) ==  |eqs[i][j]| = 1 ∈ ℤ
Lemma: exact-eq-constraint_wf
∀[eqs:ℤ List List]. ∀[i:ℕ||eqs||]. ∀[j:ℕ||eqs[i]||].  (exact-eq-constraint(eqs;i;j) ∈ ℙ)
Lemma: exact-eq-constraint-implies
∀[eqs:ℤ List List]. ∀[i:ℕ||eqs||]. ∀[j:ℕ||eqs[i]||].
  ∀ineqs:ℤ List List. ∀xs:ℤ List.
    (satisfies-integer-problem(eqs;ineqs;xs)
    
⇒ (xs[j] = if (eqs[i][j] =z 1) then -1 * eqs[i]\j ⋅ xs\j else eqs[i]\j ⋅ xs\j fi  ∈ ℤ)) 
  supposing exact-eq-constraint(eqs;i;j)
Definition: exact-reduce-constraints
exact-reduce-constraints(w;j;L) ==  evalall(map(λv.-(w[j] * v[j]) * w\j + v\j;L))
Lemma: exact-reduce-constraints_wf
∀[w:ℤ List]. ∀[j:ℕ||w||]. ∀[L:{l:ℤ List| ||l|| = ||w|| ∈ ℤ}  List].
  (exact-reduce-constraints(w;j;L) ∈ {l:ℤ List| ||l|| = (||w|| - 1) ∈ ℤ}  List)
Lemma: exact-reduce-constraints-sqequal
∀[w:ℤ List]. ∀[j:ℕ||w||]. ∀[L:{l:ℤ List| ||l|| = ||w|| ∈ ℤ}  List].
  (exact-reduce-constraints(w;j;L) ~ map(λv.-(w[j] * v[j]) * w\j + v\j;L))
Lemma: satisfiable-exact-reduce-constraints
∀eqs:ℤ List List. ∀i:ℕ||eqs||. ∀j:ℕ+||eqs[i]||.
  ∀ineqs:ℤ List List
    (satisfiable(eqs;ineqs)
    
⇒ satisfiable(exact-reduce-constraints(eqs[i];j;eqs);exact-reduce-constraints(eqs[i];j;ineqs))) 
  supposing exact-eq-constraint(eqs;i;j)
Lemma: satisfiable-elim-eq-constraints
∀eqs,ineqs:ℤ List List. ∀xs:ℤ List.
  (satisfies-integer-problem(eqs;ineqs;xs)
  
⇒ satisfies-integer-problem([];(eager-map(λeq.eager-map(λx.(-x);eq);eqs) @ eqs) @ ineqs;xs))
Definition: gcd-reduce-eq-constraints
Each equality constraint is a list [c,a1,a2,...] and represents the
constraint  c + a1*v1 + a2*v2 + ....  = 0 (on variables v1, v2, ...).
If g = gcd(a1,a2,...) is greater than 1, then if c is not divisible by g
then the constraint is unsatisfiable.
Otherwise we can divide c and all the a1,a2,... by g and preserve
satisfiability.⋅
gcd-reduce-eq-constraints(sat;LL) ==
  accumulate_abort(L,Ls.let h,t = L 
                        in if t = Ax then if h=0 then inl [L / Ls] else (inr ⋅ )
                           otherwise eval g = |gcd-list(t)| in
                                     if (1) < (g)
                                        then if h rem g=0
                                             then eval L' = eager-map(λx.(x ÷ g);L) in
                                                  inl [L' / Ls]
                                             else (inr ⋅ )
                                        else (inl [L / Ls]);inl sat;LL)
Lemma: gcd-reduce-eq-constraints_wf
∀[LL,sat:ℤ List+ List].  (gcd-reduce-eq-constraints(sat;LL) ∈ ℤ List+ List?)
Lemma: member-gcd-reduce-constraints
∀n:ℕ+. ∀eqs,sat:{L:ℤ List| ||L|| = n ∈ ℤ}  List. ∀cc:{L:ℤ List| ||L|| = n ∈ ℤ} .
  ((↑isl(gcd-reduce-eq-constraints(sat;eqs))) 
⇒ (cc ∈ sat) 
⇒ (cc ∈ outl(gcd-reduce-eq-constraints(sat;eqs))))
Lemma: satisfies-gcd-reduce-eq-constraints
∀[n:ℕ+]. ∀[eqs,sat:{L:ℤ List| ||L|| = n ∈ ℤ}  List]. ∀[xs:{L:ℤ List| ||L|| = n ∈ ℤ} ].
  uiff((∀as∈eqs.xs ⋅ as =0);(↑isl(gcd-reduce-eq-constraints(sat;eqs)))
  ∧ (∀as∈outl(gcd-reduce-eq-constraints(sat;eqs)).xs ⋅ as =0)) 
  supposing (∀as∈sat.xs ⋅ as =0) ∧ 0 < ||xs|| ∧ (hd(xs) = 1 ∈ ℤ)
Definition: gcd-reduce-ineq-constraints
Each inequality constraint is a list [c,a1,a2,...] and represents the
constraint  c + a1*v1 + a2*v2 + ....  >= 0 (on variables v1, v2, ...).
If g = gcd(a1,a2,...) is greater than 1 then we
divide all the a1,a2,... by g and replace c by the "floor" of ⌜c ÷ g⌝.
This preserves the satisfiability of the inequality.⋅
gcd-reduce-ineq-constraints(sat;LL) ==
  accumulate_abort(L,Ls.let h,t = L 
                        in if t = Ax then if (h) < (0)  then inr ⋅   else (inl [L / Ls])
                           otherwise eval g = |gcd-list(t)| in
                                     if (1) < (g)
                                        then eval h' = h ÷↓ g in
                                             eval t' = eager-map(λx.(x ÷ g);t) in
                                               inl [[h' / t'] / Ls]
                                        else (inl [L / Ls]);inl sat;LL)
Lemma: gcd-reduce-ineq-constraints_wf
∀[LL,sat:ℤ List+ List].  (gcd-reduce-ineq-constraints(sat;LL) ∈ ℤ List+ List?)
Lemma: member-gcd-reduce-ineq-constraints
∀n:ℕ+. ∀ineqs,sat:{L:ℤ List| ||L|| = n ∈ ℤ}  List. ∀cc:{L:ℤ List| ||L|| = n ∈ ℤ} .
  ((↑isl(gcd-reduce-ineq-constraints(sat;ineqs))) 
⇒ (cc ∈ sat) 
⇒ (cc ∈ outl(gcd-reduce-ineq-constraints(sat;ineqs))))
Lemma: satisfies-gcd-reduce-ineq-constraints
∀[n:ℕ+]. ∀[ineqs,sat:{L:ℤ List| ||L|| = n ∈ ℤ}  List]. ∀[xs:{L:ℤ List| ||L|| = n ∈ ℤ} ].
  uiff((∀as∈ineqs.xs ⋅ as ≥0);(↑isl(gcd-reduce-ineq-constraints(sat;ineqs)))
  ∧ (∀as∈outl(gcd-reduce-ineq-constraints(sat;ineqs)).xs ⋅ as ≥0)) 
  supposing (∀as∈sat.xs ⋅ as ≥0) ∧ 0 < ||xs|| ∧ (hd(xs) = 1 ∈ ℤ)
Definition: shadow-inequalities
For the given index, i, divide the inequality constraints into ,
those where the i-th coefficient is >0, and those where it is <0 
(and ignore -- hence delete -- those where the i-th coefficient is =0)
For each as in the first part and each bs in the second part, form the 
"shadow-vec". The list of all of these is the new set of constraints
in which the i-th variable has been eliminated.
In the worst case, N constraints in k+1 variables can result in
  (N/2)*(N/2) = N^2/4 constraints in k variables. But this does not seem
to happen in practice for typical theorem proving applications.⋅
shadow-inequalities(i;ineqs) ==
  eval Z = evalall(map(λL.L\i;filter(λL.(L[i] =z 0);ineqs))) in
  eager-append(eager-product-map(λas,bs. shadow-vec(i;as;bs);filter(λL.0 <z L[i];ineqs);filter(λL.L[i] <z 0;ineqs));Z)
Lemma: shadow-inequalities_wf
∀[n:ℕ]. ∀[ineqs:{L:ℤ List| ||L|| = n ∈ ℤ}  List]. ∀[i:ℕn].
  (shadow-inequalities(i;ineqs) ∈ {L:ℤ List| ||L|| = (n - 1) ∈ ℤ}  List)
Lemma: satisfies-shadow-inequalities
∀[n:ℕ]. ∀[ineqs:{L:ℤ List| ||L|| = n ∈ ℤ}  List]. ∀[i:ℕ+n]. ∀[xs:ℤ List].
  (∀as∈shadow-inequalities(i;ineqs).xs\i ⋅ as ≥0) supposing (∀as∈ineqs.xs ⋅ as ≥0)
Definition: max_tl_coeffs
max_tl_coeffs(ineqs) ==  eager-accum(L1,ineq.map2(λx,y. imax(x;|y|);L1;tl(ineq));map(λx.|x|;tl(hd(ineqs)));tl(ineqs))
Lemma: max_tl_coeffs_wf
∀[n:ℕ+]. ∀[ineqs:{L:ℤ List| ||L|| = n ∈ ℤ}  List+].  (max_tl_coeffs(ineqs) ∈ {L:ℤ List| ||L|| = (n - 1) ∈ ℤ} )
Definition: shadow_inequalities
Find the variable whose maximum coefficient (in any of the constraints) is
the least, and eliminate that variable by computing its
"shadow inequalities".  This the the heuristic used by Bill Pugh in the 
original version of the omega test.⋅
shadow_inequalities(ineqs) ==
  if ineqs = Ax then ineqs otherwise eval i = index-of-min(max_tl_coeffs(ineqs)) + 1 in
                                     shadow-inequalities(i;ineqs)
Lemma: shadow_inequalities_wf
∀[n:{2...}]. ∀[ineqs:{L:ℤ List| ||L|| = n ∈ ℤ}  List].  (shadow_inequalities(ineqs) ∈ {L:ℤ List| ||L|| = (n - 1) ∈ ℤ}  L\000Cist)
Lemma: satisfies-shadow_inequalities
∀[n:{2...}]
  ∀ineqs:{L:ℤ List| ||L|| = n ∈ ℤ}  List
    ((∃xs:ℤ List. (∀as∈ineqs.xs ⋅ as ≥0)) 
⇒ (∃xs:ℤ List. (∀as∈shadow_inequalities(ineqs).xs ⋅ as ≥0)))
Definition: test-exact-eq-constraint
test-exact-eq-constraint(L) ==
  rec-case(L) of
  [] => inr ⋅ 
  a::as =>
   r.if (|a| =z 1) then inl 0 else case r of inl(n) => inl (n + 1) | inr(x) => inr x  fi 
Lemma: test-exact-eq-constraint_wf
∀[L:ℤ List]. (test-exact-eq-constraint(L) ∈ ∃i:ℕ||L|| [(|L[i]| = 1 ∈ ℤ)]?)
Definition: find-exact-eq-constraint
find-exact-eq-constraint(L) ==
  let a,as = L 
  in case test-exact-eq-constraint(as) of inl(n) => inl <L, n + 1> | inr(x) => inr x 
Lemma: find-exact-eq-constraint_wf
∀[L:ℤ List]. find-exact-eq-constraint(L) ∈ x:{x:ℤ List| x = L ∈ (ℤ List)}  × {i:ℕ+||L||| |L[i]| = 1 ∈ ℤ} ? supposing 0 <\000C ||L||
Definition: int-constraint-problem
IntConstraints ==  ⋃n:ℕ.({L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List × ({L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List))?
Lemma: int-constraint-problem_wf
IntConstraints ∈ Type
Definition: satisfies-int-constraint-problem
xs |= p ==  case p of inl(q) => let eqs,ineqs = q in (∀as∈eqs.xs ⋅ as =0) ∧ (∀bs∈ineqs.xs ⋅ bs ≥0) | inr(_) => False
Lemma: satisfies-int-constraint-problem_wf
∀[p:IntConstraints]. ∀[xs:ℤ List].  (xs |= p ∈ ℙ)
Definition: unsat-int-problem
unsat(p) ==  ∀xs:ℤ List. (¬xs |= p)
Lemma: unsat-int-problem_wf
∀[p:IntConstraints]. (unsat(p) ∈ ℙ)
Definition: int-problem-dimension
If the integer problem is known to be unsatisfiable (the inr case) then 
it has dimension 0. Otherwise, all the constraints are lists of the 
same length, [c,a1,a2,...] representing the linear form 
 c+ a1*v1 + a2*v2 + ....,  so the dimension is the length of (any of) these
lists decremented by 1.⋅
dim(p) ==
  case p
   of inl(q) =>
   let eqs,ineqs = q 
   in if eqs = Ax then if ineqs = Ax then 0 otherwise ||hd(ineqs)|| - 1 otherwise ||hd(eqs)|| - 1
   | inr(_) =>
   0
Lemma: int-problem-dimension_wf
∀[p:IntConstraints]. (dim(p) ∈ ℕ)
Definition: num-eq-constraints
num-eq-constraints(p) ==  case p of inl(q) => ||fst(q)|| | inr(_) => 0
Lemma: num-eq-constraints_wf
∀[p:IntConstraints]. (num-eq-constraints(p) ∈ ℕ)
Definition: rep_int_constraint_step
Keep applying f as long as the dimension of the "integer problem" p is
greater than 0.⋅
rep_int_constraint_step(f;p)==r if (0) < (dim(p))  then let p' ⟵ f p in rep_int_constraint_step(f;p')  else p
Lemma: rep_int_constraint_step_wf
∀[f:IntConstraints ⟶ IntConstraints]. ∀[p:IntConstraints].
  rep_int_constraint_step(f;p) ∈ {p:IntConstraints| dim(p) = 0 ∈ ℤ}  
  supposing ∀p:IntConstraints
              (0 < dim(p)
              
⇒ (dim(f p) < dim(p) ∨ ((dim(f p) = dim(p) ∈ ℤ) ∧ num-eq-constraints(f p) < num-eq-constraints(p))))
Lemma: isr-rep_int_constraint_step
∀[f:IntConstraints ⟶ IntConstraints]. ∀[p:IntConstraints].
  (unsat(p)) supposing 
     ((↑isr(rep_int_constraint_step(f;p))) and 
     ((∀p:IntConstraints
         (0 < dim(p)
         
⇒ (dim(f p) < dim(p) ∨ ((dim(f p) = dim(p) ∈ ℤ) ∧ num-eq-constraints(f p) < num-eq-constraints(p)))))
     ∧ (∀p:IntConstraints. (unsat(f p) 
⇒ unsat(p)))))
Lemma: gcd-reduce-ineq-constraints_wf2
∀[n:ℕ]. ∀[LL,sat:{L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List].
  (gcd-reduce-ineq-constraints(sat;LL) ∈ {L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List?)
Lemma: gcd-reduce-eq-constraints_wf2
∀[n:ℕ]. ∀[LL,sat:{L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List].
  (gcd-reduce-eq-constraints(sat;LL) ∈ {L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List?)
Lemma: exact-reduce-constraints_wf2
∀[n:ℕ]. ∀[w:{l:ℤ List| ||l|| = (n + 1) ∈ ℤ} ]. ∀[j:ℕ||w||]. ∀[L:{l:ℤ List| ||l|| = (n + 1) ∈ ℤ}  List].
  (exact-reduce-constraints(w;j;L) ∈ {l:ℤ List| ||l|| = ((n - 1) + 1) ∈ ℤ}  List)
Definition: omega_step
The "omega step" first searches for an "exact" equality constraint (one where
the coefficient of a variable is 1 or -1). In that case, the constraint can
be solved exactly for that variable, and the variable can be eliminated.
(If that happens, we then run the "gcd-reduce" operations on the resulting
constraints.)
If there is no exact equality constraint, but there are still equality
constraints, then we convert each remaining equality constraints into
two inequality constraints.  (Bill Pugh has a better procedure for
dealing with in-exact equality constraints, but we haven't implemented it.)
If there are no more equality constraints, then omega computes the
"shadow inequalities" for a chosen variable -- which eliminates that variable. 
⋅
omega_step(p) ==
  if (dim(p)) < (1)
     then p
     else case p
           of inl(q) =>
           let eqs,ineqs = q 
           in case first-success(λL.find-exact-eq-constraint(L);eqs)
               of inl(tr) =>
               let i,wj = tr 
               in let w,j = wj 
                  in case gcd-reduce-eq-constraints([];exact-reduce-constraints(w;j;eqs))
                      of inl(eqs') =>
                      case gcd-reduce-ineq-constraints([];exact-reduce-constraints(w;j;ineqs))
                       of inl(ineqs') =>
                       inl <eqs', ineqs'>
                       | inr(x) =>
                       inr x 
                      | inr(x) =>
                      inr x 
               | inr(_) =>
               if null(eqs)
               then case gcd-reduce-ineq-constraints([];shadow_inequalities(ineqs))
                     of inl(ineqs') =>
                     inl <[], ineqs'>
                     | inr(x) =>
                     inr x 
               else inl <[], (eager-map(λeq.eager-map(λx.(-x);eq);eqs) @ eqs) @ ineqs>
               fi 
           | inr(_) =>
           p
Lemma: omega_step_wf
∀[p:IntConstraints]. (omega_step(p) ∈ IntConstraints)
Lemma: omega_step_measure
∀p:IntConstraints
  (0 < dim(p)
  
⇒ (dim((λp.omega_step(p)) p) < dim(p)
     ∨ ((dim((λp.omega_step(p)) p) = dim(p) ∈ ℤ) ∧ num-eq-constraints((λp.omega_step(p)) p) < num-eq-constraints(p))))
Lemma: unsat-omega_step
∀p:IntConstraints. (unsat(omega_step(p)) 
⇒ unsat(p))
Definition: omega_start
To create starting state of omega, we "gcd-reduce" the constraints.
This can sometimes detect that the equality constraints are unsatisfiable.⋅
omega_start(eqs;ineqs) ==
  case gcd-reduce-eq-constraints([];eqs)
   of inl(eqs') =>
   case gcd-reduce-ineq-constraints([];ineqs) of inl(ineqs') => inl <eqs', ineqs'> | inr(x) => inr x 
   | inr(x) =>
   inr x 
Lemma: omega_start_wf
∀[n:ℕ]. ∀[eqs,ineqs:{L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List].  (omega_start(eqs;ineqs) ∈ IntConstraints)
Lemma: unsat-omega_start
∀n:ℕ. ∀eqs,ineqs:{L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List.  (unsat(omega_start(eqs;ineqs)) 
⇒ (¬satisfiable(eqs;ineqs)))
Definition: omega
omega works on an "integer problem" that is a set of equality constraints
and a set of inequality constraints. It start by normalizing the constraints.
Then it repeats the "omega_step". On each step, either the number of 
equality constraints decreases, or the dimension of the problem (the number
of variables) decreases. Thus the algorithm terminates.
Each step preserves satisfiablity of the constraints, meaning that if
the resulting problem is unsatisfiable then the original problem is
unsatisfiable. Because we have not implemented Bill Pugh's "dark shadow"
test, the reverse is not true in general (the reduced problem could be
satisfiable even though the original problem was unsatisfiable).⋅
omega(eqs;ineqs) ==  let s ⟵ omega_start(eqs;ineqs) in rep_int_constraint_step(λp.omega_step(p);s)
Lemma: omega_wf
∀[n:ℕ]. ∀[eqs,ineqs:{L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List].  (omega(eqs;ineqs) ∈ {p:IntConstraints| dim(p) = 0 ∈ ℤ} )
Lemma: isr-omega
∀[n:ℕ]. ∀[eqs,ineqs:{L:ℤ List| ||L|| = (n + 1) ∈ ℤ}  List].  ¬satisfiable(eqs;ineqs) supposing ↑isr(omega(eqs;ineqs))
Definition: full-omega
full-omega works on "integer formulas". It first puts the formula
into a disjunctive-normal-form where each disjunct is a collection
of "polynomial constraints" (a polynomial in the "atoms" of the formula
which is either =0 or >= 0).
Each set of polynomial constraints is "linearized" to a (linear) 
"integer problem", a set of linear forms =0 or >= 0.
omega is run on each of these problems, and if all the results are ff
then the formula is unsatisfiable. If any of the results are tt
then the formlua might be satisfiable, but is not guaranteed to be.
That is because we have not implemented Bill Pugh's "dark shadow" test.
However, for theorem proving, a "semi decision" that can guarantees that
a formula is unsatisfiable seems to be good enough.⋅
full-omega(fmla) ==
  eval dnf = evalall(int_formula_dnf(fmla)) in
  eager-accum(sat,pc.sat
  ∨blet eqs,ineqs = pcs-to-integer-problem(pc) 
    in case omega(eqs;ineqs) of inl(x) => tt | inr(_) => ff;ff;dnf)
Lemma: full-omega_wf
∀[fmla:int_formula()]. (full-omega(fmla) ∈ {b:𝔹| b = ff 
⇒ (¬satisfiable_int_formula(fmla))} )
Lemma: satisfiable-full-omega-tt
∀[fmla:int_formula()]. ↑isl(full-omega(fmla)) supposing satisfiable_int_formula(fmla)
Lemma: full-omega-unsat
∀[fmla:int_formula()]. ¬satisfiable_int_formula(fmla) supposing inr Ax  ≤ full-omega(fmla)
Lemma: test-omega
∀x,y,z:ℤ.  ((1 ≤ ((2 * x) + (2 * y))) 
⇒ ((2 * x) ≤ ((2 * y) + 1)) 
⇒ (2 ≤ (3 * y)))
Lemma: test-omega2
∀p0,p1,q0,q1,r0,r1,t0,t1:ℤ.
  ((((p0 * q1) + (q0 * r1) + (r0 * p1)) - (p1 * q0) + (q1 * r0) + (r1 * p0))
  = ((((t0 * q1) + (q0 * r1) + (r0 * t1)) - (t1 * q0) + (q1 * r0) + (r1 * t0))
    + (((p0 * t1) + (t0 * r1) + (r0 * p1)) - (p1 * t0) + (t1 * r0) + (r1 * p0))
    + (((p0 * q1) + (q0 * t1) + (t0 * p1)) - (p1 * q0) + (q1 * t0) + (t1 * p0)))
  ∈ ℤ)
Lemma: test-omega-auto-split
∀n:ℤ. (if 2 <z n then if 1 <z n then 1 else 2 fi  if n ≤z 3 then 3 else 4 fi  ~ if 2 <z n then 1 else 3 fi )
Definition: ml-int-vec-mul
ml-int-vec-mul(a;as) ==  ml-map(λx.(a * x);as)
Lemma: ml-int-vec-mul_wf
∀[a:ℤ]. ∀[as:ℤ List].  (ml-int-vec-mul(a;as) ∈ ℤ List)
Lemma: ml-int-vec-mul-sq
∀[a:ℤ]. ∀[as:ℤ List].  (ml-int-vec-mul(a;as) ~ a * as)
Definition: ml-int-vec-add
ml-int-vec-add(as;bs) ==
  fix((λivadd,as,bs. if null(as) ∨bnull(bs)
                    then []
                    else let a.as2 = as 
                         in let b.bs2 = bs 
                            in [a + b / ivadd(as2)(bs2)]
                    fi ))(as)(bs)
Lemma: ml-int-vec-add-sq
∀[as,bs:ℤ List].  (ml-int-vec-add(as;bs) ~ as + bs)
Lemma: ml-int-vec-add_wf
∀[as,bs:ℤ List].  (ml-int-vec-add(as;bs) ∈ ℤ List)
Definition: ml-list-delete
ml-list-delete(as;i) ==
  fix((λlistdel,as,i. if null(as)
                     then []
                     else let a.more = as 
                          in if i <z 1 then more else [a / listdel(more)(i - 1)] fi 
                     fi ))(as)(i)
Lemma: ml-list-delete-sq
∀[T:Type]. ∀[L:T List]. ∀[i:ℤ].  (ml-list-delete(L;i) ~ L\i) supposing valueall-type(T)
Lemma: ml-list-delete_wf
∀[T:Type]. ∀[L:T List]. ∀[i:ℤ].  (ml-list-delete(L;i) ∈ T List) supposing valueall-type(T)
Definition: ml-accum-abort
ml-accum-abort(f;sofar;L) ==
  fix((λacca,f,sofar,L. if null(L) ∨bisr(sofar) then sofar else let x.y = L in acca(f)(f(x)(outl(sofar)))(y) fi ))(f)(so\000Cfar)(L)
Lemma: ml-accum-abort-sq
∀[A,B:Type]. ∀[F:A ⟶ B ⟶ (B?)].
  ∀[L:A List]. ∀[s:B?].  (ml-accum-abort(F;s;L) ~ accumulate_abort(x,sofar.F x sofar;s;L)) 
  supposing valueall-type(A) ∧ valueall-type(B) ∧ A ∧ B
Lemma: ml-accum-abort_wf
∀[A,B:Type]. ∀[s:B?]. ∀[F:A ⟶ B ⟶ (B?)]. ∀[L:A List].
  ml-accum-abort(F;s;L) ∈ B? supposing valueall-type(A) ∧ valueall-type(B) ∧ A ∧ B
Definition: ml-gcd-reduce-eq-constraints
ml-gcd-reduce-eq-constraints(sat;LL) ==
  ml-accum-abort(λL,Ls. let h.t = L 
                        in if null(t)
                           then if (h =z 0) then inl [L / Ls] else inr ⋅  fi 
                           else let g = ml-absval(ml-gcd-list(t)) in
                                    if 1 <z g
                                    then if (h rem g =z 0) then inl [ml-map(λx.(x ÷ g);L) / Ls] else inr ⋅  fi 
                                    else inl [L / Ls]
                                    fi 
                           fi inl sat;LL)
Definition: ml-shadow-vec
ml-shadow-vec(i;as;bs) ==
  ml-list-delete(ml-int-vec-add(ml-int-vec-mul(ml-select(i;as);bs);ml-int-vec-mul(-ml-select(i;bs);as));i)
Home
Index