QuantumLib.Prelim


This file contains basic utility, definitions, and proofs.

Require Export Bool.
Require Export Arith.
Require Export Reals.
Require Export Psatz.
Require Export Program.
Require Export List.

Export ListNotations.


Boolean notation, lemmas

Notation "¬ b" := (negb b) (at level 75, right associativity). Infix "⊕" := xorb (at level 20).

Lemma xorb_nb_b : b, (¬ b) b = true.
Lemma xorb_b_nb : b, b (¬ b) = true.

Lemma xorb_involutive_l : b b', b (b b') = b'.
Lemma xorb_involutive_r : b b', b b' b' = b.

Lemma andb_xorb_dist : b b1 b2, b && (b1 b2) = (b && b1) (b && b2).

Nat lemmas

Lemma Sn_minus_1 : (n : nat), S n - 1 = n.

Useful reflections from Software Foundations Vol 3

Lemma beq_reflect : x y, reflect (x = y) (x =? y).

Lemma blt_reflect : x y, reflect (x < y) (x <? y).

Lemma ble_reflect : x y, reflect (x y) (x <=? y).

#[export] Hint Resolve blt_reflect ble_reflect beq_reflect : bdestruct.

Ltac bdestruct X :=
  let H := fresh in let e := fresh "e" in
   evar (e: Prop);
   assert (H: reflect e X); subst e;
    [eauto with bdestruct
    | destruct H as [H|H];
       [ | try first [apply not_lt in H | apply not_le in H]]].

Ltac bdestructΩ X := bdestruct X; simpl; try lia.

Ltac bdestruct_all :=
  repeat match goal with
  | |- context[?a <? ?b] ⇒ bdestruct (a <? b)
  | |- context[?a <=? ?b] ⇒ bdestruct (a <=? b)
  | |- context[?a =? ?b] ⇒ bdestruct (a =? b)
  end; try (exfalso; lia).

Distribute functions over conditional

Lemma if_dist : (A B : Type) (b : bool) (f : A B) (x y : A),
  f (if b then x else y) = if b then f x else f y.

Generalizations of f_equals

Lemma f_equal_inv : {A B} (x : A) (f g : A B), f = g f x = g x.

Lemma f_equal2_inv : {A B C} x y (f g : A B C), f = g f x y = g x y.

Lemma f_equal_gen : {A B} (f g : A B) a b, f = g a = b f a = g b.

Currying

Definition curry {A B C : Type} (f : A × B C) : (A B C) :=
  fun x yf (x,y).

Definition uncurry {A B C : Type} (f : A B C) : (A × B C) :=
  fun pf (fst p) (snd p).

Lists

Notation "l !! i" := (nth_error l i) (at level 20).

Fixpoint remove_at {A} (i : nat) (ls : list A) :=
  match i, ls with
  | _ ,[][]
  | 0 , _ :: ls'ls'
  | S i', a :: ls'a :: remove_at i' ls'
  end.

Fixpoint update_at {A} (ls : list A) (i : nat) (a : A) : list A :=
  match ls, i with
  | [] , _[]
  | _ :: ls', 0 ⇒ a :: ls'
  | b :: ls', S i'b :: update_at ls' i' a
  end.

Lemma update_length : A (l: list A) (a : A) (n : nat),
    length (update_at l n a) = length l.

Lemma repeat_combine : A n1 n2 (a : A),
  List.repeat a n1 ++ List.repeat a n2 = List.repeat a (n1 + n2).

Lemma rev_repeat : A (a : A) n, rev (repeat a n) = repeat a n.

Lemma firstn_repeat_le : A (a : A) m n, (m n)%nat
  firstn m (repeat a n) = repeat a m.

Lemma firstn_repeat_ge : A (a : A) m n, (m n)%nat
  firstn m (repeat a n) = repeat a n.

Lemma firstn_repeat : A (a : A) m n,
  firstn m (repeat a n) = repeat a (min m n).

Lemma skipn_repeat : A (a : A) m n,
  skipn m (repeat a n) = repeat a (n-m).

Lemma skipn_length : {A} (l : list A) n,
  length (skipn n l) = (length l - n)%nat.
  Transparent skipn.
  Opaque skipn.

Lemma nth_firstn : {A} i n (l : list A) d,
  (i < n)%nat nth i (firstn n l) d = nth i l d.

Option type

Definition maybe {A} (o : option A) (default : A) : A :=
  match o with
  | Some aa
  | Nonedefault
  end.

General purpose tactics

Ltac simpl_rewrite lem :=
  let H := fresh "H" in
  specialize lem as H; simpl in H; rewrite H; clear H.

Ltac simpl_rewrite' lem :=
  let H := fresh "H" in
  specialize lem as H; simpl in H; rewrite <- H; clear H.

Ltac simpl_rewrite_h lem hyp :=
  let H := fresh "H" in
  specialize lem as H; simpl in H; rewrite <- H in hyp; clear H.

Ltac apply_with_obligations H :=
  match goal with
  | [|- ?P ?a] ⇒ match type of H with ?P ?a'
    replace a with a'; [apply H|]; trivial end
  | [|- ?P ?a ?b] ⇒ match type of H with ?P ?a' ?b'
    replace a with a'; [replace b with b'; [apply H|]|]; trivial end
  | [|- ?P ?a ?b ?c ] ⇒ match type of H with ?P ?a' ?b' ?c'
    replace a with a'; [replace b with b'; [replace c with c'; [apply H|]|]|]; trivial end
  | [|- ?P ?a ?b ?c ?d] ⇒ match type of H with ?P ?a' ?b' ?c' ?d'
    replace a with a'; [replace b with b'; [replace c with c'; [replace d with d'; [apply H|]|]|]|]; trivial end
  | [|- ?P ?a ?b ?c ?d ?e] ⇒ match type of H with ?P ?a' ?b' ?c' ?d' ?e'
    replace a with a'; [replace b with b'; [replace c with c'; [replace d with d'; [replace e with e'; [apply H|]|]|]|]|];
    trivial end
  | [|- ?P ?a ?b ?c ?d ?e ?f] ⇒ match type of H with ?P ?a' ?b' ?c' ?d' ?e' ?f'
    replace a with a'; [replace b with b'; [replace c with c'; [replace d with d'; [replace e with e'; [replace f with f';
    [apply H|]|]|]|]|]|]; trivial end
  | [|- ?P ?a ?b ?c ?d ?e ?f ?g] ⇒ match type of H with ?P ?a' ?b' ?c' ?d' ?e' ?f' ?g'
    replace a with a'; [replace b with b'; [replace c with c'; [replace d with d'; [replace e with e'; [replace f with f';
    [replace g with g'; [apply H|]|]|]|]|]|]|]; trivial end
  end.

From SF - up to five arguments
Tactic Notation "gen" ident(X1) :=
  generalize dependent X1.
Tactic Notation "gen" ident(X1) ident(X2) :=
  gen X2; gen X1.
Tactic Notation "gen" ident(X1) ident(X2) ident(X3) :=
  gen X3; gen X2; gen X1.
Tactic Notation "gen" ident(X1) ident(X2) ident(X3) ident(X4) :=
  gen X4; gen X3; gen X2; gen X1.
Tactic Notation "gen" ident(X1) ident(X2) ident(X3) ident(X4) ident(X5) :=
  gen X5; gen X4; gen X3; gen X2; gen X1.

Powers of 2

Lemma double_mult : (n : nat), (n + n = 2 × n)%nat.
Lemma pow_two_succ_l : x, (2^x × 2 = 2 ^ (x + 1))%nat.
Lemma pow_two_succ_r : x, (2 × 2^x = 2 ^ (x + 1))%nat.
Lemma double_pow : (n : nat), (2^n + 2^n = 2^(n+1))%nat.
Lemma pow_components : (a b m n : nat), a = b m = n (a^m = b^n)%nat.
Lemma pow_positive : a b, a 0 0 < a ^ b.

Ltac unify_pows_two :=
  repeat match goal with
  
  | [ |- context[ 4%nat ]] ⇒ replace 4%nat with (2^2)%nat by reflexivity
  | [ |- context[ (0 + ?a)%nat]] ⇒ rewrite plus_0_l
  | [ |- context[ (?a + 0)%nat]] ⇒ rewrite plus_0_r
  | [ |- context[ (1 × ?a)%nat]] ⇒ rewrite Nat.mul_1_l
  | [ |- context[ (?a × 1)%nat]] ⇒ rewrite Nat.mul_1_r
  | [ |- context[ (2 × 2^?x)%nat]] ⇒ rewrite <- Nat.pow_succ_r'
  | [ |- context[ (2^?x × 2)%nat]] ⇒ rewrite pow_two_succ_l
  | [ |- context[ (2^?x + 2^?x)%nat]] ⇒ rewrite double_pow
  | [ |- context[ (2^?x × 2^?y)%nat]] ⇒ rewrite <- Nat.pow_add_r
  | [ |- context[ (?a + (?b + ?c))%nat ]] ⇒ rewrite plus_assoc
  | [ |- (2^?x = 2^?y)%nat ] ⇒ apply pow_components; try lia
  end.

Subsets

Definition subset_gen {X : Type} (l1 l2 : list X) :=
   (x : X), In x l1 In x l2.

Fixpoint subset_gen' {X : Type} (l1 l2 : list X) :=
  match l1 with
  | []True
  | (l :: l1') ⇒ In l l2 subset_gen' l1' l2
  end.

Lemma subset_is_subset' : (X : Type) (l1 l2 : list X),
    subset_gen' l1 l2 subset_gen l1 l2.

Infix "⊆" := subset_gen (at level 70, no associativity).

Lemma subset_cons : (X : Type) (l1 l2 : list X) (x : X),
  l1 l2 l1 (x :: l2).

Lemma subset_concat_l : (X : Type) (l1 l2 : list X),
  l1 (l1 ++ l2).

Lemma subset_concat_r : (X : Type) (l1 l2 : list X),
  l1 (l2 ++ l1).

Corollary subset_self : (X : Type) (l1 : list X),
  l1 l1.

Lemma subsets_add : (X : Type) (l1 l2 l3 : list X),
  l1 l3 l2 l3 (l1 ++ l2) l3.

Lemma subset_trans : (X : Type) (l1 l2 l3 : list X),
    l1 l2 l2 l3 l1 l3.

#[export] Hint Resolve subset_concat_l subset_concat_r subset_self
                       subsets_add subset_trans : sub_db.

Lemma firstn_subset : {X : Type} (n : nat) (ls : list X),
    firstn n ls ls.

Lemma skipn_subset : {X : Type} (n : nat) (ls : list X),
    skipn n ls ls.

#[export] Hint Resolve firstn_subset skipn_subset : sub_db.