(**************************************************************************) (* *) (* SMTCoq *) (* Copyright (C) 2011 - 2022 *) (* *) (* See file "AUTHORS" for the list of authors *) (* *) (* This file is distributed under the terms of the CeCILL-C licence *) (* *) (**************************************************************************) Require Import PArray List Bool ZArith Psatz. Require Import Misc State SMT_terms BVList. Import Form. Local Open Scope array_scope. Local Open Scope int63_scope. Set Implicit Arguments. Unset Strict Implicit. Definition or_of_imp args := let last := PArray.length args - 1 in amapi (fun i l => if i =? last then l else Lit.neg l) args. (* Register or_of_imp as PrimInline. *) Lemma length_or_of_imp : forall args, PArray.length (or_of_imp args) = PArray.length args. Proof. intro; unfold or_of_imp; apply length_amapi. Qed. Lemma get_or_of_imp : forall args i, i (or_of_imp args).[i] = Lit.neg (args.[i]). Proof. unfold or_of_imp; intros args i H; case_eq (0 i = (PArray.length args) - 1 -> (or_of_imp args).[i] = args.[i]. Proof. unfold or_of_imp; intros args i Heq Hi; rewrite get_amapi; subst i. rewrite Int63.eqb_refl; auto. rewrite ltb_spec, (to_Z_sub_1 _ _ Heq); lia. Qed. Lemma afold_right_impb p a : (forall x, p (Lit.neg x) = negb (p x)) -> (PArray.length a =? 0) = false -> (afold_right bool true implb (amap p a)) = List.existsb p (to_list (or_of_imp a)). Proof. intros Hp Hl. case_eq (afold_right bool true implb (amap p a)); intro Heq; symmetry. - apply afold_right_implb_true_inv in Heq. rewrite length_amap in Heq. destruct Heq as [Heq|[[i [Hi Heq]]|Heq]]. + rewrite Heq in Hl. discriminate. + rewrite get_amap in Heq. rewrite existsb_exists. exists (Lit.neg (a .[ i])). split. * { apply (to_list_In_eq _ i). - rewrite length_or_of_imp. apply (ltb_trans _ (PArray.length a - 1)); auto. now apply minus_1_lt. - now rewrite get_or_of_imp. } * now rewrite Hp, Heq. * apply (ltb_trans _ (PArray.length a - 1)); auto. now apply minus_1_lt. + rewrite existsb_exists. exists (a.[(PArray.length a) - 1]). split. * { apply (to_list_In_eq _ (PArray.length a - 1)). - rewrite length_or_of_imp. now apply minus_1_lt. - symmetry. apply get_or_of_imp2; auto. unfold is_true. rewrite ltb_spec. rewrite eqb_false_spec in Hl. assert (0%Z <> [|PArray.length a|]) by (change 0%Z with [|0|]; intro H; apply to_Z_inj in H; auto). destruct (to_Z_bounded (PArray.length a)) as [H1 _]. clear -H H1. change [|0|] with 0%Z. lia. } * { specialize (Heq (PArray.length a - 1)); rewrite get_amap in Heq by now apply minus_1_lt. apply Heq. now apply minus_1_lt. } - apply afold_right_implb_false_inv in Heq. destruct Heq as [H1 [H2 H3]]. rewrite length_amap in H1, H3. case_eq (List.existsb p (to_list (or_of_imp a))); auto. rewrite existsb_exists. intros [x [H4 H5]]. apply In_to_list in H4. destruct H4 as [i [H4 ->]]. case_eq (i if Lit.is_pos l then l :: List.map Lit.neg (to_list args) else C._true | For args => if Lit.is_pos l then C._true else l :: to_list args | Fimp args => if Lit.is_pos l then C._true else if PArray.length args =? 0 then C._true else let args := or_of_imp args in l :: to_list args | Fxor a b => if Lit.is_pos l then l::a::Lit.neg b::nil else l::a::b::nil | Fiff a b => if Lit.is_pos l then l::Lit.neg a::Lit.neg b::nil else l::a::Lit.neg b::nil | Fite a b c => if Lit.is_pos l then l::a::Lit.neg c::nil else l::a::c::nil | _ => C._true end. (* * not_and : {(not (and a_1 ... a_n))} --> {(not a_1) ... (not a_n)} * or : {(or a_1 ... a_n)} --> {a_1 ... a_n} * implies : {(implies a b)} --> {(not a) b} * xor1 : {(xor a b)} --> {a b} * not_xor1 : {(not (xor a b))} --> {a (not b)} * equiv2 : {(iff a b)} --> {a (not b)} * not_equiv2 : {(not (iff a b))} --> {(not a) (not b)} * ite1 : {(if_then_else a b c)} --> {a c} * not_ite1 : {(not (if_then_else a b c))} --> {a (not c)} *) Definition check_ImmBuildDef pos := match S.get s pos with | l::nil => match get_hash (Lit.blit l) with | Fand args => if Lit.is_pos l then C._true else List.map Lit.neg (to_list args) | For args => if Lit.is_pos l then to_list args else C._true | Fimp args => if PArray.length args =? 0 then C._true else if Lit.is_pos l then let args := or_of_imp args in to_list args else C._true | Fxor a b => if Lit.is_pos l then a::b::nil else a::Lit.neg b::nil | Fiff a b => if Lit.is_pos l then a::Lit.neg b::nil else Lit.neg a::Lit.neg b::nil | Fite a b c => if Lit.is_pos l then a::c::nil else a::Lit.neg c::nil | _ => C._true end | _ => C._true end. (* * xor_pos2 : {(not (xor a b)) (not a) (not b)} * xor_neg2 : {(xor a b) (not a) b} * equiv_pos2 : {(not (iff a b)) (not a) b} * equiv_neg2 : {(iff a b) a b} * ite_pos2 : {(not (if_then_else a b c)) (not a) b} * ite_neg2 : {(if_then_else a b c) (not a) (not b)} *) Definition check_BuildDef2 l := match get_hash (Lit.blit l) with | Fxor a b => if Lit.is_pos l then l::Lit.neg a::b::nil else l::Lit.neg a::Lit.neg b::nil | Fiff a b => if Lit.is_pos l then l::a::b::nil else l::Lit.neg a::b::nil | Fite a b c => if Lit.is_pos l then l::Lit.neg a::Lit.neg b::nil else l::Lit.neg a::b::nil | _ => C._true end. (* * xor2 : {(xor a b)} --> {(not a) (not b)} * not_xor2 : {(not (xor a b))} --> {(not a) b} * equiv1 : {(iff a b)} --> {(not a) b} * not_equiv1 : {(not (iff a b))} --> {a b} * ite2 : {(if_then_else a b c)} --> {(not a) b} * not_ite2 : {(not (if_then_else a b c))} --> {(not a) (not b)} *) Definition check_ImmBuildDef2 pos := match S.get s pos with | l::nil => match get_hash (Lit.blit l) with | Fxor a b => if Lit.is_pos l then Lit.neg a::Lit.neg b::nil else Lit.neg a::b::nil | Fiff a b => if Lit.is_pos l then Lit.neg a::b::nil else a::b::nil | Fite a b c => if Lit.is_pos l then Lit.neg a::b::nil else Lit.neg a::Lit.neg b::nil | _ => C._true end | _ => C._true end. (* * or_neg : {(or a_1 ... a_n) (not a_i)} * and_pos : {(not (and a_1 ... a_n)) a_i} * implies_neg1 : {(implies a b) a} * implies_neg2 : {(implies a b) (not b)} *) Definition check_BuildProj l i := let x := Lit.blit l in match get_hash x with | For args => if i if i let len := PArray.length args in if i C._true end. (* * and : {(and a_1 ... a_n)} --> {a_i} * not_or : {(not (or a_1 ... a_n))} --> {(not a_i)} * not_implies1 : {(not (implies a b))} --> {a} * not_implies2 : {(not (implies a b))} --> {(not b)} *) Definition check_ImmBuildProj pos i := match S.get s pos with | l::nil => let x := Lit.blit l in match get_hash x with | For args => if (i if (i let len := PArray.length args in if (i C._true end | _ => C._true end. (** The correctness proofs *) Variable interp_atom : atom -> bool. Variable interp_bvatom : atom -> forall s, BITVECTOR_LIST.bitvector s. Hypothesis Hch_f : check_form t_form. Local Notation rho := (Form.interp_state_var interp_atom interp_bvatom t_form). Let Hwfrho : Valuation.wf rho. Proof. destruct (check_form_correct interp_atom interp_bvatom _ Hch_f) as (_, H);exact H. Qed. Lemma valid_check_True : C.valid rho check_True. Proof. apply C.interp_true;trivial. Qed. Lemma valid_check_False : C.valid rho check_False. Proof. unfold check_False, C.valid. change (Lit.interp rho (Lit.neg Lit._false) || false = true). rewrite Lit.interp_neg. assert (W:= Lit.interp_false _ Hwfrho). destruct (Lit.interp rho Lit._false);trivial;elim W;red;trivial. Qed. Let rho_interp : forall x : int, rho x = interp interp_atom interp_bvatom t_form (t_form.[ x]). Proof. destruct (check_form_correct interp_atom interp_bvatom _ Hch_f) as ((H,H0), _). intros x;apply wf_interp_form;trivial. Qed. Ltac tauto_check := try (rewrite !Lit.interp_neg); repeat match goal with |- context [Lit.interp rho ?x] => destruct (Lit.interp rho x);trivial end. Lemma valid_check_BuildDef : forall l, C.valid rho (check_BuildDef l). Proof. unfold check_BuildDef,C.valid;intros l. case_eq (t_form.[Lit.blit l]);intros;auto using C.interp_true; case_eq (Lit.is_pos l);intros Heq;auto using C.interp_true;simpl; try (unfold Lit.interp at 1;rewrite Heq;unfold Var.interp; rewrite rho_interp, H;simpl; tauto_check). - rewrite afold_left_and, C.Cinterp_neg;apply orb_negb_r. - rewrite afold_left_or, orb_comm;apply orb_negb_r. - case_eq (PArray.length a =? 0); auto using C.interp_true. intro Hl; simpl. unfold Lit.interp at 1;rewrite Heq;unfold Var.interp; rewrite rho_interp, H;simpl. rewrite (afold_right_impb (Lit.interp_neg _) Hl), orb_comm;try apply orb_negb_r. Qed. Lemma valid_check_BuildDef2 : forall l, C.valid rho (check_BuildDef2 l). Proof. unfold check_BuildDef2,C.valid;intros l. case_eq (t_form.[Lit.blit l]);intros;auto using C.interp_true; case_eq (Lit.is_pos l);intros Heq;auto using C.interp_true;simpl; unfold Lit.interp at 1;rewrite Heq;unfold Var.interp; rewrite rho_interp, H;simpl; tauto_check. Qed. Lemma valid_check_BuildProj : forall l i, C.valid rho (check_BuildProj l i). Proof. unfold check_BuildProj,C.valid;intros l i. case_eq (t_form.[Lit.blit l]);intros;auto using C.interp_true; case_eq (i 0%Z) by (intro H; apply Hl; now apply to_Z_inj). destruct (to_Z_bounded (PArray.length a)) as [H1 _]. lia. + now rewrite Int63.eqb_spec in Heq. } * now rewrite orb_true_r. + rewrite orb_false_r. case_eq (Lit.interp rho (a .[ i])); intro Hi. * now rewrite orb_true_r. * rewrite (afold_right_impb (Lit.interp_neg _) Hl). rewrite orb_false_r, existsb_exists. exists (Lit.neg (a .[ i])). { split. - apply (to_list_In_eq _ i). + now rewrite length_or_of_imp. + symmetry. apply get_or_of_imp. clear -Hlt Heq. unfold is_true. rewrite ltb_spec. rewrite (to_Z_sub_1 _ i); auto. rewrite eqb_false_spec in Heq. assert (H:[|i|] <> ([|PArray.length a|] - 1)%Z) by (intro H; apply Heq, to_Z_inj; rewrite (to_Z_sub_1 _ i); auto). clear Heq. rewrite ltb_spec in Hlt. lia. - now rewrite Lit.interp_neg, Hi. } Qed. Hypothesis Hs : S.valid rho s. Lemma valid_check_ImmBuildDef : forall cid, C.valid rho (check_ImmBuildDef cid). Proof. unfold check_ImmBuildDef,C.valid;intros cid. generalize (Hs cid);unfold C.valid. destruct (S.get s cid) as [ | l [ | _l _c]];auto using C.interp_true. simpl;unfold Lit.interp, Var.interp; rewrite !rho_interp; destruct (t_form.[Lit.blit l]);auto using C.interp_true; case_eq (Lit.is_pos l);intros Heq;auto using C.interp_true;simpl; tauto_check. - rewrite afold_left_and, C.Cinterp_neg, orb_false_r;trivial. - rewrite afold_left_or, orb_false_r;trivial. - case_eq (PArray.length a =? 0); auto using C.interp_true. intro Hl. now rewrite orb_false_r, (afold_right_impb (Lit.interp_neg _) Hl). - case_eq (PArray.length a =? 0); auto using C.interp_true. Qed. Lemma valid_check_ImmBuildDef2 : forall cid, C.valid rho (check_ImmBuildDef2 cid). Proof. unfold check_ImmBuildDef2,C.valid;intros cid. generalize (Hs cid);unfold C.valid. destruct (S.get s cid) as [ | l [ | _l _c]];auto using C.interp_true. simpl;unfold Lit.interp, Var.interp; rewrite !rho_interp; destruct (t_form.[Lit.blit l]);auto using C.interp_true; case_eq (Lit.is_pos l);intros Heq;auto using C.interp_true;simpl; tauto_check. Qed. Lemma valid_check_ImmBuildProj : forall cid i, C.valid rho (check_ImmBuildProj cid i). Proof. unfold check_ImmBuildProj,C.valid;intros cid i. generalize (Hs cid);unfold C.valid. destruct (S.get s cid) as [ | l [ | _l _c]];auto using C.interp_true. simpl;unfold Lit.interp, Var.interp; rewrite !rho_interp; destruct (t_form.[Lit.blit l]);auto using C.interp_true; case_eq (i ([|PArray.length a|] - 1)%Z) by (intro H1; apply Heq', to_Z_inj; rewrite (to_Z_sub_1 _ _ Hlt); auto); rewrite ltb_spec in Hlt; lia); rewrite <- (get_or_of_imp H1); apply to_list_In; rewrite length_or_of_imp; auto. Qed. End CHECKER. Unset Implicit Arguments.