(**
##Interactive Computer Theorem
Proving#
#
CS294-9, Fall 2006#
#
UC Berkeley *)
Require Import Arith Bool List.
Require Import Coq.funind.Recdef.
Require Coq.MSets.MSetPositive.
Require Coq.MSets.MSetProperties.
Require Import Coq.Structures.OrderedTypeEx.
Require Import Coq.Structures.OrdersAlt.
Require Import Coq.Program.Wf.
Require Import Vericertlib.
Module PSet := MSetPositive.PositiveSet.
Module PSetProp := MSetProperties.OrdProperties(PSet).
#[local] Open Scope positive.
(** * Problem Definition *)
Definition var := positive.
(** We identify propositional variables with natural numbers. *)
Definition lit := (bool * var)%type.
(** A literal is a combination of a truth value and a variable. *)
Definition clause := list lit.
(** A clause is a list (disjunction) of literals. *)
Definition formula := list clause.
(** A formula is a list (conjunction) of clauses. *)
Definition asgn := var -> bool.
(** An assignment is a function from variables to their truth values. *)
Definition satLit (l : lit) (a : asgn) :=
a (snd l) = fst l.
(** An assignment satisfies a literal if it maps it to true. *)
Fixpoint satClause (cl : clause) (a : asgn) {struct cl} : Prop :=
match cl with
| nil => False
| l :: cl' => satLit l a \/ satClause cl' a
end.
(** An assignment satisfies a clause if it satisfies at least one of its
literals.
*)
Fixpoint satFormula (fm: formula) (a: asgn) {struct fm} : Prop :=
match fm with
| nil => True
| cl :: fm' => satClause cl a /\ satFormula fm' a
end.
(** An assignment satisfies a formula if it satisfies all of its clauses. *)
(** * Subroutines *)
(** You'll probably want to compare booleans for equality at some point. *)
Definition bool_eq_dec : forall (x y : bool), {x = y} + {x <> y}.
decide equality.
Defined.
(** You'll probably want to compare booleans for equality at some point. *)
Definition boolpositive_eq_dec : forall (x y : (bool * positive)), {x = y} + {x <> y}.
pose proof bool_eq_dec.
pose proof peq.
decide equality.
Defined.
(** A literal and its negation can't be true simultaneously. *)
Lemma contradictory_assignment : forall s l cl a,
s <> fst l
-> satLit l a
-> satLit (s, snd l) a
-> satClause cl a.
intros.
red in H0, H1.
simpl in H1.
subst.
tauto.
Qed.
#[local] Hint Resolve contradictory_assignment : core.
(** Augment an assignment with a new mapping. *)
Definition upd (a : asgn) (l : lit) : asgn :=
fun v : var =>
if peq v (snd l)
then fst l
else a v.
(** Some lemmas about [upd] *)
Lemma satLit_upd_eq : forall l a,
satLit l (upd a l).
unfold satLit, upd; simpl; intros.
destruct (peq (snd l) (snd l)); tauto.
Qed.
#[local] Hint Resolve satLit_upd_eq : core.
Lemma satLit_upd_neq : forall v l s a,
v <> snd l
-> satLit (s, v) (upd a l)
-> satLit (s, v) a.
unfold satLit, upd; simpl; intros.
destruct (peq v (snd l)); tauto.
Qed.
#[local] Hint Resolve satLit_upd_neq : core.
Lemma satLit_upd_neq2 : forall v l s a,
v <> snd l
-> satLit (s, v) a
-> satLit (s, v) (upd a l).
unfold satLit, upd; simpl; intros.
destruct (peq v (snd l)); tauto.
Qed.
#[local] Hint Resolve satLit_upd_neq2 : core.
Lemma satLit_contra : forall s l a cl,
s <> fst l
-> satLit (s, snd l) (upd a l)
-> satClause cl a.
unfold satLit, upd; simpl; intros.
destruct (peq (snd l) (snd l)); intuition.
Qed.
#[local] Hint Resolve satLit_contra : core.
Ltac magic_solver := simpl; intros; subst; intuition eauto; firstorder;
match goal with
| [ H1 : satLit ?l ?a, H2 : satClause ?cl ?a |- _ ] =>
assert (satClause cl (upd a l)); firstorder
end.
(** Strongly-specified function to update a clause to reflect the effect of making a particular
literal true. *)
Definition setClause : forall (cl : clause) (l : lit),
{cl' : clause |
forall a, satClause cl (upd a l) <-> satClause cl' a}
+ {forall a, satLit l a -> satClause cl a}.
refine (fix setClause (cl: clause) (l: lit) {struct cl} :=
match cl with
| nil => inleft (exist _ nil _)
| x :: xs =>
match setClause xs l with
| inright p => inright _
| inleft (exist _ cl' H) =>
match peq (snd x) (snd l), bool_eq_dec (fst x) (fst l) with
| left p_eq, left bool_eq => inright _
| left eq, right ne => inleft (exist _ cl' _)
| right neq, _ => inleft (exist _ (x :: cl') _)
end
end
end); clear setClause; try magic_solver.
- intros; simpl; left; apply injective_projections in bool_eq; subst; auto.
- split; intros. simpl in H0. inversion H0. eapply satLit_contra; eauto.
destruct x; simpl in *; subst. auto.
apply H. eauto.
simpl. right. apply H; eauto.
- split; intros; simpl in *. inversion H0. destruct x; simpl in *; subst.
left. eauto.
right. apply H. eauto.
inversion H0. left. apply satLit_upd_neq2. auto. auto.
right. apply H. auto.
Defined.
(** For testing purposes, we define a weakly-specified function as a thin
wrapper around [setClause].
*)
Definition setClauseSimple (cl : clause) (l : lit) :=
match setClause cl l with
| inleft (exist _ cl' _) => Some cl'
| inright _ => None
end.
(*Eval compute in setClauseSimple ((false, 1%nat) :: nil) (true, 1%nat).*)
(*Eval compute in setClauseSimple nil (true, 0).
Eval compute in setClauseSimple ((true, 0) :: nil) (true, 0).
Eval compute in setClauseSimple ((true, 0) :: nil) (false, 0).
Eval compute in setClauseSimple ((true, 0) :: nil) (true, 1).
Eval compute in setClauseSimple ((true, 0) :: nil) (false, 1).
Eval compute in setClauseSimple ((true, 0) :: (true, 1) :: nil) (true, 1).
Eval compute in setClauseSimple ((true, 0) :: (true, 1) :: nil) (false, 1).
Eval compute in setClauseSimple ((true, 0) :: (false, 1) :: nil) (true, 1).
Eval compute in setClauseSimple ((true, 0) :: (false, 1) :: nil) (false, 1).*)
(** It's useful to have this strongly-specified nilness check. *)
Definition isNil : forall (A : Set) (ls : list A), {ls = nil} + {ls <> nil}.
destruct ls; [left|right]; [auto|]; unfold not; intros; inversion H.
Defined.
Arguments isNil [A].
(** Some more lemmas that I found helpful.... *)
Lemma satLit_idem_lit : forall l a l',
satLit l a
-> satLit l' a
-> satLit l' (upd a l).
unfold satLit, upd; simpl; intros.
destruct (peq (snd l') (snd l)); congruence.
Qed.
#[local] Hint Resolve satLit_idem_lit : core.
Lemma satLit_idem_clause : forall l a cl,
satLit l a
-> satClause cl a
-> satClause cl (upd a l).
induction cl; simpl; intuition.
Qed.
#[local] Hint Resolve satLit_idem_clause : core.
Lemma satLit_idem_formula : forall l a fm,
satLit l a
-> satFormula fm a
-> satFormula fm (upd a l).
induction fm; simpl; intuition.
Qed.
#[local] Hint Resolve satLit_idem_formula : core.
(** Function that updates an entire formula to reflect setting a literal to true. *)
Definition setFormula : forall (fm : formula) (l : lit),
{fm' : formula |
forall a, satFormula fm (upd a l) <-> satFormula fm' a}
+ {forall a, satLit l a -> ~satFormula fm a}.
refine (fix setFormula (fm: formula) (l: lit) {struct fm} :=
match fm with
| nil => inleft (exist _ nil _)
| cl' :: fm' =>
match setFormula fm' l with
| inright p => inright _
| inleft (exist _ fm'' H) =>
match setClause cl' l with
| inright H' => inleft (exist _ fm'' _)
| inleft (exist _ cl'' _) =>
if isNil cl''
then inright _
else inleft (exist _ (cl'' :: fm'') _)
end
end
end); clear setFormula; magic_solver.
Defined.
Definition setFormulaSimple (fm : formula) (l : lit) :=
match setFormula fm l with
| inleft (exist _ fm' _) => Some fm'
| inright _ => None
end.
(* Eval compute in setFormulaSimple (((true, 1%nat) :: nil) :: ((false, 1%nat) :: nil) :: nil) (true, 1%nat). *)
(* Eval compute in setFormulaSimple nil (true, 0). *)
(* Eval compute in setFormulaSimple (((true, 0) :: nil) :: nil) (true, 0). *)
(* Eval compute in setFormulaSimple (((false, 0) :: nil) :: nil) (true, 0). *)
(* Eval compute in setFormulaSimple (((false, 1) :: nil) :: nil) (true, 0). *)
(* Eval compute in setFormulaSimple (((false, 1) :: (true, 0) :: nil) :: nil) (true, 0). *)
(* Eval compute in setFormulaSimple (((false, 1) :: (false, 0) :: nil) :: nil) (true, 0). *)
#[local] Hint Extern 1 False => discriminate : core.
Local Hint Extern 1 False =>
match goal with
| [ H : In _ (_ :: _) |- _ ] => inversion H; clear H; subst
end : core.
(** Code that either finds a unit clause in a formula or declares that there are none. *)
Definition findUnitClause : forall (fm: formula),
{l : lit | In (l :: nil) fm}
+ {forall l, ~In (l :: nil) fm}.
refine (fix findUnitClause (fm: formula) {struct fm} :=
match fm with
| nil => inright _
| (l :: nil) :: fm' => inleft (exist _ l _)
| _ :: fm' =>
match findUnitClause fm' with
| inleft (exist _ l _) => inleft (exist _ l _)
| inright H => inright _
end
end
); clear findUnitClause; magic_solver.
Defined.
(** The literal in a unit clause must always be true in a satisfying assignment. *)
Lemma unitClauseTrue : forall l a fm,
In (l :: nil) fm
-> satFormula fm a
-> satLit l a.
induction fm; intuition.
inversion H.
inversion H; subst; simpl in H0; intuition.
apply IHfm; eauto. inv H0. eauto.
Qed.
#[local] Hint Resolve unitClauseTrue : core.
(** Unit propagation. The return type of [unitPropagate] signifies that three results are possible:
- [None]: There are no unit clauses.
- [Some (inleft _)]: There is a unit clause, and here is a formula reflecting
setting its literal to true.
- [Some (inright _)]: There is a unit clause, and propagating it reveals that
the formula is unsatisfiable.
*)
Definition unitPropagate : forall (fm : formula), option (sigT (fun fm' : formula =>
{l : lit |
(forall a, satFormula fm a -> satLit l a)
/\ forall a, satFormula fm (upd a l) <-> satFormula fm' a})
+ {forall a, ~satFormula fm a}).
refine (fix unitPropagate (fm: formula) {struct fm} :=
match findUnitClause fm with
| inright H => None
| inleft (exist _ l _) =>
match setFormula fm l with
| inright _ => Some (inright _)
| inleft (exist _ fm' _) =>
Some (inleft (existT _ fm' (exist _ l _)))
end
end
); clear unitPropagate; magic_solver.
Defined.
Definition unitPropagateSimple (fm : formula) :=
match unitPropagate fm with
| None => None
| Some (inleft (existT _ fm' (exist _ l _))) => Some (Some (fm', l))
| Some (inright _) => Some None
end.
(*Eval compute in unitPropagateSimple (((true, 1%nat) :: nil) :: ((false, 1%nat) :: nil) :: nil).
Eval compute in unitPropagateSimple nil.
Eval compute in unitPropagateSimple (((true, 0) :: nil) :: nil).
Eval compute in unitPropagateSimple (((true, 0) :: nil) :: ((false, 0) :: nil) :: nil).
Eval compute in unitPropagateSimple (((true, 0) :: nil) :: ((false, 1) :: nil) :: nil).
Eval compute in unitPropagateSimple (((true, 0) :: nil) :: ((false, 0) :: (false, 1) :: nil) :: nil).
Eval compute in unitPropagateSimple (((false, 0) :: (false, 1) :: nil) :: ((true, 0) :: nil) :: nil).*)
(** * The SAT Solver *)
(** This section defines a DPLL SAT solver in terms of the subroutines. *)
(** An arbitrary heuristic to choose the next variable to split on *)
Definition chooseSplit (fm : formula) :=
match fm with
| ((l :: _) :: _) => l
| _ => (true, 1)
end.
Definition negate (l : lit) := (negb (fst l), snd l).
#[local] Hint Unfold satFormula : core.
Lemma satLit_dec : forall l a,
{satLit l a} + {satLit (negate l) a}.
destruct l.
unfold satLit; simpl; intro.
destruct b; destruct (a v); simpl; auto.
Qed.
(** We'll represent assignments as lists of literals instead of functions. *)
Definition alist := list lit.
Fixpoint interp_alist (al : alist) : asgn :=
match al with
| nil => fun _ => true
| l :: al' => upd (interp_alist al') l
end.
(*Eval compute in boundedSatSimple 100 nil.
Eval compute in boundedSatSimple 100 (((true, 1%nat) :: nil) :: ((false, 1%nat) :: nil) :: nil).
Eval compute in boundedSatSimple 100 (((true, 0) :: nil) :: nil).
Eval compute in boundedSatSimple 100 (((true, 0) :: nil) :: ((false, 0) :: nil) :: nil).
Eval compute in boundedSatSimple 100 (((true, 0) :: (false, 1) :: nil) :: ((true, 1) :: nil) :: nil).
Eval compute in boundedSatSimple 100 (((true, 0) :: (false, 1) :: nil) :: ((true, 1) :: (false, 0) :: nil) :: nil).
Eval compute in boundedSatSimple 100 (((true, 0) :: (false, 1) :: nil) :: ((false, 0) :: (false, 0) :: nil) :: ((true, 1) :: nil) :: nil).
Eval compute in boundedSatSimple 100 (((false, 0) :: (true, 1) :: nil) :: ((false, 1) :: (true, 0) :: nil) :: nil).*)
Definition lit_set_cl (cl: clause) :=
fold_right PSet.add PSet.empty (map snd cl).
Lemma lit_set_cl_in_set :
forall cl v,
In v (map snd cl) ->
PSet.In v (lit_set_cl cl).
Proof.
induction cl; crush.
destruct a; cbn [snd] in *; inv H.
- cbn. apply PSetProp.P.FM.add_1; auto.
- cbn. apply PSetProp.P.FM.add_2.
now apply IHcl.
Qed.
Lemma lit_set_cl_not_in_set :
forall cl v,
~ In v (map snd cl) ->
~ PSet.In v (lit_set_cl cl).
Proof.
induction cl; crush.
destruct a; cbn [snd] in *.
assert (p <> v /\ ~ In v (map snd cl))
by (split; unfold not; intros; apply H; tauto).
inv H0. cbn. unfold not; intros.
eapply IHcl; eauto.
unfold lit_set_cl.
eapply PSetProp.P.Dec.F.add_3; eassumption.
Qed.
Definition lit_set (fm: formula) :=
fold_right PSet.union PSet.empty (map lit_set_cl fm).
(* Compute NSet.cardinal (lit_set (((true, 1)::(true, 1)::(true, 1)::nil)::nil)). *)
Definition sat_measure_cl (cl: clause) := PSet.cardinal (lit_set_cl cl).
Definition sat_measure (fm: formula) := PSet.cardinal (lit_set fm).
Lemma elim_clause :
forall (cl: clause) l, In l cl -> exists H, setClause cl l = inright H.
Proof.
induction cl; intros; simpl in *; try contradiction.
destruct (setClause cl l) eqn:?; [|econstructor; eauto].
destruct s. inversion H; subst. clear H.
destruct (peq (snd l) (snd l)); [| contradiction].
destruct (bool_eq_dec (fst l) (fst l)); [| contradiction].
econstructor. eauto. apply IHcl in H0.
inversion H0. rewrite H1 in Heqs. discriminate.
Qed.
Lemma sat_measure_setClause' :
forall cl cl' l A,
setClause cl l = inleft (exist _ cl' A) ->
~ In (snd l) (map snd cl').
Proof.
induction cl; intros.
{ simpl in *. inv H. unfold not in *. intros. inv H. }
simpl in H.
repeat (destruct_match; crush; []). destruct_match.
repeat (destruct_match; crush; []). inv H. eapply IHcl; eauto.
inv H. unfold not. intros. inv H. contradiction. eapply IHcl; eauto.
Qed.
Lemma sat_measure_setClause'' :
forall cl cl' l A,
setClause cl l = inleft (exist _ cl' A) ->
forall l',
l' <> snd l ->
In l' (map snd cl) ->
In l' (map snd cl').
Proof.
induction cl; intros.
{ inversion H1. }
{ inversion H1. subst. simpl in H.
repeat (destruct_match; crush; []). inv H. simpl.
inv H1. eauto. right. eapply IHcl; eauto.
simpl in H. repeat (destruct_match; crush; []). destruct_match.
repeat (destruct_match; crush; []). inv H. eapply IHcl; eauto.
inv H1; crush. inv H. simplify. auto.
inv H. simpl. right. eapply IHcl; eauto.
}
Qed.
Lemma sat_measure_setClause2'' :
forall cl cl' l A,
setClause cl l = inleft (exist _ cl' A) ->
forall l',
l' <> snd l ->
In l' (map snd cl') ->
In l' (map snd cl).
Proof.
induction cl; intros.
{ cbn in *. inv H. cbn in *. auto. }
exploit IHcl; eauto.
Abort.
Lemma sat_measure_setClause :
forall cl cl' l A,
In (snd l) (map snd cl) ->
setClause cl l = inleft (exist _ cl' A) ->
(PSet.cardinal (lit_set_cl cl') < PSet.cardinal (lit_set_cl cl))%nat.
Proof.
intros. pose proof H0. apply sat_measure_setClause' in H0.
pose proof (sat_measure_setClause'' _ _ _ _ H1).
Abort.
Definition InFm l (fm: formula) := exists cl b, In cl fm /\ In (b, l) cl.
Lemma satFormulaHasEmpty :
forall fm,
In nil fm ->
forall a, ~ satFormula fm a.
Proof.
induction fm; crush.
unfold not; intros. inv H0. inv H; auto.
eapply IHfm; eauto.
Qed.
Lemma InFm_chooseSplit :
forall l b c,
InFm (snd (chooseSplit ((l :: b) :: c))) ((l :: b) :: c).
Proof.
simpl; intros. destruct l; cbn.
exists ((b0, v) :: b). exists b0.
split; constructor; auto.
Qed.
Lemma InFm_negated_chooseSplit :
forall l b c,
InFm (snd (negate (chooseSplit ((l :: b) :: c)))) ((l :: b) :: c).
Proof.
simpl; intros. destruct l; cbn.
exists ((b0, v) :: b). exists b0.
split; constructor; auto.
Qed.
Definition hasNoNil : forall fm: formula, {In nil fm} + {~ In nil fm}.
refine (fix hasNoNil (fm: formula) {struct fm} :=
match fm with
| cl :: fm' =>
match isNil cl with
| left clIsNil => left _
| right clIsNotNil =>
match hasNoNil fm' with
| left hasNilfm' => left _
| right hasNoNilfm' => right _
end
end
| nil => right _
end
); auto.
- subst. apply in_eq.
- apply in_cons; assumption.
Defined.
Lemma sat_measure_setClause :
forall cl cl' l b A,
(forall b', ~ In (b', l) cl) ->
setClause cl (b, l) = inleft (exist _ cl' A) ->
lit_set_cl cl = lit_set_cl cl'.
Proof.
induction cl; intros.
- inv H0. auto.
- cbn in H0. repeat (destruct_match; try discriminate; []).
destruct_match.
+ repeat (destruct_match; try discriminate; []).
inv H0. cbn [snd fst] in *.
exfalso.
eapply H. econstructor. auto.
+ repeat (destruct_match; try discriminate; []).
inv H0. cbn [snd fst] in *.
assert (forall b', ~ In (b', l) cl).
{ unfold not; intros. eapply H. apply in_cons. eassumption. }
eapply IHcl in Heqs; [|assumption].
unfold sat_measure_cl. cbn -[PSet.cardinal].
unfold sat_measure_cl in Heqs.
replace (fold_right PSet.add PSet.empty (map snd cl))
with (lit_set_cl cl); auto.
rewrite Heqs. auto.
Qed.
Lemma in_map_snd_forall :
forall A B (cl: list (A * B)) l,
~ In l (map snd cl) ->
(forall b', ~ In (b', l) cl).
Proof.
unfold not; intros; apply H.
replace l with (snd (b', l)) by auto.
now apply in_map.
Qed.
Lemma sat_measure_setClause_In_neq :
forall cl cl' l v b A,
In v (map snd cl) ->
setClause cl (b, l) = inleft (exist _ cl' A) ->
v <> l ->
In v (map snd cl').
Proof.
induction cl; intros.
- inv H0. auto.
- cbn in H0. repeat (destruct_match; try discriminate; []).
destruct_match.
+ repeat (destruct_match; try discriminate; []).
inv H0. cbn [snd fst] in *. eapply IHcl; eauto.
inv H; auto. contradiction.
+ repeat (destruct_match; try discriminate; []).
inv H0. cbn [snd fst] in *.
destruct (peq v v0); subst.
{ now constructor. }
cbn. right. eapply IHcl; eauto. inv H; auto.
contradiction.
Qed.
Lemma sat_measure_setClause_In :
forall cl cl' l b A,
In l (map snd cl) ->
setClause cl (b, l) = inleft (exist _ cl' A) ->
(sat_measure_cl cl' < sat_measure_cl cl)%nat.
Proof.
induction cl; intros.
- crush.
- cbn in H0. repeat (destruct_match; try discriminate; []).
destruct_match.
+ repeat (destruct_match; try discriminate; []).
inv H0. cbn [snd fst] in *. clear Heqs2. clear Heqs1.
inv H; cbn [snd fst] in *.
* destruct (in_dec peq v (map snd cl)).
-- exploit IHcl; eauto; intros. unfold sat_measure_cl in *.
cbn -[PSet.cardinal]. apply lit_set_cl_in_set in i0.
rewrite PSetProp.P.add_cardinal_1; auto.
-- apply sat_measure_setClause in Heqs; [|now apply in_map_snd_forall].
unfold sat_measure_cl in *. cbn -[PSet.cardinal].
setoid_rewrite Heqs.
apply lit_set_cl_not_in_set in n0.
rewrite PSetProp.P.add_cardinal_2; auto.
now rewrite <- Heqs.
* exploit IHcl; eauto; intros. unfold sat_measure_cl in *.
cbn. rewrite PSetProp.P.add_cardinal_1; auto.
now apply lit_set_cl_in_set.
+ repeat (destruct_match; try discriminate; []). inv H0.
cbn [snd fst] in *. cbn in H. inv H; [contradiction|].
exploit IHcl; eauto; intros.
unfold sat_measure_cl in *. cbn.
destruct (in_dec peq v (map snd cl)); destruct (in_dec peq v (map snd x)).
* apply lit_set_cl_in_set in i0. apply lit_set_cl_in_set in i1.
repeat rewrite PSetProp.P.add_cardinal_1 by auto. auto.
* exploit sat_measure_setClause_In_neq. eapply i0. eauto. auto. intros.
contradiction.
* apply lit_set_cl_in_set in i0. apply lit_set_cl_not_in_set in n0.
rewrite PSetProp.P.add_cardinal_1 by auto.
rewrite PSetProp.P.add_cardinal_2 by auto. unfold lit_set_cl in *; lia.
* apply lit_set_cl_not_in_set in n0. apply lit_set_cl_not_in_set in n1.
repeat rewrite PSetProp.P.add_cardinal_2 by auto.
unfold lit_set_cl in *; lia.
Qed.
(* Lemma sat_measure_setFormula :
forall cl cl' l b b' A,
In (b', l) cl ->
setClause cl (b, l) = inleft (exist _ cl' A) ->
(sat_measure_cl cl' < sat_measure_cl cl)%nat.
Proof.
induction cl; intros.
- crush.
- cbn in H0. repeat (destruct_match; try discriminate; []).
destruct_match.
+ repeat (destruct_match; try discriminate; []).
inv H0. cbn [snd fst] in *.*)
Lemma sat_measure_setFormula :
forall fm fm' l b A,
InFm l fm ->
setFormula fm (b, l) = inleft (exist _ fm' A) ->
(sat_measure fm' < sat_measure fm)%nat.
Proof.
induction fm.
- intros. inv H. inv H1. inv H. inv H1.
- intros. unfold sat_measure, lit_set. cbn -[PSet.cardinal].
Admitted.
Lemma sat_measure_propagate_unit :
forall fm' fm H,
unitPropagate fm = Some (inleft (existT _ fm' H)) ->
(sat_measure fm' < sat_measure fm)%nat.
Proof.
induction fm; crush.
repeat (destruct_match; crush; []).
destruct_match.
repeat (destruct_match; crush; []).
inv Heqs1.
unfold sat_measure.
Admitted.
Program Fixpoint satSolve (fm: formula) { measure (sat_measure fm) }:
{al : alist | satFormula fm (interp_alist al)} + {forall a, ~satFormula fm a} :=
match isNil fm with
| left fmIsNil => inleft _ (exist _ nil _)
| right fmIsNotNil =>
match hasNoNil fm with
| left hasNilfm => inright _ _
| right hasNoNilfm =>
match unitPropagate fm with
| Some (inleft (existT _ fm' (exist _ l _))) =>
match satSolve fm' with
| inleft (exist _ al _) => inleft _ (exist _ (l :: al) _)
| inright _ => inright _ _
end
| Some (inright _) => inright _ _
| None =>
let l := chooseSplit fm in
match setFormula fm l with
| inleft (exist _ fm' _) =>
match satSolve fm' with
| inleft (exist _ al _) => inleft _ (exist _ (l :: al) _)
| inright _ =>
match setFormula fm (negate l) with
| inleft (exist _ fm' _) =>
match satSolve fm' with
| inleft (exist _ al _) => inleft _ (exist _ (negate l :: al) _)
| inright _ => inright _ _
end
| inright _ => inright _ _
end
end
| inright _ =>
match setFormula fm (negate l) with
| inleft (exist _ fm' _) =>
match satSolve fm' with
| inleft (exist _ al _) => inleft _ (exist _ (negate l :: al) _)
| inright _ => inright _ _
end
| inright _ => inright _ _
end
end
end
end
end.
Next Obligation.
apply satFormulaHasEmpty; assumption. Defined.
Next Obligation.
eapply sat_measure_propagate_unit; eauto. Defined.
Next Obligation.
apply i; auto. Defined.
Next Obligation.
unfold not; intros; eapply wildcard'; apply i; eauto. Defined.
Next Obligation.
intros. symmetry in Heq_anonymous.
destruct (chooseSplit fm) eqn:?.
apply sat_measure_setFormula in Heq_anonymous; auto. unfold isNil in *.
destruct fm; try discriminate.
assert (c <> nil).
{ unfold not; intros. apply hasNoNilfm. constructor; auto. }
destruct c; try discriminate.
replace p with (snd (b, p)) by auto. rewrite <- Heqp.
apply InFm_chooseSplit. Defined.
Next Obligation.
apply wildcard'0; auto. Defined.
Next Obligation.
eapply sat_measure_setFormula; eauto.
destruct fm; try discriminate. destruct c; try discriminate.
apply InFm_chooseSplit. Defined.
Next Obligation.
apply wildcard'2; auto. Defined.
Next Obligation.
unfold not in *; intros.
destruct (satLit_dec (chooseSplit fm) a);
[assert (satFormula fm (upd a (chooseSplit fm)))
| assert (satFormula fm (upd a (negate (chooseSplit fm))))]; firstorder.
{ eapply wildcard'1. apply wildcard'0; eauto. }
{ eapply wildcard'. apply wildcard'2; eauto. }
Defined.
Next Obligation.
unfold not in *; intros.
destruct (satLit_dec (chooseSplit fm) a);
[assert (satFormula fm (upd a (chooseSplit fm)))
| assert (satFormula fm (upd a (negate (chooseSplit fm))))]; firstorder.
{ eapply wildcard'1. eapply wildcard'0. eauto. }
{ eapply wildcard'; eauto. }
Defined.
Next Obligation.
eapply sat_measure_setFormula; eauto.
destruct fm; try discriminate. destruct c; try discriminate.
apply InFm_chooseSplit. Defined.
Next Obligation.
apply wildcard'1; auto. Defined.
Next Obligation.
unfold not in *; intros.
destruct (satLit_dec (chooseSplit fm) a);
[assert (satFormula fm (upd a (chooseSplit fm)))
| assert (satFormula fm (upd a (negate (chooseSplit fm))))]; firstorder.
{ eapply wildcard'0; eauto. }
{ eapply wildcard'; apply wildcard'1; eauto. }
Defined.
Next Obligation.
unfold not in *; intros.
destruct (satLit_dec (chooseSplit fm) a).
{ eapply wildcard'0; eauto. }
{ eapply wildcard'; eauto. }
Defined.
Definition satSolveSimple (fm : formula) :=
match satSolve fm with
| inleft (exist _ a _) => Some a
| inright _ => None
end.
(* Eval compute in satSolveSimple nil. *)