diff options
Diffstat (limited to 'src/bva')
-rw-r--r-- | src/bva/BVList.v | 2704 | ||||
-rw-r--r-- | src/bva/Bva_checker.v | 8576 |
2 files changed, 11280 insertions, 0 deletions
diff --git a/src/bva/BVList.v b/src/bva/BVList.v new file mode 100644 index 0000000..48befd6 --- /dev/null +++ b/src/bva/BVList.v @@ -0,0 +1,2704 @@ +(**************************************************************************) +(* *) +(* SMTCoq *) +(* Copyright (C) 2011 - 2019 *) +(* *) +(* See file "AUTHORS" for the list of authors *) +(* *) +(* This file is distributed under the terms of the CeCILL-C licence *) +(* *) +(**************************************************************************) + + +Require Import List Bool NArith Psatz Int63 Nnat. +Require Import Misc. +Import ListNotations. +Local Open Scope list_scope. +Local Open Scope N_scope. +Local Open Scope bool_scope. + + +Set Implicit Arguments. +Unset Strict Implicit. + +(* We temporarily assume proof irrelevance to handle dependently typed + bit vectors *) +Axiom proof_irrelevance : forall (P : Prop) (p1 p2 : P), p1 = p2. + +Lemma inj a a' : N.to_nat a = N.to_nat a' -> a = a'. +Proof. intros. lia. Qed. + + Fixpoint leb (n m: nat) : bool := + match n with + | O => + match m with + | O => true + | S m' => true + end + | S n' => + match m with + | O => false + | S m' => leb n' m' + end + end. + +Module Type BITVECTOR. + + Parameter bitvector : N -> Type. + Parameter bits : forall n, bitvector n -> list bool. + Parameter of_bits : forall (l:list bool), bitvector (N.of_nat (List.length l)). + Parameter bitOf : forall n, nat -> bitvector n -> bool. + + (* Constants *) + Parameter zeros : forall n, bitvector n. + + (*equality*) + Parameter bv_eq : forall n, bitvector n -> bitvector n -> bool. + + (*binary operations*) + Parameter bv_concat : forall n m, bitvector n -> bitvector m -> bitvector (n + m). + Parameter bv_and : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_or : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_xor : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_add : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_subt : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_mult : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_ult : forall n, bitvector n -> bitvector n -> bool. + Parameter bv_slt : forall n, bitvector n -> bitvector n -> bool. + + Parameter bv_ultP : forall n, bitvector n -> bitvector n -> Prop. + Parameter bv_sltP : forall n, bitvector n -> bitvector n -> Prop. + + Parameter bv_shl : forall n, bitvector n -> bitvector n -> bitvector n. + Parameter bv_shr : forall n, bitvector n -> bitvector n -> bitvector n. + + (*unary operations*) + Parameter bv_not : forall n, bitvector n -> bitvector n. + Parameter bv_neg : forall n, bitvector n -> bitvector n. + Parameter bv_extr : forall (i n0 n1 : N), bitvector n1 -> bitvector n0. + + (* Parameter bv_extr : forall (n i j : N) {H0: n >= j} {H1: j >= i}, bitvector n -> bitvector (j - i). *) + + Parameter bv_zextn : forall (n i: N), bitvector n -> bitvector (i + n). + Parameter bv_sextn : forall (n i: N), bitvector n -> bitvector (i + n). + (* Parameter bv_extr : forall n i j : N, bitvector n -> n >= j -> j >= i -> bitvector (j - i). *) + + (* Specification *) + Axiom bits_size : forall n (bv:bitvector n), List.length (bits bv) = N.to_nat n. + Axiom bv_eq_reflect : forall n (a b:bitvector n), bv_eq a b = true <-> a = b. + Axiom bv_eq_refl : forall n (a:bitvector n), bv_eq a a = true. + + Axiom bv_ult_B2P : forall n (a b:bitvector n), bv_ult a b = true <-> bv_ultP a b. + Axiom bv_slt_B2P : forall n (a b:bitvector n), bv_slt a b = true <-> bv_sltP a b. + Axiom bv_ult_not_eq : forall n (a b:bitvector n), bv_ult a b = true -> a <> b. + Axiom bv_slt_not_eq : forall n (a b:bitvector n), bv_slt a b = true -> a <> b. + Axiom bv_ult_not_eqP: forall n (a b:bitvector n), bv_ultP a b -> a <> b. + Axiom bv_slt_not_eqP: forall n (a b:bitvector n), bv_sltP a b -> a <> b. + + Axiom bv_and_comm : forall n (a b:bitvector n), bv_eq (bv_and a b) (bv_and b a) = true. + Axiom bv_or_comm : forall n (a b:bitvector n), bv_eq (bv_or a b) (bv_or b a) = true. + Axiom bv_add_comm : forall n (a b:bitvector n), bv_eq (bv_add a b) (bv_add b a) = true. + + Axiom bv_and_assoc : forall n (a b c: bitvector n), bv_eq (bv_and a (bv_and b c)) (bv_and (bv_and a b) c) = true. + Axiom bv_or_assoc : forall n (a b c: bitvector n), bv_eq (bv_or a (bv_or b c)) (bv_or (bv_or a b) c) = true. + Axiom bv_xor_assoc : forall n (a b c: bitvector n), bv_eq (bv_xor a (bv_xor b c)) (bv_xor (bv_xor a b) c) = true. + Axiom bv_add_assoc : forall n (a b c: bitvector n), bv_eq (bv_add a (bv_add b c)) (bv_add (bv_add a b) c) = true. + Axiom bv_not_involutive: forall n (a: bitvector n), bv_eq (bv_not (bv_not a)) a = true. + + Parameter _of_bits : forall (l: list bool) (s : N), bitvector s. + +End BITVECTOR. + +Module Type RAWBITVECTOR. + +Parameter bitvector : Type. +Parameter size : bitvector -> N. +Parameter bits : bitvector -> list bool. +Parameter of_bits : list bool -> bitvector. +Parameter _of_bits : list bool -> N -> bitvector. +Parameter bitOf : nat -> bitvector -> bool. + +(* Constants *) +Parameter zeros : N -> bitvector. + +(*equality*) +Parameter bv_eq : bitvector -> bitvector -> bool. + +(*binary operations*) +Parameter bv_concat : bitvector -> bitvector -> bitvector. +Parameter bv_and : bitvector -> bitvector -> bitvector. +Parameter bv_or : bitvector -> bitvector -> bitvector. +Parameter bv_xor : bitvector -> bitvector -> bitvector. +Parameter bv_add : bitvector -> bitvector -> bitvector. +Parameter bv_mult : bitvector -> bitvector -> bitvector. +Parameter bv_subt : bitvector -> bitvector -> bitvector. +Parameter bv_ult : bitvector -> bitvector -> bool. +Parameter bv_slt : bitvector -> bitvector -> bool. + +Parameter bv_ultP : bitvector -> bitvector -> Prop. +Parameter bv_sltP : bitvector -> bitvector -> Prop. + +Parameter bv_shl : bitvector -> bitvector -> bitvector. +Parameter bv_shr : bitvector -> bitvector -> bitvector. + +(*unary operations*) +Parameter bv_not : bitvector -> bitvector. +Parameter bv_neg : bitvector -> bitvector. +Parameter bv_extr : forall (i n0 n1: N), bitvector -> bitvector. + +(*Parameter bv_extr : forall (n i j: N) {H0: n >= j} {H1: j >= i}, bitvector -> bitvector.*) + +Parameter bv_zextn : forall (n i: N), bitvector -> bitvector. +Parameter bv_sextn : forall (n i: N), bitvector -> bitvector. + +(* All the operations are size-preserving *) + +Axiom bits_size : forall bv, List.length (bits bv) = N.to_nat (size bv). +Axiom of_bits_size : forall l, N.to_nat (size (of_bits l)) = List.length l. +Axiom _of_bits_size : forall l s,(size (_of_bits l s)) = s. +Axiom zeros_size : forall n, size (zeros n) = n. +Axiom bv_concat_size : forall n m a b, size a = n -> size b = m -> size (bv_concat a b) = n + m. +Axiom bv_and_size : forall n a b, size a = n -> size b = n -> size (bv_and a b) = n. +Axiom bv_or_size : forall n a b, size a = n -> size b = n -> size (bv_or a b) = n. +Axiom bv_xor_size : forall n a b, size a = n -> size b = n -> size (bv_xor a b) = n. +Axiom bv_add_size : forall n a b, size a = n -> size b = n -> size (bv_add a b) = n. +Axiom bv_subt_size : forall n a b, size a = n -> size b = n -> size (bv_subt a b) = n. +Axiom bv_mult_size : forall n a b, size a = n -> size b = n -> size (bv_mult a b) = n. +Axiom bv_not_size : forall n a, size a = n -> size (bv_not a) = n. +Axiom bv_neg_size : forall n a, size a = n -> size (bv_neg a) = n. +Axiom bv_shl_size : forall n a b, size a = n -> size b = n -> size (bv_shl a b) = n. +Axiom bv_shr_size : forall n a b, size a = n -> size b = n -> size (bv_shr a b) = n. + +Axiom bv_extr_size : forall i n0 n1 a, size a = n1 -> size (@bv_extr i n0 n1 a) = n0. + +(* +Axiom bv_extr_size : forall n (i j: N) a (H0: n >= j) (H1: j >= i), + size a = n -> size (@bv_extr n i j H0 H1 a) = (j - i). +*) + +Axiom bv_zextn_size : forall (n i: N) a, + size a = n -> size (@bv_zextn n i a) = (i + n). +Axiom bv_sextn_size : forall (n i: N) a, + size a = n -> size (@bv_sextn n i a) = (i + n). + +(* Specification *) +Axiom bv_eq_reflect : forall a b, bv_eq a b = true <-> a = b. +Axiom bv_eq_refl : forall a, bv_eq a a = true. + + +Axiom bv_ult_not_eq : forall a b, bv_ult a b = true -> a <> b. +Axiom bv_slt_not_eq : forall a b, bv_slt a b = true -> a <> b. +Axiom bv_ult_not_eqP : forall a b, bv_ultP a b -> a <> b. +Axiom bv_slt_not_eqP : forall a b, bv_sltP a b -> a <> b. +Axiom bv_ult_B2P : forall a b, bv_ult a b = true <-> bv_ultP a b. +Axiom bv_slt_B2P : forall a b, bv_slt a b = true <-> bv_sltP a b. + + +Axiom bv_and_comm : forall n a b, size a = n -> size b = n -> bv_and a b = bv_and b a. +Axiom bv_or_comm : forall n a b, size a = n -> size b = n -> bv_or a b = bv_or b a. +Axiom bv_add_comm : forall n a b, size a = n -> size b = n -> bv_add a b = bv_add b a. + +Axiom bv_and_assoc : forall n a b c, size a = n -> size b = n -> size c = n -> + (bv_and a (bv_and b c)) = (bv_and (bv_and a b) c). +Axiom bv_or_assoc : forall n a b c, size a = n -> size b = n -> size c = n -> + (bv_or a (bv_or b c)) = (bv_or (bv_or a b) c). +Axiom bv_xor_assoc : forall n a b c, size a = n -> size b = n -> size c = n -> + (bv_xor a (bv_xor b c)) = (bv_xor (bv_xor a b) c). +Axiom bv_add_assoc : forall n a b c, size a = n -> size b = n -> size c = n -> + (bv_add a (bv_add b c)) = (bv_add (bv_add a b) c). +Axiom bv_not_involutive: forall a, bv_not (bv_not a) = a. + +End RAWBITVECTOR. + +Module RAW2BITVECTOR (M:RAWBITVECTOR) <: BITVECTOR. + + Record bitvector_ (n:N) : Type := + MkBitvector + { bv :> M.bitvector; + wf : M.size bv = n + }. + Definition bitvector := bitvector_. + + Definition bits n (bv:bitvector n) := M.bits bv. + + Lemma of_bits_size l : M.size (M.of_bits l) = N.of_nat (List.length l). + Proof. now rewrite <- M.of_bits_size, N2Nat.id. Qed. + + Lemma _of_bits_size l s: M.size (M._of_bits l s) = s. + Proof. apply (M._of_bits_size l s). Qed. + + Definition of_bits (l:list bool) : bitvector (N.of_nat (List.length l)) := + @MkBitvector _ (M.of_bits l) (of_bits_size l). + + Definition _of_bits (l: list bool) (s : N): bitvector s := + @MkBitvector _ (M._of_bits l s) (_of_bits_size l s). + + Definition bitOf n p (bv:bitvector n) : bool := M.bitOf p bv. + + Definition zeros (n:N) : bitvector n := + @MkBitvector _ (M.zeros n) (M.zeros_size n). + + Definition bv_eq n (bv1 bv2:bitvector n) := M.bv_eq bv1 bv2. + + Definition bv_ultP n (bv1 bv2:bitvector n) := M.bv_ultP bv1 bv2. + + Definition bv_sltP n (bv1 bv2:bitvector n) := M.bv_sltP bv1 bv2. + + Definition bv_and n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_and bv1 bv2) (M.bv_and_size (wf bv1) (wf bv2)). + + Definition bv_or n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_or bv1 bv2) (M.bv_or_size (wf bv1) (wf bv2)). + + Definition bv_add n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_add bv1 bv2) (M.bv_add_size (wf bv1) (wf bv2)). + + Definition bv_subt n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_subt bv1 bv2) (M.bv_subt_size (wf bv1) (wf bv2)). + + Definition bv_mult n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_mult bv1 bv2) (M.bv_mult_size (wf bv1) (wf bv2)). + + Definition bv_xor n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_xor bv1 bv2) (M.bv_xor_size (wf bv1) (wf bv2)). + + Definition bv_ult n (bv1 bv2:bitvector n) : bool := M.bv_ult bv1 bv2. + + Definition bv_slt n (bv1 bv2:bitvector n) : bool := M.bv_slt bv1 bv2. + + Definition bv_not n (bv1: bitvector n) : bitvector n := + @MkBitvector n (M.bv_not bv1) (M.bv_not_size (wf bv1)). + + Definition bv_neg n (bv1: bitvector n) : bitvector n := + @MkBitvector n (M.bv_neg bv1) (M.bv_neg_size (wf bv1)). + + Definition bv_concat n m (bv1:bitvector n) (bv2: bitvector m) : bitvector (n + m) := + @MkBitvector (n + m) (M.bv_concat bv1 bv2) (M.bv_concat_size (wf bv1) (wf bv2)). + + Definition bv_extr (i n0 n1: N) (bv1: bitvector n1) : bitvector n0 := + @MkBitvector n0 (@M.bv_extr i n0 n1 bv1) (@M.bv_extr_size i n0 n1 bv1 (wf bv1)). + +(* + Definition bv_extr n (i j: N) (H0: n >= j) (H1: j >= i) (bv1: bitvector n) : bitvector (j - i) := + @MkBitvector (j - i) (@M.bv_extr n i j H0 H1 bv1) (@M.bv_extr_size n i j bv1 H0 H1 (wf bv1)). +*) + + Definition bv_zextn n (i: N) (bv1: bitvector n) : bitvector (i + n) := + @MkBitvector (i + n) (@M.bv_zextn n i bv1) (@M.bv_zextn_size n i bv1 (wf bv1)). + + Definition bv_sextn n (i: N) (bv1: bitvector n) : bitvector (i + n) := + @MkBitvector (i + n) (@M.bv_sextn n i bv1) (@M.bv_sextn_size n i bv1 (wf bv1)). + + Definition bv_shl n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_shl bv1 bv2) (M.bv_shl_size (wf bv1) (wf bv2)). + + Definition bv_shr n (bv1 bv2:bitvector n) : bitvector n := + @MkBitvector n (M.bv_shr bv1 bv2) (M.bv_shr_size (wf bv1) (wf bv2)). + + Lemma bits_size n (bv:bitvector n) : List.length (bits bv) = N.to_nat n. + Proof. unfold bits. now rewrite M.bits_size, wf. Qed. + + (* The next lemma is provable only if we assume proof irrelevance *) + Lemma bv_eq_reflect n (a b: bitvector n) : bv_eq a b = true <-> a = b. + Proof. + unfold bv_eq. rewrite M.bv_eq_reflect. split. + - revert a b. intros [a Ha] [b Hb]. simpl. intros ->. + rewrite (proof_irrelevance Ha Hb). reflexivity. + - intros. case a in *. case b in *. simpl in *. + now inversion H. (* now intros ->. *) + Qed. + + Lemma bv_eq_refl n (a : bitvector n) : bv_eq a a = true. + Proof. + unfold bv_eq. now rewrite M.bv_eq_reflect. + Qed. + + Lemma bv_ult_not_eqP: forall n (a b: bitvector n), bv_ultP a b -> a <> b. + Proof. + unfold bv_ultP, bv_ult. intros n a b H. + apply M.bv_ult_not_eqP in H. unfold not in *; intros. apply H. + apply M.bv_eq_reflect. rewrite H0. apply M.bv_eq_refl. + Qed. + + Lemma bv_slt_not_eqP: forall n (a b: bitvector n), bv_sltP a b -> a <> b. + Proof. + unfold bv_sltP, bv_slt. intros n a b H. + apply M.bv_slt_not_eqP in H. unfold not in *; intros. apply H. + apply M.bv_eq_reflect. rewrite H0. apply M.bv_eq_refl. + Qed. + + Lemma bv_ult_not_eq: forall n (a b: bitvector n), bv_ult a b = true -> a <> b. + Proof. + unfold bv_ult. intros n a b H. + apply M.bv_ult_not_eq in H. unfold not in *; intros. apply H. + apply M.bv_eq_reflect. rewrite H0. apply M.bv_eq_refl. + Qed. + + Lemma bv_slt_not_eq: forall n (a b: bitvector n), bv_slt a b = true -> a <> b. + Proof. + unfold bv_slt. intros n a b H. + apply M.bv_slt_not_eq in H. unfold not in *; intros. apply H. + apply M.bv_eq_reflect. rewrite H0. apply M.bv_eq_refl. + Qed. + + Lemma bv_ult_B2P: forall n (a b: bitvector n), bv_ult a b = true <-> bv_ultP a b. + Proof. + unfold bv_ultP, bv_ult; intros; split; intros; + now apply M.bv_ult_B2P. + Qed. + + Lemma bv_slt_B2P: forall n (a b: bitvector n), bv_slt a b = true <-> bv_sltP a b. + Proof. + unfold bv_ultP, bv_slt; intros; split; intros; + now apply M.bv_slt_B2P. + Qed. + + Lemma bv_and_comm n (a b:bitvector n) : bv_eq (bv_and a b) (bv_and b a) = true. + Proof. + unfold bv_eq. rewrite M.bv_eq_reflect. apply (@M.bv_and_comm n); now rewrite wf. + Qed. + + Lemma bv_or_comm n (a b:bitvector n) : bv_eq (bv_or a b) (bv_or b a) = true. + Proof. + unfold bv_eq. rewrite M.bv_eq_reflect. apply (@M.bv_or_comm n); now rewrite wf. + Qed. + + Lemma bv_add_comm n (a b:bitvector n) : bv_eq (bv_add a b) (bv_add b a) = true. + Proof. + unfold bv_eq. rewrite M.bv_eq_reflect. apply (@M.bv_add_comm n); now rewrite wf. + Qed. + + Lemma bv_and_assoc : forall n (a b c :bitvector n), bv_eq (bv_and a (bv_and b c)) (bv_and (bv_and a b) c) = true. + Proof. + intros n a b c. + unfold bv_eq. rewrite M.bv_eq_reflect. simpl. + apply (@M.bv_and_assoc n a b c); now rewrite wf. + Qed. + + Lemma bv_or_assoc : forall n (a b c :bitvector n), bv_eq (bv_or a (bv_or b c)) (bv_or (bv_or a b) c) = true. + Proof. + intros n a b c. + unfold bv_eq. rewrite M.bv_eq_reflect. simpl. + apply (@M.bv_or_assoc n a b c); now rewrite wf. + Qed. + + Lemma bv_xor_assoc : forall n (a b c :bitvector n), bv_eq (bv_xor a (bv_xor b c)) (bv_xor (bv_xor a b) c) = true. + Proof. + intros n a b c. + unfold bv_eq. rewrite M.bv_eq_reflect. simpl. + apply (@M.bv_xor_assoc n a b c); now rewrite wf. + Qed. + + Lemma bv_add_assoc : forall n (a b c :bitvector n), bv_eq (bv_add a (bv_add b c)) (bv_add (bv_add a b) c) = true. + Proof. + intros n a b c. + unfold bv_eq. rewrite M.bv_eq_reflect. simpl. + apply (@M.bv_add_assoc n a b c); now rewrite wf. + Qed. + + Lemma bv_not_involutive: forall n (a: bitvector n), bv_eq (bv_not (bv_not a)) a = true. + Proof. + intros n a. + unfold bv_eq. rewrite M.bv_eq_reflect. simpl. + apply (@M.bv_not_involutive a); now rewrite wf. + Qed. + + +End RAW2BITVECTOR. + +Module RAWBITVECTOR_LIST <: RAWBITVECTOR. + +Definition bitvector := list bool. +Definition bits (a:bitvector) : list bool := a. +Definition size (a:bitvector) := N.of_nat (List.length a). +Definition of_bits (a:list bool) : bitvector := a. + +Lemma bits_size bv : List.length (bits bv) = N.to_nat (size bv). +Proof. unfold bits, size. now rewrite Nat2N.id. Qed. + +Lemma of_bits_size l : N.to_nat (size (of_bits l)) = List.length l. +Proof. unfold of_bits, size. now rewrite Nat2N.id. Qed. + +Fixpoint beq_list (l m : list bool) {struct l} := + match l, m with + | nil, nil => true + | x :: l', y :: m' => (Bool.eqb x y) && (beq_list l' m') + | _, _ => false + end. + +Definition bv_eq (a b: bitvector): bool:= + if ((size a) =? (size b)) then beq_list (bits a) (bits b) else false. + +Fixpoint beq_listP (l m : list bool) {struct l} := + match l, m with + | nil, nil => True + | x :: l', y :: m' => (x = y) /\ (beq_listP l' m') + | _, _ => False + end. + +Lemma bv_mk_eq l1 l2 : bv_eq l1 l2 = beq_list l1 l2. +Proof. + unfold bv_eq, size, bits. + case_eq (Nat_eqb (length l1) (length l2)); intro Heq. + - now rewrite (EqNat.beq_nat_true _ _ Heq), N.eqb_refl. + - replace (N.of_nat (length l1) =? N.of_nat (length l2)) with false. + * revert l2 Heq. induction l1 as [ |b1 l1 IHl1]; intros [ |b2 l2]; simpl in *; auto. + intro Heq. now rewrite <- (IHl1 _ Heq), andb_false_r. + * symmetry. rewrite N.eqb_neq. intro H. apply Nat2N.inj in H. rewrite H in Heq. + rewrite <- EqNat.beq_nat_refl in Heq. discriminate. +Qed. + +Definition bv_concat (a b: bitvector) : bitvector := b ++ a. + +Section Map2. + + Variables A B C: Type. + Variable f : A -> B -> C. + + Fixpoint map2 (l1 : list A) (l2 : list B) {struct l1} : list C := + match l1, l2 with + | b1::tl1, b2::tl2 => (f b1 b2)::(map2 tl1 tl2) + | _, _ => nil + end. + +End Map2. + +Section Fold_left2. + + Variables A B: Type. + Variable f : A -> B -> B -> A. + + Fixpoint fold_left2 (xs ys: list B) (acc:A) {struct xs} : A := + match xs, ys with + | nil, _ | _, nil => acc + | x::xs, y::ys => fold_left2 xs ys (f acc x y) + end. + + Lemma foo : forall (I: A -> Prop) acc, I acc -> + (forall a b1 b2, I a -> I (f a b1 b2)) -> + forall xs ys, I (fold_left2 xs ys acc). + Proof. intros I acc H0 H1 xs. revert acc H0. + induction xs as [ | a xs IHxs]; intros acc H. + simpl. auto. + intros [ | b ys]. + + simpl. exact H. + + simpl. apply IHxs, H1. exact H. + Qed. + +Fixpoint mk_list_true_acc (t: nat) (acc: list bool) : list bool := + match t with + | O => acc + | S t' => mk_list_true_acc t' (true::acc) + end. + +Fixpoint mk_list_true (t: nat) : list bool := + match t with + | O => [] + | S t' => true::(mk_list_true t') + end. + +Fixpoint mk_list_false_acc (t: nat) (acc: list bool) : list bool := + match t with + | O => acc + | S t' => mk_list_false_acc t' (false::acc) + end. + +Fixpoint mk_list_false (t: nat) : list bool := + match t with + | O => [] + | S t' => false::(mk_list_false t') + end. + +Definition zeros (n : N) : bitvector := mk_list_false (N.to_nat n). + +End Fold_left2. + +Definition bitOf (n: nat) (a: bitvector): bool := nth n a false. + +Definition bv_and (a b : bitvector) : bitvector := + match (@size a) =? (@size b) with + | true => map2 andb (@bits a) (@bits b) + | _ => nil + end. + +Definition bv_or (a b : bitvector) : bitvector := + match (@size a) =? (@size b) with + | true => map2 orb (@bits a) (@bits b) + | _ => nil + end. + +Definition bv_xor (a b : bitvector) : bitvector := + match (@size a) =? (@size b) with + | true => map2 xorb (@bits a) (@bits b) + | _ => nil + end. + +Definition bv_not (a: bitvector) : bitvector := map negb (@bits a). + + +(*arithmetic operations*) + + (*addition*) + +Definition add_carry b1 b2 c := + match b1, b2, c with + | true, true, true => (true, true) + | true, true, false + | true, false, true + | false, true, true => (false, true) + | false, false, true + | false, true, false + | true, false, false => (true, false) + | false, false, false => (false, false) + end. + +(* Truncating addition in little-endian, direct style *) + +Fixpoint add_list_ingr bs1 bs2 c {struct bs1} := + match bs1, bs2 with + | nil, _ => nil + | _ , nil => nil + | b1 :: bs1, b2 :: bs2 => + let (r, c) := add_carry b1 b2 c in r :: (add_list_ingr bs1 bs2 c) + end. + +Definition add_list (a b: list bool) := add_list_ingr a b false. + +Definition bv_add (a b : bitvector) : bitvector := + match (@size a) =? (@size b) with + | true => add_list a b + | _ => nil + end. + + (*substraction*) + +Definition twos_complement b := + add_list_ingr (map negb b) (mk_list_false (length b)) true. + +Definition bv_neg (a: bitvector) : bitvector := (twos_complement a). + +Definition subst_list' a b := add_list a (twos_complement b). + +Definition bv_subt' (a b : bitvector) : bitvector := + match (@size a) =? (@size b) with + | true => (subst_list' (@bits a) (@bits b)) + | _ => nil + end. + +Definition subst_borrow b1 b2 b := + match b1, b2, b with + | true, true, true => (true, true) + | true, true, false => (false, false) + | true, false, true => (false, false) + | false, true, true => (false, true) + | false, false, true => (true, true) + | false, true, false => (true, true) + | true, false, false => (true, false) + | false, false, false => (false, false) + end. + +Fixpoint subst_list_borrow bs1 bs2 b {struct bs1} := + match bs1, bs2 with + | nil, _ => nil + | _ , nil => nil + | b1 :: bs1, b2 :: bs2 => + let (r, b) := subst_borrow b1 b2 b in r :: (subst_list_borrow bs1 bs2 b) + end. + +Definition subst_list (a b: list bool) := subst_list_borrow a b false. + +Definition bv_subt (a b : bitvector) : bitvector := + match (@size a) =? (@size b) with + | true => subst_list (@bits a) (@bits b) + | _ => nil + end. + +(*less than*) + +Fixpoint ult_list_big_endian (x y: list bool) := + match x, y with + | nil, _ => false + | _ , nil => false + | xi :: nil, yi :: nil => andb (negb xi) yi + | xi :: x', yi :: y' => + orb (andb (Bool.eqb xi yi) (ult_list_big_endian x' y')) + (andb (negb xi) yi) + end. + +Definition ult_list (x y: list bool) := + (ult_list_big_endian (List.rev x) (List.rev y)). + + +Fixpoint slt_list_big_endian (x y: list bool) := + match x, y with + | nil, _ => false + | _ , nil => false + | xi :: nil, yi :: nil => andb xi (negb yi) + | xi :: x', yi :: y' => + orb (andb (Bool.eqb xi yi) (ult_list_big_endian x' y')) + (andb xi (negb yi)) + end. + +Definition slt_list (x y: list bool) := + slt_list_big_endian (List.rev x) (List.rev y). + + +Definition bv_ult (a b : bitvector) : bool := + if @size a =? @size b then ult_list a b else false. + + +Definition bv_slt (a b : bitvector) : bool := + if @size a =? @size b then slt_list a b else false. + +Definition ult_listP (x y: list bool) := + if ult_list x y then True else False. + +Definition slt_listP (x y: list bool) := + if slt_list x y then True else False. + +Definition bv_ultP (a b : bitvector) : Prop := + if @size a =? @size b then ult_listP a b else False. + +Definition bv_sltP (a b : bitvector) : Prop := + if @size a =? @size b then slt_listP a b else False. + + + (*multiplication*) + +Fixpoint mult_list_carry (a b :list bool) n {struct a}: list bool := + match a with + | nil => mk_list_false n + | a' :: xs => + if a' then + add_list b (mult_list_carry xs (false :: b) n) + else + mult_list_carry xs (false :: b) n + end. + +Fixpoint mult_list_carry2 (a b :list bool) n {struct a}: list bool := + match a with + | nil => mk_list_false n + | a' :: xs => + if a' then + add_list b (mult_list_carry2 xs (false :: (removelast b)) n) + else + mult_list_carry2 xs (false :: (removelast b)) n + end. + +Fixpoint and_with_bool (a: list bool) (bt: bool) : list bool := + match a with + | nil => nil + | ai :: a' => (bt && ai) :: and_with_bool a' bt + end. + + +Fixpoint mult_bool_step_k_h (a b: list bool) (c: bool) (k: Z) : list bool := + match a, b with + | nil , _ => nil + | ai :: a', bi :: b' => + if (k - 1 <? 0)%Z then + let carry_out := (ai && bi) || ((xorb ai bi) && c) in + let curr := xorb (xorb ai bi) c in + curr :: mult_bool_step_k_h a' b' carry_out (k - 1) + else + ai :: mult_bool_step_k_h a' b c (k - 1) + | ai :: a' , nil => ai :: mult_bool_step_k_h a' b c k + end. + +Local Open Scope int63_scope. + +Fixpoint top_k_bools (a: list bool) (k: int) : list bool := + if (k == 0) then nil + else match a with + | nil => nil + | ai :: a' => ai :: top_k_bools a' (k - 1) + end. + + +Fixpoint mult_bool_step (a b: list bool) (res: list bool) (k k': nat) : list bool := + let ak := List.firstn (S k') a in + let b' := and_with_bool ak (nth k b false) in + let res' := mult_bool_step_k_h res b' false (Z.of_nat k) in + match k' with + | O => res' + (* | S O => res' *) + | S pk' => mult_bool_step a b res' (S k) pk' + end. + +Definition bvmult_bool (a b: list bool) (n: nat) : list bool := + let res := and_with_bool a (nth 0 b false) in + match n with + | O => res + | S O => res + | S (S k) => mult_bool_step a b res 1 k + end. + +Definition mult_list a b := bvmult_bool a b (length a). + +Definition bv_mult (a b : bitvector) : bitvector := + if ((@size a) =? (@size b)) + then mult_list a b + else zeros (@size a). + +(* Theorems *) + +Lemma length_mk_list_false: forall n, length (mk_list_false n) = n. +Proof. intro n. + induction n as [ | n' IHn]. + - simpl. auto. + - simpl. apply f_equal. exact IHn. +Qed. + +Definition _of_bits (a:list bool) (s: N) := +if (N.of_nat (length a) =? s) then a else zeros s. + +Lemma _of_bits_size l s: (size (_of_bits l s)) = s. +Proof. unfold of_bits, size. unfold _of_bits. + case_eq ( N.of_nat (length l) =? s). + intros. now rewrite N.eqb_eq in H. + intros. unfold zeros. rewrite length_mk_list_false. + now rewrite N2Nat.id. +Qed. + +Lemma length_mk_list_true: forall n, length (mk_list_true n) = n. +Proof. intro n. + induction n as [ | n' IHn]. + - simpl. auto. + - simpl. apply f_equal. exact IHn. +Qed. + +Lemma zeros_size (n : N) : size (zeros n) = n. +Proof. unfold size, zeros. now rewrite length_mk_list_false, N2Nat.id. Qed. + +Lemma List_eq : forall (l m: list bool), beq_list l m = true <-> l = m. +Proof. + induction l; destruct m; simpl; split; intro; try (reflexivity || discriminate). + - rewrite andb_true_iff in H. destruct H. rewrite eqb_true_iff in H. rewrite H. + apply f_equal. apply IHl. exact H0. + - inversion H. subst b. subst m. rewrite andb_true_iff. split. + + apply eqb_reflx. + + apply IHl; reflexivity. +Qed. + +Lemma List_eqP : forall (l m: list bool), beq_listP l m <-> l = m. +Proof. + induction l; destruct m; simpl; split; intro; try (reflexivity || discriminate); try now contradict H. + - destruct H. rewrite H. + apply f_equal. apply IHl. exact H0. + - inversion H. subst b. subst m. split. + + reflexivity. + + apply IHl; reflexivity. +Qed. + +Lemma List_eq_refl : forall (l: list bool), beq_list l l = true. +Proof. + induction l; simpl; try (reflexivity || discriminate). + - rewrite andb_true_iff. split. apply eqb_reflx. apply IHl. +Qed. + +Lemma List_eqP_refl : forall (l: list bool), beq_listP l l <-> l = l. +Proof. intro l. + induction l as [ | xl xsl IHl ]; intros. + - easy. + - simpl. repeat split. now apply IHl. +Qed. + +Lemma List_neq : forall (l m: list bool), beq_list l m = false -> l <> m. +Proof. + intro l. + induction l. + - intros. case m in *; simpl. now contradict H. easy. + - intros. simpl in H. + case_eq m; intros; rewrite H0 in H. + easy. simpl. + case_eq (Bool.eqb a b); intros. + rewrite H1 in H. rewrite andb_true_l in H. + apply Bool.eqb_prop in H1. + specialize (IHl l0 H). + rewrite H1. + unfold not in *. + intros. apply IHl. + now inversion H2. + apply Bool.eqb_false_iff in H1. + unfold not in *. + intros. apply H1. + now inversion H2. +Qed. + +Lemma List_neqP : forall (l m: list bool), ~beq_listP l m -> l <> m. +Proof. + intro l. + induction l. + - intros. case m in *; simpl. now contradict H. easy. + - intros. unfold not in H. simpl in H. + case_eq m; intros. easy. + rewrite H0 in H. + unfold not. intros. apply H. inversion H1. + split; try easy. + now apply List_eqP_refl. +Qed. + +Lemma bv_eq_reflect a b : bv_eq a b = true <-> a = b. +Proof. + unfold bv_eq. case_eq (size a =? size b); intro Heq; simpl. + - apply List_eq. + - split; try discriminate. + intro H. rewrite H, N.eqb_refl in Heq. discriminate. +Qed. + +Lemma bv_eq_refl a: bv_eq a a = true. +Proof. + unfold bv_eq. rewrite N.eqb_refl. now apply List_eq. +Qed. + +Lemma bv_concat_size n m a b : size a = n -> size b = m -> size (bv_concat a b) = (n + m)%N. +Proof. + unfold bv_concat, size. intros H0 H1. + rewrite app_length, Nat2N.inj_add, H0, H1; now rewrite N.add_comm. +Qed. + +(*list bitwise AND properties*) + +Lemma map2_and_comm: forall (a b: list bool), (map2 andb a b) = (map2 andb b a). +Proof. intros a. induction a as [ | a' xs IHxs]. + intros [ | b' ys]. + - simpl. auto. + - simpl. auto. + - intros [ | b' ys]. + + simpl. auto. + + intros. simpl. + cut (a' && b' = b' && a'). intro H. rewrite <- H. apply f_equal. + apply IHxs. apply andb_comm. +Qed. + +Lemma map2_and_assoc: forall (a b c: list bool), (map2 andb a (map2 andb b c)) = (map2 andb (map2 andb a b) c). +Proof. intro a. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b' ys]. + - simpl. auto. + - intros [ | c' zs]. + + simpl. auto. + + simpl. cut (a' && (b' && c') = a' && b' && c'). intro H. rewrite <- H. apply f_equal. + apply IHxs. apply andb_assoc. +Qed. + +Lemma map2_and_idem1: forall (a b: list bool), (map2 andb (map2 andb a b) a) = (map2 andb a b). +Proof. intros a. induction a as [ | a' xs IHxs]. + intros [ | b' ys]. + - simpl. auto. + - simpl. auto. + - intros [ | b' ys]. + + simpl. auto. + + intros. simpl. + cut (a' && b' && a' = a' && b'). intro H. rewrite H. apply f_equal. + apply IHxs. rewrite andb_comm, andb_assoc, andb_diag. reflexivity. +Qed. + +Lemma map2_and_idem_comm: forall (a b: list bool), (map2 andb (map2 andb a b) a) = (map2 andb b a). +Proof. intros a b. symmetry. rewrite <- map2_and_comm. symmetry; apply map2_and_idem1. Qed. + +Lemma map2_and_idem2: forall (a b: list bool), (map2 andb (map2 andb a b) b) = (map2 andb a b). +Proof. intros a. induction a as [ | a' xs IHxs]. + intros [ | b' ys]. + - simpl. auto. + - simpl. auto. + - intros [ | b' ys]. + + simpl. auto. + + intros. simpl. + cut (a' && b' && b' = a' && b'). intro H. rewrite H. apply f_equal. + apply IHxs. rewrite <- andb_assoc. rewrite andb_diag. reflexivity. +Qed. + +Lemma map2_and_idem_comm2: forall (a b: list bool), (map2 andb (map2 andb a b) b) = (map2 andb b a). +Proof. intros a b. symmetry. rewrite <- map2_and_comm. symmetry; apply map2_and_idem2. Qed. + +Lemma map2_and_empty_empty1: forall (a: list bool), (map2 andb a []) = []. +Proof. intros a. induction a as [ | a' xs IHxs]; simpl; auto. Qed. + +Lemma map2_and_empty_empty2: forall (a: list bool), (map2 andb [] a) = []. +Proof. intros a. rewrite map2_and_comm. apply map2_and_empty_empty1. Qed. + +Lemma map2_nth_empty_false: forall (i: nat), nth i [] false = false. +Proof. intros i. induction i as [ | IHi]; simpl; reflexivity. Qed. + +Lemma mk_list_true_equiv: forall t acc, mk_list_true_acc t acc = (List.rev (mk_list_true t)) ++ acc. +Proof. induction t as [ |t IHt]; auto; intro acc; simpl; rewrite IHt. + rewrite app_assoc_reverse. + apply f_equal. simpl. reflexivity. +Qed. + +Lemma mk_list_false_equiv: forall t acc, mk_list_false_acc t acc = (List.rev (mk_list_false t)) ++ acc. +Proof. induction t as [ |t IHt]; auto; intro acc; simpl; rewrite IHt. + rewrite app_assoc_reverse. + apply f_equal. simpl. reflexivity. +Qed. + +Lemma len_mk_list_true_empty: length (mk_list_true_acc 0 []) = 0%nat. +Proof. simpl. reflexivity. Qed. + +Lemma add_mk_list_true: forall n acc, length (mk_list_true_acc n acc) = (n + length acc)%nat. +Proof. intros n. + induction n as [ | n' IHn]. + + auto. + + intro acc. simpl. rewrite IHn. simpl. lia. +Qed. + +Lemma map2_and_nth_bitOf: forall (a b: list bool) (i: nat), + (length a) = (length b) -> + (i <= (length a))%nat -> + nth i (map2 andb a b) false = (nth i a false) && (nth i b false). +Proof. intro a. + induction a as [ | a xs IHxs]. + - intros [ | b ys]. + + intros i H0 H1. do 2 rewrite map2_nth_empty_false. reflexivity. + + intros i H0 H1. rewrite map2_and_empty_empty2. + rewrite map2_nth_empty_false. reflexivity. + - intros [ | b ys]. + + intros i H0 H1. rewrite map2_and_empty_empty1. + rewrite map2_nth_empty_false. rewrite andb_false_r. reflexivity. + + intros i H0 H1. simpl. + revert i H1. intros [ | i]; [ |intros IHi]. + * simpl. auto. + * apply IHxs. + inversion H0; reflexivity. + inversion IHi; lia. +Qed. + +Lemma length_mk_list_true_full: forall n, length (mk_list_true_acc n []) = n. +Proof. intro n. rewrite (@add_mk_list_true n []). auto. Qed. + +Lemma mk_list_app: forall n acc, mk_list_true_acc n acc = mk_list_true_acc n [] ++ acc. +Proof. intro n. + induction n as [ | n IHn]. + + auto. + + intro acc. simpl in *. rewrite IHn. + cut (mk_list_true_acc n [] ++ [true] = mk_list_true_acc n [true]). intro H. + rewrite <- H. rewrite <- app_assoc. unfold app. reflexivity. + rewrite <- IHn. reflexivity. +Qed. + +Lemma mk_list_ltrue: forall n, mk_list_true_acc n [true] = mk_list_true_acc (S n) []. +Proof. intro n. induction n as [ | n IHn]; auto. Qed. + +Lemma map2_and_1_neutral: forall (a: list bool), (map2 andb a (mk_list_true (length a))) = a. +Proof. intro a. + induction a as [ | a xs IHxs]. + + auto. + + simpl. rewrite IHxs. + rewrite andb_true_r. reflexivity. +Qed. + +Lemma map2_and_0_absorb: forall (a: list bool), (map2 andb a (mk_list_false (length a))) = (mk_list_false (length a)). +Proof. intro a. induction a as [ | a' xs IHxs]. + - simpl. reflexivity. + - simpl. rewrite IHxs. + rewrite andb_false_r; reflexivity. +Qed. + +Lemma map2_and_length: forall (a b: list bool), length a = length b -> length a = length (map2 andb a b). +Proof. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b ys]. + - simpl. intros. exact H. + - intros. simpl in *. apply f_equal. apply IHxs. + inversion H; auto. +Qed. + +(*bitvector AND properties*) + +Lemma bv_and_size n a b : size a = n -> size b = n -> size (bv_and a b) = n. +Proof. + unfold bv_and. intros H1 H2. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size in *. rewrite <- map2_and_length. + - exact H1. + - unfold bits. now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_and_comm n a b : size a = n -> size b = n -> bv_and a b = bv_and b a. +Proof. + intros H1 H2. unfold bv_and. rewrite H1, H2. + rewrite N.eqb_compare, N.compare_refl. + rewrite map2_and_comm. reflexivity. +Qed. + +Lemma bv_and_assoc: forall n a b c, size a = n -> size b = n -> size c = n -> + (bv_and a (bv_and b c)) = (bv_and (bv_and a b) c). +Proof. intros n a b c H0 H1 H2. + unfold bv_and, size, bits in *. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite N.eqb_compare. rewrite N.eqb_compare. rewrite H0. rewrite N.compare_refl. + rewrite <- (@map2_and_length a b). rewrite <- map2_and_length. rewrite H0, H1. + rewrite N.compare_refl. + rewrite map2_and_assoc; reflexivity. + now rewrite <- Nat2N.inj_iff, H1. + now rewrite <- Nat2N.inj_iff, H0. +Qed. + +Lemma bv_and_idem1: forall a b n, size a = n -> size b = n -> (bv_and (bv_and a b) a) = (bv_and a b). +Proof. intros a b n H0 H1. + unfold bv_and. rewrite H0. do 2 rewrite N.eqb_compare. + unfold size in *. + rewrite H1. rewrite N.compare_refl. + rewrite <- H0. unfold bits. + rewrite <- map2_and_length. rewrite N.compare_refl. + rewrite map2_and_idem1; reflexivity. + now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_and_idem2: forall a b n, size a = n -> size b = n -> (bv_and (bv_and a b) b) = (bv_and a b). +Proof. intros a b n H0 H1. + unfold bv_and. rewrite H0. do 2 rewrite N.eqb_compare. + unfold size in *. + rewrite H1. rewrite N.compare_refl. + rewrite <- H0. unfold bits. + rewrite <- map2_and_length. rewrite N.compare_refl. + rewrite map2_and_idem2; reflexivity. + now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Definition bv_empty: bitvector := nil. + +Lemma bv_and_empty_empty1: forall a, (bv_and a bv_empty) = bv_empty. +Proof. intros a. unfold bv_empty, bv_and, size, bits. simpl. + rewrite map2_and_empty_empty1. + case_eq (N.compare (N.of_nat (length a)) 0); intro H; simpl. + - apply (N.compare_eq (N.of_nat (length a))) in H. + rewrite H. simpl. reflexivity. + - rewrite N.eqb_compare. rewrite H; reflexivity. + - rewrite N.eqb_compare. rewrite H; reflexivity. +Qed. + +Lemma bv_and_nth_bitOf: forall a b n (i: nat), + (size a) = n -> (size b) = n -> + (i <= (nat_of_N (size a)))%nat -> + nth i (bits (bv_and a b)) false = (nth i (bits a) false) && (nth i (bits b) false). +Proof. intros a b n i H0 H1 H2. + unfold bv_and. rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + apply map2_and_nth_bitOf; unfold size in *; unfold bits. + now rewrite <- Nat2N.inj_iff, H1. rewrite Nat2N.id in H2; exact H2. +Qed. + +Lemma bv_and_empty_empty2: forall a, (bv_and bv_empty a) = bv_empty. +Proof. intro a. unfold bv_and, bv_empty, size. + case (length a); simpl; auto. +Qed. + +Lemma bv_and_1_neutral: forall a, (bv_and a (mk_list_true (length (bits a)))) = a. +Proof. intro a. unfold bv_and. + rewrite N.eqb_compare. unfold size, bits. rewrite length_mk_list_true. + rewrite N.compare_refl. + rewrite map2_and_1_neutral. reflexivity. +Qed. + +Lemma bv_and_0_absorb: forall a, (bv_and a (mk_list_false (length (bits a)))) = (mk_list_false (length (bits a))). +Proof. intro a. unfold bv_and. + rewrite N.eqb_compare. unfold size, bits. rewrite length_mk_list_false. + rewrite N.compare_refl. + rewrite map2_and_0_absorb. reflexivity. +Qed. + +(* lists bitwise OR properties *) + +Lemma map2_or_comm: forall (a b: list bool), (map2 orb a b) = (map2 orb b a). +Proof. intros a. induction a as [ | a' xs IHxs]. + intros [ | b' ys]. + - simpl. auto. + - simpl. auto. + - intros [ | b' ys]. + + simpl. auto. + + intros. simpl. + cut (a' || b' = b' || a'). intro H. rewrite <- H. apply f_equal. + apply IHxs. apply orb_comm. +Qed. + +Lemma map2_or_assoc: forall (a b c: list bool), (map2 orb a (map2 orb b c)) = (map2 orb (map2 orb a b) c). +Proof. intro a. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b' ys]. + - simpl. auto. + - intros [ | c' zs]. + + simpl. auto. + + simpl. cut (a' || (b' || c') = a' || b' || c'). intro H. rewrite <- H. apply f_equal. + apply IHxs. apply orb_assoc. +Qed. + +Lemma map2_or_length: forall (a b: list bool), length a = length b -> length a = length (map2 orb a b). +Proof. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b ys]. + - simpl. intros. exact H. + - intros. simpl in *. apply f_equal. apply IHxs. + inversion H; auto. +Qed. + +Lemma map2_or_empty_empty1: forall (a: list bool), (map2 orb a []) = []. +Proof. intros a. induction a as [ | a' xs IHxs]; simpl; auto. Qed. + +Lemma map2_or_empty_empty2: forall (a: list bool), (map2 orb [] a) = []. +Proof. intros a. rewrite map2_or_comm. apply map2_or_empty_empty1. Qed. + +Lemma map2_or_nth_bitOf: forall (a b: list bool) (i: nat), + (length a) = (length b) -> + (i <= (length a))%nat -> + nth i (map2 orb a b) false = (nth i a false) || (nth i b false). +Proof. intro a. + induction a as [ | a xs IHxs]. + - intros [ | b ys]. + + intros i H0 H1. do 2 rewrite map2_nth_empty_false. reflexivity. + + intros i H0 H1. rewrite map2_or_empty_empty2. + rewrite map2_nth_empty_false. contradict H1. simpl. unfold not. intros. easy. + - intros [ | b ys]. + + intros i H0 H1. rewrite map2_or_empty_empty1. + rewrite map2_nth_empty_false. rewrite orb_false_r. rewrite H0 in H1. + contradict H1. simpl. unfold not. intros. easy. + + intros i H0 H1. simpl. + revert i H1. intros [ | i]; [ |intros IHi]. + * simpl. auto. + * apply IHxs. + inversion H0; reflexivity. + inversion IHi; lia. +Qed. + +Lemma map2_or_0_neutral: forall (a: list bool), (map2 orb a (mk_list_false (length a))) = a. +Proof. intro a. + induction a as [ | a xs IHxs]. + + auto. + + simpl. rewrite IHxs. + rewrite orb_false_r. reflexivity. +Qed. + +Lemma map2_or_1_true: forall (a: list bool), (map2 orb a (mk_list_true (length a))) = (mk_list_true (length a)). +Proof. intro a. induction a as [ | a' xs IHxs]. + - simpl. reflexivity. + - simpl. rewrite IHxs. + rewrite orb_true_r; reflexivity. +Qed. + +(*bitvector OR properties*) + +Lemma bv_or_size n a b : size a = n -> size b = n -> size (bv_or a b) = n. +Proof. + unfold bv_or. intros H1 H2. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size in *. rewrite <- map2_or_length. + - exact H1. + - unfold bits. now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_or_comm: forall n a b, (size a) = n -> (size b) = n -> bv_or a b = bv_or b a. +Proof. intros a b n H0 H1. unfold bv_or. + rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite map2_or_comm. reflexivity. +Qed. + +Lemma bv_or_assoc: forall n a b c, (size a) = n -> (size b) = n -> (size c) = n -> + (bv_or a (bv_or b c)) = (bv_or (bv_or a b) c). +Proof. intros n a b c H0 H1 H2. + unfold bv_or. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size, bits in *. rewrite <- (@map2_or_length b c). + rewrite H0, H1. + rewrite N.compare_refl. + rewrite N.eqb_compare. rewrite N.eqb_compare. + rewrite N.compare_refl. rewrite <- (@map2_or_length a b). + rewrite H0. rewrite N.compare_refl. + rewrite map2_or_assoc; reflexivity. + now rewrite <- Nat2N.inj_iff, H0. + now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_or_empty_empty1: forall a, (bv_or a bv_empty) = bv_empty. +Proof. intros a. unfold bv_empty. + unfold bv_or, bits, size. simpl. + case_eq (N.compare (N.of_nat (length a)) 0); intro H; simpl. + - apply (N.compare_eq (N.of_nat (length a)) 0) in H. + rewrite H. simpl. rewrite map2_or_empty_empty1; reflexivity. + - rewrite N.eqb_compare. rewrite H; reflexivity. + - rewrite N.eqb_compare. rewrite H; reflexivity. +Qed. + +Lemma bv_or_nth_bitOf: forall a b n (i: nat), + (size a) = n -> (size b) = n -> + (i <= (nat_of_N (size a)))%nat -> + nth i (bits (bv_or a b)) false = (nth i (bits a) false) || (nth i (bits b) false). +Proof. intros a b n i H0 H1 H2. + unfold bv_or. rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + apply map2_or_nth_bitOf; unfold size in *; unfold bits. + now rewrite <- Nat2N.inj_iff, H1. rewrite Nat2N.id in H2; exact H2. +Qed. + +Lemma bv_or_0_neutral: forall a, (bv_or a (mk_list_false (length (bits a)))) = a. +Proof. intro a. unfold bv_or. + rewrite N.eqb_compare. unfold size, bits. rewrite length_mk_list_false. + rewrite N.compare_refl. + rewrite map2_or_0_neutral. reflexivity. +Qed. + +Lemma bv_or_1_true: forall a, (bv_or a (mk_list_true (length (bits a)))) = (mk_list_true (length (bits a))). +Proof. intro a. unfold bv_or. + rewrite N.eqb_compare. unfold size, bits. rewrite length_mk_list_true. + rewrite N.compare_refl. + rewrite map2_or_1_true. reflexivity. +Qed. + +(* lists bitwise XOR properties *) + +Lemma map2_xor_comm: forall (a b: list bool), (map2 xorb a b) = (map2 xorb b a). +Proof. intros a. induction a as [ | a' xs IHxs]. + intros [ | b' ys]. + - simpl. auto. + - simpl. auto. + - intros [ | b' ys]. + + simpl. auto. + + intros. simpl. + cut (xorb a' b' = xorb b' a'). intro H. rewrite <- H. apply f_equal. + apply IHxs. apply xorb_comm. +Qed. + +Lemma map2_xor_assoc: forall (a b c: list bool), (map2 xorb a (map2 xorb b c)) = (map2 xorb (map2 xorb a b) c). +Proof. intro a. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b' ys]. + - simpl. auto. + - intros [ | c' zs]. + + simpl. auto. + + simpl. cut (xorb a' (xorb b' c') = (xorb (xorb a' b') c')). intro H. rewrite <- H. apply f_equal. + apply IHxs. rewrite xorb_assoc_reverse. reflexivity. +Qed. + +Lemma map2_xor_length: forall (a b: list bool), length a = length b -> length a = length (map2 xorb a b). +Proof. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b ys]. + - simpl. intros. exact H. + - intros. simpl in *. apply f_equal. apply IHxs. + inversion H; auto. +Qed. + +Lemma map2_xor_empty_empty1: forall (a: list bool), (map2 xorb a []) = []. +Proof. intros a. induction a as [ | a' xs IHxs]; simpl; auto. Qed. + +Lemma map2_xor_empty_empty2: forall (a: list bool), (map2 xorb [] a) = []. +Proof. intros a. rewrite map2_xor_comm. apply map2_xor_empty_empty1. Qed. + +Lemma map2_xor_nth_bitOf: forall (a b: list bool) (i: nat), + (length a) = (length b) -> + (i <= (length a))%nat -> + nth i (map2 xorb a b) false = xorb (nth i a false) (nth i b false). +Proof. intro a. + induction a as [ | a xs IHxs]. + - intros [ | b ys]. + + intros i H0 H1. do 2 rewrite map2_nth_empty_false. reflexivity. + + intros i H0 H1. rewrite map2_xor_empty_empty2. + rewrite map2_nth_empty_false. contradict H1. simpl. unfold not. intros. easy. + - intros [ | b ys]. + + intros i H0 H1. rewrite map2_xor_empty_empty1. + rewrite map2_nth_empty_false. rewrite xorb_false_r. rewrite H0 in H1. + contradict H1. simpl. unfold not. intros. easy. + + intros i H0 H1. simpl. + revert i H1. intros [ | i]; [ |intros IHi]. + * simpl. auto. + * apply IHxs. + inversion H0; reflexivity. + inversion IHi; lia. +Qed. + +Lemma map2_xor_0_neutral: forall (a: list bool), (map2 xorb a (mk_list_false (length a))) = a. +Proof. intro a. + induction a as [ | a xs IHxs]. + + auto. + + simpl. rewrite IHxs. + rewrite xorb_false_r. reflexivity. +Qed. + +Lemma map2_xor_1_true: forall (a: list bool), (map2 xorb a (mk_list_true (length a))) = map negb a. +Proof. intro a. induction a as [ | a' xs IHxs]. + - simpl. reflexivity. + - simpl. rewrite IHxs. rewrite <- IHxs. + rewrite xorb_true_r; reflexivity. +Qed. + +(*bitvector OR properties*) + +Lemma bv_xor_size n a b : size a = n -> size b = n -> size (bv_xor a b) = n. +Proof. + unfold bv_xor. intros H1 H2. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size in *. rewrite <- map2_xor_length. + - exact H1. + - unfold bits. now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_xor_comm: forall n a b, (size a) = n -> (size b) = n -> bv_xor a b = bv_xor b a. +Proof. intros n a b H0 H1. unfold bv_xor. + rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite map2_xor_comm. reflexivity. +Qed. + +Lemma bv_xor_assoc: forall n a b c, (size a) = n -> (size b) = n -> (size c) = n -> + (bv_xor a (bv_xor b c)) = (bv_xor (bv_xor a b) c). +Proof. intros n a b c H0 H1 H2. + unfold bv_xor. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size, bits in *. rewrite <- (@map2_xor_length b c). + rewrite H0, H1. + rewrite N.compare_refl. + rewrite N.eqb_compare. rewrite N.eqb_compare. + rewrite N.compare_refl. rewrite <- (@map2_xor_length a b). + rewrite H0. rewrite N.compare_refl. + rewrite map2_xor_assoc; reflexivity. + now rewrite <- Nat2N.inj_iff, H0. + now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_xor_empty_empty1: forall a, (bv_xor a bv_empty) = bv_empty. +Proof. intros a. unfold bv_empty. + unfold bv_xor, bits, size. simpl. + case_eq (N.compare (N.of_nat (length a)) 0); intro H; simpl. + - apply (N.compare_eq (N.of_nat (length a)) 0) in H. + rewrite H. simpl. rewrite map2_xor_empty_empty1; reflexivity. + - rewrite N.eqb_compare. rewrite H; reflexivity. + - rewrite N.eqb_compare. rewrite H; reflexivity. +Qed. + +Lemma bv_xor_nth_bitOf: forall a b n (i: nat), + (size a) = n -> (size b) = n -> + (i <= (nat_of_N (size a)))%nat -> + nth i (bits (bv_xor a b)) false = xorb (nth i (bits a) false) (nth i (bits b) false). +Proof. intros a b n i H0 H1 H2. + unfold bv_xor. rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + apply map2_xor_nth_bitOf; unfold size in *; unfold bits. + now rewrite <- Nat2N.inj_iff, H1. rewrite Nat2N.id in H2; exact H2. +Qed. + +Lemma bv_xor_0_neutral: forall a, (bv_xor a (mk_list_false (length (bits a)))) = a. +Proof. intro a. unfold bv_xor. + rewrite N.eqb_compare. unfold size, bits. rewrite length_mk_list_false. + rewrite N.compare_refl. + rewrite map2_xor_0_neutral. reflexivity. +Qed. + +Lemma bv_xor_1_true: forall a, (bv_xor a (mk_list_true (length (bits a)))) = map negb a. +Proof. intro a. unfold bv_xor. + rewrite N.eqb_compare. unfold size, bits. rewrite length_mk_list_true. + rewrite N.compare_refl. + rewrite map2_xor_1_true. reflexivity. +Qed. + +(*bitwise NOT properties*) + +Lemma not_list_length: forall a, length a = length (map negb a). +Proof. intro a. + induction a as [ | a xs IHxs]. + - auto. + - simpl. apply f_equal. exact IHxs. +Qed. + +Lemma not_list_involutative: forall a, map negb (map negb a) = a. +Proof. intro a. + induction a as [ | a xs IHxs]; auto. + simpl. rewrite negb_involutive. apply f_equal. exact IHxs. +Qed. + +Lemma not_list_false_true: forall n, map negb (mk_list_false n) = mk_list_true n. +Proof. intro n. + induction n as [ | n IHn]. + - auto. + - simpl. apply f_equal. exact IHn. +Qed. + +Lemma not_list_true_false: forall n, map negb (mk_list_true n) = mk_list_false n. +Proof. intro n. + induction n as [ | n IHn]. + - auto. + - simpl. apply f_equal. exact IHn. +Qed. + +Lemma not_list_and_or: forall a b, map negb (map2 andb a b) = map2 orb (map negb a) (map negb b). +Proof. intro a. + induction a as [ | a xs IHxs]. + - auto. + - intros [ | b ys]. + + auto. + + simpl. rewrite negb_andb. apply f_equal. apply IHxs. +Qed. + +Lemma not_list_or_and: forall a b, map negb (map2 orb a b) = map2 andb (map negb a) (map negb b). +Proof. intro a. + induction a as [ | a xs IHxs]. + - auto. + - intros [ | b ys]. + + auto. + + simpl. rewrite negb_orb. apply f_equal. apply IHxs. +Qed. + +(*bitvector NOT properties*) + +Lemma bv_not_size: forall n a, (size a) = n -> size (bv_not a) = n. +Proof. intros n a H. unfold bv_not. + unfold size, bits in *. rewrite <- not_list_length. exact H. +Qed. + +Lemma bv_not_involutive: forall a, bv_not (bv_not a) = a. +Proof. intro a. unfold bv_not. + unfold size, bits. rewrite not_list_involutative. reflexivity. +Qed. + +Lemma bv_not_false_true: forall n, bv_not (mk_list_false n) = (mk_list_true n). +Proof. intros n. unfold bv_not. + unfold size, bits. rewrite not_list_false_true. reflexivity. +Qed. + +Lemma bv_not_true_false: forall n, bv_not (mk_list_true n) = (mk_list_false n). +Proof. intros n. unfold bv_not. + unfold size, bits. rewrite not_list_true_false. reflexivity. +Qed. + +Lemma bv_not_and_or: forall n a b, (size a) = n -> (size b) = n -> bv_not (bv_and a b) = bv_or (bv_not a) (bv_not b). +Proof. intros n a b H0 H1. unfold bv_and in *. + rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + unfold bv_or, size, bits in *. + do 2 rewrite <- not_list_length. rewrite H0, H1. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold bv_not, size, bits in *. + rewrite not_list_and_or. reflexivity. +Qed. + +Lemma bv_not_or_and: forall n a b, (size a) = n -> (size b) = n -> bv_not (bv_or a b) = bv_and (bv_not a) (bv_not b). +Proof. intros n a b H0 H1. unfold bv_and, size, bits in *. + do 2 rewrite <- not_list_length. + rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + unfold bv_or, size, bits in *. + rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + unfold bv_not, size, bits in *. + rewrite not_list_or_and. reflexivity. +Qed. + +(* list bitwise ADD properties*) + +Lemma add_carry_ff: forall a, add_carry a false false = (a, false). +Proof. intros a. + case a; simpl; auto. +Qed. + +Lemma add_carry_neg_f: forall a, add_carry a (negb a) false = (true, false). +Proof. intros a. + case a; simpl; auto. +Qed. + +Lemma add_carry_neg_f_r: forall a, add_carry (negb a) a false = (true, false). +Proof. intros a. + case a; simpl; auto. +Qed. + +Lemma add_carry_neg_t: forall a, add_carry a (negb a) true = (false, true). +Proof. intros a. + case a; simpl; auto. +Qed. + +Lemma add_carry_tt: forall a, add_carry a true true = (a, true). +Proof. intro a. case a; auto. Qed. + +Lemma add_list_empty_l: forall (a: list bool), (add_list [] a) = []. +Proof. intro a. induction a as [ | a xs IHxs]. + - unfold add_list. simpl. reflexivity. + - apply IHxs. +Qed. + +Lemma add_list_empty_r: forall (a: list bool), (add_list a []) = []. +Proof. intro a. induction a as [ | a xs IHxs]; unfold add_list; simpl; reflexivity. Qed. + +Lemma add_list_ingr_l: forall (a: list bool) (c: bool), (add_list_ingr [] a c) = []. +Proof. intro a. induction a as [ | a xs IHxs]; unfold add_list; simpl; reflexivity. Qed. + +Lemma add_list_ingr_r: forall (a: list bool) (c: bool), (add_list_ingr a [] c) = []. +Proof. intro a. induction a as [ | a xs IHxs]; unfold add_list; simpl; reflexivity. Qed. + +Lemma add_list_carry_comm: forall (a b: list bool) (c: bool), add_list_ingr a b c = add_list_ingr b a c. +Proof. intros a. induction a as [ | a' xs IHxs]; intros b c. + - simpl. rewrite add_list_ingr_r. reflexivity. + - case b as [ | b' ys]. + + simpl. auto. + + simpl in *. cut (add_carry a' b' c = add_carry b' a' c). + * intro H. rewrite H. destruct (add_carry b' a' c) as (r, c0). + rewrite IHxs. reflexivity. + * case a', b', c; auto. +Qed. + +Lemma add_list_comm: forall (a b: list bool), (add_list a b) = (add_list b a). +Proof. intros a b. unfold add_list. apply (add_list_carry_comm a b false). Qed. + +Lemma add_list_carry_assoc: forall (a b c: list bool) (d1 d2 d3 d4: bool), + add_carry d1 d2 false = add_carry d3 d4 false -> + (add_list_ingr (add_list_ingr a b d1) c d2) = (add_list_ingr a (add_list_ingr b c d3) d4). +Proof. intros a. induction a as [ | a' xs IHxs]; intros b c d1 d2 d3 d4. + - simpl. reflexivity. + - case b as [ | b' ys]. + + simpl. auto. + + case c as [ | c' zs]. + * simpl. rewrite add_list_ingr_r. auto. + * simpl. + case_eq (add_carry a' b' d1); intros r0 c0 Heq0. simpl. + case_eq (add_carry r0 c' d2); intros r1 c1 Heq1. + case_eq (add_carry b' c' d3); intros r3 c3 Heq3. + case_eq (add_carry a' r3 d4); intros r2 c2 Heq2. + intro H. rewrite (IHxs _ _ c0 c1 c3 c2); + revert Heq0 Heq1 Heq3 Heq2; + case a', b', c', d1, d2, d3, d4; simpl; do 4 (intros H'; inversion_clear H'); + try reflexivity; simpl in H; discriminate. +Qed. + +Lemma add_list_carry_length_eq: forall (a b: list bool) c, length a = length b -> length a = length (add_list_ingr a b c). +Proof. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b ys]. + - simpl. intros. exact H. + - intros. simpl in *. + case_eq (add_carry a' b c); intros r c0 Heq. simpl. apply f_equal. + specialize (@IHxs ys). apply IHxs. inversion H; reflexivity. +Qed. + +Lemma add_list_carry_length_ge: forall (a b: list bool) c, (length a >= length b)%nat -> length b = length (add_list_ingr a b c). +Proof. induction a as [ | a' xs IHxs]. + simpl. intros b H0 H1. lia. + intros [ | b ys]. + - simpl. intros. auto. + - intros. simpl in *. + case_eq (add_carry a' b c); intros r c0 Heq. simpl. apply f_equal. + specialize (@IHxs ys). apply IHxs. lia. +Qed. + +Lemma add_list_carry_length_le: forall (a b: list bool) c, (length b >= length a)%nat -> length a = length (add_list_ingr a b c). +Proof. induction a as [ | a' xs IHxs]. + simpl. intros b H0 H1. reflexivity. + intros [ | b ys]. + - simpl. intros. contradict H. lia. + - intros. simpl in *. + case_eq (add_carry a' b c); intros r c0 Heq. simpl. apply f_equal. + specialize (@IHxs ys). apply IHxs. lia. +Qed. + +Lemma bv_neg_size: forall n a, (size a) = n -> size (bv_neg a) = n. +Proof. intros n a H. unfold bv_neg. + unfold size, bits in *. unfold twos_complement. + specialize (@add_list_carry_length_eq (map negb a) (mk_list_false (length a)) true). + intros. rewrite <- H0. now rewrite map_length. + rewrite map_length. + now rewrite length_mk_list_false. +Qed. + +Lemma length_add_list_eq: forall (a b: list bool), length a = length b -> length a = length (add_list a b). +Proof. intros a b H. unfold add_list. apply (@add_list_carry_length_eq a b false). exact H. Qed. + +Lemma length_add_list_ge: forall (a b: list bool), (length a >= length b)%nat -> length b = length (add_list a b). +Proof. intros a b H. unfold add_list. apply (@add_list_carry_length_ge a b false). exact H. Qed. + +Lemma length_add_list_le: forall (a b: list bool), (length b >= length a)%nat -> length a = length (add_list a b). +Proof. intros a b H. unfold add_list. apply (@add_list_carry_length_le a b false). exact H. Qed. + +Lemma add_list_assoc: forall (a b c: list bool), (add_list (add_list a b) c) = (add_list a (add_list b c)). +Proof. intros a b c. unfold add_list. + apply (@add_list_carry_assoc a b c false false false false). + simpl; reflexivity. +Qed. + +Lemma add_list_carry_empty_neutral_n_l: forall (a: list bool) n, (n >= (length a))%nat -> (add_list_ingr (mk_list_false n) a false) = a. +Proof. intro a. induction a as [ | a' xs IHxs]. + - intro n. rewrite add_list_ingr_r. reflexivity. + - intros [ | n]. + + simpl. intro H. contradict H. easy. + + simpl. intro H. + case a'; apply f_equal; apply IHxs; lia. +Qed. + +Lemma add_list_carry_empty_neutral_n_r: forall (a: list bool) n, (n >= (length a))%nat -> (add_list_ingr a (mk_list_false n) false) = a. +Proof. intro a. induction a as [ | a' xs IHxs]. + - intro n. rewrite add_list_ingr_l. reflexivity. + - intros [ | n]. + + simpl. intro H. contradict H. easy. + + simpl. intro H. + case a'; apply f_equal; apply IHxs; lia. +Qed. + +Lemma add_list_carry_empty_neutral_l: forall (a: list bool), (add_list_ingr (mk_list_false (length a)) a false) = a. +Proof. intro a. + rewrite add_list_carry_empty_neutral_n_l; auto. +Qed. + +Lemma add_list_carry_empty_neutral_r: forall (a: list bool), (add_list_ingr a (mk_list_false (length a)) false) = a. +Proof. intro a. + rewrite add_list_carry_empty_neutral_n_r; auto. +Qed. + +Lemma add_list_empty_neutral_n_l: forall (a: list bool) n, (n >= (length a))%nat -> (add_list (mk_list_false n) a) = a. +Proof. intros a. unfold add_list. + apply (@add_list_carry_empty_neutral_n_l a). +Qed. + +Lemma add_list_empty_neutral_n_r: forall (a: list bool) n, (n >= (length a))%nat -> (add_list a (mk_list_false n)) = a. +Proof. intros a. unfold add_list. + apply (@add_list_carry_empty_neutral_n_r a). +Qed. + +Lemma add_list_empty_neutral_r: forall (a: list bool), (add_list a (mk_list_false (length a))) = a. +Proof. intros a. unfold add_list. + apply (@add_list_carry_empty_neutral_r a). +Qed. + +Lemma add_list_empty_neutral_l: forall (a: list bool), (add_list (mk_list_false (length a)) a) = a. +Proof. intros a. unfold add_list. + apply (@add_list_carry_empty_neutral_l a). +Qed. + +Lemma add_list_carry_unit_t : forall a, add_list_ingr a (mk_list_true (length a)) true = a. +Proof. intro a. + induction a as [ | a xs IHxs]. + - simpl. reflexivity. + - simpl. case_eq (add_carry a true true). intros r0 c0 Heq0. + rewrite add_carry_tt in Heq0. inversion Heq0. + apply f_equal. exact IHxs. +Qed. + +Lemma add_list_carry_twice: forall a c, add_list_ingr a a c = removelast (c :: a). +Proof. intro a. + induction a as [ | a xs IHxs]. + - intros c. simpl. reflexivity. + - intros [ | ]. + + simpl. case a. + * simpl. rewrite IHxs. + case_eq xs. intro Heq0. simpl. reflexivity. + reflexivity. + * simpl. rewrite IHxs. + case_eq xs. intro Heq0. simpl. reflexivity. + reflexivity. + + simpl. case a. + * simpl. rewrite IHxs. + case_eq xs. intro Heq0. simpl. reflexivity. + reflexivity. + * simpl. rewrite IHxs. + case_eq xs. intro Heq0. simpl. reflexivity. + reflexivity. +Qed. + +Lemma add_list_twice: forall a, add_list a a = removelast (false :: a). +Proof. intro a. + unfold add_list. rewrite add_list_carry_twice. reflexivity. +Qed. + +(*bitvector ADD properties*) + +Lemma bv_add_size: forall n a b, (size a) = n -> (@size b) = n -> size (bv_add a b) = n. +Proof. intros n a b H0 H1. + unfold bv_add. rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size, bits in *. rewrite <- (@length_add_list_eq a b). auto. + now rewrite <- Nat2N.inj_iff, H0. +Qed. + +Lemma bv_add_comm: forall n a b, (size a) = n -> (size b) = n -> bv_add a b = bv_add b a. +Proof. intros n a b H0 H1. + unfold bv_add, size, bits in *. rewrite H0, H1. + rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite add_list_comm. reflexivity. +Qed. + +Lemma bv_add_assoc: forall n a b c, (size a) = n -> (size b) = n -> (size c) = n -> + (bv_add a (bv_add b c)) = (bv_add (bv_add a b) c). +Proof. intros n a b c H0 H1 H2. + unfold bv_add, size, bits in *. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite <- (@length_add_list_eq b c). rewrite H0, H1. + rewrite N.compare_refl. rewrite N.eqb_compare. + rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite <- (@length_add_list_eq a b). rewrite H0. + rewrite N.compare_refl. + rewrite add_list_assoc. reflexivity. + now rewrite <- Nat2N.inj_iff, H0. + now rewrite <- Nat2N.inj_iff, H1. +Qed. + +Lemma bv_add_empty_neutral_l: forall a, (bv_add (mk_list_false (length (bits a))) a) = a. +Proof. intro a. unfold bv_add, size, bits. + rewrite N.eqb_compare. rewrite length_mk_list_false. rewrite N.compare_refl. + rewrite add_list_empty_neutral_l. reflexivity. +Qed. + +Lemma bv_add_empty_neutral_r: forall a, (bv_add a (mk_list_false (length (bits a)))) = a. +Proof. intro a. unfold bv_add, size, bits. + rewrite N.eqb_compare. rewrite length_mk_list_false. rewrite N.compare_refl. + rewrite add_list_empty_neutral_r. reflexivity. +Qed. + +Lemma bv_add_twice: forall a, bv_add a a = removelast (false :: a). +Proof. intro a. unfold bv_add, size, bits. + rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite add_list_twice. reflexivity. +Qed. + +(* bitwise SUBST properties *) + +Lemma subst_list_empty_empty_l: forall a, (subst_list [] a) = []. +Proof. intro a. unfold subst_list; auto. Qed. + +Lemma subst_list_empty_empty_r: forall a, (subst_list a []) = []. +Proof. intro a. + induction a as [ | a xs IHxs]. + - auto. + - unfold subst_list; auto. +Qed. + +Lemma subst_list'_empty_empty_r: forall a, (subst_list' a []) = []. +Proof. intro a. + induction a as [ | a xs IHxs]. + - auto. + - unfold subst_list' in *. unfold twos_complement. simpl. reflexivity. +Qed. + +Lemma subst_list_borrow_length: forall (a b: list bool) c, length a = length b -> length a = length (subst_list_borrow a b c). +Proof. induction a as [ | a' xs IHxs]. + simpl. auto. + intros [ | b ys]. + - simpl. intros. exact H. + - intros. simpl in *. + case_eq (subst_borrow a' b c); intros r c0 Heq. simpl. apply f_equal. + specialize (@IHxs ys). apply IHxs. inversion H; reflexivity. +Qed. + +Lemma length_twos_complement: forall (a: list bool), length a = length (twos_complement a). +Proof. intro a. + induction a as [ | a' xs IHxs]. + - auto. + - unfold twos_complement. specialize (@add_list_carry_length_eq (map negb (a' :: xs)) (mk_list_false (length (a' :: xs))) true). + intro H. rewrite <- H. simpl. apply f_equal. rewrite <- not_list_length. reflexivity. + rewrite length_mk_list_false. rewrite <- not_list_length. reflexivity. +Qed. + +Lemma subst_list_length: forall (a b: list bool), length a = length b -> length a = length (subst_list a b). +Proof. intros a b H. unfold subst_list. apply (@subst_list_borrow_length a b false). exact H. Qed. + +Lemma subst_list'_length: forall (a b: list bool), length a = length b -> length a = length (subst_list' a b). +Proof. intros a b H. unfold subst_list'. + rewrite <- (@length_add_list_eq a (twos_complement b)). + - reflexivity. + - rewrite <- (@length_twos_complement b). exact H. +Qed. + +Lemma subst_list_borrow_empty_neutral: forall (a: list bool), (subst_list_borrow a (mk_list_false (length a)) false) = a. +Proof. intro a. induction a as [ | a' xs IHxs]. + - simpl. reflexivity. + - simpl. + cut(subst_borrow a' false false = (a', false)). + + intro H. rewrite H. rewrite IHxs. reflexivity. + + unfold subst_borrow. case a'; auto. +Qed. + +Lemma subst_list_empty_neutral: forall (a: list bool), (subst_list a (mk_list_false (length a))) = a. +Proof. intros a. unfold subst_list. + apply (@subst_list_borrow_empty_neutral a). +Qed. + +Lemma twos_complement_cons_false: forall a, false :: twos_complement a = twos_complement (false :: a). +Proof. intro a. + induction a as [ | a xs IHxs]; unfold twos_complement; simpl; reflexivity. +Qed. + +Lemma twos_complement_false_false: forall n, twos_complement (mk_list_false n) = mk_list_false n. +Proof. intro n. + induction n as [ | n IHn]. + - auto. + - simpl. rewrite <- twos_complement_cons_false. + apply f_equal. exact IHn. +Qed. + +Lemma subst_list'_empty_neutral: forall (a: list bool), (subst_list' a (mk_list_false (length a))) = a. +Proof. intros a. unfold subst_list'. + rewrite (@twos_complement_false_false (length a)). + rewrite add_list_empty_neutral_r. reflexivity. +Qed. + +(* some list ult and slt properties *) + +Lemma ult_list_big_endian_trans : forall x y z, + ult_list_big_endian x y = true -> + ult_list_big_endian y z = true -> + ult_list_big_endian x z = true. +Proof. + intros x. induction x. + simpl. easy. + intros y z. + case y. + simpl. case x; easy. + intros b l. + intros. + simpl in *. case x in *. + case z in *. simpl in H0. case l in *; easy. + case l in *. + rewrite andb_true_iff in H. + destruct H. + apply negb_true_iff in H. subst. + simpl. case z in *. easy. + rewrite !orb_true_iff, !andb_true_iff in H0. + destruct H0. + destruct H. + apply Bool.eqb_prop in H. + subst. + rewrite orb_true_iff. now right. + destruct H. easy. + rewrite !orb_true_iff, !andb_true_iff in H, H0. + destruct H. + simpl in H. easy. + destruct H. + apply negb_true_iff in H. subst. + simpl. + destruct H0. + destruct H. + apply Bool.eqb_prop in H. + subst. + case z; easy. + destruct H. easy. + case l in *. + rewrite !orb_true_iff, !andb_true_iff in H. + simpl in H. destruct H. destruct H. case x in H1; easy. + destruct H. + apply negb_true_iff in H. subst. + simpl in H0. + case z in *; try easy. + case z in *; simpl in H0; try easy. + case b in H0; simpl in H0; try easy. + case z in *; try easy. + rewrite !orb_true_iff, !andb_true_iff in *. + destruct H. + destruct H. + destruct H0. + destruct H0. + apply Bool.eqb_prop in H. + apply Bool.eqb_prop in H0. + subst. + left. + split. + apply Bool.eqb_reflx. + now apply (IHx (b1 :: l) z H1 H2). + right. apply Bool.eqb_prop in H. now subst. + right. destruct H0, H0. + apply Bool.eqb_prop in H0. now subst. + split; easy. +Qed. + + +Lemma ult_list_trans : forall x y z, + ult_list x y = true -> ult_list y z = true -> ult_list x z = true. +Proof. unfold ult_list. intros x y z. apply ult_list_big_endian_trans. +Qed. + +Lemma ult_list_big_endian_not_eq : forall x y, + ult_list_big_endian x y = true -> x <> y. +Proof. + intros x. induction x. + simpl. easy. + intros y. + case y. + simpl. case x; easy. + intros b l. + simpl. + specialize (IHx l). + case x in *. + simpl. + case l in *. case a; case b; simpl; easy. + easy. + rewrite !orb_true_iff, !andb_true_iff. + intro. + destruct H. + destruct H. + apply IHx in H0. + apply Bool.eqb_prop in H. + rewrite H in *. + unfold not in *; intro. + inversion H1; subst. now apply H0. + destruct H. + apply negb_true_iff in H. subst. easy. +Qed. + +Lemma ult_list_not_eq : forall x y, ult_list x y = true -> x <> y. +Proof. unfold ult_list. + unfold not. intros. + apply ult_list_big_endian_not_eq in H. + subst. auto. +Qed. + +Lemma slt_list_big_endian_not_eq : forall x y, + slt_list_big_endian x y = true -> x <> y. +Proof. + intros x. induction x. + simpl. easy. + intros y. + case y. + simpl. case x; easy. + intros b l. + simpl. + specialize (IHx l). + case x in *. + simpl. + case l in *. case a; case b; simpl; easy. + easy. + rewrite !orb_true_iff, !andb_true_iff. + intro. + destruct H. + destruct H. + apply ult_list_big_endian_not_eq in H0. + apply Bool.eqb_prop in H. rewrite H in *. + unfold not in *. intros. apply H0. now inversion H1. + destruct H. + apply negb_true_iff in H0. subst. easy. +Qed. + +Lemma slt_list_not_eq : forall x y, slt_list x y = true -> x <> y. +Proof. unfold slt_list. + unfold not. intros. + apply slt_list_big_endian_not_eq in H. + subst. auto. +Qed. + + +Lemma ult_list_not_eqP : forall x y, ult_listP x y -> x <> y. +Proof. unfold ult_listP. + unfold not. intros. unfold ult_list in H. + case_eq (ult_list_big_endian (List.rev x) (List.rev y)); intros. + apply ult_list_big_endian_not_eq in H1. subst. now contradict H1. + now rewrite H1 in H. +Qed. + +Lemma slt_list_not_eqP : forall x y, slt_listP x y -> x <> y. +Proof. unfold slt_listP. + unfold not. intros. unfold slt_list in H. + case_eq (slt_list_big_endian (List.rev x) (List.rev y)); intros. + apply slt_list_big_endian_not_eq in H1. subst. now contradict H1. + now rewrite H1 in H. +Qed. + +Lemma bv_ult_B2P: forall x y, bv_ult x y = true <-> bv_ultP x y. +Proof. intros. split; intros; unfold bv_ult, bv_ultP in *. + case_eq (size x =? size y); intros; + rewrite H0 in H; unfold ult_listP. now rewrite H. + now contradict H. + unfold ult_listP in *. + case_eq (size x =? size y); intros. + rewrite H0 in H. + case_eq (ult_list x y); intros. easy. + rewrite H1 in H. now contradict H. + rewrite H0 in H. now contradict H. +Qed. + +Lemma bv_slt_B2P: forall x y, bv_slt x y = true <-> bv_sltP x y. +Proof. intros. split; intros; unfold bv_slt, bv_sltP in *. + case_eq (size x =? size y); intros; + rewrite H0 in H; unfold slt_listP. now rewrite H. + now contradict H. + unfold slt_listP in *. + case_eq (size x =? size y); intros. + rewrite H0 in H. + case_eq (slt_list x y); intros. easy. + rewrite H1 in H. now contradict H. + rewrite H0 in H. now contradict H. +Qed. + +Lemma nlt_be_neq_gt: forall x y, + length x = length y -> ult_list_big_endian x y = false -> + beq_list x y = false -> ult_list_big_endian y x = true. +Proof. intro x. + induction x as [ | x xs IHxs ]. + - intros. simpl in *. case y in *; now contradict H. + - intros. + simpl in H1. + + case_eq y; intros. + rewrite H2 in H. now contradict H. + simpl. + case_eq l. intros. case_eq xs. intros. + rewrite H2 in H1. + rewrite H4 in H0, H. simpl in H0, H. + rewrite H2, H3 in H0, H. + rewrite H4, H3 in H1. simpl in H1. rewrite andb_true_r in H1. + case b in *; case x in *; easy. + intros. + rewrite H4, H2, H3 in H. now contradict H. + intros. + rewrite H2, H3 in H0, H1. + + simpl in H0. + case_eq xs. intros. rewrite H4, H2, H3 in H. now contradict H. + intros. rewrite H4 in H0. + rewrite <- H3, <- H4. + rewrite <- H3, <- H4 in H0. + rewrite <- H3 in H1. + rewrite orb_false_iff in H0. + destruct H0. + + case_eq (Bool.eqb x b); intros. + rewrite H6 in H0, H1. + rewrite andb_true_l in H0, H1. + assert (Bool.eqb b x = true). + { case b in *; case x in *; easy. } + rewrite H7. rewrite andb_true_l. + rewrite orb_true_iff. + left. + apply IHxs. rewrite H2 in H. + now inversion H. + easy. easy. + assert (Bool.eqb b x = false). + { case b in *; case x in *; easy. } + rewrite H7. rewrite orb_false_l. + case x in *. case b in *. + now contradict H6. + now easy. + case b in *. + now contradict H5. + now contradict H6. +Qed. + +(** bitvector ult/slt *) + +Lemma bv_ult_not_eqP : forall x y, bv_ultP x y -> x <> y. +Proof. intros x y. unfold bv_ultP. + case_eq (size x =? size y); intros. + - now apply ult_list_not_eqP in H0. + - now contradict H0. +Qed. + +Lemma bv_slt_not_eqP : forall x y, bv_sltP x y -> x <> y. +Proof. intros x y. unfold bv_sltP. + case_eq (size x =? size y); intros. + - now apply slt_list_not_eqP in H0. + - now contradict H0. +Qed. + +Lemma bv_ult_not_eq : forall x y, bv_ult x y = true -> x <> y. +Proof. intros x y. unfold bv_ult. + case_eq (size x =? size y); intros. + - now apply ult_list_not_eq in H0. + - now contradict H0. +Qed. + +Lemma bv_slt_not_eq : forall x y, bv_slt x y = true -> x <> y. +Proof. intros x y. unfold bv_slt. + case_eq (size x =? size y); intros. + - now apply slt_list_not_eq in H0. + - now contradict H0. +Qed. + +Lemma rev_eq: forall x y, beq_list x y = true -> + beq_list (List.rev x) (List.rev y) = true. +Proof. intros. + apply List_eq in H. + rewrite H. + now apply List_eq_refl. +Qed. + +Lemma rev_neq: forall x y, beq_list x y = false -> + beq_list (List.rev x) (List.rev y) = false. +Proof. intros. + specialize (@List_neq x y H). + intros. + apply not_true_is_false. + unfold not in *. + intros. apply H0. + apply List_eq in H1. + + specialize (f_equal (@List.rev bool) H1 ). + intros. + now rewrite !rev_involutive in H2. +Qed. + +Lemma nlt_neq_gt: forall x y, + length x = length y -> ult_list x y = false -> + beq_list x y = false -> ult_list y x = true. +Proof. intros. + unfold ult_list in *. + apply nlt_be_neq_gt. + now rewrite !rev_length. + easy. + now apply rev_neq in H1. +Qed. + +(* bitvector SUBT properties *) + +Lemma bv_subt_size: forall n a b, size a = n -> size b = n -> size (bv_subt a b) = n. +Proof. intros n a b H0 H1. + unfold bv_subt, size, bits in *. rewrite H0, H1. rewrite N.eqb_compare. + rewrite N.compare_refl. rewrite <- subst_list_length. exact H0. + now rewrite <- Nat2N.inj_iff, H0. +Qed. + +Lemma bv_subt_empty_neutral_r: forall a, (bv_subt a (mk_list_false (length (bits a)))) = a. +Proof. intro a. unfold bv_subt, size, bits. + rewrite N.eqb_compare. rewrite length_mk_list_false. + rewrite N.compare_refl. + rewrite subst_list_empty_neutral. reflexivity. +Qed. + +Lemma bv_subt'_size: forall n a b, (size a) = n -> (size b) = n -> size (bv_subt' a b) = n. +Proof. intros n a b H0 H1. unfold bv_subt', size, bits in *. + rewrite H0, H1. rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite <- subst_list'_length. exact H0. + now rewrite <- Nat2N.inj_iff, H0. +Qed. + +Lemma bv_subt'_empty_neutral_r: forall a, (bv_subt' a (mk_list_false (length (bits a)))) = a. +Proof. intro a. unfold bv_subt', size, bits. + rewrite N.eqb_compare. rewrite length_mk_list_false. + rewrite N.compare_refl. + rewrite subst_list'_empty_neutral. reflexivity. +Qed. + +(* bitwise ADD-NEG properties *) + +Lemma add_neg_list_carry_false: forall a b c, add_list_ingr a (add_list_ingr b c true) false = add_list_ingr a (add_list_ingr b c false) true. +Proof. intro a. + induction a as [ | a xs IHxs]. + - simpl. auto. + - case b as [ | b ys]. + + simpl. auto. + + case c as [ | c zs]. + * simpl. auto. + * simpl. + case_eq (add_carry b c false); intros r0 c0 Heq0. + case_eq (add_carry b c true); intros r1 c1 Heq1. + case_eq (add_carry a r1 false); intros r2 c2 Heq2. + case_eq (add_carry a r0 true); intros r3 c3 Heq3. + case a, b, c; inversion Heq0; inversion Heq1; + inversion Heq2; inversion Heq3; rewrite <- H2 in H4; + rewrite <- H0 in H5; inversion H4; inversion H5; apply f_equal; + try reflexivity; rewrite IHxs; reflexivity. +Qed. + + +Lemma add_neg_list_carry_neg_f: forall a, (add_list_ingr a (map negb a) false) = mk_list_true (length a). +Proof. intro a. + induction a as [ | a xs IHxs]. + - simpl. reflexivity. + - simpl. + case_eq (add_carry a (negb a) false); intros r0 c0 Heq0. + rewrite add_carry_neg_f in Heq0. + inversion Heq0. rewrite IHxs. reflexivity. +Qed. + +Lemma add_neg_list_carry_neg_f_r: forall a, (add_list_ingr (map negb a) a false) = mk_list_true (length a). +Proof. intro a. + induction a as [ | a xs IHxs]. + - simpl. reflexivity. + - simpl. + case_eq (add_carry (negb a) a false); intros r0 c0 Heq0. + rewrite add_carry_neg_f_r in Heq0. + inversion Heq0. rewrite IHxs. reflexivity. +Qed. + +Lemma add_neg_list_carry_neg_t: forall a, (add_list_ingr a (map negb a) true) = mk_list_false (length a). +Proof. intro a. + induction a as [ | a xs IHxs]. + - simpl. reflexivity. + - simpl. + case_eq (add_carry a (negb a) true); intros r0 c0 Heq0. + rewrite add_carry_neg_t in Heq0. + inversion Heq0. rewrite IHxs. reflexivity. +Qed. + +Lemma add_neg_list_carry: forall a, add_list_ingr a (twos_complement a) false = mk_list_false (length a). +Proof. intro a. + induction a as [ | a xs IHxs]. + - simpl. reflexivity. + - unfold twos_complement. rewrite add_neg_list_carry_false. rewrite not_list_length at 1. + rewrite add_list_carry_empty_neutral_r. + rewrite add_neg_list_carry_neg_t. reflexivity. +Qed. + +Lemma add_neg_list_absorb: forall a, add_list a (twos_complement a) = mk_list_false (length a). +Proof. intro a. unfold add_list. rewrite add_neg_list_carry. reflexivity. Qed. + +(* bitvector ADD-NEG properties *) + +Lemma bv_add_neg_unit: forall a, bv_add a (bv_not a) = mk_list_true (nat_of_N (size a)). +Proof. intro a. unfold bv_add, bv_not, size, bits. rewrite not_list_length. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold add_list. rewrite add_neg_list_carry_neg_f. + rewrite Nat2N.id, not_list_length. reflexivity. +Qed. + + +(* bitwise ADD-SUBST properties *) + +Lemma add_subst_list_carry_opp: forall n a b, (length a) = n -> (length b) = n -> (add_list_ingr (subst_list' a b) b false) = a. +Proof. intros n a b H0 H1. + unfold subst_list', twos_complement, add_list. + rewrite add_neg_list_carry_false. rewrite not_list_length at 1. + rewrite add_list_carry_empty_neutral_r. + specialize (@add_list_carry_assoc a (map negb b) b true false false true). + intro H2. rewrite H2; try auto. rewrite add_neg_list_carry_neg_f_r. + rewrite H1. rewrite <- H0. rewrite add_list_carry_unit_t; reflexivity. +Qed. + +Lemma add_subst_opp: forall n a b, (length a) = n -> (length b) = n -> (add_list (subst_list' a b) b) = a. +Proof. intros n a b H0 H1. unfold add_list, size, bits. + apply (@add_subst_list_carry_opp n a b); easy. +Qed. + +(* bitvector ADD-SUBT properties *) + +Lemma bv_add_subst_opp: forall n a b, (size a) = n -> (size b) = n -> (bv_add (bv_subt' a b) b) = a. +Proof. intros n a b H0 H1. unfold bv_add, bv_subt', add_list, size, bits in *. + rewrite H0, H1. + rewrite N.eqb_compare. rewrite N.eqb_compare. rewrite N.compare_refl. + rewrite <- (@subst_list'_length a b). rewrite H0. + rewrite N.compare_refl. rewrite (@add_subst_list_carry_opp (nat_of_N n) a b); auto; + inversion H0; rewrite Nat2N.id; auto. + symmetry. now rewrite <- Nat2N.inj_iff, H0. + now rewrite <- Nat2N.inj_iff, H0. +Qed. + + (* bitvector MULT properties *) + +Lemma prop_mult_bool_step_k_h_len: forall a b c k, +length (mult_bool_step_k_h a b c k) = length a. +Proof. intro a. + induction a as [ | xa xsa IHa ]. + - intros. simpl. easy. + - intros. + case b in *. simpl. rewrite IHa. simpl. omega. + simpl. case (k - 1 <? 0)%Z; simpl; now rewrite IHa. +Qed. + + +Lemma empty_list_length: forall {A: Type} (a: list A), (length a = 0)%nat <-> a = []. +Proof. intros A a. + induction a; split; intros; auto; contradict H; easy. +Qed. + +Lemma prop_mult_bool_step: forall k' a b res k, + length (mult_bool_step a b res k k') = (length res)%nat. +Proof. intro k'. + induction k'. + - intros. simpl. rewrite prop_mult_bool_step_k_h_len. simpl. omega. + - intros. simpl. rewrite IHk'. rewrite prop_mult_bool_step_k_h_len. simpl; omega. +Qed. + +Lemma and_with_bool_len: forall a b, length (and_with_bool a (nth 0 b false)) = length a. +Proof. intro a. + - induction a. + intros. now simpl. + intros. simpl. now rewrite IHa. +Qed. + +Lemma bv_mult_size: forall n a b, (size a) = n -> (@size b) = n -> size (bv_mult a b) = n. +Proof. intros n a b H0 H1. + unfold bv_mult, size, bits in *. + rewrite H0, H1. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold mult_list, bvmult_bool. + case_eq (length a). + intros. + + rewrite empty_list_length in H. rewrite H in *. now simpl in *. + + intros. + case n0 in *. now rewrite and_with_bool_len. + rewrite prop_mult_bool_step. now rewrite and_with_bool_len. +Qed. + + (** list extraction *) + Fixpoint extract (x: list bool) (i j: nat) : list bool := + match x with + | [] => [] + | bx :: x' => + match i with + | O => + match j with + | O => [] + | S j' => bx :: extract x' i j' + end + | S i' => + match j with + | O => [] + | S j' => extract x' i' j' + end + end + end. + + Lemma zero_false: forall p, ~ 0 >= Npos p. + Proof. intro p. induction p; lia. Qed. + + Lemma min_distr: forall i j: N, N.to_nat (j - i) = ((N.to_nat j) - (N.to_nat i))%nat. + Proof. intros i j; case i; case j in *; try intros; lia. Qed. + + Lemma posSn: forall n, (Pos.to_nat (Pos.of_succ_nat n)) = S n. + Proof. intros; case n; [easy | intros; lia ]. Qed. + + Lemma _length_extract: forall a (i j: N) (H0: (N.of_nat (length a)) >= j) (H1: j >= i), + length (extract a 0 (N.to_nat j)) = (N.to_nat j). + Proof. intro a. + induction a as [ | xa xsa IHa ]. + - simpl. case i in *. case j in *. + easy. lia. + case j in *; lia. + - intros. simpl. + case_eq j. intros. + now simpl. + intros. rewrite <- H. + case_eq (N.to_nat j). + easy. intros. simpl. + apply f_equal. + specialize (@IHa 0%N (N.of_nat n)). + rewrite Nat2N.id in IHa. + apply IHa. + apply (f_equal (N.of_nat)) in H2. + rewrite N2Nat.id in H2. + rewrite H2 in H0. simpl in *. lia. + lia. + Qed. + + Lemma length_extract: forall a (i j: N) (H0: (N.of_nat (length a)) >= j) (H1: j >= i), + length (extract a (N.to_nat i) (N.to_nat j)) = (N.to_nat (j - i)). + Proof. intro a. + induction a as [ | xa xsa IHa]. + - intros. simpl. + case i in *. case j in *. + easy. simpl in *. + contradict H0. apply zero_false. + case j in *. now simpl. + apply zero_false in H0; now contradict H0. + - intros. simpl. + case_eq (N.to_nat i). intros. + case_eq (N.to_nat j). intros. + rewrite min_distr. now rewrite H, H2. + intros. simpl. + rewrite min_distr. rewrite H, H2. + simpl. apply f_equal. + + specialize (@IHa 0%N (N.of_nat n)). + rewrite Nat2N.id in IHa. + simpl in *. + rewrite IHa. lia. + lia. lia. + intros. + case_eq (N.to_nat j). + simpl. intros. + rewrite min_distr. rewrite H, H2. now simpl. + intros. + rewrite min_distr. rewrite H, H2. + simpl. + specialize (@IHa (N.of_nat n) (N.of_nat n0)). + rewrite !Nat2N.id in IHa. + rewrite IHa. lia. + apply (f_equal (N.of_nat)) in H2. + rewrite N2Nat.id in H2. + rewrite H2 in H0. simpl in H0. lia. + lia. +Qed. + + (** bit-vector extraction *) + Definition bv_extr (i n0 n1: N) a : bitvector := + if (N.ltb n1 (n0 + i)) then mk_list_false (nat_of_N n0) + else extract a (nat_of_N i) (nat_of_N (n0 + i)). + + Lemma not_ltb: forall (n0 n1 i: N), (n1 <? n0 + i)%N = false -> n1 >= n0 + i. + Proof. intro n0. + induction n0. + intros. simpl in *. + apply N.ltb_nlt in H. + apply N.nlt_ge in H. lia. + intros. simpl. + case_eq i. + intros. subst. simpl in H. + apply N.ltb_nlt in H. + apply N.nlt_ge in H. intros. simpl in H. lia. + intros. subst. + apply N.ltb_nlt in H. + apply N.nlt_ge in H. lia. + Qed. + + + Lemma bv_extr_size: forall (i n0 n1 : N) a, + size a = n1 -> size (@bv_extr i n0 n1 a) = n0%N. + Proof. + intros. unfold bv_extr, size in *. + case_eq (n1 <? n0 + i). + intros. now rewrite length_mk_list_false, N2Nat.id. + intros. + specialize (@length_extract a i (n0 + i)). intros. + assert ((n0 + i - i) = n0)%N. + { lia. } rewrite H2 in H1. + rewrite H1. + now rewrite N2Nat.id. + rewrite H. + now apply not_ltb. + lia. + Qed. + + (* + Definition bv_extr (n i j: N) {H0: n >= j} {H1: j >= i} {a: bitvector} : bitvector := + extract a (nat_of_N i) (nat_of_N j). + + + Lemma bv_extr_size: forall n (i j: N) a (H0: n >= j) (H1: j >= i), + size a = n -> size (@bv_extr n i j H0 H1 a) = (j - i)%N. + Proof. + intros. unfold bv_extr, size in *. + rewrite <- N2Nat.id. apply f_equal. + rewrite <- H in H0. + specialize (@length_extract a i j H0 H1); intros; apply H2. + Qed. + *) + + (** list extension *) + Fixpoint extend (x: list bool) (i: nat) (b: bool) {struct i}: list bool := + match i with + | O => x + | S i' => b :: extend x i' b + end. + + Definition zextend (x: list bool) (i: nat): list bool := + extend x i false. + + Definition sextend (x: list bool) (i: nat): list bool := + match x with + | [] => mk_list_false i + | xb :: x' => extend x i xb + end. + + Lemma extend_size_zero: forall i b, (length (extend [] i b)) = i. + Proof. + intros. + induction i as [ | xi IHi]. + - now simpl. + - simpl. now rewrite IHi. + Qed. + + Lemma extend_size_one: forall i a b, length (extend [a] i b) = S i. + Proof. intros. + induction i. + - now simpl. + - simpl. now rewrite IHi. + Qed. + + Lemma length_extend: forall a i b, length (extend a i b) = ((length a) + i)%nat. + Proof. intro a. + induction a. + - intros. simpl. now rewrite extend_size_zero. + - intros. + induction i. + + intros. simpl. lia. + + intros. simpl. apply f_equal. + rewrite IHi. simpl. lia. + Qed. + + Lemma zextend_size_zero: forall i, (length (zextend [] i)) = i. + Proof. + intros. unfold zextend. apply extend_size_zero. + Qed. + + Lemma zextend_size_one: forall i a, length (zextend [a] i) = S i. + Proof. + intros. unfold zextend. apply extend_size_one. + Qed. + + Lemma length_zextend: forall a i, length (zextend a i) = ((length a) + i)%nat. + Proof. + intros. unfold zextend. apply length_extend. + Qed. + + Lemma sextend_size_zero: forall i, (length (sextend [] i)) = i. + Proof. + intros. unfold sextend. now rewrite length_mk_list_false. + Qed. + + Lemma sextend_size_one: forall i a, length (sextend [a] i) = S i. + Proof. + intros. unfold sextend. apply extend_size_one. + Qed. + + Lemma length_sextend: forall a i, length (sextend a i) = ((length a) + i)%nat. + Proof. + intros. unfold sextend. + case_eq a. intros. rewrite length_mk_list_false. easy. + intros. apply length_extend. + Qed. + + (** bit-vector extension *) + Definition bv_zextn (n i: N) (a: bitvector): bitvector := + zextend a (nat_of_N i). + + Definition bv_sextn (n i: N) (a: bitvector): bitvector := + sextend a (nat_of_N i). + + Lemma plus_distr: forall i j: N, N.to_nat (j + i) = ((N.to_nat j) + (N.to_nat i))%nat. + Proof. intros i j; case i; case j in *; try intros; lia. Qed. + + Lemma bv_zextn_size: forall n (i: N) a, + size a = n -> size (@bv_zextn n i a) = (i + n)%N. + Proof. + intros. unfold bv_zextn, zextend, size in *. + rewrite <- N2Nat.id. apply f_equal. + specialize (@length_extend a (nat_of_N i) false). intros. + rewrite H0. rewrite plus_distr. rewrite plus_comm. + apply f_equal. + apply (f_equal (N.to_nat)) in H. + now rewrite Nat2N.id in H. + Qed. + + Lemma bv_sextn_size: forall n (i: N) a, + size a = n -> size (@bv_sextn n i a) = (i + n)%N. + Proof. + intros. unfold bv_sextn, sextend, size in *. + rewrite <- N2Nat.id. apply f_equal. + case_eq a. + intros. rewrite length_mk_list_false. + rewrite H0 in H. simpl in H. rewrite <- H. + lia. + intros. + specialize (@length_extend a (nat_of_N i) b). intros. + subst. rewrite plus_distr. rewrite plus_comm. + rewrite Nat2N.id. + now rewrite <- H1. + Qed. + + (** shift left *) + +Fixpoint pow2 (n: nat): nat := + match n with + | O => 1%nat + | S n' => (2 * pow2 n')%nat + end. + +Fixpoint _list2nat_be (a: list bool) (n i: nat) : nat := + match a with + | [] => n + | xa :: xsa => + if xa then _list2nat_be xsa (n + (pow2 i)) (i + 1) + else _list2nat_be xsa n (i + 1) + end. + +Definition list2nat_be (a: list bool) := _list2nat_be a 0 0. + +Definition _shl_be (a: list bool) : list bool := + match a with + | [] => [] + | _ => false :: removelast a + end. + +Fixpoint nshl_be (a: list bool) (n: nat): list bool := + match n with + | O => a + | S n' => nshl_be (_shl_be a) n' + end. + +Definition shl_be (a b: list bool): list bool := +nshl_be a (list2nat_be b). + +Lemma length__shl_be: forall a, length (_shl_be a) = length a. +Proof. intro a. + induction a; intros. + - now simpl. + - simpl. rewrite <- IHa. + case_eq a0; easy. +Qed. + +Lemma length_nshl_be: forall n a, length (nshl_be a n) = length a. +Proof. intro n. + induction n; intros; simpl. + - reflexivity. + - now rewrite (IHn (_shl_be a)), length__shl_be. +Qed. + +Lemma length_shl_be: forall a b n, n = (length a) -> n = (length b)%nat -> + n = (length (shl_be a b)). +Proof. + intros. + unfold shl_be. now rewrite length_nshl_be. +Qed. + + (** bit-vector extension *) +Definition bv_shl (a b : bitvector) : bitvector := + if ((@size a) =? (@size b)) + then shl_be a b + else zeros (@size a). + +Lemma bv_shl_size n a b : size a = n -> size b = n -> size (bv_shl a b) = n. +Proof. + unfold bv_shl. intros H1 H2. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size in *. rewrite <- (@length_shl_be a b (nat_of_N n)). + now rewrite N2Nat.id. + now apply (f_equal (N.to_nat)) in H1; rewrite Nat2N.id in H1. + now apply (f_equal (N.to_nat)) in H2; rewrite Nat2N.id in H2. +Qed. + + (** shift right *) + +Definition _shr_be (a: list bool) : list bool := + match a with + | [] => [] + | xa :: xsa => xsa ++ [false] + end. + +Fixpoint nshr_be (a: list bool) (n: nat): list bool := + match n with + | O => a + | S n' => nshr_be (_shr_be a) n' + end. + +Definition shr_be (a b: list bool): list bool := +nshr_be a (list2nat_be b). + +Lemma length__shr_be: forall a, length (_shr_be a) = length a. +Proof. intro a. + induction a; intros. + - now simpl. + - simpl. rewrite <- IHa. + case_eq a0; easy. +Qed. + +Lemma length_nshr_be: forall n a, length (nshr_be a n) = length a. +Proof. intro n. + induction n; intros; simpl. + - reflexivity. + - now rewrite (IHn (_shr_be a)), length__shr_be. +Qed. + +Lemma length_shr_be: forall a b n, n = (length a) -> n = (length b)%nat -> + n = (length (shr_be a b)). +Proof. + intros. + unfold shr_be. now rewrite length_nshr_be. +Qed. + + (** bit-vector extension *) +Definition bv_shr (a b : bitvector) : bitvector := + if ((@size a) =? (@size b)) + then shr_be a b + else zeros (@size a). + +Lemma bv_shr_size n a b : size a = n -> size b = n -> size (bv_shr a b) = n. +Proof. + unfold bv_shr. intros H1 H2. rewrite H1, H2. + rewrite N.eqb_compare. rewrite N.compare_refl. + unfold size in *. rewrite <- (@length_shr_be a b (nat_of_N n)). + now rewrite N2Nat.id. + now apply (f_equal (N.to_nat)) in H1; rewrite Nat2N.id in H1. + now apply (f_equal (N.to_nat)) in H2; rewrite Nat2N.id in H2. +Qed. + +End RAWBITVECTOR_LIST. + +Module BITVECTOR_LIST <: BITVECTOR. + + Include RAW2BITVECTOR(RAWBITVECTOR_LIST). + + Notation "x |0" := (cons false x) (left associativity, at level 73, format "x |0"): bv_scope. + Notation "x |1" := (cons true x) (left associativity, at level 73, format "x |1"): bv_scope. + Notation "'b|0'" := [false] (at level 70): bv_scope. + Notation "'b|1'" := [true] (at level 70): bv_scope. + Notation "# x |" := (@of_bits x) (no associativity, at level 1, format "# x |"): bv_scope. + Notation "v @ p" := (bitOf p v) (at level 1, format "v @ p ") : bv_scope. + +End BITVECTOR_LIST. + +(* + Local Variables: + coq-load-path: ((rec ".." "SMTCoq")) + End: +*) diff --git a/src/bva/Bva_checker.v b/src/bva/Bva_checker.v new file mode 100644 index 0000000..81e0a30 --- /dev/null +++ b/src/bva/Bva_checker.v @@ -0,0 +1,8576 @@ +(**************************************************************************) +(* *) +(* SMTCoq *) +(* Copyright (C) 2011 - 2019 *) +(* *) +(* See file "AUTHORS" for the list of authors *) +(* *) +(* This file is distributed under the terms of the CeCILL-C licence *) +(* *) +(**************************************************************************) + + +(** A small checker for bit-vectors bit-blasting *) + +(*Add Rec LoadPath "." as SMTCoq.*) + +Require Structures. + +Require Import Int63 Int63Properties PArray SMT_classes. + +Require Import Misc State SMT_terms BVList Psatz. +Require Import Bool List BoolEq NZParity Nnat. +Require Import BinPos BinNat Pnat Init.Peano. + +Require FArray. + +Import ListNotations. +Import Form. + +Local Open Scope array_scope. +Local Open Scope int63_scope. +Local Open Scope list_scope. + +Set Implicit Arguments. +Unset Strict Implicit. + + +Section Checker. + + Import Atom. + + Variable t_atom : PArray.array atom. + Variable t_form : PArray.array form. + + Local Notation get_form := (PArray.get t_form) (only parsing). + Local Notation get_atom := (PArray.get t_atom) (only parsing). + + (** * Bit-blasting a constant bitvector: + + --------------------------- bbConst + bbT(#b0010, [0; 1; 0; 0]) + *) + + Fixpoint check_bbc (a_bv: list bool) (bs: list _lit) := + match a_bv, bs with + | nil, nil => true + | v :: a_bv, b::bs => + if Lit.is_pos b then + match get_form (Lit.blit b), v with + | Ftrue, true | Ffalse, false => check_bbc a_bv bs + | _, _ => false + end + else false + | _, _ => false + end. + + (** Checker for bitblasting of bitvector constants *) + Definition check_bbConst lres := + if Lit.is_pos lres then + match get_form (Lit.blit lres) with + | FbbT a bs => + match get_atom a with + | Acop (CO_BV bv N) => + if check_bbc bv bs && (N.of_nat (length bv) =? N)%N + then lres::nil + else C._true + | _ => C._true + end + | _ => C._true + end + else C._true. + + + (** * Bit-blasting a variable: + + x ∈ BV n + ----------------------- bbVar + bbT(x, [x₀; ...; xₙ₋₁]) + *) + + Fixpoint check_bb (a: int) (bs: list _lit) (i n: nat) := + match bs with + | nil => Nat_eqb i n (* We go up to n *) + | b::bs => + if Lit.is_pos b then + match get_form (Lit.blit b) with + | Fatom a' => + match get_atom a' with + | Auop (UO_BVbitOf N p) a' => + (* TODO: + Do not need to check [Nat_eqb l (N.to_nat N)] at every iteration *) + if (a == a') (* We bit blast the right bv *) + && (Nat_eqb i p) (* We consider bits after bits *) + && (Nat_eqb n (N.to_nat N)) (* The bv has indeed type BV n *) + then check_bb a bs (S i) n + else false + | _ => false + end + | _ => false + end + else false + end. + + (** Checker for bitblasting of bitvector variables *) + Definition check_bbVar lres := + if Lit.is_pos lres then + match get_form (Lit.blit lres) with + | FbbT a bs => + if check_bb a bs O (List.length bs)%N + then lres::nil + else C._true + | _ => C._true + end + else C._true. + + Variable s : S.t. + + (** * Bit-blasting bitvector not ... + + bbT(a, [a0; ...; an]) + ------------------------------ bbNot + bbT(not a, [~a0; ...; ~an]) + *) + + (* Helper function for bv_not *) + Fixpoint check_not (bs br : list _lit) := + match bs, br with + | nil, nil => true + | b::bs, r::br => (r == Lit.neg b) && check_not bs br + | _, _ => false + end. + + (** Checker for bitblasting of bitvector not *) + Definition check_bbNot pos lres := + match S.get s pos with + | l::nil => + if (Lit.is_pos l) && (Lit.is_pos lres) then + match get_form (Lit.blit l), get_form (Lit.blit lres) with + | FbbT a bs, FbbT r br => + match get_atom r with + | Auop (UO_BVnot N) a' => + if (a == a') && check_not bs br && + (N.of_nat (length bs) =? N)%N + then lres::nil + else C._true + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _ => C._true + end. + + (** * Bit-blasting bitwise operations: bbAnd, bbOr, ... + + bbT(a, [a0; ...; an]) bbT(b, [b0; ...; bn]) + -------------------------------------------------- bbAnd + bbT(a&b, [a0 /\ b0; ...; an /\ bn]) + *) + +Fixpoint check_symopp (bs1 bs2 bsres : list _lit) (bvop: binop) := + match bs1, bs2, bsres with + | nil, nil, nil => true + | b1::bs1, b2::bs2, bres::bsres => + if Lit.is_pos bres then + let (ires, bvop) := + match get_form (Lit.blit bres), bvop with + + | Fand args, BO_BVand n => + ((if PArray.length args == 2 then + let a1 := args.[0] in + let a2 := args.[1] in + ((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1)) + else false), BO_BVand (n-1)) + + | For args, BO_BVor n => + ((if PArray.length args == 2 then + let a1 := args.[0] in + let a2 := args.[1] in + ((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1)) + else false), BO_BVor (n-1)) + + | Fxor a1 a2, BO_BVxor n => + (((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1)), + BO_BVxor (n-1)) + + | Fiff a1 a2, (BO_eq (Typ.TBV n)) => + (((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1)), + BO_eq (Typ.TBV n)) + + | _, _ => (false, bvop) + end in + if ires then check_symopp bs1 bs2 bsres bvop + else false + else false + | _, _, _ => false + end. + + Lemma empty_list_length: forall {A: Type} (a: list A), (length a = 0)%nat <-> a = []. + Proof. intros A a. + induction a; split; intros; auto; contradict H; easy. + Qed. + + (** Checker for bitblasting of bitwise operators on bitvectors *) + Definition check_bbOp pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, FbbT a bsres => + match get_atom a with + + | Abop (BO_BVand n) a1' a2' => + if (((a1 == a1') && (a2 == a2')) || ((a1 == a2') && (a2 == a1'))) + && (@check_symopp bs1 bs2 bsres (BO_BVand n)) + && (N.of_nat (length bs1) =? n)%N + then lres::nil + else C._true + + | Abop (BO_BVor n) a1' a2' => + if (((a1 == a1') && (a2 == a2')) || ((a1 == a2') && (a2 == a1'))) + && (check_symopp bs1 bs2 bsres (BO_BVor n)) + && (N.of_nat (length bs1) =? n)%N + then lres::nil + else C._true + + | Abop (BO_BVxor n) a1' a2' => + if (((a1 == a1') && (a2 == a2')) || ((a1 == a2') && (a2 == a1'))) + && (check_symopp bs1 bs2 bsres (BO_BVxor n)) + && (N.of_nat (length bs1) =? n)%N + then lres::nil + else C._true + + | _ => C._true + end + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + (** * Bit-blasting bitvector equality + + bbT(a, [a0; ...; an]) bbT(b, [b0; ...; bn]) + -------------------------------------------------- bbEq + (a = b) <-> ((a0 <-> b0) /\ ... /\ (an <-> bn)) + *) + + Fixpoint check_eq (bs1 bs2 bsres: list _lit) := + match bs1, bs2, bsres with + | nil, nil, nil => true + | b1::bs1, b2::bs2, bres :: bsres => + match bs1, bs2, bsres with + | _::_, _::_, [] => + if Lit.is_pos bres then + match get_form (Lit.blit bres) with + | Fand args => + match PArray.to_list args with + | bres :: bsres => + if Lit.is_pos bres then + let ires := + match get_form (Lit.blit bres) with + | Fiff a1 a2 => + ((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1)) + | _ => false + end in + if ires then check_eq bs1 bs2 bsres + else false + else false + | _ => false + end + | _ => false + end + else false + | _, _, _ => + if Lit.is_pos bres then + let ires := + match get_form (Lit.blit bres) with + | Fiff a1 a2 => + ((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1)) + | _ => false + end in + if ires then check_eq bs1 bs2 bsres + else false + else false + end + | _, _, _ => false + end. + + (** Checker for bitblasting of equality between bitvector terms *) + Definition check_bbEq pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, Fiff leq lbb => + if (Bool.eqb (Lit.is_pos leq) (Lit.is_pos lbb)) then + match get_form (Lit.blit leq), get_form (Lit.blit lbb) with + | Fatom a, _ (* | _, Fatom a *) => + match get_atom a with + | Abop (BO_eq (Typ.TBV n)) a1' a2' => + if (((a1 == a1') && (a2 == a2')) || ((a1 == a2') && (a2 == a1'))) + && (check_eq bs1 bs2 [lbb]) + && (N.of_nat (length bs1) =? n)%N + then lres::nil + else C._true + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + (** * Bitvector Arithmetic *) + + (** Representaion for symbolic carry computations *) + Inductive carry : Type := + | Clit (_:_lit) + | Cand (_:carry) (_:carry) + | Cxor (_:carry) (_:carry) + | Cor (_:carry) (_:carry) + | Ciff (_:carry) (_:carry) + . + + + (** Check if a symbolic carry computation is equal to a literal + representation. This function does not account for potential symmetries *) + (* c should always be a positive literal in carry computations *) + Fixpoint eq_carry_lit (carry : carry) (c : _lit) := + if Lit.is_pos c then + match carry with + | Clit l => l == c + + | Cand c1 c2 => + match get_form (Lit.blit c) with + | Fand args => + if PArray.length args == 2 then + (eq_carry_lit c1 (args.[0]) && eq_carry_lit c2 (args.[1])) + (* || (eq_carry_lit c1 (args.[1]) && eq_carry_lit c2 (args.[0])) *) + else false + | _ => false + end + + | Cxor c1 c2 => + match get_form (Lit.blit c) with + | Fxor a1 a2 => + (eq_carry_lit c1 a1 && eq_carry_lit c2 a2) + (* || (eq_carry_lit c1 a2 && eq_carry_lit c2 a1) *) + | _ => false + end + + | Cor c1 c2 => + match get_form (Lit.blit c) with + | For args => + if PArray.length args == 2 then + (eq_carry_lit c1 (args.[0]) && eq_carry_lit c2 (args.[1])) + (* || (eq_carry_lit c1 (args.[1]) && eq_carry_lit c2 (args.[0])) *) + else false + | _ => false + end + + | Ciff c1 c2 => + match get_form (Lit.blit c) with + | Fiff a1 a2 => + (eq_carry_lit c1 a1 && eq_carry_lit c2 a2) + (* || (eq_carry_lit c1 a2 && eq_carry_lit c2 a1) *) + | _ => false + end + end + else + (* c can be negative only when it is literal false *) + match carry with + | Clit l => l == c + | _ => false + end. + + (** Checks if [bsres] is the result of bvand of bs1 and bs2. The inital + value for the carry is [false]. *) + Fixpoint check_add (bs1 bs2 bsres : list _lit) (carry : carry) := + match bs1, bs2, bsres with + | nil, nil, nil => true + | b1::bs1, b2::bs2, bres::bsres => + if Lit.is_pos bres then + match get_form (Lit.blit bres) with + | Fxor xab c => + if Lit.is_pos xab then + match get_form (Lit.blit xab) with + | Fxor a1 a2 => + (* This is the way LFSC computes carries *) + let carry' := Cor (Cand (Clit b1) (Clit b2)) + (Cand (Cxor (Clit b1) (Clit b2)) carry) in + (((a1 == b1) && (a2 == b2)) || ((a1 == b2) && (a2 == b1))) + && eq_carry_lit carry c + && check_add bs1 bs2 bsres carry' + | _ => false + end + else false + | _ => false + end + else false + | _, _, _ => false + end. + + (** * Checker for bitblasting of bitvector addition *) + Definition check_bbAdd pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, FbbT a bsres => + match get_atom a with + + | Abop (BO_BVadd n) a1' a2' => + if (((a1 == a1') && (a2 == a2')) || ((a1 == a2') && (a2 == a1'))) + && (check_add bs1 bs2 bsres (Clit Lit._false)) + && (N.of_nat (length bs1) =? n)%N + then lres::nil + else C._true + + | _ => C._true + end + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + (** * Bit-blasting bitvector negation ... + + bbT(a, [a0; ...; an]) + ------------------------------ bbNeg + bbT(-a, [...]) + *) + + (* Helper function for bv_neg *) + Definition check_neg (bs br : list _lit) := + let z := map (fun _ => Lit._false) bs in + let nbs := map (fun l => Lit.neg l) bs in + check_add nbs z br (Clit Lit._true). + + (** Checker for bitblasting of bitvector negation *) + Definition check_bbNeg pos lres := + match S.get s pos with + | l::nil => + if (Lit.is_pos l) && (Lit.is_pos lres) then + match get_form (Lit.blit l), get_form (Lit.blit lres) with + | FbbT a bs, FbbT r br => + match get_atom r with + | Auop (UO_BVneg n) a' => + if (a == a') && check_neg bs br && + (N.of_nat (length bs) =? n)%N + then lres::nil + else C._true + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _ => C._true + end. + + Fixpoint and_with_bit (a: list _lit) (bt: _lit) : list carry := + match a with + | nil => nil + | ai :: a' => (Cand (Clit bt) (Clit ai)) :: and_with_bit a' bt + end. + + Fixpoint mult_step_k_h (a b: list carry) (c: carry) (k: Z) : list carry := + match a, b with + | nil, _ => [] + | ai :: a', bi :: b' => + if (k - 1 <? 0)%Z then + let carry_out := Cor (Cand ai bi) (Cand (Cxor ai bi) c) in + let curr := Cxor (Cxor ai bi) c in + curr :: mult_step_k_h a' b' carry_out (k - 1) + else + ai :: mult_step_k_h a' b c (k - 1) + | ai :: a', nil => ai :: mult_step_k_h a' b c k + end. + + Fixpoint mult_step (a b: list _lit) (res: list carry) (k k': nat) : list carry := + let ak := List.firstn (S k') a in + let b' := and_with_bit ak (nth k b Lit._false) in + let res' := mult_step_k_h res b' (Clit Lit._false) (Z.of_nat k) in + match k' with + | O => res' + (* | S O => res' *) + | S pk' => mult_step a b res' (S k) pk' + end. + + Definition bblast_bvmult (a b: list _lit) (n: nat) : list carry := + let res := and_with_bit a (nth 0 b Lit._false) in + match n with + | O => res + | S O => res + | S (S k) => mult_step a b res 1 k + end. + + Fixpoint mkzeros (k: nat) : list carry := + match k with + | O => nil + | S k => (Clit Lit._false) :: mkzeros k + end . + + Fixpoint bblast_bvadd (a b: list carry) (c: carry) : list carry := + match a, b with + | nil, _ | _, nil => nil + | ai :: a', bi :: b' => + let c' := (Cor (Cand ai bi) (Cand (Cxor ai bi) c)) in + (Cxor (Cxor ai bi) c') :: (bblast_bvadd a' b' c') + end. + + Fixpoint mult_shift (a b: list _lit) (n: nat) : list carry := + match a with + | nil => mkzeros n + | ai :: a' => + (bblast_bvadd (and_with_bit b ai) + (mult_shift a' (Lit._false :: b) n) (Clit Lit._false)) + end. + + Definition check_mult (bs1 bs2 bsres: list _lit) : bool := + if Nat_eqb (length bs1) (length bs2)%nat then + let bvm12 := bblast_bvmult bs1 bs2 (length bs1) in + forallb2 eq_carry_lit bvm12 bsres + else false. + + (** * Checker for bitblasting of bitvector multiplication *) + Definition check_bbMult pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, FbbT a bsres => + match get_atom a with + + | Abop (BO_BVmult n) a1' a2' => + if (((a1 == a1') && (a2 == a2')) (* || ((a1 == a2') && (a2 == a1')) *) ) + && (check_mult bs1 bs2 bsres) + && (N.of_nat (length bs1) =? n)%N + then lres::nil + else C._true + + | _ => C._true + end + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + (** * Checker for bitblasting of bitvector comparison: lt *) + + Fixpoint ult_big_endian_lit_list (bs1 bs2: list _lit) := + match bs1, bs2 with + | nil, _ => Clit (Lit._false) + | _, nil => Clit (Lit._false) + | xi :: nil, yi :: nil => (Cand (Clit (Lit.neg xi)) (Clit yi)) + | xi :: x', yi :: y' => + (Cor (Cand (Ciff (Clit xi) (Clit yi)) (ult_big_endian_lit_list x' y')) + (Cand (Clit (Lit.neg xi)) (Clit yi))) + end. + + Definition ult_lit_list (x y: list _lit) := + ult_big_endian_lit_list (List.rev x) (List.rev y). + + Definition check_ult (bs1 bs2: list _lit) (bsres: _lit) : bool := + if Lit.is_pos bsres then + eq_carry_lit (ult_lit_list bs1 bs2) bsres + else false. + + Definition check_bbUlt pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, Fiff llt lbb => + if (Bool.eqb (Lit.is_pos llt) (Lit.is_pos lbb)) then + match get_form (Lit.blit llt), get_form (Lit.blit lbb) with + | Fatom a, _ (* | _, Fatom a *) => + match get_atom a with + | Abop (BO_BVult n) a1' a2' => + if ((a1 == a1') && (a2 == a2')) + && (check_ult bs1 bs2 lbb) + && (N.of_nat (length bs1) =? n)%N + && (N.of_nat (length bs2) =? n)%N + then lres::nil + else C._true + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + Definition slt_big_endian_lit_list (x y: list _lit) := + match x, y with + | nil, _ => Clit (Lit._false) + | _, nil => Clit (Lit._false) + | xi :: nil, yi :: nil => (Cand (Clit xi) (Clit (Lit.neg yi))) + | xi :: x', yi :: y' => + (Cor (Cand (Ciff (Clit xi) (Clit yi)) (ult_big_endian_lit_list x' y')) + (Cand (Clit xi) (Clit (Lit.neg yi)))) + end. + + Definition slt_lit_list (x y: list _lit) := + slt_big_endian_lit_list (List.rev x) (List.rev y). + + Definition check_slt (bs1 bs2: list _lit) (bsres: _lit) : bool := + if Lit.is_pos bsres then + eq_carry_lit (slt_lit_list bs1 bs2) bsres + else false. + + Definition check_bbSlt pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, Fiff llt lbb => + if (Bool.eqb (Lit.is_pos llt) (Lit.is_pos lbb)) then + match get_form (Lit.blit llt), get_form (Lit.blit lbb) with + | Fatom a, _ (* | _, Fatom a *) => + match get_atom a with + | Abop (BO_BVslt n) a1' a2' => + if ((a1 == a1') && (a2 == a2')) + && (check_slt bs1 bs2 lbb) + && (N.of_nat (length bs1) =? n)%N + && (N.of_nat (length bs2) =? n)%N + then lres::nil + else C._true + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + (** * Checker for bitblasting of bitvector concatenation *) + +(* + Fixpoint lit_to_carry (bs: list _lit) : list carry := + match bs with + | nil => [] + | xbs :: xsbs => Clit xbs :: lit_to_carry xsbs + end. + + Fixpoint h_check_bbConcat (bs1 bs2: list _lit) {struct bs1}: list carry := + match bs1 with + | nil => + match bs2 with + | nil => [] + | xbs2 :: xsbs2 => lit_to_carry bs2 + end + | xbs1 :: xsbs1 => Clit xbs1 :: (h_check_bbConcat xsbs1 bs2) + end. + *) + + Fixpoint lit_to_carry (bs: list _lit) : list carry := + match bs with + | nil => [] + | xbs :: xsbs => Clit xbs :: lit_to_carry xsbs + end. + + Definition check_concat (bs1 bs2 bsres: list _lit) : bool := + if (forallb2 eq_carry_lit (lit_to_carry (bs2 ++ bs1)) bsres) then true else false. + + Definition check_bbConcat pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, FbbT a2 bs2, FbbT a bsres => + match get_atom a with + + | Abop (BO_BVconcat n m) a1' a2' => + if (((a1 == a1') && (a2 == a2')) (* || ((a1 == a2') && (a2 == a1')) *) ) + && (check_concat bs1 bs2 bsres) + && (N.of_nat (length bs1) =? n)%N + && (N.of_nat (length bs2) =? m)%N + then lres::nil + else C._true + + | _ => C._true + end + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + +(* bitwise disequality *) + + Fixpoint List_diseqb (a b: list bool) : bool := + match a, b with + | nil, nil => false + | xa :: xsa, xb :: xsb => + if (Bool.eqb xa false) then + (if (Bool.eqb xb false) then List_diseqb xsa xsb else true) + else (if (Bool.eqb xb true) then List_diseqb xsa xsb else true) + | _, _ => true + end. + + + (** Checker for bitvector disequality *) + Definition check_bbDiseq lres := + if negb (Lit.is_pos lres) then + match get_form (Lit.blit lres) with + | Fatom f => + match (get_atom f) with + | Abop (BO_eq (Typ.TBV n)) a b => + match (get_atom a), (get_atom b) with + | (Acop (CO_BV bv1 n1)), (Acop (CO_BV bv2 n2)) => + if List_diseqb bv1 bv2 + && (N.of_nat (length bv1) =? n)%N + && (N.of_nat (length bv2) =? n)%N + && (n1 =? n)%N && (n2 =? n)%N + then lres::nil + else C._true + | _, _ => C._true + end + | _ => C._true + end + | _ => C._true + end + else C._true. + + + (** Checker for bitvector extraction *) + Fixpoint extract_lit (x: list _lit) (i j: nat) : list _lit := + match x with + | [] => [] + | bx :: x' => + match i with + | O => + match j with + | O => [] + | S j' => bx :: extract_lit x' i j' + end + | S i' => + match j with + | O => [] + | S j' => extract_lit x' i' j' + end + end + end. + + Definition check_extract (bs bsres: list _lit) (i j: N) : bool := + if (N.ltb (N.of_nat (length bs)) j) + then false + else + if (forallb2 eq_carry_lit (lit_to_carry (extract_lit bs (nat_of_N i) (nat_of_N j))) bsres) + then true + else false. + + Definition check_extract3 (bs bsres: list _lit) (i j: N) : bool := + forallb2 (fun l1 l2 => l1 == l2) (extract_lit bs (nat_of_N i) (nat_of_N j)) bsres. + + + (** Checker for bitvector extraction *) + Fixpoint check_extract2 (x bsres: list _lit) (i j: nat) : bool := + match x with + | [] => match bsres with [] => true | _ => false end + | bx :: x' => + match i with + | O => + match j, bsres with + | O, nil => true + | S j', b :: bsres' => (bx == b) && check_extract2 x' bsres' i j' + | _, _ => false + end + | S i' => + match j, bsres with + | O, nil => true + | S j', _ => check_extract2 x' bsres i' j' + | _, _ => false + end + end + end. + + Definition check_bbExtract pos lres := + match S.get s pos with + | l1::nil => + if (Lit.is_pos l1) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit lres) with + | FbbT a1 bs, FbbT a bsres => + match get_atom a with + + | Auop (UO_BVextr i n0 n1) a1' => + if ((a1 == a1') (* || ((a1 == a2') && (a2 == a1')) *) ) + && (check_extract bs bsres i (n0 + i)) + && (N.of_nat (length bs) =? n1)%N + && (N.leb (n0 + i) n1) + then lres::nil + else C._true + + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _ => C._true + end. + + + (** Checker for unsigned bitvector extension *) + Fixpoint extend_lit (x: list _lit) (i: nat) (b: _lit) {struct i}: list _lit := + match i with + | O => x + | S i' => b :: extend_lit x i' b + end. + + Definition zextend_lit (x: list _lit) (i: nat): list _lit := + extend_lit x i Lit._false. + + Definition lit_of_bool (b: bool) :_lit := + if (Bool.eqb b true) then Lit._true + else Lit._false. + + Definition check_zextend (bs bsres: list _lit) (i: N) : bool := + if (forallb2 eq_carry_lit (lit_to_carry (zextend_lit bs (nat_of_N i))) bsres) + then true else false. + + Definition check_bbZextend pos lres := + match S.get s pos with + | l1::nil => + if (Lit.is_pos l1) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit lres) with + | FbbT a1 bs, FbbT a bsres => + match get_atom a with + + | Auop (UO_BVzextn n i) a1' => + if ((a1 == a1') (* || ((a1 == a2') && (a2 == a1')) *) ) + && (check_zextend bs bsres i) + && (N.of_nat (length bs) =? n)%N + then lres::nil + else C._true + + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _ => C._true + end. + + (** Checker for signed bitvector extension *) + + + Fixpoint mk_list_lit_false (t: nat) : list _lit := + match t with + | O => [] + | S t' => Lit._false :: (mk_list_lit_false t') + end. + + Definition sextend_lit (x: list _lit) (i: nat): list _lit := + match x with + | [] => mk_list_lit_false i + | xb :: x' => extend_lit x i xb + end. + + Definition check_sextend (bs bsres: list _lit) (i: N) : bool := + if (forallb2 eq_carry_lit (lit_to_carry (sextend_lit bs (nat_of_N i))) bsres) + then true else false. + + Definition check_bbSextend pos lres := + match S.get s pos with + | l1::nil => + if (Lit.is_pos l1) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit lres) with + | FbbT a1 bs, FbbT a bsres => + match get_atom a with + + | Auop (UO_BVsextn n i) a1' => + if ((a1 == a1') (* || ((a1 == a2') && (a2 == a1')) *) ) + && (check_sextend bs bsres i) + && (N.of_nat (length bs) =? n)%N + then lres::nil + else C._true + + | _ => C._true + end + | _, _ => C._true + end + else C._true + | _ => C._true + end. + + +(** Checker for the bit-blasted left shift (in big endian) *) + +Definition _shl_lit_be (a: list _lit) : list _lit := + match a with + | [] => [] + | _ => Lit._false :: removelast a + end. + +Fixpoint nshl_lit_be (a: list _lit) (n: nat): list _lit := + match n with + | O => a + | S n' => nshl_lit_be (_shl_lit_be a) n' + end. + +Definition shl_lit_be (a: list _lit) (b: list bool): list _lit := + nshl_lit_be a (RAWBITVECTOR_LIST.list2nat_be b). + + + Definition check_shl (bs1: list _lit) (bs2: list bool) (bsres: list _lit) : bool := + if (Structures.nat_eqb (length bs1) (length bs2)) then + if (forallb2 eq_carry_lit (lit_to_carry (shl_lit_be bs1 bs2)) bsres) + then true else false + else false. + + Definition check_bbShl pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, Fatom a2, FbbT a bsres => + match get_atom a with + | Abop (BO_BVshl n) a1' a2' => + match (get_atom a2) with + | (Acop (CO_BV bv2 n2)) => + if (((a1 == a1') && (a2 == a2')) (* || ((a1 == a2') && (a2 == a1')) *) ) + && check_shl bs1 bv2 bsres + && (N.of_nat (length bs1) =? n)%N + && (N.of_nat (length bv2) =? n)%N + && (n2 =? n)%N + then lres::nil + else C._true + | _ => C._true + end + | _ => C._true + end + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + +(** Checker for the bit-blasted right shift (in big endian) *) + +Definition _shr_lit_be (a: list _lit) : list _lit := + match a with + | [] => [] + | xa :: xsa => xsa ++ [Lit._false] + end. + +Fixpoint nshr_lit_be (a: list _lit) (n: nat): list _lit := + match n with + | O => a + | S n' => nshr_lit_be (_shr_lit_be a) n' + end. + +Definition shr_lit_be (a: list _lit) (b: list bool): list _lit := + nshr_lit_be a (RAWBITVECTOR_LIST.list2nat_be b). + + + Definition check_shr (bs1: list _lit) (bs2: list bool) (bsres: list _lit) : bool := + if (Structures.nat_eqb (length bs1) (length bs2)) then + if (forallb2 eq_carry_lit (lit_to_carry (shr_lit_be bs1 bs2)) bsres) + then true else false + else false. + + Definition check_bbShr pos1 pos2 lres := + match S.get s pos1, S.get s pos2 with + | l1::nil, l2::nil => + if (Lit.is_pos l1) && (Lit.is_pos l2) && (Lit.is_pos lres) then + match get_form (Lit.blit l1), get_form (Lit.blit l2), get_form (Lit.blit lres) with + | FbbT a1 bs1, Fatom a2, FbbT a bsres => + match get_atom a with + | Abop (BO_BVshr n) a1' a2' => + match (get_atom a2) with + | (Acop (CO_BV bv2 n2)) => + if (((a1 == a1') && (a2 == a2')) (* || ((a1 == a2') && (a2 == a1')) *) ) + && check_shr bs1 bv2 bsres + && (N.of_nat (length bs1) =? n)%N + && (N.of_nat (length bv2) =? n)%N + && (n2 =? n)%N + then lres::nil + else C._true + | _ => C._true + end + | _ => C._true + end + | _, _, _ => C._true + end + else C._true + | _, _ => C._true + end. + + Section Proof. + + Variables (t_i : array typ_compdec) + (t_func : array (Atom.tval t_i)) + (ch_atom : Atom.check_atom t_atom) + (ch_form : Form.check_form t_form) + (wt_t_atom : Atom.wt t_i t_func t_atom). + + Local Notation check_atom := + (check_aux t_i t_func (get_type t_i t_func t_atom)). + + Local Notation interp_form_hatom := + (Atom.interp_form_hatom t_i t_func t_atom). + + Local Notation interp_form_hatom_bv := + (Atom.interp_form_hatom_bv t_i t_func t_atom). + + Local Notation rho := + (Form.interp_state_var interp_form_hatom interp_form_hatom_bv t_form). + + Fixpoint interp_carry (c: carry) : bool := + match c with + | Clit l => (Lit.interp rho l) + | Cand c1 c2 => (interp_carry c1) && (interp_carry c2) + | Cor c1 c2 => (interp_carry c1) || (interp_carry c2) + | Cxor c1 c2 => xorb (interp_carry c1) (interp_carry c2) + | Ciff c1 c2 => Bool.eqb (interp_carry c1) (interp_carry c2) + end. + + Hypothesis Hs : S.valid rho s. + + Local Notation t_interp := (t_interp t_i t_func t_atom). + + Local Notation interp_atom := + (interp_aux t_i t_func (get t_interp)). + + Let wf_t_atom : Atom.wf t_atom. + Proof. destruct (Atom.check_atom_correct _ ch_atom); auto. Qed. + + Let def_t_atom : default t_atom = Atom.Acop Atom.CO_xH. + Proof. destruct (Atom.check_atom_correct _ ch_atom); auto. Qed. + + Let def_t_form : default t_form = Form.Ftrue. + Proof. + destruct (Form.check_form_correct interp_form_hatom interp_form_hatom_bv _ ch_form) as [H _]; destruct H; auto. + Qed. + + Let wf_t_form : Form.wf t_form. + Proof. + destruct (Form.check_form_correct interp_form_hatom interp_form_hatom_bv _ ch_form) as [H _]; destruct H; auto. + Qed. + + Let wf_rho : Valuation.wf rho. + Proof. + destruct (Form.check_form_correct interp_form_hatom interp_form_hatom_bv _ ch_form); auto. + Qed. + + Lemma lit_interp_true : Lit.interp rho Lit._true = true. + Proof. + apply Lit.interp_true. + apply wf_rho. + Qed. + + Lemma lit_interp_false : Lit.interp rho Lit._false = false. + Proof. + specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. + Qed. + + Let rho_interp : forall x : int, rho x = Form.interp interp_form_hatom interp_form_hatom_bv t_form (t_form.[ x]). + Proof. intros x;apply wf_interp_form;trivial. Qed. + + Definition wf := PArray.forallbi lt_form t_form. + + Hypothesis wf_t_i : wf. + Variable interp_bvatom : atom -> forall s, BITVECTOR_LIST.bitvector s. + Notation atom := int (only parsing). + +Lemma id'' a : N.of_nat (N.to_nat a) = a. +Proof. + destruct a as [ | p]; simpl; trivial. + destruct (Pos2Nat.is_succ p) as (n,H). rewrite H. simpl. f_equal. + apply Pos2Nat.inj. rewrite H. apply SuccNat2Pos.id_succ. +Qed. + +Lemma inj a a' : N.to_nat a = N.to_nat a' -> a = a'. +Proof. + intro H. rewrite <- (id'' a), <- (id'' a'). now f_equal. +Qed. + +Lemma inj_iff a a' : N.to_nat a = N.to_nat a' <-> a = a'. +Proof. + split. apply inj. intros; now subst. +Qed. + +Lemma id' n : N.to_nat (N.of_nat n) = n. +Proof. + induction n; simpl; trivial. apply SuccNat2Pos.id_succ. +Qed. + +Lemma nth_eq1: forall i a xs, +nth (S i) (a :: xs) 1 = nth i xs 1. +Proof. intros. + now simpl. +Qed. + +Theorem nat_case: forall (n:nat) (P:nat -> Prop), P 0%nat -> (forall m:nat, P (S m)) -> P n. +Proof. induction n; auto. Qed. + +Theorem le_lt_or_eq : forall (n m: nat), (n <= m)%nat -> (n < m)%nat \/ n = m. +Proof. +induction 1; auto with arith. +Qed. + +Lemma le_le_S_eq : forall (n m: nat), (n <= m)%nat -> (S n <= m)%nat \/ n = m. +Proof le_lt_or_eq. + +Lemma Nat_eqb_eq: forall n m, Nat_eqb n m = true -> n = m. +Proof. induction n. + intros n Hm. simpl in Hm. case_eq n. reflexivity. + intros. rewrite H in Hm. now contradict H. + intros m Hm. + case_eq m. intros. rewrite H in Hm. simpl in Hm. + now contradict Hm. + intros. rewrite H in Hm. simpl in Hm. + specialize (@IHn n0 Hm). now rewrite IHn. +Qed. + +Lemma diseq_neg_eq: forall (la lb: list bool), + List_diseqb la lb = true -> negb (RAWBITVECTOR_LIST.beq_list la lb) = true. +Proof. intro la. + induction la. + - intros. simpl in H. case lb in *. + now contradict H. + now simpl. + - intros. + simpl in *. + case lb in *. + easy. + case_eq (Bool.eqb a false). + intros. rewrite H0 in H. + case_eq (Bool.eqb b false). + intros. rewrite H1 in H. + case a in *. now contradict H0. + case b in *. now contradict H1. + simpl. + apply IHla. easy. + case a in *. now contradict H0. + case b in *. intros. + now simpl. + intros. simpl. + apply IHla. + simpl in H. easy. + intros. rewrite H0 in H. + case_eq (Bool.eqb b true ). intros. + case a in *. + case b in *. simpl. + apply IHla. simpl in H. easy. + now simpl. + now contradict H0. + intros. + case a in *. + case b in *. simpl in *. now contradict H1. + now simpl in *. + case b in *. now simpl in *. + simpl in *. now contradict H. +Qed. + +Lemma valid_check_bbDiseq lres : C.valid rho (check_bbDiseq lres). +Proof. + unfold check_bbDiseq. + case_eq (Lit.is_pos lres); intro Heq; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros f Heq2. + case_eq (t_atom .[ f]); try (intros; now apply C.interp_true). + + intros [ | | | | | | |[ A B | A| | | |n]|N|N|N|N|N|N|N|N|N| | | | ]; + try (intros; now apply C.interp_true). intros a b Heq3. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros c Heq4. + case_eq c; try (intros; now apply C.interp_true). + intros la n1 Heq5. + case_eq (t_atom .[ b]); try (intros; now apply C.interp_true). + intros c0 Heq6. + case_eq c0; try (intros; now apply C.interp_true). + intros lb n2 Heq7. + case_eq (List_diseqb la lb && (N.of_nat (Datatypes.length la) =? n)%N + && (N.of_nat (Datatypes.length lb) =? n)%N + && (n1 =? n)%N && (n2 =? n)%N); + try (intros; now apply C.interp_true). intros Heq8. + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq2. simpl. + unfold Atom.interp_form_hatom, interp_hatom. + rewrite Atom.t_interp_wf; trivial. + rewrite Heq3. simpl. + rewrite !Atom.t_interp_wf; trivial. + rewrite Heq4, Heq6. simpl. + rewrite Heq5, Heq7. simpl. + + rewrite !andb_true_iff in Heq8. + destruct Heq8 as (((Heq8, Ha), Hb), Hc). + destruct Heq8 as (Heq8, Hd). + rewrite N.eqb_eq in Hb, Hc. + rewrite Hb, Hc. + rewrite Typ.N_cast_refl. simpl. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + (* a *) + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq4, Heq5. easy. } + specialize (@H0 H1). rewrite Heq4 in H0. simpl in H0. + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + rewrite Atom.t_interp_wf in Htia; trivial. + rewrite Heq4, Heq5 in Htia. simpl in Htia. + rewrite Hb in Htia. + unfold Bval in Htia. + rewrite Heq5 in H0. simpl in H0. + inversion Htia. + + generalize dependent v_vala. + rewrite <- H3. intros. + + (* b *) + pose proof (H b). + assert (b < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq6, Heq7. easy. } + specialize (@H2 H4). rewrite Heq6 in H2. simpl in H2. + unfold get_type' in H2. unfold v_type in H2. + case_eq (t_interp .[ b]). + intros v_typeb v_valb Htib. rewrite Htib in H2. + rewrite Atom.t_interp_wf in Htib; trivial. + rewrite Heq6, Heq7 in Htib. simpl in Htib. + rewrite Hc in Htib. + unfold Bval in Htib. + rewrite Heq7 in H2. simpl in H2. + inversion Htib. + + generalize dependent v_valb. + rewrite <- H6. intros. + + (* f *) + pose proof (H f). + assert (f < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq3. easy. } + specialize (@H5 H7). rewrite Heq3 in H5. simpl in H5. + unfold get_type' in H5. unfold v_type in H5. + case_eq (t_interp .[ f]). + intros v_typef v_valf Htif. rewrite Htif in H5. + rewrite Atom.t_interp_wf in Htif; trivial. + rewrite Heq3 in Htif. simpl in Htif. + rewrite !Atom.t_interp_wf in Htif; trivial. + rewrite Heq4, Heq6 in Htif. + rewrite Heq5, Heq7 in Htif. + simpl in Htif. + rewrite Hb, Hc in Htif. + rewrite Typ.N_cast_refl in Htif. + unfold Bval in Htif. + rewrite !andb_true_iff in H5. + destruct H5. destruct H5. + + inversion Htif. + + generalize dependent v_valf. + rewrite <- H11. intros. + + unfold BITVECTOR_LIST._of_bits, RAWBITVECTOR_LIST._of_bits. + rewrite N.eqb_eq in Ha, Hd. + + generalize (BITVECTOR_LIST._of_bits_size la n). + + unfold BITVECTOR_LIST._of_bits, RAWBITVECTOR_LIST._of_bits. + + rewrite Hd. + + generalize (BITVECTOR_LIST._of_bits_size lb n). + unfold BITVECTOR_LIST._of_bits, RAWBITVECTOR_LIST._of_bits. + rewrite Ha. + intros. + + unfold Typ.i_eqb. simpl. + unfold BITVECTOR_LIST.bv_eq, RAWBITVECTOR_LIST.bv_eq. + simpl. + rewrite e, e0. + rewrite N.eqb_refl. + unfold RAWBITVECTOR_LIST.bits. + + apply diseq_neg_eq. easy. +Qed. + +Lemma prop_checkbb: forall (a: int) (bs: list _lit) (i n: nat), + (length bs = (n - i))%nat -> + (check_bb a bs i n = true) -> + (forall i0, (i <= i0 < n )%nat -> + Lit.interp rho (nth (i0 - i) bs 1) = + (@BITVECTOR_LIST.bitOf (N.of_nat n) i0 (interp_form_hatom_bv a (N.of_nat n)))). +Proof. intros a bs. + revert a. + induction bs as [ | b ys IHys]. + - intros. simpl in H. + cut (i = n). intro Hn. rewrite Hn in H1. + contradict H1. omega. omega. + - intros. simpl in H0. + case_eq (Lit.is_pos b). intros Heq0. rewrite Heq0 in H0. + case_eq (t_form .[ Lit.blit b] ). intros i1 Heq1. rewrite Heq1 in H0. + case_eq (t_atom .[ i1]). intros c Heq2. + rewrite Heq2 in H0; now contradict H0. + intros u i2 Heq2. + rewrite Heq2 in H0. + case_eq u; try (intro Heq'; rewrite Heq' in H0; now contradict H0). + + intros. rewrite H2 in H0. + case_eq ((a == i2) && Nat_eqb i n1 && Nat_eqb n (N.to_nat n0)). intros Hif. + rewrite Hif in H0. + do 2 rewrite andb_true_iff in Hif. destruct Hif as ((Hif0 & Hif1) & Hif2). + specialize (@IHys a (S i) n). + inversion H. + cut (Datatypes.length ys = (n - S i)%nat). intro HSi. + specialize (@IHys HSi H0). + + cut (((S i) <= i0 < n)%nat \/ i = i0). + intro Hd. destruct Hd as [Hd | Hd]. + inversion Hd. + induction i0 as [ | k IHk]. + now contradict H3. + specialize (@IHys (S k)). + cut ((S k - i)%nat = S (k - i)%nat). intro ISk. + rewrite ISk. + rewrite (@nth_eq1 (k - i) b ys). + cut ((S k - S i)%nat = (k - i)%nat). intro ISki. + specialize (@IHys Hd). + now rewrite ISki in IHys. + now simpl. omega. + rewrite Hd. + cut ((i0 - i0 = 0)%nat). intro Hi0. rewrite Hi0. + simpl. + + unfold Lit.interp. + rewrite Heq0. + unfold Var.interp. + rewrite rho_interp. + rewrite Heq1. + + rewrite Lit.eqb_spec in Hif0. + rewrite Hif0. rewrite <- Hd. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + assert (i1 < PArray.length t_atom). + { + apply PArray.get_not_default_lt. + rewrite Heq2. now rewrite def_t_atom. + } + + specialize (@H3 i1 H5). + rewrite Heq2 in H3. simpl in H3. + rewrite H2 in H3. simpl in H3. + rewrite !andb_true_iff in H3. + decompose [and] H3. clear H3. + simpl in H7. + + unfold get_type' in H6, H7. + unfold v_type in H6, H7. + case_eq (t_interp .[ i1]). + intros. rewrite H3 in H6. simpl in H6. + case_eq (v_type0); intros; try (rewrite H8 in H6; now contradict H6). + simpl. + + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_form_hatom. + unfold Atom.interp_hatom. + rewrite Atom.t_interp_wf; trivial. + rewrite Heq2. + simpl. + + rewrite H2. simpl. + cut (i = n1). intro Hin1. rewrite Hin1. + cut (n = (N.to_nat n0)). intro Hnn0. + rewrite Hnn0. + rewrite id''. + case_eq (t_interp .[ i2]). + + intros. rewrite H9 in H7. rewrite <- H9. + case_eq v_type1; intros; rewrite H10 in H7; try (now contradict H7). + cut (n2 = n0)%N. intros Hn2n0. rewrite Hn2n0 in H10. + + rewrite H9. simpl. + unfold interp_bool. + case_eq (Typ.cast v_type1 (Typ.TBV n0)). + (* split *) + split. rewrite H10. + simpl. + rewrite Typ.N_cast_refl. intros. + contradict H11. easy. + + apply Typ.eqb_spec in H7. inversion H7. easy. + + now apply Nat_eqb_eq in Hif2. + now apply Nat_eqb_eq in Hif1. + + omega. + destruct H1. + specialize (@le_le_S_eq i i0). intros H11. + specialize (@H11 H1). + destruct H11. left. split. exact H5. exact H3. + right. exact H5. + omega. + intro H3. rewrite H3 in H0. now contradict H0. + intros n0 Hn. rewrite Hn in H0. now contradict H0. + intros n0 Hn. rewrite Hn in H0. now contradict H0. + intros i3 n0 n1 Heq. rewrite Heq in H0. now contradict H0. + intros n0 i3 Heq. rewrite Heq in H0. now contradict H0. + intros n0 i3 Heq. rewrite Heq in H0. now contradict H0. + intros b0 i2 i3 Heq. rewrite Heq in H0. now contradict H0. + intros t i2 i3 i4 Heq. rewrite Heq in H0. now contradict H0. + intros n0 l Heq. rewrite Heq in H0. now contradict H0. + intros i2 l Heq. rewrite Heq in H0. now contradict H0. + intros Heq. rewrite Heq in H0. now contradict H0. + intros Heq. rewrite Heq in H0. now contradict H0. + intros i1 i2 Heq. rewrite Heq in H0. now contradict H0. + intros a0 Heq. rewrite Heq in H0. now contradict H0. + intros a0 Heq. rewrite Heq in H0. now contradict H0. + intros a0 Heq. rewrite Heq in H0. now contradict H0. + intros i1 i2 Heq. rewrite Heq in H0. now contradict H0. + intros i1 i2 Heq. rewrite Heq in H0. now contradict H0. + intros i1 i2 i3 Heq. rewrite Heq in H0. now contradict H0. + intros i1 l Heq. rewrite Heq in H0. now contradict H0. + intros Heq. rewrite Heq in H0. now contradict H0. +Qed. + +Lemma prop_checkbb': forall (a: int) (bs: list _lit), + (check_bb a bs 0 (length bs) = true) -> + (forall i0, (i0 < (length bs) )%nat -> + (Lit.interp rho (nth i0 bs 1)) = + (@BITVECTOR_LIST.bitOf (N.of_nat(length bs)) i0 + (interp_form_hatom_bv a (N.of_nat (length bs))))). +Proof. intros. + specialize (@prop_checkbb a bs 0 (length bs)). + intros Hp. + cut ((i0 - 0)%nat = i0%nat). + intro Hc. + cut (Datatypes.length bs = (Datatypes.length bs - 0)%nat). + intro Hc2. + specialize (@Hp Hc2 H i0). + cut ( (0 <= i0 < Datatypes.length bs)%nat). intro Hc3. + specialize (@Hp Hc3). + now rewrite Hc in Hp. + omega. omega. omega. +Qed. + + +Lemma eq_rec: forall (n: N) (a b: BITVECTOR_LIST.bitvector n), BITVECTOR_LIST.bv a = BITVECTOR_LIST.bv b + -> + a = b. +Proof. intros. destruct a, b. + unfold BITVECTOR_LIST.bv in H. + revert wf0. + rewrite H. intros. + now rewrite (proof_irrelevance wf0 wf1). +Qed. + +Lemma nth_eq0: forall i a b xs ys, +nth (S i) (a :: xs) false = nth (S i) (b :: ys) false -> nth i xs false = nth i ys false. +Proof. intros. + now simpl in H. +Qed. + +Lemma nth_eq: forall (a b: list bool), (length a) = (length b) -> + (forall (i: nat), + (i < length a)%nat -> + nth i a false = nth i b false) -> a = b. +Proof. intros a. + induction a as [ | a xs IHxs]. + - intros. simpl in *. symmetry in H. + now rewrite empty_list_length in H. + - intros [ | b ys] H0. + + simpl in *. now contradict H0. + + specialize (@IHxs ys). + inversion H0. specialize (@IHxs H1). + intros. + pose proof (@H 0%nat). simpl in H2. + cut ((0 < S (Datatypes.length xs))%nat). intro HS. + specialize (@H2 HS). rewrite H2; apply f_equal. + apply IHxs. intros. apply (@nth_eq0 i a b xs ys). + apply H. simpl. omega. omega. +Qed. + +Lemma is_even_0: is_even 0 = true. +Proof. apply refl_equal. Qed. + +Lemma rho_1: Lit.interp rho 1 = false. +Proof. unfold Lit.interp. + unfold Lit.is_pos. + simpl. + cut (is_even 1 = false). intro Hev. rewrite Hev. + unfold Var.interp. + destruct wf_rho. unfold Lit.blit. + cut (1 >> 1 = 0). intros Heq0. rewrite Heq0. + unfold negb. now rewrite H. + easy. easy. +Qed. + +Lemma rho_false: Lit.interp rho false = true. +Proof. unfold Lit.interp. + unfold Lit.is_pos. + simpl. + cut (is_even 0 = true). intro Hev. rewrite Hev. + unfold Var.interp. + destruct wf_rho. simpl. unfold Lit.blit. + cut (0 >> 1 = 0). intros Heq0. rewrite Heq0. exact H. + now rewrite lsr_0_l. + apply is_even_0. +Qed. + +Lemma bitOf_of_bits: forall l (a: BITVECTOR_LIST.bitvector (N.of_nat (length l))), + (forall i, + (i < (length l))%nat -> + nth i l false = + (@BITVECTOR_LIST.bitOf (N.of_nat (length l)) i a)) + -> + (BITVECTOR_LIST.bv_eq a (BITVECTOR_LIST.of_bits l)). +Proof. intros l a H. + unfold BITVECTOR_LIST.of_bits in *. + unfold BITVECTOR_LIST.bitOf in *. + unfold BITVECTOR_LIST.bv_eq, BITVECTOR_LIST.bv in *. + unfold RAWBITVECTOR_LIST.bitOf in *. + destruct a. + unfold RAWBITVECTOR_LIST.of_bits. + unfold RAWBITVECTOR_LIST.bv_eq, RAWBITVECTOR_LIST.size, RAWBITVECTOR_LIST.bits in *. + rewrite wf0. + rewrite N.eqb_compare. + rewrite N.compare_refl. + cut (Datatypes.length l = Datatypes.length bv). intro wf1. + + apply (@nth_eq l bv wf1) in H. + + rewrite H. + unfold RAWBITVECTOR_LIST.bv_eq, RAWBITVECTOR_LIST.size, RAWBITVECTOR_LIST.bits in *. + rewrite RAWBITVECTOR_LIST.List_eq_refl; auto. + apply inj_iff in wf0. now do 2 rewrite id' in wf0. + +Qed. + +Lemma valid_check_bbVar lres : C.valid rho (check_bbVar lres). +Proof. + unfold check_bbVar. + case_eq (Lit.is_pos lres); intro Heq1; [ |now apply C.interp_true]. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bs Heq0. + case_eq (check_bb a bs 0 (Datatypes.length bs)); intro Heq2; [ |now apply C.interp_true]. + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq1. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq0. simpl. + apply bitOf_of_bits. intros. + cut (Lit.interp rho 1 = false). intro Hr. rewrite <- Hr. + rewrite map_nth. + remember (@prop_checkbb' a bs Heq2 i). + rewrite map_length in H. + rewrite map_length. + clear Heqe. + now apply e in H. + now apply rho_1. +Qed. + +Lemma check_bbc_length : forall bv bs, check_bbc bv bs = true -> length bv = length bs. +Proof. + intro bv. induction bv. + intro bs. case bs. + simpl; trivial. + simpl; easy. + intro bs. case bs in *. + simpl; easy. + simpl. + case (Lit.is_pos i); try easy. + case (t_form .[ Lit.blit i]); try easy; + case a; try easy; intro Hc; apply IHbv in Hc; now rewrite Hc. +Qed. + +Lemma nth_nil : forall A i (d:A), nth i [] d = d. +Proof. + intros. unfold nth. case i; trivial. +Qed. + +Lemma prop_check_bbc: forall bv bs, + (check_bbc bv bs = true) -> + (forall i, (i < (length bs) )%nat -> + (Lit.interp rho (nth i bs 1)) = nth i bv false). +Proof. + intro bv. induction bv. + intros bs. case bs. + intros. + do 2 rewrite nth_nil. easy. + simpl. easy. + intros bs. + case bs. simpl. easy. + intros b l Hc i Hlen. + case i in *. + simpl. + simpl in Hc. + case_eq (Lit.is_pos b). + intro Hposb. + rewrite Hposb in Hc. + case_eq (t_form .[ Lit.blit b]); try (intros; rewrite H in Hc; now contradict Hc). + intros Hb. + rewrite Hb in Hc. + generalize (rho_interp (Lit.blit b)). rewrite Hb. simpl. + intro Hbb. + unfold Lit.interp, Var.interp. + rewrite Hbb, Hposb. + case a in *. + trivial. now contradict Hc. + intro Hb. + rewrite Hb in Hc. + generalize (rho_interp (Lit.blit b)). rewrite Hb. simpl. + intro Hbb. + unfold Lit.interp, Var.interp. + rewrite Hbb, Hposb. + case a in *. + now contradict Hc. trivial. + intro Hposb. rewrite Hposb in Hc. now contradict Hc. + simpl. + apply IHbv. + simpl in Hc. + case (Lit.is_pos b) in Hc; try now contradict Hc. + case (t_form .[ Lit.blit b]) in Hc; try now contradict Hc. + case a in Hc; try now contradict Hc. exact Hc. + case a in Hc; try now contradict Hc. exact Hc. + simpl in Hlen. omega. +Qed. + +Lemma prop_check_bbc2: forall l bs, check_bbc l bs = true -> +RAWBITVECTOR_LIST.beq_list l (map (Lit.interp rho) bs) = true. +Proof. intro l. + induction l as [ | xl xsl IHl ]. + - intros. simpl in *. + case bs in *. now simpl. now contradict H. + - intros. simpl in H. + case bs in *. now contradict H. + simpl. + case_eq (Lit.is_pos i); intros. + rewrite H0 in H. + case_eq (t_form .[ Lit.blit i]); intros; try (rewrite H1 in H; now contradict H). + rewrite H1 in H. + case xl in *. + rewrite andb_true_iff. split. + unfold Lit.interp. rewrite H0. + unfold Var.interp. + specialize (rho_interp (Lit.blit i)). + rewrite H1 in rho_interp. simpl in rho_interp. + rewrite rho_interp. easy. + apply IHl; easy. + now contradict H. + rewrite H1 in H. + case xl in *. now contradict H. + rewrite andb_true_iff. + split. + specialize (rho_interp (Lit.blit i)). + rewrite H1 in rho_interp. simpl in rho_interp. + unfold Lit.interp. rewrite H0. + unfold Var.interp. + rewrite rho_interp. easy. + apply IHl; easy. + rewrite H0 in H. now contradict H. +Qed. + +Lemma valid_check_bbConst lres : C.valid rho (check_bbConst lres). +Proof. + unfold check_bbConst. + case_eq (Lit.is_pos lres); intro Heq1; [ |now apply C.interp_true]. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bs Heq0. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros c Ha. + case_eq c; try (intros; now apply C.interp_true). + intros l N Hc. + case_eq (check_bbc l bs && + (N.of_nat (Datatypes.length l) =? N)%N); + try (intros; now apply C.interp_true). + intro Hcheck. + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq1. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq0. simpl. + + assert (Hinterpa: + (interp_form_hatom_bv a = interp_bv t_i (interp_atom (t_atom .[a])))). + { + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + } + rewrite Hinterpa. + rewrite Ha, Hc. simpl. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert ((N.of_nat (Datatypes.length (map (Lit.interp rho) bs))) = N). + { + rewrite andb_true_iff in Hcheck. + destruct Hcheck as (Hcheck1 & Hcheck2). + apply check_bbc_length in Hcheck1. + rewrite N.eqb_eq in Hcheck2. + rewrite Hcheck1 in Hcheck2. + now rewrite map_length. + } + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs) + ). + + rewrite H. + intros. + + rewrite Typ.N_cast_refl. + + unfold BITVECTOR_LIST.bv_eq, RAWBITVECTOR_LIST.bv_eq. + simpl. + unfold RAWBITVECTOR_LIST.size, RAWBITVECTOR_LIST._of_bits. + + rewrite andb_true_iff in Hcheck. + destruct Hcheck as (Hcheck1 & Hcheck2). + pose proof Hcheck1. + apply check_bbc_length in Hcheck1. + rewrite N.eqb_eq in Hcheck2. + rewrite Hcheck2. + rewrite N.eqb_refl. + rewrite Hcheck1, map_length, N.eqb_refl. + unfold RAWBITVECTOR_LIST.bits. + + now apply prop_check_bbc2. +Qed. + +Lemma prop_check_not: + forall bs br, length bs = length br -> + check_not bs br = true -> + map (Lit.interp rho) br = map (fun l => negb (Lit.interp rho l)) bs. +Proof. + intro bs; induction bs; intros br Hlen Hcheck. + - simpl in Hlen. symmetry in Hlen. apply empty_list_length in Hlen. rewrite Hlen; now simpl. + - case br in *. + + simpl in Hcheck; now contradict Hcheck. + + simpl in Hlen. inversion Hlen as [Hlen']. + simpl in Hcheck. rewrite andb_true_iff in Hcheck; destruct Hcheck as (Hcheck1, Hcheck2). + apply Int63Properties.eqb_spec in Hcheck1; rewrite Hcheck1. + simpl. rewrite Lit.interp_neg. apply f_equal. + apply IHbs; auto. +Qed. + +Lemma check_not_length: + forall bs br, check_not bs br = true -> length bs = length br. +Proof. + intro bs; induction bs; intros br Hcheck. + - case br in *. + + auto. + + simpl in Hcheck; now contradict Hcheck. + - case br in *. + + simpl in Hcheck; now contradict Hcheck. + + simpl in *. + rewrite andb_true_iff in Hcheck. + destruct Hcheck as (_, Hcheck'). + apply IHbs in Hcheck'; auto. +Qed. + +Lemma valid_check_bbNot pos lres : C.valid rho (check_bbNot pos lres). +Proof. + unfold check_bbNot. + case_eq (S.get s pos); [ (intros; now apply C.interp_true) | ]. + intros l ls Hpos. + case_eq ls; [ | (intros; now apply C.interp_true) ]. + intro Hnil. + case_eq (Lit.is_pos l && Lit.is_pos lres); [ | (intros; now apply C.interp_true) ]. + intro Hpos'. + case_eq (t_form .[ Lit.blit l]); try (intros; now apply C.interp_true). + intros a bs HBl. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros r br HBr. + case_eq (t_atom .[ r]); try (intros; now apply C.interp_true). + intros u a'. + case_eq u; try (intros; now apply C.interp_true). + intros n Huot Hr. + case_eq ((a == a') + && check_not bs br + && (N.of_nat (Datatypes.length bs) =? n)%N); + try (intros; now apply C.interp_true). + intro Hc. + rewrite !andb_true_iff in Hc. + destruct Hc as ((Ha, Hcheck), Hlen). + rewrite N.eqb_eq in Hlen. + apply Int63Properties.eqb_spec in Ha. + generalize (Hs pos). + rewrite Hpos, Hnil. + unfold C.valid, C.interp; simpl; rewrite !orb_false_r. + unfold Lit.interp, Var.interp. + rewrite andb_true_iff in Hpos'. + destruct Hpos' as (Hposl, Hposlres). + rewrite Hposl, Hposlres. + rewrite !rho_interp. rewrite HBl, HBr. simpl. + + intro Heqa. + apply BITVECTOR_LIST.bv_eq_reflect in Heqa. + apply BITVECTOR_LIST.bv_eq_reflect. + + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H r). + assert (r < PArray.length t_atom). + { + apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Hr. easy. + } + + specialize (@H0 H1). rewrite Hr in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ r]). + intros v_typer v_valr Htir. rewrite Htir in H0. + case_eq (v_typer); intros; rewrite H3 in H0; try (now contradict H1). + rename H3 into Hv. + + (* interp_form_hatom_bv r = + interp_bv t_i (interp_atom (t_atom .[r])) *) + assert (interp_form_hatom_bv r = + interp_bv t_i (interp_atom (t_atom .[r]))). + { + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + } + + rewrite H3, Hr. simpl. + unfold interp_bv. + apply Typ.eqb_spec in H2. + unfold get_type' in H2. + unfold v_type in H2. + case_eq (t_interp .[ a']). + intros. rewrite H4 in H2. simpl. + + revert v_val0 H4. + rewrite H2. intros. + rewrite Typ.cast_refl. + simpl. + + assert ( (N.of_nat (Datatypes.length (map (Lit.interp rho) br))) = n). + { + apply check_not_length in Hcheck. rewrite Hcheck in Hlen. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) br) + ). + + rewrite H5. + intros. + rewrite Typ.N_cast_refl. + unfold BITVECTOR_LIST.bv_not, RAWBITVECTOR_LIST.bv_not. + + apply eq_rec. + simpl. + + rewrite <- Ha in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + } + + rewrite H6 in Heqa. + unfold interp_bv in Heqa. + rewrite <- !Atom.t_interp_wf in Heqa; trivial. + rewrite H4 in Heqa. + revert Heqa . + + assert ( (N.of_nat (Datatypes.length (map (Lit.interp rho) bs))) = n). + { + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs) + ). + + rewrite H7. + rewrite Typ.cast_refl. intros. + rewrite Heqa. simpl. + + specialize (@prop_check_not bs br). intros. + symmetry. + unfold RAWBITVECTOR_LIST.bits. + rewrite map_map; apply H8; auto. + + now apply check_not_length in Hcheck. + +Qed. + +Lemma eq_head: forall {A: Type} a b (l: list A), (a :: l) = (b :: l) <-> a = b. +Proof. intros A a b l; split; [intros H; inversion H|intros ->]; auto. Qed. + +Axiom afold_left_and : forall a, + afold_left bool int true andb (Lit.interp rho) a = List.forallb (Lit.interp rho) (to_list a). + + Axiom afold_left_or : forall a, + afold_left bool int false orb (Lit.interp rho) a = + C.interp rho (to_list a). + + Axiom afold_left_xor : forall a, + afold_left bool int false xorb (Lit.interp rho) a = + C.interp rho (to_list a). + +Lemma eqb_spec : forall x y, (x == y) = true <-> x = y. +Proof. + split;auto using eqb_correct, eqb_complete. +Qed. + +Lemma to_list_two: forall {A:Type} (a: PArray.array A), + PArray.length a = 2 -> (to_list a) = a .[0] :: a .[1] :: nil. +Proof. intros A a H. + rewrite to_list_to_list_ntr. unfold to_list_ntr. + rewrite H. + cut (0 == 2 = false). intro H1. + rewrite H1. + unfold foldi_ntr. rewrite foldi_cont_lt; auto. + auto. +Qed. + +Lemma check_symopp_and: forall ibs1 ibs2 xbs1 ybs2 ibsres zbsres N, + check_symopp (ibs1 :: xbs1) (ibs2 :: ybs2) (ibsres :: zbsres) (BO_BVand N) = true -> + check_symopp xbs1 ybs2 zbsres (BO_BVand (N-1)) = true. +Proof. intros. + induction N. simpl. + simpl in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case (PArray.length a == 2) in H. + case ((a .[ 0] == ibs1) && (a .[ 1] == ibs2) + || (a .[ 0] == ibs2) && (a .[ 1] == ibs1)) in H. + exact H. + now contradict H. + now contradict H. + now contradict H. + unfold check_symopp in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case (PArray.length a == 2) in H. + case ((a .[ 0] == ibs1) && (a .[ 1] == ibs2) + || (a .[ 0] == ibs2) && (a .[ 1] == ibs1)) in H. + apply H. + now contradict H. + now contradict H. + now contradict H. +Qed. + +Lemma check_symopp_or: forall ibs1 ibs2 xbs1 ybs2 ibsres zbsres N, + check_symopp (ibs1 :: xbs1) (ibs2 :: ybs2) (ibsres :: zbsres) (BO_BVor N) = true -> + check_symopp xbs1 ybs2 zbsres (BO_BVor (N-1)) = true. +Proof. intros. + induction N. simpl. + simpl in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case (PArray.length a == 2) in H. + case ((a .[ 0] == ibs1) && (a .[ 1] == ibs2) + || (a .[ 0] == ibs2) && (a .[ 1] == ibs1)) in H. + exact H. + now contradict H. + now contradict H. + now contradict H. + unfold check_symopp in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case (PArray.length a == 2) in H. + case ((a .[ 0] == ibs1) && (a .[ 1] == ibs2) + || (a .[ 0] == ibs2) && (a .[ 1] == ibs1)) in H. + apply H. + now contradict H. + now contradict H. + now contradict H. +Qed. + +Lemma check_symopp_xor: forall ibs1 ibs2 xbs1 ybs2 ibsres zbsres N, + check_symopp (ibs1 :: xbs1) (ibs2 :: ybs2) (ibsres :: zbsres) (BO_BVxor N) = true -> + check_symopp xbs1 ybs2 zbsres (BO_BVxor (N-1)) = true. +Proof. intros. + induction N. simpl. + simpl in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case ((i == ibs1) && (i0 == ibs2) || (i == ibs2) && (i0 == ibs1)) in H. + exact H. + now contradict H. + now contradict H. + unfold check_symopp in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case ((i == ibs1) && (i0 == ibs2) || (i == ibs2) && (i0 == ibs1)) in H. + apply H. + now contradict H. + now contradict H. +Qed. + +Lemma check_symopp_bvand: forall bs1 bs2 bsres N, + let n := length bsres in + (length bs1 = n)%nat -> + (length bs2 = n)%nat -> + check_symopp bs1 bs2 bsres (BO_BVand N) = true -> + (List.map (Lit.interp rho) bsres) = + (RAWBITVECTOR_LIST.map2 andb (List.map (Lit.interp rho) bs1) (List.map (Lit.interp rho) bs2)). +Proof. intro bs1. + induction bs1 as [ | ibs1 xbs1 IHbs1]. + - intros. simpl in *. rewrite <- H0 in H. + rewrite <- H in H0. unfold n in H0. + symmetry in H0. + rewrite empty_list_length in H0. + unfold map. now rewrite H0. + - intros [ | ibs2 ybs2]. + + intros. + simpl in *. now contradict H1. + + intros [ | ibsres zbsres ]. + * intros. simpl in *. now contradict H. + * intros. simpl. + specialize (IHbs1 ybs2 zbsres (N-1)%N). + rewrite IHbs1. rewrite eq_head. + unfold Lit.interp, Var.interp. + case_eq (Lit.is_pos ibsres); intro Heq0. + case_eq (Lit.is_pos ibs1); intro Heq1. + case_eq (Lit.is_pos ibs2); intro Heq2. + rewrite wf_interp_form; trivial. + simpl in H1. + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H2 in H1. simpl. + rewrite afold_left_and. + + case_eq (PArray.length a == 2). intros. rewrite H3 in H1. + rewrite eqb_spec in H3. + apply to_list_two in H3. + (* apply length_to_list in H4. *) + unfold forallb. + rewrite H3. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite andb_true_r. + intros. rewrite H4 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). + intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. + rewrite H5, H6. rewrite andb_true_r. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite andb_comm. + intros. rewrite H5 in H1. now contradict H1. + intros. rewrite H3 in H1. now contradict H1. + + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H2 in H1. simpl. + rewrite afold_left_and. + + case_eq (PArray.length a == 2). intros. rewrite H3 in H1. + rewrite eqb_spec in H3. + apply to_list_two in H3. + unfold forallb. + rewrite H3. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite andb_true_r. + intros H4. rewrite H4 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. rewrite andb_true_r. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite andb_comm. + intros. rewrite H5 in H1. now contradict H1. + intros. rewrite H3 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + case_eq (Lit.is_pos ibs2). + intro Heq2. + + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H2 in H1. simpl. + rewrite afold_left_and. + + case_eq (PArray.length a == 2). intros. rewrite H3 in H1. + rewrite eqb_spec in H3. + apply to_list_two in H3. + unfold forallb. + rewrite H3. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite andb_true_r. + intros. rewrite H4 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. rewrite andb_true_r. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite andb_comm. + intros. rewrite H5 in H1. now contradict H1. + intros. rewrite H3 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + intros. + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H3 in H1. simpl. + rewrite afold_left_and. + + case_eq (PArray.length a == 2). intros H5. + rewrite H5 in H1. + rewrite eqb_spec in H5. + apply to_list_two in H5. + unfold forallb. + rewrite H5. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H6. + rewrite andb_true_iff in H6. destruct H6 as (H6 & H7). + rewrite eqb_spec in H6, H7. rewrite H6, H7. + unfold Lit.interp. + rewrite Heq1, H2. + unfold Var.interp. now rewrite andb_true_r. + intros H6. rewrite H6 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). intros H7. + rewrite andb_true_iff in H7. destruct H7 as (H7 & H8). + rewrite eqb_spec in H7, H8. + rewrite H7, H8. rewrite andb_true_r. + unfold Lit.interp. + rewrite Heq1, H2. + unfold Var.interp. now rewrite andb_comm. + intros. rewrite H4 in H1. now contradict H1. + intros. rewrite H4 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + rewrite wf_interp_form; trivial. simpl in H1. + rewrite Heq0 in H1. now contradict H1. + now inversion H. + now inversion H0. + apply (@check_symopp_and ibs1 ibs2 xbs1 ybs2 ibsres zbsres N). + exact H1. +Qed. + + +Lemma check_symopp_bvor: forall bs1 bs2 bsres N, + let n := length bsres in + (length bs1 = n)%nat -> + (length bs2 = n)%nat -> + check_symopp bs1 bs2 bsres (BO_BVor N) = true -> + (List.map (Lit.interp rho) bsres) = + (RAWBITVECTOR_LIST.map2 orb (List.map (Lit.interp rho) bs1) (List.map (Lit.interp rho) bs2)). +Proof. intro bs1. + induction bs1 as [ | ibs1 xbs1 IHbs1]. + - intros. simpl in *. rewrite <- H0 in H. + rewrite <- H in H0. unfold n in H0. + symmetry in H0. + rewrite empty_list_length in H0. + unfold map. now rewrite H0. + - intros [ | ibs2 ybs2]. + + intros. + simpl in *. now contradict H1. + + intros [ | ibsres zbsres ]. + * intros. simpl in *. now contradict H. + * intros. simpl. + specialize (IHbs1 ybs2 zbsres (N-1)%N). + rewrite IHbs1. rewrite eq_head. + unfold Lit.interp, Var.interp. + case_eq (Lit.is_pos ibsres); intro Heq0. + case_eq (Lit.is_pos ibs1); intro Heq1. + case_eq (Lit.is_pos ibs2); intro Heq2. + rewrite wf_interp_form; trivial. + simpl in H1. + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + + intros. rewrite H2 in H1. simpl. + rewrite afold_left_or. + + case_eq (PArray.length a == 2). intros. rewrite H3 in H1. + rewrite eqb_spec in H3. + apply to_list_two in H3. + unfold forallb. + rewrite H3. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold C.interp. unfold existsb. rewrite orb_false_r. + + unfold Lit.interp. + rewrite Heq1, Heq2. + now unfold Var.interp. + + intros. rewrite H4 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). + intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. + rewrite H5, H6. rewrite orb_false_r. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite orb_comm. + intros. rewrite H5 in H1. now contradict H1. + intros. rewrite H3 in H1. now contradict H1. + + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H2 in H1. simpl. + rewrite afold_left_or. + + case_eq (PArray.length a == 2). intros. rewrite H3 in H1. + rewrite eqb_spec in H3. + apply to_list_two in H3. + unfold C.interp. + unfold existsb. + + rewrite H3. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite orb_false_r. + intros H4. rewrite H4 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. rewrite orb_false_r. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite orb_comm. + intros. rewrite H5, Heq0 in H1. now contradict H1. + intros. rewrite H3, Heq0 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + case_eq (Lit.is_pos ibs2). + intro Heq2. + + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H2 in H1. simpl. + rewrite afold_left_or. + + case_eq (PArray.length a == 2). intros. rewrite H3 in H1. + rewrite eqb_spec in H3. + apply to_list_two in H3. + unfold forallb. + rewrite H3. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold C.interp, existsb. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite orb_false_r. + intros. rewrite H4 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. rewrite orb_false_r. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite orb_comm. + intros. rewrite Heq0, H5 in H1. now contradict H1. + intros. rewrite Heq0, H3 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + intros. + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H3 in H1. simpl. + rewrite afold_left_or. + + case_eq (PArray.length a == 2). intros H5. + rewrite H5 in H1. + rewrite eqb_spec in H5. + apply to_list_two in H5. + unfold forallb. + rewrite H5. + case_eq ((a .[ 0] == ibs1) && (a .[ 1] == ibs2)). intros H6. + rewrite andb_true_iff in H6. destruct H6 as (H6 & H7). + rewrite eqb_spec in H6, H7. rewrite H6, H7. + unfold C.interp, Lit.interp, existsb. + rewrite Heq1, H2. + unfold Var.interp. now rewrite orb_false_r. + intros H6. rewrite H6 in H1. simpl in *. + case_eq ((a .[ 0] == ibs2) && (a .[ 1] == ibs1)). intros H7. + rewrite andb_true_iff in H7. destruct H7 as (H7 & H8). + rewrite eqb_spec in H7, H8. + rewrite H7, H8. rewrite orb_false_r. + unfold Lit.interp. + rewrite Heq1, H2. + unfold Var.interp. now rewrite orb_comm. + intros. rewrite Heq0, H4 in H1. now contradict H1. + intros. rewrite Heq0, H4 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + rewrite wf_interp_form; trivial. simpl in H1. + rewrite Heq0 in H1. now contradict H1. + now inversion H. + now inversion H0. + apply (@check_symopp_or ibs1 ibs2 xbs1 ybs2 ibsres zbsres N). + exact H1. +Qed. + + +Lemma check_symopp_bvxor: forall bs1 bs2 bsres N, + let n := length bsres in + (length bs1 = n)%nat -> + (length bs2 = n)%nat -> + check_symopp bs1 bs2 bsres (BO_BVxor N) = true -> + (List.map (Lit.interp rho) bsres) = + (RAWBITVECTOR_LIST.map2 xorb (List.map (Lit.interp rho) bs1) (List.map (Lit.interp rho) bs2)). +Proof. intro bs1. + induction bs1 as [ | ibs1 xbs1 IHbs1]. + - intros. simpl in *. rewrite <- H0 in H. + rewrite <- H in H0. unfold n in H0. + symmetry in H0. + rewrite empty_list_length in H0. + unfold map. now rewrite H0. + - intros [ | ibs2 ybs2]. + + intros. + simpl in *. now contradict H1. + + intros [ | ibsres zbsres ]. + * intros. simpl in *. now contradict H. + * intros. simpl. + specialize (IHbs1 ybs2 zbsres (N-1)%N). + rewrite IHbs1. rewrite eq_head. + unfold Lit.interp, Var.interp. + case_eq (Lit.is_pos ibsres); intro Heq0. + case_eq (Lit.is_pos ibs1); intro Heq1. + case_eq (Lit.is_pos ibs2); intro Heq2. + rewrite wf_interp_form; trivial. + simpl in H1. + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + intros. rewrite H2 in H1. simpl. + case_eq ((i == ibs1) && (i0 == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + + unfold Lit.interp. + rewrite Heq1, Heq2. + now unfold Var.interp. + + intros H4. rewrite H4 in H1. simpl in *. + case_eq ((i == ibs2) && (i0 == ibs1)). + intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. + rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite xorb_comm. + intros. rewrite H3 in H1. now contradict H1. + + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + + intros. rewrite H2 in H1. simpl. + case_eq ((i == ibs1) && (i0 == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + now unfold Var.interp. + intros H4. rewrite Heq0, H4 in H1. simpl in *. + case_eq ((i == ibs2) && (i0 == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite xorb_comm. + intros. rewrite H3 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + case_eq (Lit.is_pos ibs2). + intro Heq2. + + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + + intros. rewrite H2 in H1. simpl. + + case_eq ((i == ibs1) && (i0 == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + now unfold Var.interp. + intros H4. rewrite Heq0, H4 in H1. simpl in *. + case_eq ((i == ibs2) && (i0 == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite xorb_comm. + intros. rewrite H3 in H1. now contradict H1. + + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + intro Heq2. + rewrite wf_interp_form; trivial. simpl in H1. + case_eq (t_form .[ Lit.blit ibsres]). + rewrite Heq0 in H1. + case_eq (t_form .[ Lit.blit ibsres]). + try (intros i Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros Heq; rewrite Heq in H1; now contradict H1). + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + try (intros a Heq; rewrite Heq in H1; now contradict H1). + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + intros. contradict H3. discriminate. + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros a Heq; rewrite Heq in H1; now contradict H1). + + intros. rewrite H2 in H1. simpl. + case_eq ((i == ibs1) && (i0 == ibs2)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H5 & H6). + rewrite eqb_spec in H5, H6. rewrite H5, H6. + unfold Lit.interp. + rewrite Heq1, Heq2. + now unfold Var.interp. + intros H4. rewrite Heq0, H4 in H1. simpl in *. + case_eq ((i == ibs2) && (i0 == ibs1)). intros H5. + rewrite andb_true_iff in H5. destruct H5 as (H6 & H7). + rewrite eqb_spec in H6, H7. + rewrite H6, H7. + unfold Lit.interp. + rewrite Heq1, Heq2. + unfold Var.interp. now rewrite xorb_comm. + intros. rewrite H3 in H1. now contradict H1. + rewrite Heq0 in H1. + try (intros i i0 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i i0 i1 Heq; rewrite Heq in H1; now contradict H1). + rewrite Heq0 in H1. + try (intros i l Heq; rewrite Heq in H1; now contradict H1). + + rewrite wf_interp_form; trivial. simpl in H1. + rewrite Heq0 in H1. now contradict H1. + now inversion H. + now inversion H0. + apply (@check_symopp_xor ibs1 ibs2 xbs1 ybs2 ibsres zbsres N). + exact H1. +Qed. + +Lemma check_symopp_bvand_length: forall bs1 bs2 bsres N, + let n := length bsres in + check_symopp bs1 bs2 bsres (BO_BVand N) = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 N H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case (PArray.length a == 2) in H; try easy. + case ((a .[ 0] == i) && (a .[ 1] == i0) || (a .[ 0] == i0) && (a .[ 1] == i)) in H; try easy. + specialize (IHrbsres bs1 bs2 (N - 1)%N H). + simpl. + simpl in n. + fold n' in n. + unfold n. + split; apply f_equal. easy. easy. + easy. +Qed. + + +Lemma check_symopp_bvand_length2: forall bs1 bs2 bsres N, + let n := length bsres in + check_symopp bs1 bs2 bsres (BO_BVand N) = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 N H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case (PArray.length a == 2) in H; try easy. + case ((a .[ 0] == i) && (a .[ 1] == i0) || (a .[ 0] == i0) && (a .[ 1] == i)) in H; try easy. + specialize (IHrbsres bs1 bs2 (N - 1)%N H). + simpl. + simpl in n. + fold n' in n. + unfold n. + split; apply f_equal. easy. easy. + easy. +Qed. + +Lemma check_symopp_bvand_length3: forall bs1 bs2 bsres n, + check_symopp bs1 bs2 bsres (BO_BVand (N.of_nat n)) = true -> + (length bs1 = n)%nat -> + (length bsres = n)%nat. +Proof. intros bs1 bs2 bsres. + revert bs1 bs2. + induction bsres as [ | xbsres xsbsres IHbsres ]. + - intros. + case bs1 in *. + simpl in H. + case bs2 in *. + easy. now contradict H. + case bs2 in *. + simpl in H. now contradict H. + simpl in H. now contradict H. + - intros. + case bs1 in *. + simpl in H. + case bs2 in *. + now contradict H. + now contradict H. + simpl in H. + case bs2 in *. + now contradict H. + case (Lit.is_pos xbsres) in *. + case (t_form .[ Lit.blit xbsres] ) in *; try now contradict H. + case (PArray.length a == 2) in *. + case ((a .[ 0] == i) && (a .[ 1] == i0) || (a .[ 0] == i0) && (a .[ 1] == i)) in *. + specialize (IHbsres bs1 bs2 (n-1)%nat). + simpl in H0. + assert (length bs1 = (n-1)%nat). + { omega. } + + cut ( (BO_BVand (N.of_nat n - 1)) = (BO_BVand (N.of_nat (n - 1)))). + + intros. + revert H. + rewrite H2. + intros. + specialize (IHbsres H H1). + simpl. rewrite IHbsres. omega. + + simpl. + cut ((N.of_nat n - 1)%N = (N.of_nat (n - 1))). + intros. now rewrite H2. + + case n. now simpl. + intros. lia. + now contradict H. + now contradict H. + now contradict H. +Qed. + +Lemma check_symopp_bvor_length: forall bs1 bs2 bsres N, + let n := length bsres in + check_symopp bs1 bs2 bsres (BO_BVor N) = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 N H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case (PArray.length a == 2) in H; try easy. + case ((a .[ 0] == i) && (a .[ 1] == i0) || (a .[ 0] == i0) && (a .[ 1] == i)) in H; try easy. + specialize (IHrbsres bs1 bs2 (N - 1)%N H). + simpl. + simpl in n. + fold n' in n. + unfold n. + split; apply f_equal. easy. easy. + easy. +Qed. + +Lemma check_symopp_bvor_length2: forall bs1 bs2 bsres N, + let n := length bsres in + check_symopp bs1 bs2 bsres (BO_BVor N) = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 N H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case (PArray.length a == 2) in H; try easy. + case ((a .[ 0] == i) && (a .[ 1] == i0) || (a .[ 0] == i0) && (a .[ 1] == i)) in H; try easy. + specialize (IHrbsres bs1 bs2 (N - 1)%N H). + simpl. + simpl in n. + fold n' in n. + unfold n. + split; apply f_equal. easy. easy. + easy. +Qed. + +Lemma check_symopp_bvor_length3: forall bs1 bs2 bsres n, + check_symopp bs1 bs2 bsres (BO_BVor (N.of_nat n)) = true -> + (length bs1 = n)%nat -> + (length bsres = n)%nat. +Proof. intros bs1 bs2 bsres. + revert bs1 bs2. + induction bsres as [ | xbsres xsbsres IHbsres ]. + - intros. + case bs1 in *. + simpl in H. + case bs2 in *. + easy. now contradict H. + case bs2 in *. + simpl in H. now contradict H. + simpl in H. now contradict H. + - intros. + case bs1 in *. + simpl in H. + case bs2 in *. + now contradict H. + now contradict H. + simpl in H. + case bs2 in *. + now contradict H. + case (Lit.is_pos xbsres) in *. + case (t_form .[ Lit.blit xbsres] ) in *; try now contradict H. + case (PArray.length a == 2) in *. + case ((a .[ 0] == i) && (a .[ 1] == i0) || (a .[ 0] == i0) && (a .[ 1] == i)) in *. + specialize (IHbsres bs1 bs2 (n-1)%nat). + simpl in H0. + assert (length bs1 = (n-1)%nat). + { omega. } + + cut ( (BO_BVor (N.of_nat n - 1)) = (BO_BVor (N.of_nat (n - 1)))). + + intros. + revert H. + rewrite H2. + intros. + specialize (IHbsres H H1). + simpl. rewrite IHbsres. omega. + + simpl. + cut ((N.of_nat n - 1)%N = (N.of_nat (n - 1))). + intros. now rewrite H2. + + case n. now simpl. + intros. lia. + now contradict H. + now contradict H. + now contradict H. +Qed. + +Lemma check_symopp_bvxor_length: forall bs1 bs2 bsres N, + let n := length bsres in + check_symopp bs1 bs2 bsres (BO_BVxor N) = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 N H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case ((i1 == i) && (i2 == i0) || (i1 == i0) && (i2 == i)) in H; try easy. + specialize (IHrbsres bs1 bs2 (N - 1)%N H). + simpl. + simpl in n. + fold n' in n. + unfold n. + split; apply f_equal. easy. easy. + easy. +Qed. + + +Lemma check_symopp_bvxor_length2: forall bs1 bs2 bsres N, + let n := length bsres in + check_symopp bs1 bs2 bsres (BO_BVxor N) = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 N H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case ((i1 == i) && (i2 == i0) || (i1 == i0) && (i2 == i)) in H; try easy. + specialize (IHrbsres bs1 bs2 (N - 1)%N H). + simpl. + simpl in n. + fold n' in n. + unfold n. + split; apply f_equal. easy. easy. + easy. +Qed. + +Lemma check_symopp_bvxor_length3: forall bs1 bs2 bsres n, + check_symopp bs1 bs2 bsres (BO_BVxor (N.of_nat n)) = true -> + (length bs1 = n)%nat -> + (length bsres = n)%nat. +Proof. intros bs1 bs2 bsres. + revert bs1 bs2. + induction bsres as [ | xbsres xsbsres IHbsres ]. + - intros. + case bs1 in *. + simpl in H. + case bs2 in *. + easy. now contradict H. + case bs2 in *. + simpl in H. now contradict H. + simpl in H. now contradict H. + - intros. + case bs1 in *. + simpl in H. + case bs2 in *. + now contradict H. + now contradict H. + simpl in H. + case bs2 in *. + now contradict H. + case (Lit.is_pos xbsres) in *. + case (t_form .[ Lit.blit xbsres] ) in *; try now contradict H. + case ((i1 == i) && (i2 == i0) || (i1 == i0) && (i2 == i)) in *. + specialize (IHbsres bs1 bs2 (n-1)%nat). + simpl in H0. + assert (length bs1 = (n-1)%nat). + { omega. } + + cut ( (BO_BVxor (N.of_nat n - 1)) = (BO_BVxor (N.of_nat (n - 1)))). + + intros. + revert H. + rewrite H2. + intros. + specialize (IHbsres H H1). + simpl. rewrite IHbsres. omega. + + simpl. + cut ((N.of_nat n - 1)%N = (N.of_nat (n - 1))). + intros. now rewrite H2. + + case n. now simpl. + intros. lia. + now contradict H. + now contradict H. +Qed. + +Lemma check_symopp_bvand_nl: forall bs1 bs2 bsres N, + check_symopp bs1 bs2 bsres (BO_BVand N) = true -> + (List.map (Lit.interp rho) bsres) = + (RAWBITVECTOR_LIST.map2 andb (List.map (Lit.interp rho) bs1) + (List.map (Lit.interp rho) bs2)). +Proof. + intros. + pose proof H. + apply check_symopp_bvand_length in H. + destruct H. + apply check_symopp_bvand in H0. easy. easy. easy. +Qed. + +Lemma check_symopp_bvor_nl: forall bs1 bs2 bsres N, + check_symopp bs1 bs2 bsres (BO_BVor N) = true -> + (List.map (Lit.interp rho) bsres) = + (RAWBITVECTOR_LIST.map2 orb (List.map (Lit.interp rho) bs1) + (List.map (Lit.interp rho) bs2)). +Proof. + intros. + pose proof H. + apply check_symopp_bvor_length in H. + destruct H. + apply check_symopp_bvor in H0. easy. easy. easy. +Qed. + +Lemma check_symopp_bvxor_nl: forall bs1 bs2 bsres N, + check_symopp bs1 bs2 bsres (BO_BVxor N) = true -> + (List.map (Lit.interp rho) bsres) = + (RAWBITVECTOR_LIST.map2 xorb (List.map (Lit.interp rho) bs1) + (List.map (Lit.interp rho) bs2)). +Proof. + intros. + pose proof H. + apply check_symopp_bvxor_length in H. + destruct H. + apply check_symopp_bvxor in H0. easy. easy. easy. +Qed. + +Lemma valid_check_bbOp pos1 pos2 lres: C.valid rho (check_bbOp pos1 pos2 lres). +Proof. + unfold check_bbOp. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | | [ A B | A | | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; + try (intros; now apply C.interp_true). + (* BVand *) + - case_eq ((a1 == a1') && (a2 == a2') || (a1 == a2') && (a2 == a1')); + simpl; intros Heq10; try (now apply C.interp_true). + + case_eq ( + check_symopp bs1 bs2 bsres (BO_BVand N) && + (N.of_nat (Datatypes.length bs1) =? N)%N); + simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + unfold Atom.interp_form_hatom_bv at 2, Atom.interp_hatom. + rewrite Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite Atom.t_interp_wf; trivial. + rewrite Atom.t_interp_wf; trivial. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. rewrite Htia1, Htia2. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea). + intros i j Hv. rewrite Hv in H0. now contradict H0. + intros i Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros n Hv. rewrite Hv in H0. + + (** n = N **) + apply N.eqb_eq in H0. + rewrite <- H0 in *. + revert v_vala Htia. rewrite Hv. + intros v_vala Htia. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + revert v_vala1 Htia1 v_vala2 Htia2. + rewrite H2, H3. + unfold bvtrue. + rewrite Typ.cast_refl. + + intros v_vala1 Htia1 v_vala2 Htia2. + + (** case a1 = a1' and a2 = a2' **) + rewrite orb_true_iff in Heq10. + do 2 rewrite andb_true_iff in Heq10. + destruct Heq10 as [Heq10 | Heq10]; + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2. + rewrite Heq10a1, Heq10a2 in *. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp1. + rewrite Htia1 in HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' + = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp2. + simpl in HSp2. + rewrite Htia2 in HSp2. + + apply BITVECTOR_LIST.bv_eq_reflect. + unfold Bval, interp_bv. + + rewrite (@check_symopp_bvand_nl bs1 bs2 bsres N). + + assert ( + H100: (N.of_nat + (Datatypes.length + (RAWBITVECTOR_LIST.map2 andb (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + specialize (@RAWBITVECTOR_LIST.map2_and_length + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2)). + intros. rewrite <- H6. + now rewrite map_length. + apply check_symopp_bvand_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite !map_length, Heq11a, Heq11b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + generalize ( + BITVECTOR_LIST.of_bits_size (RAWBITVECTOR_LIST.map2 andb + (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)) + ). + + rewrite H100. + rewrite Typ.cast_refl. intros. + + unfold BITVECTOR_LIST.bv_and, RAWBITVECTOR_LIST.bv_and. + unfold RAWBITVECTOR_LIST.size. + unfold RAWBITVECTOR_LIST.bits. + + unfold interp_bv in HSp1, HSp2. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits in HSp1, HSp2. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_symopp_bvand_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + revert HSp2. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2) + ). + + rewrite H101. intros. + + assert ( + H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp1. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1) + ). + + rewrite H102. intros. + + rewrite Typ.cast_refl in *. + rewrite HSp1, HSp2. simpl. + apply eq_rec. simpl. + + rewrite H101, H102. + rewrite N.eqb_compare, N.compare_refl. easy. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + exact Heq11. + + (** symmetric case*) + rewrite Heq10a1, Heq10a2 in *. + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp2. + rewrite Htia1 in HSp2. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' + = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp1. + simpl in HSp1. + rewrite Htia2 in HSp1. + + apply BITVECTOR_LIST.bv_eq_reflect. + unfold Bval, interp_bv. + + rewrite (@check_symopp_bvand_nl bs1 bs2 bsres N). + + assert ( + H100: (N.of_nat + (Datatypes.length + (RAWBITVECTOR_LIST.map2 andb (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + specialize (@RAWBITVECTOR_LIST.map2_and_length + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2)). + intros. rewrite <- H6. + apply check_symopp_bvand_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite map_length. + apply check_symopp_bvand_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite !map_length, Heq11a, Heq11b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + generalize ( + BITVECTOR_LIST.of_bits_size (RAWBITVECTOR_LIST.map2 andb + (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)) + ). + + rewrite H100. + rewrite Typ.cast_refl. intros. + + unfold BITVECTOR_LIST.bv_and, RAWBITVECTOR_LIST.bv_and. + unfold RAWBITVECTOR_LIST.size. + unfold RAWBITVECTOR_LIST.bits. + + unfold interp_bv in HSp1, HSp2. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits in HSp1, HSp2. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_symopp_bvand_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp2. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2) + ). + + rewrite H101. intros. + + assert ( + H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp1. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1) + ). + + rewrite H102. intros. + rewrite Typ.cast_refl in *. + rewrite HSp1, HSp2. simpl. + apply eq_rec. simpl. + rewrite H101, H102. + rewrite N.eqb_compare, N.compare_refl. + now rewrite RAWBITVECTOR_LIST.map2_and_comm. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + exact Heq11. + + (* BVor *) + - case_eq ((a1 == a1') && (a2 == a2') || (a1 == a2') && (a2 == a1')); + simpl; intros Heq10; try (now apply C.interp_true). + + case_eq ( + check_symopp bs1 bs2 bsres (BO_BVor N) && + (N.of_nat (Datatypes.length bs1) =? N)%N); + simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + unfold Atom.interp_form_hatom_bv at 2, Atom.interp_hatom. + rewrite Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite Atom.t_interp_wf; trivial. + rewrite Atom.t_interp_wf; trivial. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. rewrite Htia1, Htia2. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea). + intros i j Hv. rewrite Hv in H0. now contradict H0. + intros i Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros n Hv. rewrite Hv in H0. + + (** n = N **) + apply N.eqb_eq in H0. + rewrite <- H0 in *. + revert v_vala Htia. rewrite Hv. + intros v_vala Htia. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + revert v_vala1 Htia1 v_vala2 Htia2. + rewrite H2, H3. + unfold bvtrue. + rewrite Typ.cast_refl. + + intros v_vala1 Htia1 v_vala2 Htia2. + + (** case a1 = a1' and a2 = a2' **) + rewrite orb_true_iff in Heq10. + do 2 rewrite andb_true_iff in Heq10. + destruct Heq10 as [Heq10 | Heq10]; + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2. + rewrite Heq10a1, Heq10a2 in *. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp1. + rewrite Htia1 in HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' + = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp2. + simpl in HSp2. + rewrite Htia2 in HSp2. + + apply BITVECTOR_LIST.bv_eq_reflect. + unfold Bval, interp_bv. + + rewrite (@check_symopp_bvor_nl bs1 bs2 bsres N). + + assert ( + H100: (N.of_nat + (Datatypes.length + (RAWBITVECTOR_LIST.map2 orb (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)))) = N). + rewrite andb_true_iff in Heq11. + { + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + specialize (@RAWBITVECTOR_LIST.map2_or_length + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2)). + intros. rewrite <- H6. + now rewrite map_length. + apply check_symopp_bvor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite !map_length, Heq11a, Heq11b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + generalize ( + BITVECTOR_LIST.of_bits_size (RAWBITVECTOR_LIST.map2 orb + (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)) + ). + + rewrite H100. + rewrite Typ.cast_refl. intros. + + unfold BITVECTOR_LIST.bv_or, RAWBITVECTOR_LIST.bv_or. + unfold RAWBITVECTOR_LIST.size. + unfold RAWBITVECTOR_LIST.bits. + + unfold interp_bv in HSp1, HSp2. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits in HSp1, HSp2. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_symopp_bvor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp2. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2) + ). + + rewrite H101. intros. + + assert ( + H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp1. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1) + ). + + rewrite H102. intros. + + rewrite Typ.cast_refl in *. + rewrite HSp1, HSp2. simpl. + apply eq_rec. simpl. + rewrite H101, H102. + rewrite N.eqb_compare, N.compare_refl. easy. + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + exact Heq11. + + (** symmetric case*) + rewrite Heq10a1, Heq10a2 in *. + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp2. + rewrite Htia1 in HSp2. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' + = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp1. + simpl in HSp1. + rewrite Htia2 in HSp1. + + apply BITVECTOR_LIST.bv_eq_reflect. + unfold Bval, interp_bv. + + rewrite (@check_symopp_bvor_nl bs1 bs2 bsres N). + + assert ( + H100: (N.of_nat + (Datatypes.length + (RAWBITVECTOR_LIST.map2 orb (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)))) = N). + rewrite andb_true_iff in Heq11. + { + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + specialize (@RAWBITVECTOR_LIST.map2_or_length + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2)). + intros. rewrite <- H6. + apply check_symopp_bvor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite map_length. + apply check_symopp_bvor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite !map_length, Heq11a, Heq11b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + generalize ( + BITVECTOR_LIST.of_bits_size (RAWBITVECTOR_LIST.map2 orb + (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)) + ). + + rewrite H100. + rewrite Typ.cast_refl. intros. + + unfold BITVECTOR_LIST.bv_or, RAWBITVECTOR_LIST.bv_or. + unfold RAWBITVECTOR_LIST.size. + unfold RAWBITVECTOR_LIST.bits. + + unfold interp_bv in HSp1, HSp2. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits in HSp1, HSp2. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_symopp_bvor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + revert HSp2. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2) + ). + + rewrite H101. intros. + + assert ( + H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp1. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1) + ). + + rewrite H102. intros. + + rewrite Typ.cast_refl in *. + rewrite HSp1, HSp2. simpl. + apply eq_rec. simpl. + rewrite H101, H102. + rewrite N.eqb_compare, N.compare_refl. + now rewrite RAWBITVECTOR_LIST.map2_or_comm. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + exact Heq11. + + (** BVxor **) + - case_eq ((a1 == a1') && (a2 == a2') || (a1 == a2') && (a2 == a1')); + simpl; intros Heq10; try (now apply C.interp_true). + + case_eq ( + check_symopp bs1 bs2 bsres (BO_BVxor N) && + (N.of_nat (Datatypes.length bs1) =? N)%N); + simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + unfold Atom.interp_form_hatom_bv at 2, Atom.interp_hatom. + rewrite Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite Atom.t_interp_wf; trivial. + rewrite Atom.t_interp_wf; trivial. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. rewrite Htia1, Htia2. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea). + intros i j Hv. rewrite Hv in H0. now contradict H0. + intros i Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros Hv. rewrite Hv in H0. now contradict H0. + intros n Hv. rewrite Hv in H0. + + (** n = N **) + apply N.eqb_eq in H0. + rewrite <- H0 in *. + revert v_vala Htia. rewrite Hv. + intros v_vala Htia. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + revert v_vala1 Htia1 v_vala2 Htia2. + rewrite H2, H3. + unfold bvtrue. + rewrite Typ.cast_refl. + + intros v_vala1 Htia1 v_vala2 Htia2. + + (** case a1 = a1' and a2 = a2' **) + rewrite orb_true_iff in Heq10. + do 2 rewrite andb_true_iff in Heq10. + destruct Heq10 as [Heq10 | Heq10]; + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2. + rewrite Heq10a1, Heq10a2 in *. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + rewrite H4 in HSp1. + rewrite Htia1 in HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' + = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp2. + simpl in HSp2. + rewrite Htia2 in HSp2. + + apply BITVECTOR_LIST.bv_eq_reflect. + unfold Bval, interp_bv. + + rewrite (@check_symopp_bvxor_nl bs1 bs2 bsres N). + + assert ( + H100: (N.of_nat + (Datatypes.length + (RAWBITVECTOR_LIST.map2 xorb (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)))) = N). + rewrite andb_true_iff in Heq11. + { + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + specialize (@RAWBITVECTOR_LIST.map2_xor_length + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2)). + intros. rewrite <- H6. + now rewrite map_length. + apply check_symopp_bvxor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite !map_length, Heq11a, Heq11b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + generalize ( + BITVECTOR_LIST.of_bits_size (RAWBITVECTOR_LIST.map2 xorb + (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)) + ). + + rewrite H100. + rewrite Typ.cast_refl. intros. + + unfold BITVECTOR_LIST.bv_xor, RAWBITVECTOR_LIST.bv_xor. + unfold RAWBITVECTOR_LIST.size. + unfold RAWBITVECTOR_LIST.bits. + + unfold interp_bv in HSp1, HSp2. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits in HSp1, HSp2. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_symopp_bvxor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp2. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2) + ). + + rewrite H101. intros. + + assert ( + H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp1. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1) + ). + + rewrite H102. intros. + + rewrite Typ.cast_refl in *. + rewrite HSp1, HSp2. simpl. + apply eq_rec. simpl. + + rewrite H101, H102. + rewrite N.eqb_compare, N.compare_refl. easy. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + exact Heq11. + + (** symmetric case*) + rewrite Heq10a1, Heq10a2 in *. + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp2. + rewrite Htia1 in HSp2. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' + = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp1. + simpl in HSp1. + rewrite Htia2 in HSp1. + + apply BITVECTOR_LIST.bv_eq_reflect. + unfold Bval, interp_bv. + + rewrite (@check_symopp_bvxor_nl bs1 bs2 bsres N). + + assert ( + H100: (N.of_nat + (Datatypes.length + (RAWBITVECTOR_LIST.map2 xorb (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)))) = N). + rewrite andb_true_iff in Heq11. + { + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + specialize (@RAWBITVECTOR_LIST.map2_xor_length + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2)). + intros. rewrite <- H6. + apply check_symopp_bvxor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite map_length. + apply check_symopp_bvxor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + now rewrite !map_length, Heq11a, Heq11b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + generalize ( + BITVECTOR_LIST.of_bits_size (RAWBITVECTOR_LIST.map2 xorb + (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2)) + ). + + rewrite H100. + rewrite Typ.cast_refl. intros. + + unfold BITVECTOR_LIST.bv_xor, RAWBITVECTOR_LIST.bv_xor. + unfold RAWBITVECTOR_LIST.size. + unfold RAWBITVECTOR_LIST.bits. + + unfold interp_bv in HSp1, HSp2. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits in HSp1, HSp2. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_symopp_bvxor_length2 in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp2. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2) + ). + + rewrite H101. intros. + + assert ( + H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + revert HSp1. + + generalize ( + BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1) + ). + + rewrite H102. intros. + + rewrite Typ.cast_refl in *. + rewrite HSp1, HSp2. simpl. + apply eq_rec. simpl. + rewrite H101, H102. + rewrite N.eqb_compare, N.compare_refl. + now rewrite RAWBITVECTOR_LIST.map2_xor_comm. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + exact Heq11. +Qed. + +Lemma check_symopp_eq: forall ibs1 ibs2 xbs1 ybs2 ibsres zbsres n, + check_symopp (ibs1 :: xbs1) (ibs2 :: ybs2) (ibsres :: zbsres) (BO_eq (Typ.TBV n)) = true -> + check_symopp xbs1 ybs2 zbsres (BO_eq (Typ.TBV n)) = true. +Proof. intros. + simpl in H. + case (Lit.is_pos ibsres) in H. + case (t_form .[ Lit.blit ibsres]) in H; try (contradict H; easy). + case ((i == ibs1) && (i0 == ibs2) || (i == ibs2) && (i0 == ibs1)) in H. + exact H. + now contradict H. + now contradict H. +Qed. + +Lemma bool_eqb_comm: forall ibs1 ibs2, Bool.eqb ibs1 ibs2 = Bool.eqb ibs2 ibs1. +Proof. intros. case_eq ibs1. intros. case_eq ibs2. intros. easy. intros. easy. intros. easy. Qed. + +Lemma check_symopp_eq': forall ibs1 ibs2 xbs1 ybs2 ibsres zbsres n, + check_symopp (ibs1 :: xbs1) (ibs2 :: ybs2) (ibsres :: zbsres) (BO_eq (Typ.TBV n)) = true -> + Bool.eqb (Lit.interp rho ibs1) (Lit.interp rho ibs2) = Lit.interp rho ibsres. +Proof. intros. + simpl in H. + case_eq (Lit.is_pos ibsres). intros. rewrite H0 in H. + case_eq (t_form .[ Lit.blit ibsres]); intros; rewrite H1 in H; try (now contradict H). + specialize (@rho_interp ( Lit.blit ibsres)). + rewrite H1 in rho_interp. simpl in rho_interp. + case_eq ((i == ibs1) && (i0 == ibs2) || (i == ibs2) && (i0 == ibs1)). + intros. rewrite orb_true_iff in H2. destruct H2. + rewrite andb_true_iff in H2. destruct H2. rewrite eqb_spec in H2, H3. + rewrite H2, H3 in rho_interp. + rewrite <- rho_interp. unfold Lit.interp. rewrite H0. now unfold Var.interp. + intros. rewrite andb_true_iff in H2. destruct H2. rewrite eqb_spec in H2, H3. + rewrite H2, H3 in rho_interp. rewrite bool_eqb_comm in rho_interp. + rewrite <- rho_interp. unfold Lit.interp. rewrite H0. now unfold Var.interp. + intros. rewrite H2 in H. now contradict H. + intros. rewrite H0 in H. now contradict H. +Qed. + +Lemma check_symopp_bveq: forall bs1 bs2 a4 n, check_symopp bs1 bs2 (to_list a4) (BO_eq (Typ.TBV n)) = true -> + RAWBITVECTOR_LIST.beq_list (map (Lit.interp rho) bs1) + (map (Lit.interp rho) bs2) = forallb (Lit.interp rho) (to_list a4). +Proof. intros. revert bs1 bs2 H. + induction (to_list a4) as [ | xa4 xsa4 IHa4]. + - intros. + case_eq bs1. intros. rewrite H0 in H. + case_eq bs2. intros. rewrite H1 in H. + simpl. easy. + intros. rewrite H1 in H. simpl in H. now contradict H. + intros. rewrite H0 in H. simpl in H. + case_eq bs2. intros. rewrite H1 in H. now contradict H. + intros. rewrite H1 in H. now contradict H. + - intros. unfold check_symopp in H. + case_eq bs1. intros. rewrite H0 in H. + case_eq bs2. intros. rewrite H1 in H. now contradict H. + intros. rewrite H1 in H. now contradict H. + intros. fold check_symopp in H. + case_eq bs2. intros. rewrite H1 in H. simpl in H. + rewrite H0 in H. simpl in H. now contradict H. + intros. rewrite H0, H1 in H. + pose proof H. apply check_symopp_eq' in H2. + apply check_symopp_eq in H. + specialize (IHa4 l l0 H). simpl. rewrite IHa4. + case (forallb (Lit.interp rho) xsa4); [ do 2 rewrite andb_true_r | now do 2 rewrite andb_false_r]. + exact H2. +Qed. + +Lemma beq_list_comm: forall bs1 bs2, RAWBITVECTOR_LIST.beq_list bs2 bs1 = + RAWBITVECTOR_LIST.beq_list bs1 bs2. +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. case bs2. easy. + intros. easy. + - intros. case bs2. easy. + intros. simpl. + specialize (@IHbs1 l). rewrite IHbs1. + case (RAWBITVECTOR_LIST.beq_list xsbs1 l). do 2 rewrite andb_true_r. + unfold Bool.eqb. + case b. easy. easy. + now do 2 rewrite andb_false_r. +Qed. + +Lemma prop_check_eq: forall bs1 bs2 bsres, + (length bs1) = (length bs2) -> + check_eq bs1 bs2 bsres = true -> + forallb2 Bool.eqb (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2) = + forallb (Lit.interp rho) bsres. +Proof. intro bs1. + induction bs1 as [ | x1 bs1 IHbs1 ]. + - intros bs2 bsres Hlen Hcheck. + case bs2 in *. + + case bsres in *. + * now simpl. + * contradict Hcheck; now simpl. + + contradict Hcheck; now simpl. + - intros bs2 bsres Hlen Hcheck. + symmetry. + case bs2 in *. + + case bsres in *; contradict Hcheck; now simpl. + + case bsres in *. + * contradict Hcheck; now simpl. + * simpl. + rename i into x2. rename i0 into r1. + simpl in Hlen. inversion Hlen. + rename H0 into Hlen'. + + case bsres in *. + (*--*) simpl in Hcheck. + case_eq (Lit.is_pos r1); intros; rewrite H in Hcheck; + try (case bs1 in *; try (now contradict Hcheck); case bs2 in *; + try (now contradict Hcheck)); + rename H into Hposr1; + case_eq (t_form .[ Lit.blit r1]);intros; rewrite H in Hcheck; try (now contradict Hcheck); + rename H into Hform_r1; + generalize (rho_interp (Lit.blit r1)); rewrite Hform_r1; simpl; + intro Hi. + (*++*) rename i into arg1; rename i0 into arg2. + unfold Lit.interp at 1, Var.interp at 1. + rewrite Hposr1, Hi. repeat (rewrite andb_true_r). + case_eq ((arg1 == x1) && (arg2 == x2) || (arg1 == x2) && (arg2 == x1)). + (* ** *) intros Hif. + rewrite orb_true_iff in Hif. + repeat (rewrite andb_true_iff in Hif). + repeat (rewrite eqb_spec in Hif). + destruct Hif as [ Hif1 | Hif2 ]. + (* --- *) destruct Hif1 as (Hx1, Hx2). now rewrite Hx1, Hx2. + (* --- *) destruct Hif2 as (Hx2, Hx1). rewrite Hx1, Hx2. + now rewrite bool_eqb_comm. + (* ** *)intros Hif. rewrite Hif in Hcheck. now contradict Hcheck. + + (* ++ *) + case_eq (to_list a); + intros; rewrite H in Hcheck; try (now contradict Hcheck). + rename H into Ha, i1 into a1, l into rargs. + case_eq (Lit.is_pos a1); + intros; rewrite H in Hcheck; try (now contradict Hcheck). + rename H into Hposa1. + case_eq (t_form .[ Lit.blit a1]); + intros; rewrite H in Hcheck; try (now contradict Hcheck). + rename H into Hform_a1. + rename i into x1', i0 into x2', i1 into arg1, i2 into arg2. + generalize (rho_interp (Lit.blit a1)). rewrite Hform_a1. simpl. + intro Heqx1x2. + rewrite afold_left_and in Hi. + rewrite Ha in Hi. simpl in Hi. + unfold Lit.interp at 1, Var.interp at 1. + rewrite Hposr1, Hi. repeat (rewrite andb_true_r). + unfold Lit.interp at 1, Var.interp at 1. + rewrite Hposa1. rewrite Heqx1x2. + + case_eq ((arg1 == x1) && (arg2 == x2) || (arg1 == x2) && (arg2 == x1)). + (* ** *) intros Hif. + rewrite Hif in Hcheck. + apply (@IHbs1 _ _ Hlen') in Hcheck. + simpl in Hcheck. rewrite Hcheck. + repeat (rewrite orb_true_iff in Hif). + repeat (rewrite andb_true_iff in Hif). + repeat (rewrite eqb_spec in Hif). + destruct Hif as [ Hif1 | Hif2 ]. + (* --- *) destruct Hif1 as (Hx1, Hx2). now rewrite Hx1, Hx2. + (* --- *) destruct Hif2 as (Hx2, Hx1). rewrite Hx1, Hx2. + now rewrite bool_eqb_comm. + (* ** *) intros Hif. rewrite Hif in Hcheck. now contradict Hcheck. + + (* -- *) simpl in Hcheck. + case_eq (Lit.is_pos r1); intros; rewrite H in Hcheck; + try (case bs1 in *; try (now contradict Hcheck); case bs2 in *; + try (now contradict Hcheck)); + rename H into Hposr1; + case_eq (t_form .[ Lit.blit r1]);intros; rewrite H in Hcheck; try (now contradict Hcheck); + rename H into Hform_r1; + generalize (rho_interp (Lit.blit r1)); rewrite Hform_r1; simpl; + intro Hi. + (* ++ *) contradict Hcheck. simpl. + case ((i0 == x1) && (i1 == x2) || (i0 == x2) && (i1 == x1)); easy. + (* ++ *) rename i0 into x1', i1 into x2', i2 into arg1, i3 into arg2. + unfold Lit.interp at 1, Var.interp at 1. + rewrite Hposr1, Hi. + case_eq ((arg1 == x1) && (arg2 == x2) || (arg1 == x2) && (arg2 == x1)). + (* ** *) intros Hif. rewrite Hif in Hcheck. + apply (@IHbs1 _ _ Hlen') in Hcheck. + simpl in Hcheck. rewrite Hcheck. + repeat (rewrite orb_true_iff in Hif). + repeat (rewrite andb_true_iff in Hif). + repeat (rewrite eqb_spec in Hif). + destruct Hif as [ Hif1 | Hif2 ]. + (* --- *) destruct Hif1 as (Hx1, Hx2). now rewrite Hx1, Hx2. + (* --- *) destruct Hif2 as (Hx2, Hx1). rewrite Hx1, Hx2. + now rewrite bool_eqb_comm. + (* ** *) intros Hif. rewrite Hif in Hcheck. now contradict Hcheck. +Qed. + +Lemma length_check_eq: forall bs1 bs2 bsres, + check_eq bs1 bs2 bsres = true -> length bs1 = length bs2. +Proof. + intro bs1. + induction bs1. + + intros. case bs2 in *. trivial. + simpl in H. now contradict H. + + intros. + case bs2 in *. + - simpl in H. now contradict H. + - simpl. apply f_equal. + simpl in H. + revert H. + case bsres. easy. + intros r rl. + case rl. + case (Lit.is_pos r). + case (t_form .[ Lit.blit r]); try easy. + intro a0. + case bs1 in *; try easy; case bs2; try easy. + case bs1 in *; try easy; case bs2; try easy. + case bs1 in *; try easy; case bs2; try easy. + case bs1 in *; try easy; case bs2; try easy. + case bs1 in *; try easy; case bs2; try easy. + case bs1 in *; try easy; case bs2; try easy. + intros i1 l a0. + case (to_list a0); try easy. + intros i2 l0. + case (Lit.is_pos i2); try easy. + case (t_form .[ Lit.blit i2]); try easy. + intros i3 i4. + case ((i3 == a) && (i4 == i) || (i3 == i) && (i4 == a)). + apply IHbs1. + easy. + intros _ _ i2 l0 a0. + case (to_list a0); try easy. + intros i1 l. + case (Lit.is_pos i1); try easy. + case (t_form .[ Lit.blit i1]); try easy. + intros i3 i4. + case ((i3 == a) && (i4 == i) || (i3 == i) && (i4 == a)). + apply IHbs1. + easy. + intros i2 l0 a0. + case (to_list a0); try easy. + intros i9 l. + case (Lit.is_pos i9); try easy. + case (t_form .[ Lit.blit i9]); try easy. + intros i3 i4. + case ((i3 == a) && (i4 == i) || (i3 == i) && (i4 == a)). + apply IHbs1. + easy. + intros _ _ i2 l0 a0. + case (to_list a0); try easy. + intros i9 l. + case (Lit.is_pos i9); try easy. + case (t_form .[ Lit.blit i9]); try easy. + intros i3 i4. + case ((i3 == a) && (i4 == i) || (i3 == i) && (i4 == a)). + apply IHbs1. + easy. + case bs1; try easy; case bs2; easy. + case bs1; try easy; case bs2; easy. + case bs1; try easy; case bs2; easy. + case bs1; try easy; case bs2. + + simpl. easy. + + intros i0 l i1 i2. + case ((i1 == a) && (i2 == i) || (i1 == i) && (i2 == a)); easy. + simpl. + intros _ l i1 i2. + case ((i1 == a) && (i2 == i) || (i1 == i) && (i2 == a)); easy. + easy. + case bs1 in *; try easy; case bs2; easy. + case bs1 in *; try easy; case bs2; easy. + case bs1 in *; try easy; case bs2; easy. + case bs1 in *; try easy; case bs2; try easy. + case (Lit.is_pos r); try easy. + case (t_form .[ Lit.blit r]); try easy. + simpl. intros x y. case ((x == a) && (y == i) || (x == i) && (y == a)); easy. + case (Lit.is_pos r); try easy. + case (t_form .[ Lit.blit r]); try easy. + simpl. intros x y. case ((x == a) && (y == i) || (x == i) && (y == a)); easy. + case (Lit.is_pos r); try easy. + case (t_form .[ Lit.blit r]); try easy. + intros x y. case ((x == a) && (y == i) || (x == i) && (y == a)). + intros x2 rbs2 xr rbrs. + apply IHbs1. easy. +Qed. + +Lemma valid_check_bbEq pos1 pos2 lres : C.valid rho (check_bbEq pos1 pos2 lres). + Proof. + unfold check_bbEq. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). intros a bsres Heq8. + case_eq (Bool.eqb (Lit.is_pos a) (Lit.is_pos bsres)); try (intros; now apply C.interp_true). intros Heq12. + case_eq (t_form .[ Lit.blit a]); try (intros; now apply C.interp_true). intros a3 Heq10. + case_eq (t_atom .[ a3]); try (intros; now apply C.interp_true). + + intros [ | | | | | | | [ A B | A | | | |n]|N|N|N|N|N|N|N|N|N| | | | ]; + try (intros; now apply C.interp_true). + + intros a1' a2' Heq9. + case_eq ((a1 == a1') && (a2 == a2') || (a1 == a2') && (a2 == a1')); + simpl; intros Heq15; try (now apply C.interp_true). + + case_eq (check_eq bs1 bs2 [bsres] && + (N.of_nat (Datatypes.length bs1) =? n)%N); + simpl; intros Heq16; try (now apply C.interp_true). + + unfold C.valid. simpl. + rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a3). + assert (a3 < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a3]). + intros v_typea3 v_vala3 Htia3. rewrite Htia3 in H0. + + case_eq (v_typea3); intros; rewrite H4 in H0; try (now contradict H0). + rename H4 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + simpl in v_vala2, v_vala2. + + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + (** case a1 = a1' and a2 = a2' **) + rewrite orb_true_iff in Heq15. + do 2 rewrite andb_true_iff in Heq15. + destruct Heq15 as [Heq15 | Heq15]; + destruct Heq15 as (Heq15a1 & Heq15a2); rewrite eqb_spec in Heq15a1, Heq15a2 + ;rewrite Heq15a1, Heq15a2 in *. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp1. + unfold interp_bv in HSp1. + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp2. + unfold interp_bv in HSp2. + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2 in HSp2. + unfold interp_bv in HSp2. + + generalize dependent v_vala1. generalize dependent v_vala2. + + rewrite H2, H3. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert ( + H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = n + ). + { + rewrite !andb_true_iff in Heq16. + destruct Heq16 as (Heq16, Heq16r). + rewrite N.eqb_eq in Heq16r. + apply length_check_eq in Heq16. + rewrite Heq16 in Heq16r. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H100. + rewrite Typ.cast_refl. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n + ). + { + rewrite !andb_true_iff in Heq16. + destruct Heq16 as (Heq16, Heq16r). + rewrite N.eqb_eq in Heq16r. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite !Typ.cast_refl. intros. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + apply (@Bool.eqb_true_iff (Lit.interp rho a) (Lit.interp rho bsres)). + + unfold Lit.interp, Var.interp. + rewrite rho_interp. + rewrite Heq10. simpl. + + unfold Atom.interp_form_hatom. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1, Htia2. simpl. + rewrite Typ.N_cast_refl. simpl. + + rewrite Form.wf_interp_form; trivial. + simpl. + apply Bool.eqb_prop in Heq12. + rewrite Heq12. + rewrite HSp1, HSp2. + simpl. + + rewrite Typ.i_eqb_t. simpl. + + unfold BITVECTOR_LIST.bv_eq. + unfold RAWBITVECTOR_LIST.bv_eq, RAWBITVECTOR_LIST.bits. + unfold BITVECTOR_LIST.bv, BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + unfold RAWBITVECTOR_LIST.size. + + case_eq (Lit.is_pos bsres). + intros Hpos. + + rewrite andb_true_iff in Heq16. + destruct Heq16 as (Heq16 & Heq16r). + rewrite N.eqb_eq in Heq16r. simpl. + pose proof Heq16 as Heq16p. + + apply length_check_eq in Heq16. + rewrite !map_length, Heq16. + rewrite N.eqb_compare, N.compare_refl. + pose proof (Heq16) as Hleq. + + rewrite (@prop_check_eq _ _ [bsres]). simpl. + rewrite andb_true_r. unfold Lit.interp, Var.interp. + generalize (rho_interp (Lit.blit bsres)). simpl. + intro Hbres. rewrite Hbres. simpl. + rewrite Hpos. + simpl. now unfold Atom.interp_form_hatom, interp_hatom. + exact Hleq. + + exact Heq16p. + + intros Hpos. + rewrite andb_true_iff in Heq16. + destruct Heq16 as (Heq16 & Heq16r). + + contradict Heq16. + case bs1 in *; try now simpl; case bs2 in *; now simpl. + case bs2 in *. simpl. easy. + simpl. rewrite Hpos. case bs1; intros; auto; case bs2; auto. + + pose proof Heq16 as Heq16'. + + rewrite andb_true_iff in Heq16. + destruct Heq16 as (Heq16 & Heq16r). + apply length_check_eq in Heq16; auto. + + (** case symmetry **) + + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp2. + unfold interp_bv in HSp2. + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1 in HSp2. + unfold interp_bv in HSp2. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp1. + unfold interp_bv in HSp1. + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2 in HSp1. + unfold interp_bv in HSp1. + + generalize dependent v_vala1. generalize dependent v_vala2. + + rewrite H2, H3. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert ( + H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n + ). + { + rewrite N.eqb_eq in Heq16r. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H100. + rewrite !Typ.cast_refl. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = n + ). + { + rewrite N.eqb_eq in Heq16r. + rewrite Heq16 in Heq16r. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H101. + rewrite Typ.cast_refl. + + intros. + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + apply (@Bool.eqb_true_iff (Lit.interp rho a) (Lit.interp rho bsres)). + + unfold Lit.interp, Var.interp. + rewrite rho_interp. + rewrite Heq10. simpl. + + unfold Atom.interp_form_hatom. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1, Htia2. simpl. + rewrite Typ.N_cast_refl. simpl. + + rewrite Form.wf_interp_form; trivial. + simpl. + apply Bool.eqb_prop in Heq12. + rewrite Heq12. + rewrite HSp1, HSp2. + simpl. + + rewrite Typ.i_eqb_t. simpl. + + unfold BITVECTOR_LIST.bv_eq. + unfold RAWBITVECTOR_LIST.bv_eq, RAWBITVECTOR_LIST.bits. + unfold BITVECTOR_LIST.bv, BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + unfold RAWBITVECTOR_LIST.size. + + case_eq (Lit.is_pos bsres). + intros Hpos. + + rewrite beq_list_comm. + rewrite !map_length, Heq16, N.eqb_compare, N.compare_refl. + + rewrite (@prop_check_eq _ _ [bsres]). simpl. + rewrite andb_true_r. unfold Lit.interp, Var.interp. + generalize (rho_interp (Lit.blit bsres)). simpl. + intro Hbres. rewrite Hbres. + + rewrite andb_true_iff in Heq16'. + destruct Heq16' as (Heq16' & Heq16'r). + rewrite Hpos. + now unfold Atom.interp_form_hatom, interp_hatom. + intros. exact Heq16. + + rewrite andb_true_iff in Heq16'. + destruct Heq16' as (Heq16' & Heq16'r). + exact Heq16'. + + intros Hpos. + contradict Heq16'. + case bs1 in *; try now simpl; case bs2 in *; now simpl. + case bs2 in *; try now simpl; case bs2 in *; now simpl. + simpl. easy. + simpl. + case bs1 in *; try now simpl; case bs2 in *; now simpl. + rewrite Hpos. + case bs2 in *; try now simpl; case bs2 in *; now simpl. + now rewrite andb_false_l. + + case bs2 in *; rewrite Hpos; simpl; easy. +Qed. + +Lemma check_add_bvadd_length: forall bs1 bs2 bsres c, + let n := length bsres in + check_add bs1 bs2 bsres c = true -> + (length bs1 = n)%nat /\ (length bs2 = n)%nat . +Proof. + intros. + revert bs1 bs2 c H. + induction bsres as [ | r rbsres ]. + intros. + simpl in H. + case bs1 in *. simpl in H. + case bs2 in *. simpl in *. easy. easy. + case bs2 in *. simpl in *. easy. + simpl in *. easy. + intros. + case bs1 in *. + case bs2 in *. + simpl in *. easy. + simpl in *. easy. + case bs2 in *. simpl in *. easy. + set (n' := length rbsres). + fold n' in n, IHrbsres, H. + simpl in IHrbsres. + simpl in H. + case (Lit.is_pos r) in H. + case (t_form .[ Lit.blit r]) in H; try easy. + case (Lit.is_pos i1) in H. + case (t_form .[ Lit.blit i1]) in H; try now contradict H. + rewrite andb_true_iff in H. destruct H. + specialize (IHrbsres bs1 bs2 ((Cor (Cand (Clit i) (Clit i0)) (Cand (Cxor (Clit i) (Clit i0)) c))) H0). + simpl. + simpl in n. + split; apply f_equal. easy. easy. + easy. easy. +Qed. + +Lemma prop_eq_carry_lit: forall c i, eq_carry_lit c i = true -> interp_carry c = (Lit.interp rho i). +Proof. intro c. + induction c. + - intros. simpl in *. + case (Lit.is_pos i0 ) in H; rewrite eqb_spec in H; now rewrite H. + - intros. simpl. + pose proof IHc1. pose proof IHc2. + simpl in H. + case_eq ( Lit.is_pos i). intros Hip0. + rewrite Hip0 in H. + case_eq (t_form .[ Lit.blit i]); intros; rewrite H2 in H; try now contradict H. + case_eq (PArray.length a == 2). intros Hl. rewrite Hl in H. + (* rewrite orb_true_iff in H; do 2 *) rewrite andb_true_iff in H. + + specialize (@rho_interp ( Lit.blit i)). rewrite H2 in rho_interp. + simpl in rho_interp. + rewrite afold_left_and in rho_interp. + rewrite eqb_spec in Hl. + apply to_list_two in Hl. + rewrite Hl in rho_interp. + simpl in rho_interp. + rewrite andb_true_r in rho_interp. + + (* destruct H. *) + + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. + unfold Lit.interp at 3. unfold Var.interp. + rewrite Hip0. now rewrite rho_interp. + (* + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. *) + (* unfold Lit.interp at 3. unfold Var.interp. *) + (* rewrite Hip0. rewrite rho_interp. now rewrite andb_comm. *) + + intros. rewrite H3 in H. now contradict H. + + intros. rewrite H2 in H. now contradict H. + + - intros. simpl. + pose proof IHc1. pose proof IHc2. + simpl in H. + case_eq ( Lit.is_pos i). intros Hip0. + rewrite Hip0 in H. + case_eq (t_form .[ Lit.blit i]); intros; rewrite H2 in H; try now contradict H. + (* rewrite orb_true_iff in H; do 2 *) rewrite andb_true_iff in H. + + specialize (@rho_interp ( Lit.blit i)). rewrite H2 in rho_interp. + simpl in rho_interp. + + (* destruct H. *) + + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. + unfold Lit.interp at 3. unfold Var.interp. + rewrite Hip0. now rewrite rho_interp. + (* + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. *) + (* unfold Lit.interp at 3. unfold Var.interp. *) + (* rewrite Hip0. rewrite rho_interp. now rewrite xorb_comm. *) + + intros. rewrite H2 in H. now contradict H. + + - intros. simpl. + pose proof IHc1. pose proof IHc2. + simpl in H. + case_eq ( Lit.is_pos i). intros Hip0. + rewrite Hip0 in H. + case_eq (t_form .[ Lit.blit i]); intros; rewrite H2 in H; try now contradict H. + case_eq (PArray.length a == 2). intros Hl. rewrite Hl in H. + (* rewrite orb_true_iff in H; do 2 *) rewrite andb_true_iff in H. + + specialize (@rho_interp ( Lit.blit i)). rewrite H2 in rho_interp. + simpl in rho_interp. + rewrite afold_left_or in rho_interp. + rewrite eqb_spec in Hl. + apply to_list_two in Hl. + rewrite Hl in rho_interp. + simpl in rho_interp. + rewrite orb_false_r in rho_interp. + + (* destruct H. *) + + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. + unfold Lit.interp at 3. unfold Var.interp. + rewrite Hip0. now rewrite rho_interp. + (* + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. *) + (* unfold Lit.interp at 3. unfold Var.interp. *) + (* rewrite Hip0. rewrite rho_interp. now rewrite orb_comm. *) + + intros. rewrite H3 in H. now contradict H. + + intros. rewrite H2 in H. now contradict H. + + - intros. simpl. + pose proof IHc1. pose proof IHc2. + simpl in H. + case_eq ( Lit.is_pos i). intros Hip0. + rewrite Hip0 in H. + case_eq (t_form .[ Lit.blit i]); intros; rewrite H2 in H; try now contradict H. + (* rewrite orb_true_iff in H; do 2 *) rewrite andb_true_iff in H. + + specialize (@rho_interp ( Lit.blit i)). rewrite H2 in rho_interp. + simpl in rho_interp. + + (* destruct H. *) + + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. + unfold Lit.interp at 3. unfold Var.interp. + rewrite Hip0. now rewrite rho_interp. + (* + destruct H. apply H0 in H. apply H1 in H3. rewrite H, H3. *) + (* unfold Lit.interp at 3. unfold Var.interp. *) + (* rewrite Hip0. rewrite rho_interp. *) + (* case_eq (Bool.eqb (Lit.interp rho i0) (Lit.interp rho i1)). *) + (* intros. apply Bool.eqb_prop in H4. rewrite H4. apply Bool.eqb_reflx. *) + (* intros. apply Bool.eqb_false_iff in H4. apply Bool.eqb_false_iff. unfold not in *. intro. symmetry in H5. *) + (* apply H4; trivial. *) + + intros. rewrite H2 in H. now contradict H. +Qed. + + + +Lemma map_cons T U (f: T -> U) (h: T) (l: list T): map f (h :: l) = f h :: map f l. +Proof. auto. Qed. + +Lemma prop_check_ult: forall bs1 bs2, + length bs1 = length bs2 -> + RAWBITVECTOR_LIST.ult_list_big_endian + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2) + = interp_carry (ult_big_endian_lit_list bs1 bs2). +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1 ]. + - intros. simpl in *. + symmetry in H; rewrite empty_list_length in H. + specialize (Lit.interp_false rho wf_rho). + intros. unfold is_true in H0; now rewrite not_true_iff_false in H0. + - intros. + case_eq bs2. intros. rewrite H0 in *. now contradict H. + intros. rewrite H0 in *. + inversion H. + rewrite !map_cons. + simpl. + case xsbs1 in *. simpl. + case l in *. simpl. now rewrite Lit.interp_neg. + now contradict H2. + case l in *. simpl. + now contradict H2. + rewrite !map_cons. + unfold interp_carry. + fold interp_carry. + specialize (@IHbs1 (i1 :: l)). + rewrite !map_cons in IHbs1. + rewrite Lit.interp_neg. + now rewrite IHbs1. +Qed. + +Lemma prop_check_slt: forall bs1 bs2, + length bs1 = length bs2 -> + RAWBITVECTOR_LIST.slt_list_big_endian + (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2) + = interp_carry (slt_big_endian_lit_list bs1 bs2). +Proof. intros. + case bs1 in *. simpl. + specialize (Lit.interp_false rho wf_rho). + intros. unfold is_true in H0; now rewrite not_true_iff_false in H0. + case bs2 in *. + now contradict H. + rewrite !map_cons. + case bs1 in *. simpl. + case bs2 in *. simpl. now rewrite Lit.interp_neg. + now contradict H. + case bs2 in *. + now contradict H. + unfold slt_big_endian_lit_list. + unfold RAWBITVECTOR_LIST.slt_list_big_endian. + rewrite !map_cons. + unfold interp_carry. + fold interp_carry. + rewrite <- !map_cons. + rewrite Lit.interp_neg. + rewrite prop_check_ult. + now apply f_equal. + simpl. + now inversion H. +Qed. + +Lemma prop_check_ult2: forall bs1 bs2 bsres, +length bs1 = length bs2 -> +check_ult bs1 bs2 bsres = true -> +interp_carry (ult_big_endian_lit_list (rev bs1) (rev bs2)) = Lit.interp rho bsres. +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. + case bs2 in *. + unfold check_ult in H0. + simpl in *. + case_eq (Lit.is_pos bsres). intros Hbsres. + rewrite Hbsres in H0. + case (Lit.is_pos bsres) in H0; rewrite eqb_spec in H0; now rewrite H0. + intros. rewrite H1 in H0. now contradict H0. + + now contradict H. + + - intros. + case bs2 in *. + now contradict H. + simpl. + unfold check_ult,ult_lit_list in H0. + simpl in H0. + case_eq (Lit.is_pos bsres). intros Hbsres. + rewrite Hbsres in H0. + + now apply prop_eq_carry_lit. + + intros. rewrite H1 in H0. now contradict H0. +Qed. + +Lemma prop_check_slt2: forall bs1 bs2 bsres, +length bs1 = length bs2 -> +check_slt bs1 bs2 bsres = true -> +interp_carry (slt_big_endian_lit_list (rev bs1) (rev bs2)) = Lit.interp rho bsres. +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. + case bs2 in *. + unfold check_slt in H0. + simpl in *. + case_eq (Lit.is_pos bsres). intros Hbsres. + rewrite Hbsres in H0. + case (Lit.is_pos bsres) in H0; rewrite eqb_spec in H0; now rewrite H0. + intros. rewrite H1 in H0. now contradict H0. + + now contradict H. + + - intros. + case bs2 in *. + now contradict H. + simpl. + unfold check_slt, slt_lit_list in H0. + simpl in H0. + case_eq (Lit.is_pos bsres). intros Hbsres. + rewrite Hbsres in H0. + now apply prop_eq_carry_lit. + + intros. rewrite H1 in H0. now contradict H0. +Qed. + +Lemma prop_lit: forall bsres, +Lit.is_pos bsres = true -> +Lit.interp + (interp_state_var (fun a0 : int => interp_bool t_i (t_interp .[ a0])) + interp_form_hatom_bv t_form) bsres = +Form.interp (fun a0 : int => interp_bool t_i (t_interp .[ a0])) + interp_form_hatom_bv t_form (t_form .[ Lit.blit bsres]). +Proof. intros. + rewrite <- rho_interp. + simpl. + unfold Lit.interp, Var.interp. + rewrite H. + simpl. easy. +Qed. + +Lemma prop_lit2: forall bsres, +Lit.is_pos bsres = false -> +Lit.interp + (interp_state_var (fun a0 : int => interp_bool t_i (t_interp .[ a0])) + interp_form_hatom_bv t_form) bsres = +negb (Form.interp (fun a0 : int => interp_bool t_i (t_interp .[ a0])) + interp_form_hatom_bv t_form (t_form .[ Lit.blit bsres])). +Proof. intros. + rewrite <- rho_interp. + simpl. + unfold Lit.interp, Var.interp. + rewrite H. + simpl. easy. +Qed. + +Lemma valid_check_bbUlt pos1 pos2 lres : C.valid rho (check_bbUlt pos1 pos2 lres). +Proof. + unfold check_bbUlt. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). intros a bsres Heq8. + case_eq (Bool.eqb (Lit.is_pos a) (Lit.is_pos bsres)); try (intros; now apply C.interp_true). intros Heq12. + case_eq (t_form .[ Lit.blit a]); try (intros; now apply C.interp_true). intros a3 Heq10. + case_eq (t_atom .[ a3]); try (intros; now apply C.interp_true). + + intros [ | | | | | | | [ A B | A | | | | ]|N|N|N|N|N|N|N|N|N| | | | ]; + try (intros; now apply C.interp_true). + + intros a1' a2' Heq9. + case_eq ((a1 == a1') && (a2 == a2')); simpl; intros Heq15; try (now apply C.interp_true). + + case_eq (check_ult bs1 bs2 bsres && + (N.of_nat (Datatypes.length bs1) =? N)%N && + (N.of_nat (Datatypes.length bs2) =? N)%N); + simpl; intros Heq16; try (now apply C.interp_true). + + unfold C.valid. simpl. + + rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a3). + assert (a3 < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a3]). + intros v_typea3 v_vala3 Htia3. rewrite Htia3 in H0. + case_eq (v_typea3); intros; rewrite H4 in H0; try (now contradict H0). + rename H4 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + simpl in v_vala2, v_vala2. + + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + (** case a1 = a1' and a2 = a2' **) + rewrite andb_true_iff in Heq15. + destruct Heq15 as (Heq15a1 & Heq15a2); rewrite eqb_spec in Heq15a1, Heq15a2 + ;rewrite Heq15a1, Heq15a2 in *. + + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp1. + unfold interp_bv in HSp1. + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp2. + unfold interp_bv in HSp2. + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2 in HSp2. + unfold interp_bv in HSp2. + + generalize dependent v_vala1. generalize dependent v_vala2. + + rewrite H2, H3. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert ( + H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16a, Heq16b), Heq16c). + rewrite N.eqb_eq in Heq16c. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H100. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16a, Heq16b), Heq16c). + rewrite N.eqb_eq in Heq16b. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + + rewrite Typ.cast_refl in *. + + intros. + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + apply (@Bool.eqb_true_iff (Lit.interp rho a) (Lit.interp rho bsres)). + + unfold Lit.interp, Var.interp. + rewrite rho_interp. + rewrite Heq10. simpl. + + unfold Atom.interp_form_hatom. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1, Htia2. simpl. + + rewrite Form.wf_interp_form; trivial. + simpl. + apply Bool.eqb_prop in Heq12. + rewrite Heq12. + rewrite HSp1, HSp2. + + case_eq (Lit.is_pos bsres). + intros Hpos. + + unfold BITVECTOR_LIST.bv_ult. + unfold RAWBITVECTOR_LIST.bv_ult, RAWBITVECTOR_LIST.bits. + unfold BITVECTOR_LIST.bv, BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + simpl. + unfold RAWBITVECTOR_LIST.size. + simpl. + + rewrite !Typ.N_cast_refl. + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16 & Heq16l) & Heq16r). + rewrite N.eqb_eq in Heq16r, Heq16l. + rewrite map_length, Heq16l. + rewrite H100. + rewrite N.eqb_compare. rewrite N.compare_refl. + + unfold RAWBITVECTOR_LIST.ult_list. + specialize (@prop_check_ult (List.rev bs1) (List.rev bs2)). + intros. + + cut ( Datatypes.length (List.rev bs1) = Datatypes.length (List.rev bs2)). + intros. specialize (H6 H7). + do 2 rewrite <- List.map_rev. + rewrite H6. + + pose proof (rho_interp). + specialize (H8 (Lit.blit a)). + rewrite Heq10 in H8. + simpl in H8. + + rewrite !rev_length in H7. + specialize (@prop_check_ult2 bs1 bs2 bsres H7 Heq16). + intros. + rewrite H9. + simpl. + unfold Atom.interp_form_hatom, interp_hatom. + simpl. + now rewrite prop_lit. + + rewrite !rev_length. + apply (f_equal nat_of_N) in Heq16l. + apply (f_equal nat_of_N) in Heq16r. + rewrite Nat2N.id in Heq16l, Heq16r. + now rewrite Heq16l, Heq16r. + + intros. + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16 & Heq16l) & Heq16r). + rewrite N.eqb_eq in Heq16r, Heq16l. + + contradict Heq16. + unfold check_ult. + rewrite H6. easy. +Qed. + +Lemma valid_check_bbSlt pos1 pos2 lres : C.valid rho (check_bbSlt pos1 pos2 lres). +Proof. + unfold check_bbSlt. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). intros a bsres Heq8. + case_eq (Bool.eqb (Lit.is_pos a) (Lit.is_pos bsres)); try (intros; now apply C.interp_true). intros Heq12. + case_eq (t_form .[ Lit.blit a]); try (intros; now apply C.interp_true). intros a3 Heq10. + case_eq (t_atom .[ a3]); try (intros; now apply C.interp_true). + + intros [ | | | | | | | [ A B | A | | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; + try (intros; now apply C.interp_true). + + case_eq ((a1 == a1') && (a2 == a2')); simpl; intros Heq15; try (now apply C.interp_true). + + case_eq (check_slt bs1 bs2 bsres && + (N.of_nat (Datatypes.length bs1) =? N)%N && + (N.of_nat (Datatypes.length bs2) =? N)%N); + simpl; intros Heq16; try (now apply C.interp_true). + + unfold C.valid. simpl. + + rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a3). + assert (a3 < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a3]). + intros v_typea3 v_vala3 Htia3. rewrite Htia3 in H0. + case_eq (v_typea3); intros; rewrite H4 in H0; try (now contradict H0). + rename H4 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + simpl in v_vala2, v_vala2. + + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + (** case a1 = a1' and a2 = a2' **) + rewrite andb_true_iff in Heq15. + destruct Heq15 as (Heq15a1 & Heq15a2); rewrite eqb_spec in Heq15a1, Heq15a2 + ;rewrite Heq15a1, Heq15a2 in *. + + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp1. + unfold interp_bv in HSp1. + rewrite !Atom.t_interp_wf in Htia1; trivial. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H5 in HSp2. + unfold interp_bv in HSp2. + rewrite !Atom.t_interp_wf in Htia2; trivial. + rewrite Htia2 in HSp2. + unfold interp_bv in HSp2. + + generalize dependent v_vala1. generalize dependent v_vala2. + rewrite H2, H3. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert ( + H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N + ). + { + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16a, Heq16b), Heq16c). + rewrite N.eqb_eq in Heq16c. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H100. + + assert ( + H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N + ). + { + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16a, Heq16b), Heq16c). + rewrite N.eqb_eq in Heq16b. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + + rewrite Typ.cast_refl in *. + + intros. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + apply (@Bool.eqb_true_iff (Lit.interp rho a) (Lit.interp rho bsres)). + + unfold Lit.interp, Var.interp. + rewrite rho_interp. + rewrite Heq10. simpl. + + unfold Atom.interp_form_hatom. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Heq9. simpl. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1, Htia2. simpl. + + rewrite Form.wf_interp_form; trivial. + simpl. + apply Bool.eqb_prop in Heq12. + rewrite Heq12. + rewrite HSp1, HSp2. + + case_eq (Lit.is_pos bsres). + intros Hpos. + + unfold BITVECTOR_LIST.bv_slt. + unfold RAWBITVECTOR_LIST.bv_slt, RAWBITVECTOR_LIST.bits. + unfold BITVECTOR_LIST.bv, BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + simpl. + unfold RAWBITVECTOR_LIST.size. + simpl. + + rewrite !Typ.N_cast_refl. + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16 & Heq16l) & Heq16r). + rewrite N.eqb_eq in Heq16r, Heq16l. + rewrite map_length, Heq16l. + rewrite H100. + rewrite N.eqb_compare. rewrite N.compare_refl. + + unfold RAWBITVECTOR_LIST.slt_list. + specialize (@prop_check_slt (List.rev bs1) (List.rev bs2)). + intros. + + cut ( Datatypes.length (List.rev bs1) = Datatypes.length (List.rev bs2)). + intros. specialize (H6 H7). + do 2 rewrite <- List.map_rev. + rewrite H6. + + pose proof (rho_interp). + specialize (H8 (Lit.blit a)). + rewrite Heq10 in H8. + simpl in H8. + + rewrite !rev_length in H7. + specialize (@prop_check_slt2 bs1 bs2 bsres H7 Heq16). + intros. + rewrite H9. + simpl. + unfold Atom.interp_form_hatom, interp_hatom. + simpl. + now rewrite prop_lit. + + rewrite !rev_length. + apply (f_equal nat_of_N) in Heq16l. + apply (f_equal nat_of_N) in Heq16r. + rewrite Nat2N.id in Heq16l, Heq16r. + now rewrite Heq16l, Heq16r. + + intros. + rewrite !andb_true_iff in Heq16. + destruct Heq16 as ((Heq16 & Heq16l) & Heq16r). + rewrite N.eqb_eq in Heq16r, Heq16l. + + contradict Heq16. + unfold check_slt. + rewrite H6. easy. +Qed. + +Lemma check_add_list:forall bs1 bs2 bsres c, + let n := length bsres in + (length bs1 = n)%nat -> + (length bs2 = n)%nat -> + check_add bs1 bs2 bsres c -> + (RAWBITVECTOR_LIST.add_list_ingr (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2) + (interp_carry c)) + = + (map (Lit.interp rho) bsres). +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. simpl in H1. + case_eq bs2. intros. rewrite H2 in H1. simpl. + case_eq bsres. intros. rewrite H3 in H1. now simpl. + intros. rewrite H3 in H1. now contradict H1. + intros. rewrite H2 in H1. now contradict H1. + - intros. + case_eq bs2. intros. rewrite H2 in H1. simpl in H1. now contradict H1. + intros. rewrite H2 in H1. + case_eq bsres. intros. rewrite H3 in H1. simpl in H1. now contradict H1. + intros. rewrite H3 in H1. simpl in H1. + case_eq ( Lit.is_pos i0). intros. rewrite H4 in H1. + case_eq ( t_form .[ Lit.blit i0]); intros; rewrite H5 in H1; try now contradict H. + case_eq ( Lit.is_pos i1). intros. rewrite H6 in H1. + case_eq ( t_form .[ Lit.blit i1]); intros; rewrite H7 in H1; try now contradict H. + unfold is_true in H1. + rewrite andb_true_iff in H1. destruct H1. + unfold n in *. + rewrite H3 in H. + rewrite H2, H3 in H0. + inversion H. inversion H0. + + specialize + (@IHbs1 l l0 + ((Cor (Cand (Clit xbs1) (Clit i)) (Cand (Cxor (Clit xbs1) (Clit i)) c))) + H10 H11 H8). + + simpl in *. unfold RAWBITVECTOR_LIST.of_bits in IHbs1. + case_eq (RAWBITVECTOR_LIST.add_carry (Lit.interp rho xbs1) (Lit.interp rho i) + (interp_carry c)). intros r c0 Heqrc. + + (** rho_interp Lit.blit i0 **) + pose proof (rho_interp (Lit.blit i0)). + rewrite H5 in H9. simpl in H9. + + (** rho_interp Lit.blit i1 **) + pose proof (rho_interp (Lit.blit i1)). + rewrite H7 in H12. simpl in H12. + + unfold Lit.interp at 3. + rewrite H4. unfold Var.interp. rewrite H9. + rewrite <- IHbs1. + simpl. + cut (r = xorb (Lit.interp rho i1) (Lit.interp rho i2)). + cut (c0 = (Lit.interp rho xbs1 && Lit.interp rho i + || xorb (Lit.interp rho xbs1) (Lit.interp rho i) && interp_carry c)). + intros. now rewrite H13, H14. + + (* c *) + case ((Lit.interp rho xbs1)) in *. + case ((Lit.interp rho i)) in *. + case ((interp_carry c)) in *. + inversion Heqrc. easy. + inversion Heqrc. easy. + case ((interp_carry c)) in *. + inversion Heqrc. easy. + inversion Heqrc. easy. + case ((Lit.interp rho i)) in *. + case ((interp_carry c)) in *. + inversion Heqrc. easy. + inversion Heqrc. easy. + case ((interp_carry c)) in *. + inversion Heqrc. easy. + inversion Heqrc. easy. + + (* r *) + rewrite andb_true_iff in H1. + destruct H1. + rewrite orb_true_iff in H1. + destruct H1; rewrite andb_true_iff in H1; destruct H1. + rewrite eqb_spec in H1, H14. rewrite H1, H14 in *. + + apply prop_eq_carry_lit in H13. rewrite <- H13. + + case ((Lit.interp rho xbs1)) in *. + case ((Lit.interp rho i)) in *. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + case ((Lit.interp rho i)) in *. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + + rewrite eqb_spec in H1, H14. rewrite H1, H14 in *. + + apply prop_eq_carry_lit in H13. rewrite <- H13. + + case ((Lit.interp rho xbs1)) in *. + case ((Lit.interp rho i)) in *. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + case ((Lit.interp rho i)) in *. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + case ((interp_carry c)) in *. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + inversion Heqrc. + unfold Lit.interp, Var.interp. + rewrite H6, H12. easy. + + (** contradictions **) + intros. rewrite H6 in H1. now contradict H1. + intros. rewrite H4 in H1. now contradict H1. +Qed. + +Lemma check_add_bvadd: forall bs1 bs2 bsres n, + (N.of_nat(length bs1) = n)%N -> + (N.of_nat(length bs2) = n)%N -> + (N.of_nat(length bsres) = n)%N -> + check_add bs1 bs2 bsres (Clit Lit._false) = true -> + (RAWBITVECTOR_LIST.bv_add (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2) = + (map (Lit.interp rho) bsres)). +Proof. intros. + pose proof H as H'. pose proof H0 as H0'. pose proof H1 as H1'. + rewrite <- H1 in H. apply Nat2N.inj in H. + rewrite <- H1 in H0. apply Nat2N.inj in H0. + specialize (@check_add_list bs1 bs2 bsres ( (Clit Lit._false)) H H0 H2). intros. + unfold RAWBITVECTOR_LIST.bv_add. + unfold RAWBITVECTOR_LIST.size, RAWBITVECTOR_LIST.bits. + unfold BITVECTOR_LIST.of_bits. + rewrite !map_length, H, H0. + rewrite N.eqb_refl. + + assert ( (interp_carry (Clit Lit._false)) = false). + { + specialize (Lit.interp_false rho wf_rho). intros. + unfold is_true in H4. + rewrite not_true_iff_false in H4. + now unfold interp_carry. + } + + rewrite H4 in H3. + unfold RAWBITVECTOR_LIST.add_list. + apply H3. +Qed. + +Lemma valid_check_bbAdd pos1 pos2 lres : C.valid rho (check_bbAdd pos1 pos2 lres). +Proof. + unfold check_bbAdd. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | |[ A B | A| | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; + try (intros; now apply C.interp_true). + + (* BVadd *) + - case_eq ((a1 == a1') && (a2 == a2') || (a1 == a2') && (a2 == a1')); + simpl; intros Heq10; try (now apply C.interp_true). + case_eq ( + check_add bs1 bs2 bsres (Clit Lit._false) && + (N.of_nat (Datatypes.length bs1) =? N)%N + ); simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H4 in H0; try (now contradict H0). + rename H4 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + (** case a1 = a1' and a2 = a2' **) + rewrite orb_true_iff in Heq10. + do 2 rewrite andb_true_iff in Heq10. + destruct Heq10 as [Heq10 | Heq10]; + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2 + ;rewrite Heq10a1, Heq10a2 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H4. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + revert v_vala1 Htia1. rewrite H3. revert v_vala2 Htia2. rewrite H2. + intros v_vala2 Htia2 v_vala1 Htia1. + rewrite Htia1, Htia2. + rewrite Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_add_bvadd_length in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite N.eqb_eq in Heq11r. + rewrite Heq11a in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + rewrite H5 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + rewrite H6 in HSp2. + unfold interp_bv in HSp2. + rewrite Htia2 in HSp2. + unfold interp_bv in HSp2. + + revert HSp2. + + assert (H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_add_bvadd_length in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite Heq11a, <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H102. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp2. + + pose proof Heq11. + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11 & Heq11r). + rewrite N.eqb_eq in Heq11r. + + apply check_add_bvadd_length in Heq11. + + unfold BITVECTOR_LIST.bv_add. simpl. + apply eq_rec. + simpl. + + specialize (@check_add_bvadd bs1 bs2 bsres N). + + intros. apply H8. + exact Heq11r. + destruct Heq11 as (Heq11a & Heq11b). + rewrite <- Heq11b in Heq11a. + rewrite Heq11a in Heq11r. easy. + destruct Heq11 as (Heq11a & Heq11b). + rewrite Heq11a in Heq11r. easy. + rewrite andb_true_iff in H7. + destruct H7 as (H7 & H7r). + exact H7. + + (** symmetic case **) + + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H4. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + revert v_vala1 Htia1. rewrite H3. revert v_vala2 Htia2. rewrite H2. + intros v_vala2 Htia2 v_vala1 Htia1. + rewrite Htia1, Htia2. + rewrite Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_add_bvadd_length in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite N.eqb_eq in Heq11r. + rewrite Heq11a in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H5 in HSp2. + unfold interp_bv in HSp2. + rewrite Htia1 in HSp2. + unfold interp_bv in HSp2. + + revert HSp2. + + assert (H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + apply check_add_bvadd_length in Heq11. + destruct Heq11 as (Heq11a, Heq11b). + rewrite Heq11a, <- Heq11b in Heq11r. + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H102. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp2. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H6 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia2 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp1. + + pose proof Heq11. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11 & Heq11r). + rewrite N.eqb_eq in Heq11r. + + apply check_add_bvadd_length in Heq11. + + unfold BITVECTOR_LIST.bv_add. simpl. + apply eq_rec. + simpl. + + specialize (@RAWBITVECTOR_LIST.bv_add_comm N). + intros. rewrite H8. + + specialize (@check_add_bvadd bs1 bs2 bsres N). + + intros. apply H9. + exact Heq11r. + destruct Heq11 as (Heq11a & Heq11b). + rewrite <- Heq11b in Heq11a. + rewrite Heq11a in Heq11r. easy. + destruct Heq11 as (Heq11a & Heq11b). + rewrite Heq11a in Heq11r. easy. + + rewrite andb_true_iff in H7. + destruct H7 as (H7 & H7r). + exact H7. + + unfold RAWBITVECTOR_LIST.size. + destruct Heq11 as (Heq11a, Heq11b). + rewrite <- Heq11a in Heq11b. + rewrite <- Heq11b in Heq11r. + now rewrite map_length. + + unfold RAWBITVECTOR_LIST.size. + now rewrite map_length. +Qed. + +Lemma mk_list_false_eq: forall bs, (map (fun _ : int => Lit.interp rho Lit._false) bs) = + (RAWBITVECTOR_LIST.mk_list_false (Datatypes.length bs)). +Proof. intro bs. + induction bs as [ | xbs xsbs IHbs ]. + - now simpl. + - simpl. rewrite IHbs. specialize (@Lit.interp_false rho wf_rho). + intros. unfold is_true in H. apply not_true_is_false in H. + now rewrite H. +Qed. + +Lemma map_interp_neg: forall bs, (map (fun x : int => negb (Lit.interp rho x)) bs) = + (map (fun x : int => Lit.interp rho (Lit.neg x)) bs). +Proof. intro bs. + induction bs as [ | xbs xsbs IHbs ]. + - now simpl. + - simpl. rewrite IHbs. + now rewrite Lit.interp_neg. +Qed. + +Lemma prop_check_neg: forall bs bsres n, + (N.of_nat(length bs) = n)%N -> + (N.of_nat(length bsres) = n)%N -> + check_neg bs bsres = true -> + RAWBITVECTOR_LIST.bv_neg (map (Lit.interp rho) bs) = map (Lit.interp rho) bsres. +Proof. intros. + + unfold check_neg in H1. + specialize (@check_add_list (map (fun l : int => Lit.neg l) bs) + (map (fun _ : int => Lit._false) bs) bsres (Clit Lit._true)). + + intros. simpl in H2. + cut ( Datatypes.length (map (fun l : int => Lit.neg l) bs) = + Datatypes.length bsres ). intros. + cut (Datatypes.length (map (fun _ : int => Lit._false) bs) = + Datatypes.length bsres). intros. + specialize (H2 H3 H4 H1). + unfold BITVECTOR_LIST.bv_neg, RAWBITVECTOR_LIST.bv_neg. + unfold RAWBITVECTOR_LIST.twos_complement. + + rewrite !map_map in H2. + rewrite !map_map. + rewrite mk_list_false_eq in H2. + rewrite <- map_interp_neg in H2. + rewrite Lit.interp_true in H2. + rewrite <- H2. + now rewrite map_length. + + easy. + + rewrite map_length. + apply (f_equal (N.to_nat)) in H. + apply (f_equal (N.to_nat)) in H0. + rewrite Nat2N.id in H, H0. + now rewrite H, H0. + + rewrite map_length. + apply (f_equal (N.to_nat)) in H. + apply (f_equal (N.to_nat)) in H0. + rewrite Nat2N.id in H, H0. + now rewrite H, H0. +Qed. + +Lemma check_neg_length: forall bs bsres, + check_neg bs bsres = true -> (length bs = length bsres)%nat. +Proof. intros. + unfold check_neg in H. + specialize (@check_add_bvadd_length (map (fun l : int => Lit.neg l) bs) + (map (fun _ : int => Lit._false) bs) bsres (Clit Lit._true)). + intros. simpl in H0. + specialize (H0 H). + destruct H0. now rewrite map_length in H0. +Qed. + +Lemma valid_check_bbNeg pos lres : C.valid rho (check_bbNeg pos lres). +Proof. + unfold check_bbNeg. + case_eq (S.get s pos); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | | | | | ] a1' Heq9; try now apply C.interp_true. + + case_eq ((a1 == a1') && check_neg bs1 bsres && + (N.of_nat (Datatypes.length bs1) =? n)%N); + simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H3 in H0; try (now contradict H0). + rename H3 into Hv. + + generalize (Hs pos). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + unfold get_type' in H2. unfold v_type in H2. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. + + (** case a1 = a1' **) + do 2 rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq10, Heq11). + destruct Heq10 as (Heq10a1 & Heq10a2). + rewrite Int63Properties.eqb_spec in Heq10a1; rewrite Heq10a1 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H3. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + revert v_vala1 Htia1. rewrite H2. intros. + rewrite Htia1. + unfold apply_unop. + rewrite Typ.cast_refl. + unfold Bval. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = n). + { + apply check_neg_length in Heq10a2. + rewrite N.eqb_eq in Heq11. + rewrite Heq10a2 in Heq11. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + + rewrite Typ.cast_refl. + intros. + unfold BITVECTOR_LIST.bv_neg. + apply eq_rec. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n). + { + rewrite N.eqb_eq in Heq11. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + + rewrite Typ.cast_refl. + intros. + rewrite HSp1. simpl. + + specialize(@prop_check_neg bs1 bsres). + intros. apply H5 with n. + now rewrite N.eqb_eq in Heq11. + + pose proof Heq10a2 as Heq10a3. + apply check_neg_length in Heq10a3. + rewrite <- Heq10a3. + now rewrite N.eqb_eq in Heq11. + + easy. +Qed. + +Lemma prop_forallb2: forall {A B} {f: A -> B -> bool} l1 l2, forallb2 f l1 l2 = true -> length l1 = length l2. +Proof. intros A B f l1. + induction l1 as [ | xl1 xsl1 IHl1]. + - intros. simpl in H. + case l2 in *. easy. + now contradict H. + - intros. simpl in H. + case l2 in *. + now contradict H. + simpl. + rewrite andb_true_iff in H. destruct H. + apply IHl1 in H0. now rewrite H0. +Qed. + +Lemma prop_and_with_bit: forall a b, map interp_carry (and_with_bit a b) = + RAWBITVECTOR_LIST.and_with_bool (map (Lit.interp rho) a) (Lit.interp rho b). +Proof. intro a. + induction a as [ | xa xsa IHa ]. + - intros. now simpl in *. + - intros. simpl in *. now rewrite IHa. +Qed. + +Lemma prop_mult_step_k_h: forall a b c k, + map interp_carry (mult_step_k_h a b c k) = + RAWBITVECTOR_LIST.mult_bool_step_k_h + (map interp_carry a) (map interp_carry b) + (interp_carry c) k. +Proof. intro a. + induction a as [ | xa xsa IHa ]. + - intros. case b. + now simpl. + intros. now simpl. + - intros. case b in *. simpl. + rewrite IHa. now simpl. + intros. simpl. + case (k - 1 <? 0)%Z. + simpl. apply f_equal. + apply IHa. + rewrite <- map_cons. simpl. apply f_equal. + apply IHa. +Qed. + +Lemma prop_interp_firstn: forall xk' a, map (Lit.interp rho) (List.firstn xk' a) = (List.firstn xk' (map (Lit.interp rho) a)). +Proof. intro xk'0. + induction xk'0. + + intros. now simpl. + + intros. simpl. + case a. now simpl. + intros. simpl. apply f_equal. apply IHxk'0. +Qed. + +Lemma map_firstn: forall A B n (l: list A) (f:A -> B), firstn n (map f l) = map f (firstn n l). +Proof. + intros A B n. + induction n; intro l; induction l; try now simpl. + intros. simpl. apply f_equal. apply IHn. +Qed. + +Lemma prop_mult_step: forall a b res k k', + (map interp_carry (mult_step a b res k k')) = + RAWBITVECTOR_LIST.mult_bool_step (map (Lit.interp rho) a) (map (Lit.interp rho) b) + (map interp_carry res) k k'. +Proof. intros. revert a b res k. + assert (false = (Lit.interp rho (Lit._false))) as Ha. + { + specialize (Lit.interp_false rho wf_rho). intros. + unfold is_true in H. rewrite not_true_iff_false in H. + now rewrite H. + } + + assert (false = interp_carry (Clit Lit._false)). + { + unfold interp_carry. + specialize (Lit.interp_false rho wf_rho). intros. + unfold is_true in H. rewrite not_true_iff_false in H. + now rewrite H. + } + + assert ([] = map (interp_carry) []). { now simpl. } + + induction k' as [ | xk' xsk' IHk' ]. + - intros. + case a. simpl. rewrite H; apply prop_mult_step_k_h. + intros. simpl. rewrite H. rewrite prop_mult_step_k_h. simpl. now rewrite map_nth. + - intros. simpl. + rewrite xsk', prop_mult_step_k_h, prop_and_with_bit. + rewrite <- map_nth, <- Ha, <- H. + case a. now simpl. simpl. intros. + case l. now simpl. simpl. intros. + case xk'. now simpl. intros. now rewrite map_firstn. +Qed. + +Lemma prop_bblast_bvmult: forall a b n, + (map interp_carry (bblast_bvmult a b n)) = + RAWBITVECTOR_LIST.bvmult_bool (map (Lit.interp rho) a) + (map (Lit.interp rho) b) + n. +Proof. intros. + revert a b. + induction n. + - intros. simpl. rewrite prop_and_with_bit. + rewrite <- map_nth. + specialize (Lit.interp_false rho wf_rho). intros. + unfold is_true in H. rewrite not_true_iff_false in H. + now rewrite H. + - intros. simpl. + specialize (Lit.interp_false rho wf_rho). intros. + unfold is_true in H. rewrite not_true_iff_false in H. + case n in *. + rewrite prop_and_with_bit; rewrite <- map_nth; now rewrite H. + rewrite prop_mult_step; rewrite prop_and_with_bit; rewrite <- map_nth; now rewrite H. +Qed. + +Lemma prop_mult_step_k_h_len: forall a b c k, +length (mult_step_k_h a b c k) = length a . +Proof. intro a. + induction a as [ | xa xsa IHa ]. + - intros. simpl. easy. + - intros. + case b in *. simpl. rewrite IHa. simpl. omega. + simpl. case (k - 1 <? 0)%Z; simpl; now rewrite IHa. +Qed. + +Lemma prop_mult_step3: forall k' a b res k, + length (mult_step a b res k k') = (length res)%nat. +Proof. intro k'. + induction k'. + - intros. simpl. rewrite prop_mult_step_k_h_len. simpl. omega. + - intros. simpl. + rewrite IHk'. rewrite prop_mult_step_k_h_len. simpl; omega. +Qed. + +Lemma prop_and_with_bit2: forall bs1 b, length (and_with_bit bs1 b) = length bs1. +Proof. intros bs1. + induction bs1. + - intros. now simpl. + - intros. simpl. now rewrite IHbs1. +Qed. + +Lemma check_bvmult_length: forall bs1 bs2, + let bsres0 := bblast_bvmult bs1 bs2 (length bs1) in + length bs1 = length bs2 -> length bs1 = length bsres0. +Proof. intros. unfold bblast_bvmult in bsres0. + case_eq (length bs1). intros. unfold bsres0. + rewrite H0. + specialize (@prop_and_with_bit2 bs1 (nth 0 bs2 Lit._false)). intros. + now rewrite H1. + intros. unfold bsres0. rewrite H0. + case n in *. + simpl. rewrite prop_and_with_bit2. auto. + rewrite prop_mult_step3. rewrite prop_and_with_bit2. auto. +Qed. + +Lemma check_bvmult_length2: forall bs1 bs2 bsres, + check_mult bs1 bs2 bsres = true -> length bs1 = length bs2 . +Proof. intros bs1. + induction bs1. + - intros. case bs2 in *. + + easy. + + unfold check_mult in H. + now contradict H. + - intros. unfold check_mult in H. + case_eq (Nat_eqb (Datatypes.length (a :: bs1)) ((Datatypes.length bs2))). + intros. now apply Nat_eqb_eq in H0. + intros. rewrite H0 in H. now contradict H. +Qed. + +Lemma prop_eq_carry_lit2: forall a b, forallb2 eq_carry_lit a b = true -> + (map interp_carry a) = (map (Lit.interp rho) b). +Proof. intro a. + induction a. + - intros. simpl in H. + case b in *. now simpl. + now contradict H. + - intros. + case b in *. + now simpl. + simpl in *. rewrite andb_true_iff in H; destruct H. + apply prop_eq_carry_lit in H. + rewrite H. apply f_equal. now apply IHa. +Qed. + +Lemma prop_main: forall bs1 bs2 bsres, + check_mult bs1 bs2 bsres = true -> + map interp_carry (bblast_bvmult bs1 bs2 (Datatypes.length (map (Lit.interp rho) bs1))) = + map (Lit.interp rho) bsres. +Proof. intros. unfold check_mult in H. + case_eq (Nat_eqb (Datatypes.length bs1) (Datatypes.length bs2)). intros. + rewrite H0 in H. apply prop_eq_carry_lit2 in H. + rewrite map_length. + now rewrite H. + intros. rewrite H0 in H. now contradict H. +Qed. + +Lemma valid_check_bbMult pos1 pos2 lres : C.valid rho (check_bbMult pos1 pos2 lres). +Proof. + unfold check_bbMult. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | |[ A B | A| | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; try (intros; now apply C.interp_true). + (* BVmult *) + - case_eq ((a1 == a1') && (a2 == a2') (* || (a1 == a2') && (a2 == a1')*) ); + simpl; intros Heq10; try (now apply C.interp_true). + + case_eq ( + check_mult bs1 bs2 bsres && + (N.of_nat (Datatypes.length bs1) =? N)%N + ); simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H4 in H0; try (now contradict H0). + rename H4 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + + (** case a1 = a1' and a2 = a2' **) + rewrite andb_true_iff in Heq10. + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2; + rewrite Heq10a1, Heq10a2 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H4. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + revert v_vala1 Htia1. rewrite H3. revert v_vala2 Htia2. rewrite H2. + intros v_vala2 Htia2 v_vala1 Htia1. + rewrite Htia1, Htia2. + rewrite Typ.cast_refl. + unfold Bval. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + pose proof Heq11 as Heq11'. + apply prop_main in Heq11. + rewrite <- Heq11. rewrite !map_length. + specialize (@check_bvmult_length bs1 bs2). + intros. simpl in H5. rewrite <- H5. + now rewrite N.eqb_eq in Heq11r. + now apply check_bvmult_length2 in Heq11'. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + + rewrite Typ.cast_refl. + intros. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H5 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + rewrite H101. + + rewrite Typ.cast_refl. + intros. + + rewrite HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H6 in HSp2. + unfold interp_bv in HSp2. + rewrite Htia2 in HSp2. + unfold interp_bv in HSp2. + + revert HSp2. + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + assert (H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = N). + { + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11, Heq11r). + rewrite N.eqb_eq in Heq11r. + apply check_bvmult_length2 in Heq11. + rewrite Heq11 in Heq11r. + now rewrite map_length. + } + + generalize (BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H102. + + rewrite Typ.cast_refl. + intros. rewrite HSp2. + + pose proof Heq11. + + unfold BITVECTOR_LIST.bv_mult. + unfold RAWBITVECTOR_LIST.bv_mult. + unfold RAWBITVECTOR_LIST.size, RAWBITVECTOR_LIST.bits. + unfold BITVECTOR_LIST.of_bits. + + unfold BITVECTOR_LIST.bv. + unfold RAWBITVECTOR_LIST.of_bits. + apply eq_rec. simpl. + + rewrite andb_true_iff in Heq11. + destruct Heq11 as (Heq11 & Heq11r). + rewrite N.eqb_eq in Heq11r. + rewrite map_length, Heq11r. + + apply check_bvmult_length2 in Heq11. + rewrite Heq11 in Heq11r. + rewrite map_length, Heq11r. + rewrite N.eqb_compare, N.compare_refl. + unfold RAWBITVECTOR_LIST.mult_list. + rewrite <- prop_bblast_bvmult. + + rewrite andb_true_iff in H7. + destruct H7 as (H7 & H7r). + + rewrite map_length. + apply prop_main in H7. + rewrite map_length in H7. + rewrite <- H7. + + easy. +Qed. + + +Lemma prop_interp_carry3: forall bs2, map interp_carry (lit_to_carry bs2) = map (Lit.interp rho) bs2. +Proof. intro bs2. + induction bs2 as [ | xbs2 xsbs2 IHbs2 ]. + - now simpl. + - simpl. now rewrite IHbs2. +Qed. + +Lemma check_concat_map: forall bs1 bs2, + map (Lit.interp rho) bs1 ++ map (Lit.interp rho) bs2 = map (Lit.interp rho) (bs1 ++ bs2). +Proof. intro bs1. + induction bs1. + - intros. now simpl. + - intros. simpl. now rewrite IHbs1. +Qed. + +Lemma concat_nil: forall {A} (a: list A), a ++ [] = a. +Proof. intros A a. + case a; [ easy | intros; apply app_nil_r ]. +Qed. + + +(* for native-coq compatibility *) +Lemma concat_map : forall (A B : Set) (f : A -> B) (l0 l1 : list A), + map f (l0 ++ l1) = (map f l0) ++ (map f l1). +Proof. + induction l0 as [ | xl0 xsl0 IHl0]; intros. + - now simpl. + - simpl. now rewrite IHl0. +Qed. + +Lemma check_concat_bvconcat: forall bs1 bs2 bsres , + check_concat bs1 bs2 bsres = true -> + (RAWBITVECTOR_LIST.bv_concat (map (Lit.interp rho) bs1) (map (Lit.interp rho) bs2) = + (map (Lit.interp rho) bsres)). +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1 ]. + - intros. simpl. + unfold check_concat in H. simpl in H. + case_eq (forallb2 eq_carry_lit (lit_to_carry bs2) bsres); intros. + rewrite concat_nil in H. + apply prop_eq_carry_lit2 in H0. + unfold RAWBITVECTOR_LIST.bv_concat. + rewrite concat_nil. + now rewrite prop_interp_carry3 in H0. + unfold RAWBITVECTOR_LIST.bv_concat. + rewrite concat_nil. + rewrite concat_nil in H. + rewrite H0 in H. now contradict H. + - intros. unfold check_concat in H. + case_eq (forallb2 eq_carry_lit (lit_to_carry (bs2 ++ xbs1 :: xsbs1)) bsres); intros. + apply prop_eq_carry_lit2 in H0. + rewrite prop_interp_carry3 in H0. + simpl in H0. simpl. + unfold RAWBITVECTOR_LIST.bv_concat. + specialize (concat_map (Lit.interp rho)). intros. + rewrite <- H0. simpl. + rewrite <- !check_concat_map. + apply f_equal. + now simpl. + rewrite H0 in H; now contradict H. +Qed. + +Lemma app_length : forall (l1 l2: list bool), (length (l1 ++ l2))%nat = ((length l1) + (length l2))%nat. +Proof. + induction l1; simpl; auto. +Qed. + +Lemma concat_len: forall (bs1 bs2 bsres: list bool), bs1 ++ bs2 = bsres -> + ((length bs1) + (length bs2))%nat = (length bsres)%nat. +Proof. intro bs1. + induction bs1. + - intros. simpl. simpl in H. now rewrite H. + - intros. simpl. simpl in H. rewrite <- H. simpl. + now rewrite app_length. +Qed. + +Lemma valid_check_bbConcat pos1 pos2 lres : C.valid rho (check_bbConcat pos1 pos2 lres). +Proof. + unfold check_bbConcat. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 bs2 Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | |[ A B | A| | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; try (intros; now apply C.interp_true). + (* BVconcat *) + - case_eq ((a1 == a1') && (a2 == a2')); simpl; intros Heq10; try (now apply C.interp_true). + case_eq ( + check_concat bs1 bs2 bsres && (N.of_nat (Datatypes.length bs1) =? N)%N && + (N.of_nat (Datatypes.length bs2) =? n)%N + ); simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H4 in H0; try (now contradict H0). + rename H4 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp2. + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + (** case a1 = a1' and a2 = a2' **) + rewrite andb_true_iff in Heq10. + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2; + rewrite Heq10a1, Heq10a2 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H4. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + + revert v_vala1 Htia1. rewrite H3. revert v_vala2 Htia2. rewrite H2. + intros v_vala2 Htia2 v_vala1 Htia1. + rewrite Htia1, Htia2. + rewrite !Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = (N + n)%N). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as ((Heq11, Heq11l) & Heq11r). + apply check_concat_bvconcat in Heq11. + unfold RAWBITVECTOR_LIST.bv_concat in Heq11. + apply concat_len in Heq11. + apply N.eqb_eq in Heq11l. + apply N.eqb_eq in Heq11r. + rewrite !map_length in Heq11. + rewrite <- Heq11l, <- Heq11r. + rewrite map_length. lia. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H5 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = N). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as ((Heq11, Heq11l) & Heq11r). + apply check_concat_bvconcat in Heq11. + apply N.eqb_eq in Heq11l. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp1. + + (* interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2'])) *) + assert (interp_form_hatom_bv a2' = + interp_bv t_i (interp_atom (t_atom .[a2']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia2. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia2. easy. + } + + rewrite H6 in HSp2. + unfold interp_bv in HSp2. + rewrite Htia2 in HSp2. + unfold interp_bv in HSp2. + + revert HSp2. + + assert (H102: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs2))) = n). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as ((Heq11, Heq11l) & Heq11r). + apply check_concat_bvconcat in Heq11. + apply N.eqb_eq in Heq11r. + now rewrite map_length. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs2)). + + rewrite H102. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp2. simpl. + unfold BITVECTOR_LIST.bv_concat. + apply eq_rec. simpl. + apply check_concat_bvconcat. + + rewrite !andb_true_iff in Heq11. + now destruct Heq11 as ((Heq11, Heq11l) & Heq11r). +Qed. + +Lemma extract_interp_zero: forall a n, RAWBITVECTOR_LIST.extract (map (Lit.interp rho) a) 0 n = +map (Lit.interp rho) (extract_lit a 0 n). +Proof. intro a. + induction a as [ | xa xsa IHa]. + - intros. now simpl. + - intros. simpl. + case_eq n. + now simpl. + intros. simpl. apply f_equal. + now rewrite IHa. +Qed. + +Lemma extract_interp_all: forall a m n, RAWBITVECTOR_LIST.extract (map (Lit.interp rho) a) m n = +map (Lit.interp rho) (extract_lit a m n). +Proof. intro a. + induction a as [ | xa xsa IHa]. + - intros. now simpl. + - intros. case_eq m. + intros. apply extract_interp_zero. + intros. simpl. + case_eq n. + now simpl. + intros. simpl. + now rewrite IHa. +Qed. + +Lemma extract_interp_main: forall bs1 bsres (i n0: N), + check_extract bs1 bsres i (n0 + i) = true -> + @RAWBITVECTOR_LIST.bv_extr i n0 (N.of_nat (length bs1)) + (map (Lit.interp rho) bs1) = map (Lit.interp rho) bsres. +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. simpl. + unfold check_extract in H. simpl in H. + unfold RAWBITVECTOR_LIST.bv_extr. + case_eq (nat_of_N i). + intros. simpl. + case_eq (nat_of_N n0). + intros. simpl. + case_eq ((0 <? n0 + i)%N); intros. + rewrite H2 in H. now contradict H. + rewrite H2 in H. + case_eq bsres. intros. now simpl. + intros. rewrite H3 in H. now contradict H. + intros. + case_eq bsres. intros. + apply (f_equal (N.of_nat)) in H1. + apply (f_equal (N.of_nat)) in H0. + rewrite N2Nat.id in H1, H0. rewrite H1, H0 in H. + simpl in H. now contradict H0. + intros. rewrite H2 in H. + case ((0 <? n0 + i)%N) in H; now contradict H. + intros. + case_eq (N.to_nat n0). + intros. + apply (f_equal (N.of_nat)) in H1. + apply (f_equal (N.of_nat)) in H0. + rewrite N2Nat.id in H1, H0. rewrite H1, H0 in H. + simpl in H. now contradict H0. + intros. + apply (f_equal (N.of_nat)) in H1. + apply (f_equal (N.of_nat)) in H0. + rewrite N2Nat.id in H1, H0. rewrite H1, H0 in H. + simpl in H. now contradict H0. + - intros. unfold check_extract in H. + case_eq ((N.of_nat (Datatypes.length (xbs1 :: xsbs1)) <? n0 + i)%N). + intros. rewrite H0 in H. now contradict H. + intros. rewrite H0 in H. + case_eq ( + forallb2 eq_carry_lit + (lit_to_carry + (extract_lit (xbs1 :: xsbs1) + (N.to_nat i) (N.to_nat (n0 + i)))) bsres); intros. + apply prop_eq_carry_lit2 in H1. + rewrite prop_interp_carry3 in H1. + simpl in H1. simpl. + + unfold RAWBITVECTOR_LIST.bv_extr in *. + simpl in *. + case_eq (N.to_nat i); intros; rewrite H2 in H1. + case_eq (N.to_nat (n0 + i)); intros; rewrite H3 in H1. + rewrite <- H1. rewrite H0. easy. + rewrite H0. + + simpl in H1. + rewrite <- H1. simpl. apply f_equal. + + now rewrite extract_interp_zero. + + case_eq (N.to_nat (n0 + i)); intros; rewrite H3 in H1. + rewrite H0. + rewrite <- H1. easy. + + rewrite H0. + now rewrite extract_interp_all. + + rewrite H1 in H. now contradict H. +Qed. + + Lemma Npos_dist: forall p p0: positive, (Npos (p + p0))%N = (Npos p + Npos p0)%N. + Proof. intros. case p in *; case p0 in *; easy. Qed. + + Lemma not_ltb2: forall (n0 n1 i: N), (n1 >= n0 + i)%N -> (n1 <? n0 + i)%N = false. + Proof. intro n0. + induction n0. + intros. simpl in *. + now apply N.ltb_nlt in H. + + intros. simpl. + case_eq i. + intros. subst. simpl in H. + now apply N.ltb_nlt in H. + intros. subst. + apply N.ltb_nlt in H. + now rewrite Npos_dist. + Qed. + +Lemma valid_check_bbExtract pos lres : C.valid rho (check_bbExtract pos lres). +Proof. + unfold check_bbExtract. + case_eq (S.get s pos); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq2; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq3; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq4. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq5. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | | | | | ] a1' Heq6; try (intros; now apply C.interp_true). + (* BVextract *) + - case_eq ((a1 == a1')); simpl; intros Heq7; try (now apply C.interp_true). + case_eq ( + check_extract bs1 bsres i (n0 + i) && + (N.of_nat (Datatypes.length bs1) =? n1)%N && (n0 + i <=? n1)%N + ); simpl; intros Heq8; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq3. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq5. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq6. easy. } + specialize (@H0 H1). rewrite Heq6 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H3 in H0; try (now contradict H2). + rename H0 into Hv. + + generalize (Hs pos). intros HSp. unfold C.valid in HSp. rewrite Heq1 in HSp. + unfold C.interp in HSp. unfold existsb in HSp. rewrite orb_false_r in HSp. + unfold Lit.interp in HSp. rewrite Heq2 in HSp. unfold Var.interp in HSp. + rewrite rho_interp in HSp. rewrite Heq4 in HSp. simpl in HSp. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp. + + unfold get_type' in H2. unfold v_type in H2. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. + + (** case a1 = a1' **) + rewrite eqb_spec in Heq7; rewrite Heq7 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H0. rewrite Heq6. simpl. + unfold interp_bv. unfold apply_unop. + + rewrite !Atom.t_interp_wf; trivial. + + revert v_vala1 Htia1. rewrite H2. + intros v_vala1 Htia1. + rewrite Htia1. + rewrite !Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = n0%N). + { + rewrite !andb_true_iff in Heq8. + destruct Heq8 as ((Heq8a, Heq8b), Heq8c). + rewrite map_length. + specialize (@extract_interp_main bs1 bsres i n0 Heq8a). + intros. + unfold RAWBITVECTOR_LIST.bv_extr in H4. + assert (length (RAWBITVECTOR_LIST.extract (map (Lit.interp rho) bs1) (N.to_nat i) + (N.to_nat (n0 + i))) = length (map (Lit.interp rho) bsres)). + rewrite N.eqb_eq in Heq8b. + rewrite Heq8b in H4. + case_eq ((n1 <? n0 + i)%N); intros. + apply N.leb_le in Heq8c. + assert ((n0 + i <= n1)%N -> (n1 >= n0 + i)%N). + { lia. } apply H6 in Heq8c. + apply not_ltb2 in Heq8c. + rewrite Heq8c in H5. now contradict H5. + rewrite H5 in H4. + now rewrite H4. + rewrite RAWBITVECTOR_LIST.length_extract, !map_length in H5. + assert ((n0 + i - i)%N = n0). + { lia. } rewrite H6 in H5. + now rewrite <- H5, N2Nat.id. + + rewrite map_length. + rewrite N.eqb_eq in Heq8b. + rewrite Heq8b. unfold is_true. + apply N.leb_le in Heq8c. + assert ((n0 + i <= n1)%N -> (n1 >= n0 + i)%N). + { lia. } now apply H6 in Heq8c. + lia. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp. + unfold interp_bv in HSp. + rewrite Htia1 in HSp. + unfold interp_bv in HSp. + + revert HSp. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n1). + { rewrite !andb_true_iff in Heq8. + destruct Heq8 as ((Heq8a, Heq8b), Heq8c). + rewrite map_length. + now rewrite N.eqb_eq in Heq8b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp. simpl. + unfold BITVECTOR_LIST.bv_extr. + apply eq_rec. simpl. + rewrite !andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + specialize (@extract_interp_main bs1 bsres i n0). + intros. + rewrite map_length in H101. + rewrite H101 in H5. now apply H5. +Qed. + +Lemma zextend_interp_zero: forall a, RAWBITVECTOR_LIST.zextend (map (Lit.interp rho) a) O = +(map (Lit.interp rho) (zextend_lit a 0)). +Proof. now simpl. Qed. + +Lemma zextend_interp_empty: forall i, RAWBITVECTOR_LIST.zextend (map (Lit.interp rho) []) i = +map (Lit.interp rho) (zextend_lit [] i). +Proof. simpl. intro i. + induction i. + - intros. now simpl. + - intros. simpl. + unfold RAWBITVECTOR_LIST.zextend in *. + simpl. rewrite IHi. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. } + now rewrite H. + Qed. + +Lemma zextend_interp_all: forall a i, RAWBITVECTOR_LIST.zextend (map (Lit.interp rho) a) i = +map (Lit.interp rho) (zextend_lit a i). +Proof. intro a. + induction a as [ | xa xsa IHa]. + - intros. simpl. + induction i. + + intros. now simpl. + + intros. unfold RAWBITVECTOR_LIST.zextend in *. + simpl. rewrite IHi. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. } + now rewrite H. + - intros. + induction i. + + now simpl. + + unfold RAWBITVECTOR_LIST.zextend, zextend_lit in *. + simpl in *. rewrite <- IHi. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. } + now rewrite H. +Qed. + +Lemma zextend_interp_main: forall bs1 bsres (n i: N), + check_zextend bs1 bsres i = true -> + @RAWBITVECTOR_LIST.bv_zextn n i + (map (Lit.interp rho) bs1) = map (Lit.interp rho) bsres. +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. simpl. + unfold check_zextend in H. simpl in H. + case_eq (forallb2 eq_carry_lit + (lit_to_carry (zextend_lit [] (N.to_nat i))) bsres). + intros. + apply prop_eq_carry_lit2 in H0. + rewrite prop_interp_carry3 in H0. + simpl in H0. + unfold RAWBITVECTOR_LIST.bv_zextn. + now rewrite zextend_interp_empty. + intros. rewrite H0 in H. now contradict H0. + - intros. unfold RAWBITVECTOR_LIST.bv_zextn, check_zextend in H. + case_eq ( + forallb2 eq_carry_lit + (lit_to_carry + (zextend_lit (xbs1 :: xsbs1) (N.to_nat i))) + bsres); intros. + apply prop_eq_carry_lit2 in H0. + rewrite prop_interp_carry3 in H0. + simpl in H0. simpl. + + unfold RAWBITVECTOR_LIST.bv_zextn in *. + case_eq (N.to_nat i). intros. rewrite H1 in H0. + now simpl in *. + intros. rewrite H1 in H0. + rewrite <- H0. + rewrite <- zextend_interp_all. + simpl. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H2. } + reflexivity. + + rewrite H0 in H. now contradict H. +Qed. + +Lemma valid_check_bbZextend pos lres : C.valid rho (check_bbZextend pos lres). +Proof. + unfold check_bbZextend. + case_eq (S.get s pos); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq2; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq3; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq4. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq5. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | | | | | ] a1' Heq6; try (intros; now apply C.interp_true). + (* BVzextend *) + - case_eq ((a1 == a1')); simpl; intros Heq7; try (now apply C.interp_true). + case_eq ( + check_zextend bs1 bsres i && (N.of_nat (Datatypes.length bs1) =? n)%N + ); simpl; intros Heq8; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq3. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq5. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq6. easy. } + specialize (@H0 H1). rewrite Heq6 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H3 in H0; try (now contradict H0). + rename H0 into Hv. + + generalize (Hs pos). intros HSp. unfold C.valid in HSp. rewrite Heq1 in HSp. + unfold C.interp in HSp. unfold existsb in HSp. rewrite orb_false_r in HSp. + unfold Lit.interp in HSp. rewrite Heq2 in HSp. unfold Var.interp in HSp. + rewrite rho_interp in HSp. rewrite Heq4 in HSp. simpl in HSp. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp. + + unfold get_type' in H2. unfold v_type in H2. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. + + (** case a1 = a1' **) + rewrite eqb_spec in Heq7; rewrite Heq7 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H0. rewrite Heq6. simpl. + unfold interp_bv. unfold apply_unop. + + rewrite !Atom.t_interp_wf; trivial. + + revert v_vala1 Htia1. rewrite H2. + intros v_vala1 Htia1. + rewrite Htia1. + rewrite !Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = (i + n)%N). + { + rewrite andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + rewrite map_length. + specialize (@zextend_interp_main bs1 bsres n i). + intros. + apply H4 in Heq8a. + unfold RAWBITVECTOR_LIST.bv_zextn in Heq8a. + assert (length (RAWBITVECTOR_LIST.zextend (map (Lit.interp rho) bs1) (N.to_nat i)) + = length (map (Lit.interp rho) bsres)). + { now rewrite Heq8a. } + rewrite RAWBITVECTOR_LIST.length_zextend, !map_length in H5. + apply (f_equal (N.of_nat)) in H5. + rewrite <- H5. + + rewrite N.eqb_eq in Heq8b. + apply (f_equal (N.to_nat)) in Heq8b. + rewrite Nat2N.id in Heq8b. + rewrite Heq8b. lia. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp. + unfold interp_bv in HSp. + rewrite Htia1 in HSp. + unfold interp_bv in HSp. + + revert HSp. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n). + { + rewrite andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + rewrite map_length. + now rewrite N.eqb_eq in Heq8b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp. simpl. + unfold BITVECTOR_LIST.bv_zextn. + apply eq_rec. simpl. + rewrite andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + now apply zextend_interp_main. +Qed. + +Lemma sextend_interp_zero: forall a, RAWBITVECTOR_LIST.sextend (map (Lit.interp rho) a) O = +(map (Lit.interp rho) (sextend_lit a 0)). +Proof. intros. + unfold RAWBITVECTOR_LIST.sextend. + case_eq a; intros; now simpl. +Qed. + +Lemma sextend_interp_empty: forall i, RAWBITVECTOR_LIST.sextend (map (Lit.interp rho) []) i = +map (Lit.interp rho) (sextend_lit [] i). +Proof. simpl. intro i. + induction i. + - intros. now simpl. + - intros. simpl. + unfold RAWBITVECTOR_LIST.sextend in *. + simpl. rewrite IHi. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. } + now rewrite H. + Qed. + +Lemma sextend_interp_all: forall a i, RAWBITVECTOR_LIST.sextend (map (Lit.interp rho) a) i = +map (Lit.interp rho) (sextend_lit a i). +Proof. intro a. + induction a as [ | xa xsa IHa]. + - intros. simpl. + induction i. + + intros. now simpl. + + intros. unfold RAWBITVECTOR_LIST.sextend in *. + simpl. rewrite IHi. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. } + now rewrite H. + - intros. + induction i. + + now simpl. + + unfold RAWBITVECTOR_LIST.sextend, zextend_lit in *. + simpl in *. rewrite <- IHi. + assert (Lit.interp rho Lit._false = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H. } + reflexivity. +Qed. + +Lemma sextend_interp_main: forall bs1 bsres (n i: N), + check_sextend bs1 bsres i = true -> + @RAWBITVECTOR_LIST.bv_sextn n i + (map (Lit.interp rho) bs1) = map (Lit.interp rho) bsres. +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1]. + - intros. simpl. + unfold check_zextend in H. simpl in H. + case_eq (forallb2 eq_carry_lit + (lit_to_carry (sextend_lit [] (N.to_nat i))) bsres). + intros. + apply prop_eq_carry_lit2 in H0. + rewrite prop_interp_carry3 in H0. + simpl in H0. + unfold RAWBITVECTOR_LIST.bv_sextn. + now rewrite sextend_interp_empty. + intros. + unfold check_sextend in H. + rewrite H0 in H. now contradict H0. + - intros. unfold RAWBITVECTOR_LIST.bv_sextn, check_sextend in H. + case_eq ( + forallb2 eq_carry_lit + (lit_to_carry + (sextend_lit (xbs1 :: xsbs1) (N.to_nat i))) + bsres); intros. + apply prop_eq_carry_lit2 in H0. + rewrite prop_interp_carry3 in H0. + simpl in H0. + + unfold RAWBITVECTOR_LIST.bv_sextn in *. + case_eq (N.to_nat i). intros. rewrite H1 in H0. + now simpl in *. + intros. rewrite H1 in H0. + rewrite <- H0. + + rewrite sextend_interp_all. + now simpl. + + rewrite H0 in H. now contradict H. +Qed. + +Lemma valid_check_bbSextend pos lres : C.valid rho (check_bbSextend pos lres). +Proof. + unfold check_bbSextend. + case_eq (S.get s pos); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq2; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq3; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq4. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq5. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | | | | | ] a1' Heq6; try (intros; now apply C.interp_true). + (* BVsextend *) + - case_eq ((a1 == a1')); simpl; intros Heq7; try (now apply C.interp_true). + case_eq ( + check_sextend bs1 bsres i && (N.of_nat (Datatypes.length bs1) =? n)%N + ); simpl; intros Heq8; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq3. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq5. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq6. easy. } + specialize (@H0 H1). rewrite Heq6 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H3 in H0; try (now contradict H0). + rename H0 into Hv. + + generalize (Hs pos). intros HSp. unfold C.valid in HSp. rewrite Heq1 in HSp. + unfold C.interp in HSp. unfold existsb in HSp. rewrite orb_false_r in HSp. + unfold Lit.interp in HSp. rewrite Heq2 in HSp. unfold Var.interp in HSp. + rewrite rho_interp in HSp. rewrite Heq4 in HSp. simpl in HSp. + + apply BITVECTOR_LIST.bv_eq_reflect in HSp. + + unfold get_type' in H2. unfold v_type in H2. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. + + (** case a1 = a1' **) + rewrite eqb_spec in Heq7; rewrite Heq7 in *. + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H0. rewrite Heq6. simpl. + unfold interp_bv. unfold apply_unop. + + rewrite !Atom.t_interp_wf; trivial. + + revert v_vala1 Htia1. rewrite H2. + intros v_vala1 Htia1. + rewrite Htia1. + rewrite !Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = (i + n)%N). + { + rewrite andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + rewrite map_length. + specialize (@sextend_interp_main bs1 bsres n i). + intros. + apply H4 in Heq8a. + unfold RAWBITVECTOR_LIST.bv_sextn in Heq8a. + assert (length (RAWBITVECTOR_LIST.sextend (map (Lit.interp rho) bs1) (N.to_nat i)) + = length (map (Lit.interp rho) bsres)). + { now rewrite Heq8a. } + rewrite RAWBITVECTOR_LIST.length_sextend, !map_length in H5. + apply (f_equal (N.of_nat)) in H5. + rewrite <- H5. + + rewrite N.eqb_eq in Heq8b. + apply (f_equal (N.to_nat)) in Heq8b. + rewrite Nat2N.id in Heq8b. + rewrite Heq8b. lia. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H4 in HSp. + unfold interp_bv in HSp. + rewrite Htia1 in HSp. + unfold interp_bv in HSp. + + revert HSp. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n). + { + rewrite andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + rewrite map_length. + now rewrite N.eqb_eq in Heq8b. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp. simpl. + unfold BITVECTOR_LIST.bv_sextn. + apply eq_rec. simpl. + rewrite andb_true_iff in Heq8. + destruct Heq8 as (Heq8a, Heq8b). + now apply sextend_interp_main. +Qed. + + +Lemma nshl_lit_empty: forall b, nshl_lit_be [] b = []. +Proof. intro b. + induction b; intros; now simpl. +Qed. + +Lemma shl_lit_empty: forall b, shl_lit_be [] b = []. +Proof. intro b. unfold shl_lit_be. now rewrite nshl_lit_empty. Qed. + +Lemma rawbv_nshl_empty: forall b, RAWBITVECTOR_LIST.nshl_be [] b = []. +Proof. intro b. + induction b; intros; now simpl. +Qed. + +Lemma bv_shl_empty: forall b, RAWBITVECTOR_LIST.bv_shl [] b = []. +Proof. intro b. unfold RAWBITVECTOR_LIST.bv_shl. + case_eq b; simpl; intros. + unfold RAWBITVECTOR_LIST.shl_be. now rewrite rawbv_nshl_empty. + unfold RAWBITVECTOR_LIST.size. simpl. + unfold RAWBITVECTOR_LIST.zeros. now simpl. + Qed. + +Lemma helper: forall {A} (l0: list A) i0, S (S (length match l0 with + | [] => [] + | _ :: _ => i0 :: removelast l0 + end)) = S (S (length l0)). +Proof. intros A l0. + induction l0; intros. + - now simpl. + - simpl. now rewrite IHl0. +Qed. + +Lemma length_shl_lit_be: forall a, length (_shl_lit_be a) = length a. +Proof. intro a. + induction a; intros. + - now simpl. + - unfold _shl_lit_be. simpl. + case_eq a0; intros. + + easy. + + apply f_equal. + case_eq l; intros. + now simpl. + simpl. now rewrite helper. +Qed. + +Lemma length_nshl_lit_be: forall n a, length (nshl_lit_be a n) = length a. +Proof. intros n. + induction n; intros. + - now simpl. + - simpl. rewrite (IHn (_shl_lit_be a)). + simpl. unfold nshl_lit_be. now rewrite length_shl_lit_be. +Qed. + +Lemma length_shl_be: forall a b, length a = length (shl_lit_be a b). +Proof. intros. unfold shl_lit_be. now rewrite length_nshl_lit_be. Qed. + +Lemma length_check_shsl: forall bs1 bs2 bsres , + check_shl bs1 bs2 bsres = true -> length bs1 = length bs2 -> length bs1 = length bsres. +Proof. intro bs1. + induction bs1; intros. + - case_eq bs2; simpl; intros. + + subst. unfold check_shl in H. simpl in H. + case_eq bsres; simpl; intros; subst; easy. + + rewrite H1 in H. unfold check_shl in H. simpl in H. + now contradict H. + - simpl in *. + unfold check_shl in H. simpl in H. + case_eq bs2; simpl; intros; subst. simpl in H. now contradict H. + simpl in *. inversion H0. rewrite H2, Structures.nat_eqb_refl in H. + case_eq (forallb2 eq_carry_lit (lit_to_carry (shl_lit_be (a :: bs1) (b :: l))) bsres); intros. + + apply prop_eq_carry_lit2 in H1. + rewrite prop_interp_carry3 in H1. + simpl in H1. + assert (length (map (Lit.interp rho) (shl_lit_be (a :: bs1) (b :: l))) = + length (map (Lit.interp rho) bsres)). + { now rewrite H1. } + rewrite !map_length in H3. + rewrite <- (length_shl_be (a :: bs1) (b :: l)) in H3. + now simpl in *. + + rewrite H1 in H; now contradict H. +Qed. + +Lemma map_lst: forall l i, match map (Lit.interp rho) l with +| [] => [] +| _ :: _ => Lit.interp rho i :: removelast (map (Lit.interp rho) l) +end = map (Lit.interp rho) match l with + | [] => [] + | _ :: _ => i :: removelast l + end. +Proof. intro l. + induction l; intros. now simpl. + simpl. apply f_equal. now rewrite IHl. +Qed. + +Lemma prop_shl_be: forall a, RAWBITVECTOR_LIST._shl_be (map (Lit.interp rho) a) = + (map (Lit.interp rho) (_shl_lit_be a)). +Proof. intro a. + case_eq a; intros. + - now simpl. + - unfold RAWBITVECTOR_LIST._shl_be, _shl_lit_be. simpl. + assert (Lit.interp rho (Lit._false) = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H0. + } + rewrite H0. apply f_equal. + now rewrite map_lst. +Qed. + +Lemma nshl_interp: forall n bs1, +RAWBITVECTOR_LIST.nshl_be (map (Lit.interp rho) bs1) n = +map (Lit.interp rho) (nshl_lit_be bs1 n). +Proof. intro n. + induction n; intros. + - now simpl. + - simpl. specialize (@IHn (_shl_lit_be bs1)). + rewrite <- IHn. simpl. + now rewrite prop_shl_be. +Qed. + +Lemma shl_interp: forall bs1 bs2, +RAWBITVECTOR_LIST.shl_be (map (Lit.interp rho) bs1) bs2 = +map (Lit.interp rho) (shl_lit_be bs1 bs2). +Proof. intros. + unfold RAWBITVECTOR_LIST.shl_be, shl_lit_be. + now rewrite nshl_interp. +Qed. + + +Lemma check_shl_bvshl: forall bs1 bs2 bsres , + check_shl bs1 bs2 bsres = true -> + (RAWBITVECTOR_LIST.bv_shl (map (Lit.interp rho) bs1) bs2 = + (map (Lit.interp rho) bsres)). +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1 ]. + - intros. simpl. + unfold check_shl, shl_lit_be in H. + case_eq (Structures.nat_eqb (@length int []) (length bs2)); intros. + rewrite Structures.nat_eqb_eq in H0. + rewrite <- H0 in H. simpl in H. + rewrite nshl_lit_empty in H. + case_eq bsres; intros. simpl. + now rewrite bv_shl_empty. + subst; now contradict H. + rewrite H0 in H; now contradict H. + - intros. unfold check_shl in H. + case_eq (Structures.nat_eqb (Datatypes.length (xbs1 :: xsbs1)) (Datatypes.length bs2)); intros. + rewrite H0 in H. + case_eq ( + forallb2 eq_carry_lit (lit_to_carry (shl_lit_be (xbs1 :: xsbs1) bs2)) bsres); intros. + apply prop_eq_carry_lit2 in H1. + rewrite prop_interp_carry3 in H1. + + unfold RAWBITVECTOR_LIST.bv_shl. + rewrite Structures.nat_eqb_eq in H0. + unfold RAWBITVECTOR_LIST.size. + rewrite !map_length. rewrite H0, N.eqb_refl. + now rewrite <- H1, shl_interp. + + rewrite H1 in H; now contradict H. + rewrite H0 in H; now contradict H. +Qed. + +Lemma valid_check_bbShl pos1 pos2 lres : C.valid rho (check_bbShl pos1 pos2 lres). +Proof. + unfold check_bbShl. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 (*bs2*) Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | |[ A B | A| | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; try (intros; now apply C.interp_true). + case_eq (t_atom .[ a2]); try (intros; now apply C.interp_true). intros c Heqa2. + case_eq c; try (intros; now apply C.interp_true). intros bv2 n0 Heqc. + (* BVshl *) + case_eq ((a1 == a1') && (a2 == a2')); simpl; intros Heq10; try (now apply C.interp_true). + case_eq ( + check_shl bs1 bv2 bsres && (N.of_nat (Datatypes.length bs1) =? n)%N && + (N.of_nat (Datatypes.length bv2) =? n)%N && (n0 =? n)%N + ); simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + pose proof (H a2). + assert (a2 < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heqa2, Heqc. easy. } + specialize (@H4 H5). rewrite Heqa2 in H4. simpl in H4. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H6 in H0; try (now contradict H0). + rename H6 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + (*apply BITVECTOR_LIST.bv_eq_reflect in HSp2.*) + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (** case a1 = a1' and a2 = a2' **) + rewrite andb_true_iff in Heq10. + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2; + rewrite Heq10a1, Heq10a2 in *. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H6. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + + revert v_vala1 Htia1. rewrite H3. revert v_vala2 Htia2. rewrite H2. + intros v_vala2 Htia2 v_vala1 Htia1. + rewrite Htia1, Htia2. + rewrite !Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = n%N). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as (((Heq11, Heq11l) & Heq11r), Heq11d). + apply length_check_shsl in Heq11. + rewrite map_length, <- Heq11. + now apply N.eqb_eq in Heq11l. + apply N.eqb_eq in Heq11r. + apply N.eqb_eq in Heq11l. + apply (f_equal (N.to_nat)) in Heq11l. + apply (f_equal (N.to_nat)) in Heq11r. + rewrite Nat2N.id in Heq11l, Heq11r. + now rewrite Heq11l, Heq11r. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H7 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as (((Heq11, Heq11l) & Heq11r), Heq11d). + rewrite map_length. + now apply N.eqb_eq in Heq11l. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp1. + + rewrite Heqa2 in Htia2. simpl in Htia2. + unfold interp_cop in Htia2. rewrite Heqc in Htia2. unfold Bval in Htia2. + rewrite !andb_true_iff in Heq11. + destruct Heq11 as (((Heq1a, Heq11b), Heq11c), Heq11d). + apply N.eqb_eq in Heq11d. + rewrite Heq11d in *. + specialize (Bval_inj2 _ (Typ.TBV n) (BITVECTOR_LIST._of_bits bv2 n) v_vala2); intros. + apply H8 in Htia2. rewrite <- Htia2. + + unfold BITVECTOR_LIST.bv_shl. + apply eq_rec. simpl. + apply check_shl_bvshl. + + now unfold RAWBITVECTOR_LIST._of_bits; rewrite Heq11c. +Qed. + + +Lemma nshr_lit_empty: forall b, nshr_lit_be [] b = []. +Proof. intro b. + induction b; intros; now simpl. +Qed. + +Lemma shr_lit_empty: forall b, shr_lit_be [] b = []. +Proof. intro b. unfold shr_lit_be. now rewrite nshr_lit_empty. Qed. + +Lemma rawbv_nshr_empty: forall b, RAWBITVECTOR_LIST.nshr_be [] b = []. +Proof. intro b. + induction b; intros; now simpl. +Qed. + +Lemma bv_shr_empty: forall b, RAWBITVECTOR_LIST.bv_shr [] b = []. +Proof. intro b. unfold RAWBITVECTOR_LIST.bv_shr. + case_eq b; simpl; intros. + unfold RAWBITVECTOR_LIST.shr_be. now rewrite rawbv_nshr_empty. + unfold RAWBITVECTOR_LIST.size. simpl. + unfold RAWBITVECTOR_LIST.zeros. now simpl. + Qed. + +Lemma helper2: forall {A} (l: list A) a, Datatypes.length (l ++ [a]) = S (Datatypes.length l). +Proof. intros A l. + induction l; intros. + - now simpl. + - simpl. now rewrite IHl. +Qed. + +Lemma length_shr_lit_be: forall a, length (_shr_lit_be a) = length a. +Proof. intro a. + induction a; intros. + - now simpl. + - unfold _shr_lit_be. simpl. + case_eq a0; intros. + + easy. + + simpl. apply f_equal. + case_eq l; intros. + now simpl. + simpl. now rewrite helper2. +Qed. + +Lemma length_nshr_lit_be: forall n a, length (nshr_lit_be a n) = length a. +Proof. intros n. + induction n; intros. + - now simpl. + - simpl. rewrite (IHn (_shr_lit_be a)). + simpl. unfold nshr_lit_be. now rewrite length_shr_lit_be. +Qed. + +Lemma length_shr_be: forall a b, length a = length (shr_lit_be a b). +Proof. intros. unfold shr_lit_be. now rewrite length_nshr_lit_be. Qed. + +Lemma length_check_shsr: forall bs1 bs2 bsres , + check_shr bs1 bs2 bsres = true -> length bs1 = length bs2 -> length bs1 = length bsres. +Proof. intro bs1. + induction bs1; intros. + - case_eq bs2; simpl; intros. + + subst. unfold check_shl in H. simpl in H. + case_eq bsres; simpl; intros; subst; easy. + + rewrite H1 in H. unfold check_shl in H. simpl in H. + now contradict H. + - simpl in *. + unfold check_shr in H. simpl in H. + case_eq bs2; simpl; intros; subst. simpl in H. now contradict H. + simpl in *. inversion H0. rewrite H2, Structures.nat_eqb_refl in H. + case_eq (forallb2 eq_carry_lit (lit_to_carry (shr_lit_be (a :: bs1) (b :: l))) bsres); intros. + + apply prop_eq_carry_lit2 in H1. + rewrite prop_interp_carry3 in H1. + simpl in H1. + assert (length (map (Lit.interp rho) (shr_lit_be (a :: bs1) (b :: l))) = + length (map (Lit.interp rho) bsres)). + { now rewrite H1. } + rewrite !map_length in H3. + rewrite <- (length_shr_be (a :: bs1) (b :: l)) in H3. + now simpl in *. + + rewrite H1 in H; now contradict H. +Qed. + +Lemma prop_shr_be: forall a, RAWBITVECTOR_LIST._shr_be (map (Lit.interp rho) a) = + (map (Lit.interp rho) (_shr_lit_be a)). +Proof. intro a. + case_eq a; intros. + - now simpl. + - unfold RAWBITVECTOR_LIST._shr_be, _shr_lit_be. simpl. + rewrite map_app. simpl. + assert (Lit.interp rho (Lit._false) = false). + { specialize (Lit.interp_false rho wf_rho). intros. + rewrite <- not_true_iff_false. + unfold not in *. + intros. now apply H0. + } + now rewrite H0. +Qed. + +Lemma nshr_interp: forall n bs1, +RAWBITVECTOR_LIST.nshr_be (map (Lit.interp rho) bs1) n = +map (Lit.interp rho) (nshr_lit_be bs1 n). +Proof. intro n. + induction n; intros. + - now simpl. + - simpl. specialize (@IHn (_shr_lit_be bs1)). + rewrite <- IHn. simpl. + now rewrite prop_shr_be. +Qed. + +Lemma shr_interp: forall bs1 bs2, +RAWBITVECTOR_LIST.shr_be (map (Lit.interp rho) bs1) bs2 = +map (Lit.interp rho) (shr_lit_be bs1 bs2). +Proof. intros. + unfold RAWBITVECTOR_LIST.shr_be, shr_lit_be. + now rewrite nshr_interp. +Qed. + + +Lemma check_shr_bvshr: forall bs1 bs2 bsres , + check_shr bs1 bs2 bsres = true -> + (RAWBITVECTOR_LIST.bv_shr (map (Lit.interp rho) bs1) bs2 = + (map (Lit.interp rho) bsres)). +Proof. intro bs1. + induction bs1 as [ | xbs1 xsbs1 IHbs1 ]. + - intros. simpl. + unfold check_shr, shr_lit_be in H. + case_eq (Structures.nat_eqb (@length int []) (length bs2)); intros. + rewrite Structures.nat_eqb_eq in H0. + rewrite <- H0 in H. simpl in H. + rewrite nshr_lit_empty in H. + case_eq bsres; intros. simpl. + now rewrite bv_shr_empty. + subst; now contradict H. + rewrite H0 in H; now contradict H. + - intros. unfold check_shr in H. + case_eq (Structures.nat_eqb (Datatypes.length (xbs1 :: xsbs1)) (Datatypes.length bs2)); intros. + rewrite H0 in H. + case_eq ( + forallb2 eq_carry_lit (lit_to_carry (shr_lit_be (xbs1 :: xsbs1) bs2)) bsres); intros. + apply prop_eq_carry_lit2 in H1. + rewrite prop_interp_carry3 in H1. + + unfold RAWBITVECTOR_LIST.bv_shr. + rewrite Structures.nat_eqb_eq in H0. + unfold RAWBITVECTOR_LIST.size. + rewrite !map_length. rewrite H0, N.eqb_refl. + now rewrite <- H1, shr_interp. + + rewrite H1 in H; now contradict H. + rewrite H0 in H; now contradict H. +Qed. + + +Lemma valid_check_bbShr pos1 pos2 lres : C.valid rho (check_bbShr pos1 pos2 lres). +Proof. + unfold check_bbShr. + case_eq (S.get s pos1); [intros _|intros l1 [ |l] Heq1]; try now apply C.interp_true. + case_eq (S.get s pos2); [intros _|intros l2 [ |l] Heq2]; try now apply C.interp_true. + case_eq (Lit.is_pos l1); intro Heq3; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos l2); intro Heq4; simpl; try now apply C.interp_true. + case_eq (Lit.is_pos lres); intro Heq5; simpl; try now apply C.interp_true. + case_eq (t_form .[ Lit.blit l1]); try (intros; now apply C.interp_true). intros a1 bs1 Heq6. + case_eq (t_form .[ Lit.blit l2]); try (intros; now apply C.interp_true). intros a2 (*bs2*) Heq7. + case_eq (t_form .[ Lit.blit lres]); try (intros; now apply C.interp_true). + intros a bsres Heq8. + case_eq (t_atom .[ a]); try (intros; now apply C.interp_true). + intros [ | | | | | | |[ A B | A| | | | ]|N|N|N|N|N|N|N|N|N| | | | ] a1' a2' Heq9; try (intros; now apply C.interp_true). + case_eq (t_atom .[ a2]); try (intros; now apply C.interp_true). intros c Heqa2. + case_eq c; try (intros; now apply C.interp_true). intros bv2 n0 Heqc. + (* BVshr *) + case_eq ((a1 == a1') && (a2 == a2')); simpl; intros Heq10; try (now apply C.interp_true). + case_eq ( + check_shr bs1 bv2 bsres && (N.of_nat (Datatypes.length bs1) =? n)%N && + (N.of_nat (Datatypes.length bv2) =? n)%N && (n0 =? n)%N + ); simpl; intros Heq11; try (now apply C.interp_true). + + unfold C.valid. simpl. rewrite orb_false_r. + unfold Lit.interp. rewrite Heq5. + unfold Var.interp. + rewrite wf_interp_form; trivial. rewrite Heq8. simpl. + + apply BITVECTOR_LIST.bv_eq_reflect. + + generalize wt_t_atom. unfold Atom.wt. unfold is_true. + rewrite PArray.forallbi_spec;intros. + + pose proof (H a). + assert (a < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heq9. easy. } + specialize (@H0 H1). rewrite Heq9 in H0. simpl in H0. + rewrite !andb_true_iff in H0. destruct H0. destruct H0. + + pose proof (H a2). + assert (a2 < PArray.length t_atom). + { apply PArray.get_not_default_lt. rewrite def_t_atom. rewrite Heqa2, Heqc. easy. } + specialize (@H4 H5). rewrite Heqa2 in H4. simpl in H4. + + unfold get_type' in H0. unfold v_type in H0. + case_eq (t_interp .[ a]). + intros v_typea v_vala Htia. rewrite Htia in H0. + case_eq (v_typea); intros; rewrite H6 in H0; try (now contradict H0). + rename H6 into Hv. + + generalize (Hs pos1). intros HSp1. unfold C.valid in HSp1. rewrite Heq1 in HSp1. + unfold C.interp in HSp1. unfold existsb in HSp1. rewrite orb_false_r in HSp1. + unfold Lit.interp in HSp1. rewrite Heq3 in HSp1. unfold Var.interp in HSp1. + rewrite rho_interp in HSp1. rewrite Heq6 in HSp1. simpl in HSp1. + + generalize (Hs pos2). intro HSp2. unfold C.valid in HSp2. rewrite Heq2 in HSp2. + unfold C.interp in HSp2. unfold existsb in HSp2. rewrite orb_false_r in HSp2. + unfold Lit.interp in HSp2. rewrite Heq4 in HSp2. unfold Var.interp in HSp2. + rewrite rho_interp in HSp2. rewrite Heq7 in HSp2. simpl in HSp2. + + (*apply BITVECTOR_LIST.bv_eq_reflect in HSp2.*) + apply BITVECTOR_LIST.bv_eq_reflect in HSp1. + + (** case a1 = a1' and a2 = a2' **) + rewrite andb_true_iff in Heq10. + destruct Heq10 as (Heq10a1 & Heq10a2); rewrite eqb_spec in Heq10a1, Heq10a2; + rewrite Heq10a1, Heq10a2 in *. + + unfold get_type' in H2, H3. unfold v_type in H2, H3. + case_eq (t_interp .[ a1']). + intros v_typea1 v_vala1 Htia1. rewrite Htia1 in H3. + case_eq (t_interp .[ a2']). + intros v_typea2 v_vala2 Htia2. rewrite Htia2 in H2. + rewrite Atom.t_interp_wf in Htia1; trivial. + rewrite Atom.t_interp_wf in Htia2; trivial. + unfold apply_binop. + apply Typ.eqb_spec in H2. apply Typ.eqb_spec in H3. + + + (* interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a])) *) + assert (interp_form_hatom_bv a = + interp_bv t_i (interp_atom (t_atom .[a]))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia. easy. + } + + rewrite H6. rewrite Heq9. simpl. + unfold interp_bv. unfold apply_binop. + + rewrite !Atom.t_interp_wf; trivial. + + revert v_vala1 Htia1. rewrite H3. revert v_vala2 Htia2. rewrite H2. + intros v_vala2 Htia2 v_vala1 Htia1. + rewrite Htia1, Htia2. + rewrite !Typ.cast_refl. + unfold Bval. + + assert (H100: (N.of_nat (Datatypes.length (map (Lit.interp rho) bsres))) = n%N). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as (((Heq11, Heq11l) & Heq11r), Heq11d). + apply length_check_shsr in Heq11. + rewrite map_length, <- Heq11. + now apply N.eqb_eq in Heq11l. + apply N.eqb_eq in Heq11r. + apply N.eqb_eq in Heq11l. + apply (f_equal (N.to_nat)) in Heq11l. + apply (f_equal (N.to_nat)) in Heq11r. + rewrite Nat2N.id in Heq11l, Heq11r. + now rewrite Heq11l, Heq11r. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bsres)). + + rewrite H100. + rewrite Typ.cast_refl. intros. + simpl. + + (* interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1'])) *) + assert (interp_form_hatom_bv a1' = + interp_bv t_i (interp_atom (t_atom .[a1']))). + { + rewrite !Atom.t_interp_wf in Htia; trivial. + rewrite Htia1. + unfold Atom.interp_form_hatom_bv. + unfold Atom.interp_hatom. + rewrite !Atom.t_interp_wf; trivial. + rewrite Htia1. easy. + } + + rewrite H7 in HSp1. + unfold interp_bv in HSp1. + rewrite Htia1 in HSp1. + unfold interp_bv in HSp1. + + revert HSp1. + + assert (H101: (N.of_nat (Datatypes.length (map (Lit.interp rho) bs1))) = n). + { + rewrite !andb_true_iff in Heq11. + destruct Heq11 as (((Heq11, Heq11l) & Heq11r), Heq11d). + rewrite map_length. + now apply N.eqb_eq in Heq11l. + } + + unfold BITVECTOR_LIST.of_bits, RAWBITVECTOR_LIST.of_bits. + + generalize ( BITVECTOR_LIST.of_bits_size (map (Lit.interp rho) bs1)). + + rewrite H101. + rewrite Typ.cast_refl. intros. + simpl. + + rewrite HSp1. + + rewrite Heqa2 in Htia2. simpl in Htia2. + unfold interp_cop in Htia2. rewrite Heqc in Htia2. unfold Bval in Htia2. + rewrite !andb_true_iff in Heq11. + destruct Heq11 as (((Heq1a, Heq11b), Heq11c), Heq11d). + apply N.eqb_eq in Heq11d. + rewrite Heq11d in *. + specialize (Bval_inj2 _ (Typ.TBV n) (BITVECTOR_LIST._of_bits bv2 n) v_vala2); intros. + apply H8 in Htia2. rewrite <- Htia2. + + unfold BITVECTOR_LIST.bv_shr. + apply eq_rec. simpl. + apply check_shr_bvshr. + + now unfold RAWBITVECTOR_LIST._of_bits; rewrite Heq11c. +Qed. + + End Proof. + +End Checker. + + +(* + Local Variables: + coq-load-path: ((rec ".." "SMTCoq")) + End: +*) |