(* Quantifier-free formula are normalized into DNF. A DNF is *)
(* represented by the type seq (seq (term R) * seq (term R)), where we *)
(* separate positive and negative literals *)
(* DNF preserving conjunction *)
Definition and_dnf bcs1 bcs2 :=
\big[cat/nil]_(bc1 <- bcs1)
map (fun bc2 => (bc1.1 ++ bc2.1, bc1.2 ++ bc2.2)) bcs2.
(* Computes a DNF from a qf ring formula *)
Fixpoint qf_to_dnf (f : formula R) (neg : bool) {struct f} :=
match f with
| Bool b => if b (+) neg then [:: ([::], [::])] else [::]
| t1 == t2 => [:: if neg then ([::], [:: t1 - t2]) else ([:: t1 - t2], [::])]
| f1 /\ f2 => (if neg then cat else and_dnf) [rec f1, neg] [rec f2, neg]
| f1 \/ f2 => (if neg then and_dnf else cat) [rec f1, neg] [rec f2, neg]
| f1 ==> f2 => (if neg then and_dnf else cat) [rec f1, ~~ neg] [rec f2, neg]
| ~ f1 => [rec f1, ~~ neg]
| _ =>  if neg then [:: ([::], [::])] else [::]
end%T where "[ 'rec' f , neg ]" := (qf_to_dnf f neg).
(* Conversely, transforms a DNF into a formula *)
Definition dnf_to_form :=
let pos_lit t := And (t == 0) in let neg_lit t := And (t != 0) in
let cls bc := Or (foldr pos_lit True bc.1 /\ foldr neg_lit True bc.2) in
foldr cls False.

(* Catenation of dnf is the Or of formulas *)
Lemma cat_dnfP e bcs1 bcs2 :
qf_eval e (dnf_to_form (bcs1 ++ bcs2))
= qf_eval e (dnf_to_form bcs1 \/ dnf_to_form bcs2).