vericert.hls.Predicate



Definition predicate : Type := positive.

Inductive pred_op : Type :=
| Plit: (bool * predicate) -> pred_op
| Ptrue: pred_op
| Pfalse: pred_op
| Pand: pred_op -> pred_op -> pred_op
| Por: pred_op -> pred_op -> pred_op.


Notation "A ∧ B" := (Pand A B) (at level 20) : pred_op.
Notation "A ∨ B" := (Por A B) (at level 25) : pred_op.
Notation "⟂" := (Pfalse) : pred_op.
Notation "'T'" := (Ptrue) : pred_op.

#[local] Open Scope pred_op.

Fixpoint sat_predicate (p: pred_op) (a: asgn) : bool :=
  match p with
  | Plit (b, p') => if b then a (Pos.to_nat p') else negb (a (Pos.to_nat p'))
  | Ptrue => true
  | Pfalse => false
  | Pand p1 p2 => sat_predicate p1 a && sat_predicate p2 a
  | Por p1 p2 => sat_predicate p1 a || sat_predicate p2 a
  end.

Definition sat_equiv p1 p2 := forall c, sat_predicate p1 c = sat_predicate p2 c.

Lemma equiv_symm : forall a b, sat_equiv a b -> sat_equiv b a.

Lemma equiv_trans : forall a b c, sat_equiv a b -> sat_equiv b c -> sat_equiv a c.

Lemma equiv_refl : forall a, sat_equiv a a.

#[global]
Instance Equivalence_SAT : Equivalence sat_equiv :=
  { Equivalence_Reflexive := equiv_refl ;
    Equivalence_Symmetric := equiv_symm ;
    Equivalence_Transitive := equiv_trans ;
  }.

#[global]
Instance SATSetoid : Setoid pred_op :=
  { equiv := sat_equiv; }.

#[global]
Instance PandProper : Proper (equiv ==> equiv ==> equiv) Pand.

#[global]
Instance PorProper : Proper (equiv ==> equiv ==> equiv) Por.

#[global]
Instance sat_predicate_Proper : Proper (equiv ==> eq ==> eq) sat_predicate.

Fixpoint negate (p: pred_op) :=
  match p with
  | Plit (b, pr) => Plit (negb b, pr)
  | T =>
  | => T
  | A B => negate A negate B
  | A B => negate A negate B
  end.

Notation "¬ A" := (negate A) (at level 15) : pred_op.

Lemma negate_correct :
  forall h a, sat_predicate (negate h) a = negb (sat_predicate h a).

Definition unsat p := forall a, sat_predicate p a = false.
Definition sat p := exists a, sat_predicate p a = true.

Lemma unsat_correct1 :
  forall a b c,
    unsat (Pand a b) ->
    sat_predicate a c = true ->
    sat_predicate b c = false.

Lemma unsat_correct2 :
  forall a b c,
    unsat (Pand a b) ->
    sat_predicate b c = true ->
    sat_predicate a c = false.

Lemma unsat_not a: unsat (a (¬ a)).

Lemma unsat_commut a b: unsat (a b) -> unsat (b a).

Lemma sat_imp_equiv :
  forall a b,
    unsat (a ¬ b ¬ a b) -> a == b.

Lemma sat_predicate_and :
  forall a b c,
    sat_predicate (a b) c = sat_predicate a c && sat_predicate b c.

Lemma sat_predicate_or :
  forall a b c,
    sat_predicate (a b) c = sat_predicate a c || sat_predicate b c.

Lemma sat_equiv2 :
  forall a b,
    a == b -> unsat (a ¬ b ¬ a b).

Lemma sat_equiv3 :
  forall a b,
    unsat (a ¬ b b ¬ a) -> a == b.

Lemma sat_equiv4 :
  forall a b,
    a == b -> unsat (a ¬ b b ¬ a).

Definition simplify' (p: pred_op) :=
  match p with
  | (Plit (b1, a)) (Plit (b2, b)) as p' =>
      if Pos.eqb a b then
        if negb (xorb b1 b2) then Plit (b1, a) else
      else p'
  | (Plit (b1, a)) (Plit (b2, b)) as p' =>
      if Pos.eqb a b then
        if negb (xorb b1 b2) then Plit (b1, a) else T
      else p'
  | A T => A
  | T A => A
  | _ =>
  | _ =>
  | _ T => T
  | T _ => T
  | A => A
  | A => A
  | A => A
  end.

Lemma pred_op_dec :
  forall p1 p2: pred_op,
  { p1 = p2 } + { p1 <> p2 }.

Fixpoint simplify (p: pred_op) :=
  match p with
  | A B =>
    let A' := simplify A in
    let B' := simplify B in
    simplify' (A' B')
  | A B =>
    let A' := simplify A in
    let B' := simplify B in
    simplify' (A' B')
  | T => T
  | =>
  | Plit a => Plit a
  end.

Lemma simplify'_correct :
  forall h a,
    sat_predicate (simplify' h) a = sat_predicate h a.

Lemma simplify_correct :
  forall h a,
    sat_predicate (simplify h) a = sat_predicate h a.

Fixpoint mult {A: Type} (a b: list (list A)) : list (list A) :=
  match a with
  | nil => nil
  | l :: ls => mult ls b ++ (List.map (fun x => l ++ x) b)
  end.

Lemma satFormula_concat:
  forall a b agn,
  satFormula a agn ->
  satFormula b agn ->
  satFormula (a ++ b) agn.

Lemma satFormula_concat2:
  forall a b agn,
  satFormula (a ++ b) agn ->
  satFormula a agn /\ satFormula b agn.

Lemma satClause_concat:
  forall a a1 a0,
  satClause a a1 ->
  satClause (a0 ++ a) a1.

Lemma satClause_concat2:
  forall a a1 a0,
  satClause a0 a1 ->
  satClause (a0 ++ a) a1.

Lemma satClause_concat3:
  forall a b c,
  satClause (a ++ b) c ->
  satClause a c \/ satClause b c.

Lemma satFormula_mult':
  forall p2 a a0,
  satFormula p2 a0 \/ satClause a a0 ->
  satFormula (map (fun x : list lit => a ++ x) p2) a0.

Lemma satFormula_mult2':
  forall p2 a a0,
  satFormula (map (fun x : list lit => a ++ x) p2) a0 ->
  satClause a a0 \/ satFormula p2 a0.

Lemma satFormula_mult:
  forall p1 p2 a,
  satFormula p1 a \/ satFormula p2 a ->
  satFormula (mult p1 p2) a.

Lemma satFormula_mult2:
  forall p1 p2 a,
  satFormula (mult p1 p2) a ->
  satFormula p1 a \/ satFormula p2 a.

Fixpoint trans_pred (p: pred_op) :
  {fm: formula | forall a,
      sat_predicate p a = true <-> satFormula fm a}.
Defined.

Definition bar (p1: lit): lit := (negb (fst p1), (snd p1)).

Definition stseytin_or (cur p1 p2: lit) : formula :=
  (bar cur :: p1 :: p2 :: nil)
    :: (cur :: bar p1 :: nil)
    :: (cur :: bar p2 :: nil) :: nil.

Definition stseytin_and (cur p1 p2: lit) : formula :=
  (cur :: bar p1 :: bar p2 :: nil)
    :: (bar cur :: p1 :: nil)
    :: (bar cur :: p2 :: nil) :: nil.

Fixpoint xtseytin (next: nat) (p: pred_op) {struct p} : (nat * lit * formula) :=
  match p with
  | Plit (b, p') => (next, (b, Pos.to_nat p'), nil)
  | Ptrue =>
      ((next+1)%nat, (true, next), ((true, next)::nil)::nil)
  | Pfalse =>
      ((next+1)%nat, (true, next), ((false, next)::nil)::nil)
  | Por p1 p2 =>
      let '(m1, n1, f1) := xtseytin next p1 in
      let '(m2, n2, f2) := xtseytin m1 p2 in
      ((m2+1)%nat, (true, m2), stseytin_or (true, m2) n1 n2 ++ f1 ++ f2)
  | Pand p1 p2 =>
      let '(m1, n1, f1) := xtseytin next p1 in
      let '(m2, n2, f2) := xtseytin m1 p2 in
      ((m2+1)%nat, (true, m2), stseytin_and (true, m2) n1 n2 ++ f1 ++ f2)
  end.

Lemma stseytin_and_correct :
  forall cur p1 p2 fm c,
    stseytin_and cur p1 p2 = fm ->
    satLit cur c ->
    satLit p1 c /\ satLit p2 c ->
    satFormula fm c.

Lemma stseytin_and_correct2 :
  forall cur p1 p2 fm c,
    stseytin_and cur p1 p2 = fm ->
    satFormula fm c ->
    satLit cur c <-> satLit p1 c /\ satLit p2 c.

Lemma stseytin_or_correct :
  forall cur p1 p2 fm c,
    stseytin_or cur p1 p2 = fm ->
    satLit cur c ->
    satLit p1 c \/ satLit p2 c ->
    satFormula fm c.

Lemma stseytin_or_correct2 :
  forall cur p1 p2 fm c,
    stseytin_or cur p1 p2 = fm ->
    satFormula fm c ->
    satLit cur c <-> satLit p1 c \/ satLit p2 c.

Lemma xtseytin_correct :
  forall p next l n fm c,
    xtseytin next p = (n, l, fm) ->
    sat_predicate p c = true <-> satFormula ((l::nil)::fm) c.

Fixpoint max_predicate (p: pred_op) : positive :=
  match p with
  | Plit (b, p) => p
  | Ptrue => 1
  | Pfalse => 1
  | Pand a b => Pos.max (max_predicate a) (max_predicate b)
  | Por a b => Pos.max (max_predicate a) (max_predicate b)
  end.

Definition tseytin (p: pred_op) :
  {fm: formula | forall a,
      sat_predicate p a = true <-> satFormula fm a}.


Definition tseytin_simple (p: pred_op) : formula :=
    let m := Pos.to_nat (max_predicate p + 1) in
    let '(m, n, fm) := xtseytin m p in
    (n::nil) :: fm.

Definition sat_pred_tseytin (p: pred_op) :
  ({al : alist | sat_predicate p (interp_alist al) = true}
   + {forall a : asgn, sat_predicate p a = false}).
Defined.

Definition sat_pred_simple (p: pred_op) : option alist :=
  match sat_pred_tseytin p with
  | inleft (exist _ a _) => Some a
  | inright _ => None
  end.

Definition sat_pred (p: pred_op) :
  ({al : alist | sat_predicate p (interp_alist al) = true}
   + {forall a : asgn, sat_predicate p a = false}).
Defined.

#[local] Open Scope positive.


Lemma sat_dec a: {sat a} + {unsat a}.

Definition equiv_check p1 p2 :=
  match sat_pred_simple (simplify (p1 ¬ p2 p2 ¬ p1)) with
  | None => true
  | _ => false
  end.


Lemma equiv_check_correct :
  forall p1 p2, equiv_check p1 p2 = true -> p1 == p2.


Lemma equiv_check_correct2 :
  forall p1 p2, p1 == p2 -> equiv_check p1 p2 = true.

Lemma equiv_check_dec :
  forall p1 p2, equiv_check p1 p2 = true <-> p1 == p2.

Lemma equiv_check_decidable :
  forall p1 p2, decidable (p1 == p2).

Lemma equiv_check_decidable2 :
  forall p1 p2, {p1 == p2} + {p1 =/= p2}.

#[global]
Instance DecidableSATSetoid : DecidableSetoid SATSetoid :=
  { setoid_decidable := equiv_check_decidable }.

#[global]
Instance SATSetoidEqDec : EqDec SATSetoid := equiv_check_decidable2.

Definition Pimplies p p' := ¬ p p'.

Notation "A → B" := (Pimplies A B) (at level 30) : pred_op.

Definition implies p p' :=
  forall c, sat_predicate p c = true -> sat_predicate p' c = true.

Notation "A ⇒ B" := (implies A B) (at level 35) : pred_op.

Lemma Pimplies_implies: forall p p', (p p') p p'.

#[global]
Instance PimpliesProper : Proper (equiv ==> equiv ==> equiv) Pimplies.

#[global]
Instance simplifyProper : Proper (equiv ==> equiv) simplify.