(* 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.

(* Specifications: *)
(* 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).
(* and_dnf is the And of formulas *)
Lemma and_dnfP e bcs1 bcs2 :
qf_eval e (dnf_to_form (and_dnf bcs1 bcs2))
= qf_eval e (dnf_to_form bcs1 /\ dnf_to_form bcs2).
Lemma qf_to_dnfP e :
let qev f b := qf_eval e (dnf_to_form (qf_to_dnf f b)) in
forall f, qf_form f && rformula f -> qev f false = qf_eval e f.
Lemma dnf_to_form_qf bcs : qf_form (dnf_to_form bcs).
Definition dnf_rterm cl := all rterm cl.1 && all rterm cl.2.
Lemma qf_to_dnf_rterm f b : rformula f -> all dnf_rterm (qf_to_dnf f b).
Lemma dnf_to_rform bcs : rformula (dnf_to_form bcs) = all dnf_rterm bcs.
Section If.