├── src ├── Ingest │ ├── SQIRIngest.v │ └── ZXPad.v ├── Gates │ ├── Gates.v │ ├── GateDefinitions.v │ └── GateRules.v ├── DiagramRules │ ├── DiagramRules.v │ ├── Universality.v │ ├── Soundness.v │ └── Bell.v ├── dune ├── CoreData │ ├── CoreData.v │ ├── Stacks.v │ ├── CapCup.v │ ├── StrongInduction.v │ ├── Addition.v │ ├── States.v │ ├── Swaps.v │ ├── Gadgets.v │ ├── Controlizer.v │ └── QlibTemp.v ├── CoreRules │ ├── CoreRules.v │ ├── WireRules.v │ ├── SemanticsComp.v │ ├── ComposeRules.v │ ├── CoreAutomation.v │ ├── ScalarSemanticsComp.v │ ├── StackComposeRules.v │ ├── ChoiJamiolchosky.v │ ├── StackRules.v │ ├── SwapRules.v │ ├── StateRules.v │ ├── ZXRules.v │ ├── SpiderInduction.v │ └── AdditionRules.v ├── Examples │ └── Teleportation.v ├── Permutations │ ├── ZXperm.v │ ├── ZXpermSemantics.v │ └── ZXpermAutomation.v └── Quarantine.v ├── _CoqProject ├── Makefile ├── dune-project ├── .hooks ├── pre-commit ├── Nocheck_finder.py ├── Search_validator.py ├── Z_X_rules_validator.py └── Name_validator.py ├── .github └── workflows │ ├── static-check-action.yml │ └── coq-action.yml ├── coq-vyzx.opam ├── LICENSE ├── README.md └── .gitignore /src/Ingest/SQIRIngest.v: -------------------------------------------------------------------------------- 1 | From VyZX Require Export Ingest. 2 | From VyZX Require Export ZXPad. -------------------------------------------------------------------------------- /src/Gates/Gates.v: -------------------------------------------------------------------------------- 1 | From VyZX Require Export GateDefinitions. 2 | From VyZX Require Export GateRules. -------------------------------------------------------------------------------- /src/DiagramRules/DiagramRules.v: -------------------------------------------------------------------------------- 1 | From VyZX Require Export Bialgebra. 2 | From VyZX Require Export Bell. -------------------------------------------------------------------------------- /src/dune: -------------------------------------------------------------------------------- 1 | (include_subdirs qualified) 2 | (coq.theory 3 | (name VyZX) 4 | (package coq-vyzx)) 5 | -------------------------------------------------------------------------------- /_CoqProject: -------------------------------------------------------------------------------- 1 | -I _build/default/src/CoreData 2 | -I _build/default/src/CoreRules 3 | -I _build/default/src/Ingest 4 | -I _build/default/externals/SQIR 5 | 6 | -R _build/default/src VyZX 7 | -------------------------------------------------------------------------------- /src/CoreData/CoreData.v: -------------------------------------------------------------------------------- 1 | Require Export ZXCore. 2 | Require Export Proportional. 3 | Require Export Swaps. 4 | Require Export StrongInduction. 5 | Require Export CapCup. 6 | Require Export Stacks. 7 | Require Export Gadgets. 8 | Require Export States. 9 | Require Export Controlizer. 10 | Require Export Addition. 11 | -------------------------------------------------------------------------------- /src/DiagramRules/Universality.v: -------------------------------------------------------------------------------- 1 | Require Import CoreRules. 2 | 3 | (** Universality of ZX-diagrams *) 4 | 5 | Theorem universality {n m} : forall (A : Matrix (2^m) (2^n)), WF_Matrix A -> 6 | exists (zx : ZX n m), ⟦ zx ⟧ = A. 7 | Proof. 8 | intros A HA. 9 | exists (zx_of_matrix A). 10 | now apply zx_of_matrix_semantics. 11 | Qed. 12 | -------------------------------------------------------------------------------- /src/CoreData/Stacks.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore. 2 | 3 | (** Definitions involving arbitrary stacks *) 4 | 5 | (* TODO: Move n_stack / n_stack1 / n_wire / n_box in here *) 6 | 7 | Definition associator n m o : ZX (n + m + o) (n + (m + o)) := 8 | cast _ _ eq_refl (Nat.add_assoc _ _ _) (n_wire _). 9 | 10 | Definition invassociator n m o : ZX (n + (m + o)) (n + m + o) := 11 | cast _ _ (Nat.add_assoc _ _ _) eq_refl (n_wire _). 12 | -------------------------------------------------------------------------------- /src/DiagramRules/Soundness.v: -------------------------------------------------------------------------------- 1 | From QuantumLib Require Complex Matrix RealAux Polar. 2 | 3 | From VyZX Require Import CoreRules. 4 | 5 | Local Open Scope matrix_scope. 6 | 7 | (** Soundness of proportionality for ZX-diagrams *) 8 | 9 | Theorem soundness {n m} (zx0 zx1 : ZX n m) : 10 | zx0 ∝ zx1 -> 11 | exists c, ⟦ zx0 ⟧ = c .* ⟦ zx1 ⟧ /\ c <> C0. 12 | Proof. 13 | intros (c & Hc)%propotional_to_prop_by_sig. 14 | exists c. 15 | apply Hc. 16 | Qed. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @dune build 3 | 4 | clean: 5 | @dune clean 6 | 7 | install: 8 | @dune install 9 | 10 | uninstall: 11 | @dune uninstall 12 | 13 | # hacky :) we should replace with dune in a future version 14 | FILES=$(shell find . -name "*.v" -depth 1) 15 | doc: all 16 | mkdir -p docs 17 | cd _build/default && coqdoc -g --utf8 --toc --no-lib-name -d ../../docs -R . QuantumLib $(FILES) 18 | 19 | hooks: 20 | @git config core.hooksPath .hooks 21 | 22 | .PHONY: all clean install uninstall doc 23 | -------------------------------------------------------------------------------- /src/CoreRules/CoreRules.v: -------------------------------------------------------------------------------- 1 | Require Export StackComposeRules. 2 | Require Export WireRules. 3 | Require Export ZRules. 4 | Require Export CapCupRules. 5 | Require Export CastRules. 6 | Require Export CoreAutomation. 7 | Require Export XRules. 8 | Require Export ZXRules. 9 | Require Export SwapRules. 10 | Require Export GadgetRules. 11 | Require Export StateRules. 12 | Require Export ZXStateRules. 13 | Require Export ChoiJamiolchosky. 14 | Require Export ControlizerRules. 15 | Require Export AdditionRules. 16 | 17 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.8) 2 | (name coq-vyzx) 3 | (version 0.1.0) 4 | (using coq 0.2) 5 | 6 | (generate_opam_files true) 7 | 8 | (license MIT) 9 | (authors "inQWIRE") 10 | (maintainers "inQWIRE Developers") 11 | (source (github inQWIRE/VyZX)) 12 | 13 | (package 14 | (name coq-vyzx) 15 | (synopsis "Coq library for reasoning about ZX diagrams") 16 | (description "\| inQWIRE's QuantumLib is a Coq library for reasoning 17 | "\| about ZX diagrams. 18 | ) 19 | 20 | (depends 21 | (coq-quantumlib (>= 1.6.0)) 22 | (coq-sqir (>= 1.3.2)) 23 | (coq-voqc (>= 1.3.2)) 24 | (coq (>= 8.16)))) 25 | -------------------------------------------------------------------------------- /.hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR=$(dirname "$0") 4 | 5 | # Stash changes that are not staged to check if the commited state if valid 6 | # Make sure to pop later! 7 | git stash --keep-index -u 2>/dev/null 8 | 9 | unstash() { 10 | git stash pop > /dev/null 2>/dev/null 11 | exit $1 12 | } 13 | 14 | 15 | "$BASEDIR/Z_X_rules_validator.py" || { echo "Error - disallowing commit: Z_X validator failed"; unstash 1; } 16 | 17 | "$BASEDIR/Search_validator.py" || { echo "Error - disallowing commit: Search validator failed"; unstash 1; } 18 | 19 | "$BASEDIR/Name_validator.py" || { echo "Error - disallowing commit: Naming validator failed"; unstash 1; } 20 | 21 | unstash 0 22 | -------------------------------------------------------------------------------- /.github/workflows/static-check-action.yml: -------------------------------------------------------------------------------- 1 | name: Static validation 2 | 3 | on: 4 | push: 5 | branches: ['main'] 6 | pull_request: 7 | branches: ['**'] # for all submitted Pull Requests 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: setup python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.10' # install the python version needed 18 | - name: execute static checks 19 | run: .hooks/pre-commit 20 | - name: Get changed files in the docs folder 21 | id: changed-files-specific 22 | uses: tj-actions/changed-files@v35 23 | with: 24 | files: src/**/*.v 25 | - name: Get new nochecks 26 | run: python .hooks/Nocheck_finder.py ${{ steps.changed-files-specific.outputs.all_changed_files }} 27 | -------------------------------------------------------------------------------- /src/Gates/GateDefinitions.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore. 2 | From VyZX Require Import Proportional. 3 | 4 | Local Open Scope ZX_scope. 5 | 6 | (** Gate Definitions in the ZX Calculus *) 7 | 8 | Notation "'_Z_'" := (Z 1 1 PI) (at level 40). 9 | Notation "'_X_'" := (X 1 1 PI) (at level 40). 10 | Definition _Rz_ α : ZX 1 1 := Z 1 1 α. 11 | 12 | Notation "'_H_'" := 13 | ((Z 1 1 (PI/2)) ⟷ (X 1 1 (PI/2)) ⟷ (Z 1 1 (PI/2))) 14 | (at level 40). 15 | 16 | Notation "'_CNOT_'" := 17 | ((Z 1 2 0 ↕ —) ⟷ (— ↕ X 2 1 0)). 18 | 19 | Notation "'_CNOT_inv_'" := ((2 ↑ □) ⟷ _CNOT_ ⟷ (2 ↑ □)). 20 | 21 | Notation "'_CNOT_R'" := 22 | ((— ↕ X 1 2 0) ⟷ (Z 2 1 0 ↕ —)). 23 | 24 | Notation "'_NOTC_'" := 25 | ((— ↕ Z 1 2 0 ) ⟷ (X 2 1 0 ↕ —)). 26 | 27 | Notation "'_NOTC_R'" := 28 | ((X 1 2 0 ↕ —) ⟷ (— ↕ Z 2 1 0 )). 29 | 30 | Notation "'_3_CNOT_SWAP_'" := 31 | (_CNOT_ ⟷ _NOTC_ ⟷ _CNOT_). 32 | 33 | 34 | -------------------------------------------------------------------------------- /coq-vyzx.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | version: "0.1.0" 4 | synopsis: "Coq library for reasoning about ZX diagrams" 5 | description: """ 6 | inQWIRE's QuantumLib is a Coq library for reasoning 7 | about ZX diagrams. 8 | """ 9 | maintainer: ["inQWIRE Developers"] 10 | authors: ["inQWIRE"] 11 | license: "MIT" 12 | homepage: "https://github.com/inQWIRE/VyZX" 13 | bug-reports: "https://github.com/inQWIRE/VyZX/issues" 14 | depends: [ 15 | "dune" {>= "2.8"} 16 | "coq-quantumlib" {>= "1.6.0"} 17 | "coq-sqir" {>= "1.3.2"} 18 | "coq-voqc" {>= "1.3.2"} 19 | "coq" {>= "8.16"} 20 | "odoc" {with-doc} 21 | ] 22 | build: [ 23 | ["dune" "subst"] {dev} 24 | [ 25 | "dune" 26 | "build" 27 | "-p" 28 | name 29 | "-j" 30 | jobs 31 | "@install" 32 | "@runtest" {with-test} 33 | "@doc" {with-doc} 34 | ] 35 | ] 36 | dev-repo: "git+https://github.com/inQWIRE/VyZX.git" 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 INQWIRE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/coq-action.yml: -------------------------------------------------------------------------------- 1 | name: Coq Build 2 | 3 | on: 4 | push: 5 | branches: ['main'] 6 | pull_request: 7 | branches: ['**'] # for all submitted Pull Requests 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | coq_version: 15 | - '8.16' 16 | - '8.17' 17 | - '8.18' 18 | - '8.19' 19 | - '8.20' 20 | ocaml_version: 21 | - 'default' 22 | fail-fast: false # don't stop jobs if one fails 23 | steps: 24 | - uses: actions/checkout@v3 25 | - uses: coq-community/docker-coq-action@v1 26 | with: 27 | opam_file: 'coq-vyzx.opam' 28 | before_install: | 29 | startGroup "Print opam config" 30 | opam update -y 31 | opam pin -y coq-sqir https://github.com/inQWIRE/SQIR.git; 32 | opam pin -y coq-voqc https://github.com/inQWIRE/SQIR.git; 33 | opam config list; opam repo list; opam list 34 | endGroup 35 | coq_version: ${{ matrix.coq_version }} 36 | ocaml_version: ${{ matrix.ocaml_version }} 37 | 38 | -------------------------------------------------------------------------------- /src/CoreData/CapCup.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore. 2 | Require Import Swaps. 3 | Require Export QuantumLib.Quantum. 4 | Require Export QuantumLib.Permutations. 5 | 6 | Local Open Scope ZX_scope. 7 | 8 | (** Generalized cups and caps with arbitrary sizes*) 9 | 10 | Lemma n_cup_dim : forall n, ((S n) + (S n) = 1 + (n +n) + 1)%nat. 11 | Proof. lia. Qed. 12 | 13 | Fixpoint n_cup_unswapped (n : nat) : ZX (n + n) 0 := 14 | match n with 15 | | 0 => ⦰ 16 | | (S n) => @Compose ((S n) + (S n))%nat (2)%nat _ 17 | (cast _ _ (n_cup_dim _) (eq_refl) (— ↕ (n_cup_unswapped n) ↕ —)) 18 | ⊃ 19 | end. 20 | 21 | Definition n_cap_unswapped n := (n_cup_unswapped n)⊤. 22 | 23 | Definition n_cup n := (n_swap (n) ↕ n_wire n) ⟷ (n_cup_unswapped n). 24 | 25 | Definition n_cap n := (n_cup n) ⊤. 26 | 27 | 28 | Lemma n_stacked_pf_1 {n} : (n + n = n * 2)%nat. Proof. lia. Qed. 29 | 30 | Lemma n_stacked_pf_2 {n} : (0 = n * 0)%nat. Proof. lia. Qed. 31 | 32 | Definition n_stacked_caps n : ZX (n + n) 0 := 33 | cast _ _ n_stacked_pf_1 n_stacked_pf_2 (n ⇑ ⊃). 34 | 35 | Definition n_stacked_cups n : ZX 0 (n + n) := 36 | cast _ _ n_stacked_pf_2 n_stacked_pf_1 (n ⇑ ⊂). 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VyZX 2 | 3 | Verifying the ZX Calculus 4 | 5 | [Check out the paper on arxiv](https://arxiv.org/abs/2205.05781) 6 | 7 | ## Building VyZX 8 | 9 | Works with Coq 8.16-8.20. 10 | 11 | First, install [QuantumLib](https://github.com/inQWIRE/QuantumLib) through opam. 12 | 13 | ```bash 14 | opam repo add coq-released https://coq.inria.fr/opam/released 15 | opam update 16 | opam install coq-quantumlib 17 | ``` 18 | 19 | Then install [SQIR and VOQC](https://github.com/inQWIRE/SQIR) 20 | 21 | ```bash 22 | opam pin -y coq-sqir https://github.com/inQWIRE/SQIR.git 23 | opam pin -y coq-voqc https://github.com/inQWIRE/SQIR.git 24 | ``` 25 | 26 | Finally, build VyZX: 27 | 28 | ```bash 29 | make 30 | ``` 31 | 32 | ## Using the visualizer 33 | 34 | To use the integrated visualization, two things will need to be installed and you must be using VSCode. 35 | 36 | First, install [rocq-lsp](https://github.com/ejgallego/rocq-lsp) and install the associated VSCode extension. 37 | 38 | Then install our VSCode extension, [ZXViz](https://marketplace.visualstudio.com/items?itemName=inQWIRE.vizx). It can also be built from source following the instructions [here](https://github.com/inQWIRE/ViZX/). 39 | 40 | ## Contributing 41 | 42 | To contribute please make sure you use our validator hooks. 43 | To configure the hooks run (you should only need to do this once): 44 | 45 | ```sh 46 | make hooks 47 | ``` 48 | -------------------------------------------------------------------------------- /src/CoreData/StrongInduction.v: -------------------------------------------------------------------------------- 1 | (* Source: https://github.com/tchajed/strong-induction *) 2 | (* This should really be in the coq std library *) 3 | 4 | Local Open Scope nat_scope. 5 | (** Here we prove the principle of strong induction, induction on the natural 6 | numbers where the inductive hypothesis includes all smaller natural numbers. *) 7 | 8 | Require Import PeanoNat. 9 | 10 | Section StrongInduction. 11 | 12 | Variable P : nat -> Prop. 13 | 14 | (** The stronger inductive hypothesis given in strong induction. The standard 15 | [nat ] induction principle provides only n = pred m, with [P 0] required 16 | separately. *) 17 | (* @nocheck name *) 18 | Hypothesis IH : forall m, (forall n, n < m -> P n) -> P m. 19 | 20 | (* @nocheck name *) 21 | Lemma P0 : P 0. 22 | Proof. 23 | apply IH; intros. 24 | exfalso; inversion H. 25 | Qed. 26 | 27 | Hint Resolve P0 : strong_ind_db. 28 | 29 | Lemma pred_increasing : forall n m, 30 | n <= m -> 31 | Nat.pred n <= Nat.pred m. 32 | Proof. 33 | induction n; cbn; intros. 34 | apply le_0_n. 35 | induction H; subst; cbn; eauto. 36 | destruct m; eauto. 37 | Qed. 38 | 39 | Hint Resolve le_S_n : strong_ind_db. 40 | 41 | (** * Strengthen the induction hypothesis. *) 42 | 43 | Local Lemma strong_induction_all : forall n, 44 | (forall m, m <= n -> P m). 45 | Proof. 46 | induction n; intros; 47 | match goal with 48 | | [ H: _ <= _ |- _ ] => 49 | inversion H 50 | end; eauto with strong_ind_db. 51 | Qed. 52 | 53 | Theorem strong_induction : forall n, P n. 54 | Proof. 55 | eauto using strong_induction_all. 56 | Qed. 57 | 58 | End StrongInduction. 59 | 60 | Global Tactic Notation "strong" "induction" ident(n) := induction n using strong_induction. 61 | 62 | -------------------------------------------------------------------------------- /.hooks/Nocheck_finder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import os 5 | import sys 6 | 7 | 8 | MIN_PYTHON = (3, 10) 9 | if sys.version_info < MIN_PYTHON: 10 | print(f"Your python version is {sys.version_info.major}.{sys.version_info.minor}. {MIN_PYTHON[0]}.{MIN_PYTHON[1]} is required") 11 | exit(3) 12 | 13 | 14 | b_color_yellow = '\033[93m' 15 | b_color_reset = '\033[0m' 16 | 17 | curr_dir = os.path.dirname(os.path.realpath(__file__)) 18 | src_dir = f"{curr_dir}/../src" 19 | 20 | nocheck_regex = re.compile("\\s*\\(\\*\\s*\\@nocheck\\s+(([a-z]|[A-Z]|[0-9])+)\\s*\\*\\)") 21 | 22 | class Warning: 23 | line_no : int = 0 24 | type : str 25 | file : str = "" 26 | 27 | def __init__(self, line_no : int, type: str, file : str): 28 | self.file = file 29 | self.type = type 30 | self.line_no = line_no 31 | 32 | def _fmt_file(self) -> str: 33 | prefix, _, postfix = self.file.partition(".hooks/../") # strip going into the hooks directory 34 | return prefix + postfix 35 | 36 | def __str__(self) -> str: 37 | return f"{b_color_yellow}Warning: @nocheck {self.type} found: {b_color_reset}({self._fmt_file()}:{self.line_no})" 38 | pass 39 | 40 | def validate_file(file) -> list[Warning]: 41 | warnings : list[Warning] = list() 42 | with open(file) as lines: 43 | for (line_no, line) in enumerate(lines, 1): 44 | match = re.match(nocheck_regex, line) 45 | if match: 46 | warnings.append(Warning(line_no, match.groups()[0], file)) 47 | return warnings 48 | 49 | 50 | all_warnings : list[Warning] = list() 51 | 52 | args = sys.argv[1:] 53 | 54 | print(f"Checking {args} for any files containing @nochecks ...") 55 | for arg in args: 56 | all_warnings += validate_file(arg) 57 | 58 | 59 | if not all_warnings: 60 | print("No warnings found") 61 | 62 | num_violations = len(all_warnings) 63 | 64 | for (n, violation) in enumerate(all_warnings, 1): 65 | print(f"({n}/{num_violations}) {violation}") 66 | -------------------------------------------------------------------------------- /src/CoreRules/WireRules.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData.CoreData. 2 | Require Import StackRules. 3 | Require Import CastRules. 4 | 5 | Local Open Scope ZX_scope. 6 | 7 | (** Rules relating to wires ([—]) and [n_wire]s *) 8 | 9 | Lemma Z_0_is_wire : Z 1 1 0 ∝= —. 10 | Proof. 11 | lma'. 12 | now rewrite Cexp_0. 13 | Qed. 14 | 15 | Lemma Z_2_0_0_is_cap : Z 2 0 0 ∝= ⊃. 16 | Proof. 17 | lma'. 18 | now rewrite Cexp_0. 19 | Qed. 20 | 21 | Lemma Z_0_2_0_is_cup : Z 0 2 0 ∝= ⊂. 22 | Proof. 23 | lma'. 24 | now rewrite Cexp_0. 25 | Qed. 26 | 27 | Lemma yank_r : 28 | (⊂ ↕ —) ⟷ (— ↕ ⊃) ∝= —. 29 | Proof. 30 | lma'. 31 | Qed. 32 | 33 | Lemma yank_l : 34 | (— ↕ ⊂) ⟷ (⊃ ↕ —) ∝= —. 35 | Proof. 36 | lma'. 37 | Qed. 38 | 39 | Lemma n_wire_stack : forall n m, 40 | n_wire n ↕ n_wire m ∝= n_wire (n + m). 41 | Proof. 42 | intros n m. 43 | unfold proportional_by_1. 44 | cbn. 45 | rewrite 3!n_wire_semantics. 46 | rewrite id_kron. 47 | now unify_pows_two. 48 | Qed. 49 | 50 | Lemma X_0_is_wire : X 1 1 0 ∝= —. 51 | Proof. 52 | apply colorswap_diagrams_eq. 53 | simpl. 54 | apply Z_0_is_wire. 55 | Qed. 56 | 57 | Lemma wire_to_n_wire : 58 | — ∝= n_wire 1. 59 | Proof. 60 | symmetry. 61 | apply nstack1_1. 62 | Qed. 63 | 64 | Lemma wire_transpose : —⊤ = —. 65 | Proof. reflexivity. Qed. 66 | 67 | Lemma n_wire_colorswap : forall n, ⊙ (n_wire n) = n_wire n. 68 | Proof. 69 | intros. 70 | apply nstack1_colorswap. 71 | Qed. 72 | 73 | Lemma wire_loop : — ∝= (⊂ ↕ —) ⟷ (— ↕ ⨉) ⟷ (⊃ ↕ —). 74 | Proof. 75 | unfold proportional_by_1. 76 | prep_matrix_equivalence. 77 | cbn. 78 | rewrite 2!Kronecker.kron_I_r, Kronecker.kron_I_l. 79 | by_cell; cbn; lca. 80 | Qed. 81 | 82 | Lemma n_stack_n_wire_1_n_wire : forall n, n ↑ (n_wire 1) ∝= n_wire n. 83 | Proof. 84 | intros. rewrite <- wire_to_n_wire. reflexivity. 85 | Qed. 86 | 87 | Lemma n_wire_grow_r : forall n prfn prfm, n_wire (S n) ∝= 88 | cast _ _ prfn prfm (n_wire n ↕ —). 89 | Proof. 90 | intros. 91 | rewrite wire_to_n_wire. 92 | rewrite n_wire_stack. 93 | now rewrite cast_n_wire. 94 | Qed. 95 | 96 | Lemma box_compose : □ ⟷ □ ∝= —. 97 | Proof. 98 | apply MmultHH. 99 | Qed. -------------------------------------------------------------------------------- /src/CoreData/Addition.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore CapCup States Gadgets Controlizer. 2 | Import Setoid. 3 | 4 | (** Definitions about sums of ZX-diagrams, using controlizers *) 5 | 6 | (* The sum of two ZX-diagrams, defined using controlizers *) 7 | Definition zx_plus {n m} (zx0 zx1 : ZX n m) : ZX n m := 8 | cast 0 0 (eq_sym (Nat.mul_0_r _)) (eq_sym (Nat.mul_0_r _)) ((n + m) ⇑ zx_invsqrt2) ↕ 9 | state_to_proc (state_1 ⟷ sum_controlizer (controlizer zx0) (controlizer zx1)). 10 | 11 | Lemma zx_plus_defn {n m} (zx0 zx1 : ZX n m) : 12 | zx_plus zx0 zx1 = 13 | cast 0 0 (eq_sym (Nat.mul_0_r _)) (eq_sym (Nat.mul_0_r _)) ((n + m) ⇑ zx_invsqrt2) ↕ 14 | state_to_proc (state_1 ⟷ sum_controlizer (controlizer zx0) (controlizer zx1)). 15 | Proof. reflexivity. Qed. 16 | 17 | (* We don't want reduction to unfold zx_plus *) 18 | Global Opaque zx_plus. 19 | 20 | Notation "zx0 .+ zx1" := (zx_plus zx0 zx1) 21 | (at level 50, left associativity) : ZX_scope. 22 | 23 | 24 | (* TODO: When/if the [Monoid] typeclass in Qlib no longer requires 25 | leibnix equality and uses setoids, this can be replaced *) 26 | (* The indexed sum of a list of ZX-diagrams *) 27 | Fixpoint zx_sum {n m} (f : nat -> ZX n m) k : ZX n m := 28 | match k with 29 | | O => zx_zero 30 | | 1 => f O 31 | | S k' => zx_sum f k' .+ f k' 32 | end. 33 | 34 | (* A ZX-diagram whose semantics are those of a given vector *) 35 | Definition state_of_vector {n} (v : Vector (2^n)) : ZX 0 n := 36 | zx_sum (fun i => 37 | v i O .* f_to_state n (nat_to_funbool n i)) (2^n). 38 | 39 | (* TODO: figure out the exact vector used (mx_to_vec A?). Not critical, 40 | but it would be better *) 41 | (* A ZX-diagram whose semantics are those of a given matrix *) 42 | Definition zx_of_matrix {n m} (A : Matrix (2^m) (2^n)) : ZX n m := 43 | state_to_proc (state_of_vector 44 | (@Mmult _ (2^(n+n)) _ (I (2^n) ⊗ A) (⟦ n_cap n ⟧))). 45 | 46 | (* An alternate definition of a ZX-diagram, whose semantic is 47 | a given matrix, which does not use the Choi-Jamiolchosky isomorphism *) 48 | Definition zx_of_matrix' {n m} (A : Matrix (2^m) (2^n)) : ZX n m := 49 | zx_sum (fun i => 50 | zx_sum (fun j => 51 | A i j .* 52 | ((f_to_state n (nat_to_funbool n j)) ⊤ ⟷ 53 | f_to_state m (nat_to_funbool m i)) 54 | )%ZX (2^n)) (2^m). -------------------------------------------------------------------------------- /src/CoreRules/SemanticsComp.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData. 2 | 3 | (** Various computational results about explicit ZX-diagrams *) 4 | 5 | Local Open Scope matrix_scope. 6 | 7 | Lemma X_0_0_semantics (r : R) : 8 | ⟦ X 0 0 r ⟧ = (1 + Cexp r) .* I 1. 9 | Proof. 10 | lma'. 11 | Qed. 12 | 13 | Lemma Z_0_0_semantics (r : R) : 14 | ⟦ Z 0 0 r ⟧ = (1 + Cexp r) .* I 1. 15 | Proof. 16 | lma'. 17 | Qed. 18 | 19 | Lemma Z_semantics_0_0' (r : R) : 20 | Z_semantics 0 0 r = (1 + Cexp r) .* I 1. 21 | Proof. 22 | exact (Z_0_0_semantics r). 23 | Qed. 24 | 25 | 26 | Lemma Z_0_2_semantics α : 27 | Z_semantics 0 2 α = make_WF (list2D_to_matrix [[C1];[C0];[C0];[Cexp α]]). 28 | Proof. 29 | prep_matrix_equivalence. 30 | rewrite make_WF_equiv. 31 | by_cell; reflexivity. 32 | Qed. 33 | 34 | Lemma X_2_1_0_semantics : X_semantics 2 1 0 = 35 | make_WF (list2D_to_matrix [[/√2;C0;C0;/√2];[C0;/√2;/√2;C0]]). 36 | Proof. 37 | rewrite X_semantics_equiv. 38 | cbn. 39 | rewrite 4 kron_1_l, Cexp_0, Mscale_1_l by auto_wf. 40 | prep_matrix_equivalence. 41 | rewrite make_WF_equiv. 42 | unfold xbasis_plus, xbasis_minus, braplus, braminus; 43 | autounfold with U_db; cbn; by_cell_no_intros; cbn; 44 | Csimpl; group_radicals; C_field; lca. 45 | Qed. 46 | 47 | Lemma Z_4_1_0_semantics : Z_semantics 4 1 0 = make_WF 48 | (list2D_to_matrix 49 | [[C1;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0]; 50 | [C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0; 51 | C1]]). 52 | Proof. 53 | prep_matrix_equivalence. 54 | rewrite make_WF_equiv. 55 | by_cell; [reflexivity..|]. 56 | rewrite Cexp_0. 57 | reflexivity. 58 | Qed. 59 | 60 | 61 | Lemma zx_triangle_semantics_alt : ⟦ ▷ ⟧ = 62 | make_WF (list2D_to_matrix [[C1;C0];[C1;C1]]). 63 | Proof. 64 | rewrite zx_triangle_semantics. 65 | prep_matrix_equivalence. 66 | rewrite make_WF_equiv. 67 | by_cell; autounfold with U_db; cbn; lca. 68 | Qed. 69 | 70 | Lemma zx_left_triangle_semantics_alt : ⟦ ◁ ⟧ = 71 | make_WF (list2D_to_matrix [[C1;C1];[C0;C1]]). 72 | Proof. 73 | change zx_triangle_left with (▷ ⊤%ZX). 74 | rewrite semantics_transpose_comm. 75 | rewrite zx_triangle_semantics_alt. 76 | prep_matrix_equivalence. 77 | by_cell; reflexivity. 78 | Qed. 79 | 80 | 81 | Lemma X_semantics_0_1 β : 82 | X_semantics 0 1 β = 83 | ((C1 + Cexp β)/√2 .* qubit0 .+ (C1 - Cexp β)/√2 .* qubit1)%M. 84 | Proof. 85 | change (_ = ?x) with (⟦ ⊙ (Z 0 1 β) ⟧ = x). 86 | rewrite colorswap_is_bihadamard. 87 | cbn [n_stack1]. 88 | prep_matrix_equivalence. 89 | cbn. 90 | rewrite kron_1_r, Mmult_1_r by 91 | (apply WF_mult; [auto_wf | apply (@WF_Z_semantics 0 1)]). 92 | unfold Mplus, scale; 93 | by_cell; cbn; lca. 94 | Qed. -------------------------------------------------------------------------------- /src/Ingest/ZXPad.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData. 2 | Require Import CoreRules. 3 | 4 | (** Results about padding ZX-diagrams *) 5 | 6 | Definition pad_bot {n m} pad (zx : ZX n m) : ZX (n + pad) (m + pad) := zx ↕ (n_wire pad). 7 | 8 | Definition pad_top {n m} pad (zx : ZX n m) : ZX (pad + n) (pad + m) := (n_wire pad) ↕ zx. 9 | 10 | Definition pad_bot_1 {n m} (zx : ZX n m) : ZX (S n) (S m) := cast _ _ (eq_sym (Nat.add_1_r n)) (eq_sym (Nat.add_1_r m)) (pad_bot 1 zx). 11 | 12 | Notation padbt zx := (pad_bot _ (pad_top _ zx)). 13 | Notation padtb zx := (pad_top _ (pad_bot _ zx)). 14 | 15 | Lemma pad_top_contract : forall {n m} (zx : ZX n m) pad1 pad2 prfn prfm, 16 | pad_top pad1 (pad_top pad2 zx) ∝= cast (pad1 + (pad2 + n)) (pad1 + (pad2 + m)) prfn prfm (pad_top (pad1 + pad2) zx). 17 | Proof. 18 | intros. 19 | unfold pad_top. 20 | rewrite stack_assoc_back. 21 | simpl_casts. 22 | bundle_wires. 23 | easy. 24 | Unshelve. 25 | all: lia. 26 | Qed. 27 | 28 | Lemma pad_bot_1_simpl : forall {n m} (zx : ZX n m) prfn prfm, 29 | pad_bot 1 zx ∝= cast _ _ prfn prfm (pad_bot_1 zx). 30 | Proof. 31 | intros. 32 | unfold pad_bot_1. 33 | simpl_casts. 34 | easy. 35 | Qed. 36 | 37 | Lemma pad_bot_contract : forall {n m} (zx : ZX n m) pad1 pad2 prfn prfm, pad_bot pad2 (pad_bot pad1 zx) ∝= cast (n + pad1 + pad2) (m + pad1 + pad2) prfn prfm (pad_bot (pad1 + pad2) zx). 38 | Proof. 39 | intros. 40 | unfold pad_bot. 41 | rewrite stack_assoc. 42 | simpl_casts. 43 | bundle_wires. 44 | easy. 45 | Unshelve. 46 | all: lia. 47 | Qed. 48 | 49 | Lemma pad_top_bot_comm : forall {n m} (zx : ZX n m) padT padB prfn prfm, 50 | (pad_top padT (pad_bot padB zx)) ∝= cast (padT + (n + padB)) (padT + (m + padB)) prfn prfm (pad_bot padB (pad_top padT zx)). 51 | Proof. 52 | intros. 53 | unfold pad_top, pad_bot. 54 | rewrite stack_assoc_back. 55 | simpl_casts. 56 | easy. 57 | Unshelve. 58 | all: lia. 59 | Qed. 60 | 61 | 62 | Lemma pad_bot_top_comm : forall {n m} (zx : ZX n m) padT padB prfn prfm, 63 | (pad_bot padB (pad_top padT zx)) ∝= cast (padT + n + padB) (padT + m + padB) prfn prfm (pad_top padT (pad_bot padB zx)). 64 | Proof. 65 | intros. 66 | unfold pad_top, pad_bot. 67 | rewrite stack_assoc. 68 | simpl_casts. 69 | easy. 70 | Unshelve. 71 | all: lia. 72 | Qed. 73 | 74 | Lemma pad_top_bot_semantics : forall {n m} (zx : ZX n m) padT padB, ⟦ pad_top padT (pad_bot padB zx) ⟧ = I (2 ^ padT) ⊗ (⟦ zx ⟧) ⊗ I (2 ^ padB). 75 | Proof. 76 | intros. simpl. rewrite 2 n_wire_semantics. rewrite kron_assoc; auto with wf_db. 77 | Qed. 78 | 79 | Lemma pad_bot_top_semantics : forall {n m} (zx : ZX n m) padT padB, ⟦ pad_bot padB (pad_top padT zx) ⟧ = I (2 ^ padT) ⊗ (⟦ zx ⟧) ⊗ I (2 ^ padB). 80 | Proof. 81 | intros. simpl. rewrite 2 n_wire_semantics. easy. 82 | Qed. -------------------------------------------------------------------------------- /src/CoreRules/ComposeRules.v: -------------------------------------------------------------------------------- 1 | Require Export CoreData.CoreData. 2 | Require Import CastRules. 3 | Require Import SpiderInduction. 4 | 5 | Local Open Scope ZX_scope. 6 | 7 | (** Rules for manipulating compositions *) 8 | 9 | Lemma compose_assoc : forall {n m0 m1 o} 10 | (zx1 : ZX n m0) (zx2 : ZX m0 m1) (zx3 : ZX m1 o), 11 | zx1 ⟷ zx2 ⟷ zx3 ∝= zx1 ⟷ (zx2 ⟷ zx3). 12 | Proof. 13 | intros. 14 | symmetry. 15 | exact (Mmult_assoc _ _ _). 16 | Qed. 17 | 18 | (* Distributivity *) 19 | 20 | Lemma stack_compose_distr : 21 | forall {n1 m1 o2 n3 m2 o4} 22 | (zx1 : ZX n1 m1) (zx2 : ZX m1 o2) (zx3 : ZX n3 m2) (zx4 : ZX m2 o4), 23 | (zx1 ⟷ zx2) ↕ (zx3 ⟷ zx4) ∝= (zx1 ↕ zx3) ⟷ (zx2 ↕ zx4). 24 | Proof. 25 | intros. 26 | symmetry. 27 | unfold proportional_by_1. 28 | cbn. 29 | restore_dims. 30 | exact (kron_mixed_product _ _ _ _). 31 | Qed. 32 | 33 | Lemma compose_simplify_eq : forall {n m o} 34 | (zx1 zx3 : ZX n m) (zx2 zx4 : ZX m o), 35 | zx1 ∝= zx3 -> zx2 ∝= zx4 -> zx1 ⟷ zx2 ∝= zx3 ⟷ zx4. 36 | Proof. 37 | now intros * -> ->. 38 | Qed. 39 | 40 | Lemma compose_simplify : forall {n m o} 41 | (zx1 zx3 : ZX n m) (zx2 zx4 : ZX m o), 42 | zx1 ∝ zx3 -> zx2 ∝ zx4 -> zx1 ⟷ zx2 ∝ zx3 ⟷ zx4. 43 | Proof. 44 | now intros * -> ->. 45 | Qed. 46 | 47 | 48 | Lemma compose_transpose_eq : forall {n m o} (zx1 : ZX n m) (zx2 : ZX m o), 49 | (zx1 ⟷ zx2) ⊤ = (zx2⊤ ⟷ zx1⊤). 50 | Proof. 51 | reflexivity. 52 | Qed. 53 | 54 | Lemma compose_transpose : forall {n m o} (zx1 : ZX n m) (zx2 : ZX m o), 55 | (zx1 ⟷ zx2) ⊤ ∝= (zx2⊤ ⟷ zx1⊤). 56 | Proof. 57 | reflexivity. 58 | Qed. 59 | 60 | (* Empty diagram removal *) 61 | 62 | 63 | Lemma compose_empty_r : forall {nIn} (zx : ZX nIn 0), 64 | zx ⟷ ⦰ ∝= zx. 65 | Proof. 66 | intros. 67 | apply (Mmult_1_l _ _). 68 | auto_wf. 69 | Qed. 70 | 71 | Lemma compose_empty_l : forall {nOut} (zx : ZX 0 nOut), 72 | ⦰ ⟷ zx ∝= zx. 73 | Proof. 74 | intros. 75 | apply (Mmult_1_r _ _). 76 | auto_wf. 77 | Qed. 78 | 79 | Lemma nwire_removal_l: forall {n nOut} (zx : ZX n nOut), 80 | n_wire n ⟷ zx ∝= zx. 81 | Proof. 82 | intros. 83 | unfold proportional_by_1. 84 | cbn. 85 | now rewrite n_wire_semantics, Mmult_1_r by auto_wf. 86 | Qed. 87 | 88 | Lemma nwire_removal_r: forall {n nIn} (zx : ZX nIn n), zx ⟷ n_wire n ∝= zx. 89 | Proof. 90 | intros. 91 | unfold proportional_by_1. 92 | cbn. 93 | now rewrite n_wire_semantics, Mmult_1_l by auto_wf. 94 | Qed. 95 | 96 | Lemma wire_removal_l : forall {nOut} (zx : ZX 1 nOut), — ⟷ zx ∝= zx. 97 | Proof. 98 | intros. 99 | apply (Mmult_1_r _ _). 100 | auto_wf. 101 | Qed. 102 | 103 | Lemma wire_removal_r : forall {nIn} (zx : ZX nIn 1), zx ⟷ — ∝= zx. 104 | Proof. 105 | intros. 106 | apply (Mmult_1_l _ _). 107 | auto_wf. 108 | Qed. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/coq,emacs,macos,windows 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=coq,emacs,macos,windows 4 | 5 | ### Coq ### 6 | .*.aux 7 | .*.d 8 | *.a 9 | *.cma 10 | *.cmi 11 | *.cmo 12 | *.cmx 13 | *.cmxa 14 | *.cmxs 15 | *.glob 16 | *.ml.d 17 | *.ml4.d 18 | *.mlg.d 19 | *.mli.d 20 | *.mllib.d 21 | *.mlpack.d 22 | *.native 23 | *.o 24 | *.v.d 25 | *.vio 26 | *.vo 27 | *.vok 28 | *.vos 29 | .coq-native 30 | .csdp.cache 31 | .lia.cache 32 | .nia.cache 33 | .nlia.cache 34 | .nra.cache 35 | csdp.cache 36 | lia.cache 37 | nia.cache 38 | nlia.cache 39 | nra.cache 40 | native_compute_profile_*.data 41 | 42 | # generated timing files 43 | *.timing.diff 44 | *.v.after-timing 45 | *.v.before-timing 46 | *.v.timing 47 | time-of-build-after.log 48 | time-of-build-before.log 49 | time-of-build-both.log 50 | time-of-build-pretty.log 51 | 52 | ### Emacs ### 53 | # -*- mode: gitignore; -*- 54 | *~ 55 | \#*\# 56 | /.emacs.desktop 57 | /.emacs.desktop.lock 58 | *.elc 59 | auto-save-list 60 | tramp 61 | .\#* 62 | 63 | # Org-mode 64 | .org-id-locations 65 | *_archive 66 | 67 | # flymake-mode 68 | *_flymake.* 69 | 70 | # eshell files 71 | /eshell/history 72 | /eshell/lastdir 73 | 74 | # elpa packages 75 | /elpa/ 76 | 77 | # reftex files 78 | *.rel 79 | 80 | # AUCTeX auto folder 81 | /auto/ 82 | 83 | # cask packages 84 | .cask/ 85 | dist/ 86 | 87 | # Flycheck 88 | flycheck_*.el 89 | 90 | # server auth directory 91 | /server/ 92 | 93 | # projectiles files 94 | .projectile 95 | 96 | # directory configuration 97 | .dir-locals.el 98 | 99 | # network security 100 | /network-security.data 101 | 102 | 103 | ### macOS ### 104 | # General 105 | .DS_Store 106 | .AppleDouble 107 | .LSOverride 108 | 109 | # Icon must end with two \r 110 | Icon 111 | 112 | 113 | # Thumbnails 114 | ._* 115 | 116 | # Files that might appear in the root of a volume 117 | .DocumentRevisions-V100 118 | .fseventsd 119 | .Spotlight-V100 120 | .TemporaryItems 121 | .Trashes 122 | .VolumeIcon.icns 123 | .com.apple.timemachine.donotpresent 124 | 125 | # Directories potentially created on remote AFP share 126 | .AppleDB 127 | .AppleDesktop 128 | Network Trash Folder 129 | Temporary Items 130 | .apdisk 131 | 132 | ### Windows ### 133 | # Windows thumbnail cache files 134 | Thumbs.db 135 | Thumbs.db:encryptable 136 | ehthumbs.db 137 | ehthumbs_vista.db 138 | 139 | # Dump file 140 | *.stackdump 141 | 142 | # Folder config file 143 | [Dd]esktop.ini 144 | 145 | # Recycle Bin used on file shares 146 | $RECYCLE.BIN/ 147 | 148 | # Windows Installer files 149 | *.cab 150 | *.msi 151 | *.msix 152 | *.msm 153 | *.msp 154 | 155 | # Windows shortcuts 156 | *.lnk 157 | 158 | # End of https://www.toptal.com/developers/gitignore/api/coq,emacs,macos,windows 159 | 160 | _build 161 | 162 | settings.json -------------------------------------------------------------------------------- /src/CoreData/States.v: -------------------------------------------------------------------------------- 1 | Require Export ZXCore Proportional. 2 | Require Import CapCup Gadgets. 3 | 4 | (** Definitions about states, i.e. [ZX 0 n]'s, including the 5 | process-state (Choi-Jamiolchosky) isomorphism *) 6 | 7 | (* The Choi-Jamiolchosky isomorphism *) 8 | 9 | Definition proc_to_state {n m} (zx : ZX n m) : ZX 0 (n + m) := 10 | n_cap n ⟷ (n_wire n ↕ zx). 11 | 12 | Definition state_to_proc {n m} (zx : ZX 0 (n + m)) : ZX n m := 13 | cast _ _ (eq_sym (Nat.add_0_r _)) 14 | (eq_sym (Nat.add_assoc _ _ _)) 15 | (n_wire n ↕ zx) ⟷ (n_cup n ↕ n_wire m). 16 | 17 | Import Setoid. 18 | 19 | Add Parametric Morphism {n m} : (@proc_to_state n m) 20 | with signature proportional_by_1 ==> proportional_by_1 as proc_to_state_mor. 21 | Proof. 22 | unfold proc_to_state. 23 | now intros czx czx' ->. 24 | Qed. 25 | 26 | Add Parametric Morphism {n m} : (@state_to_proc n m) 27 | with signature proportional_by_1 ==> proportional_by_1 as state_to_proc_mor. 28 | Proof. 29 | unfold state_to_proc. 30 | now intros czx czx' ->. 31 | Qed. 32 | 33 | 34 | (** The zero state |0⟩ *) 35 | Definition state_0 : ZX 0 1 := zx_invsqrt2 ↕ X 0 1 0. 36 | 37 | Lemma state_0_defn' : 38 | state_0 = zx_invsqrt2 ↕ X 0 1 0. 39 | Proof. reflexivity. Qed. 40 | 41 | (* Don't want this to reduce, ever. *) 42 | Global Opaque state_0. 43 | 44 | (** The one state |a⟩ *) 45 | Definition state_1 : ZX 0 1 := zx_invsqrt2 ↕ X 0 1 PI. 46 | 47 | Lemma state_1_defn' : 48 | state_1 = zx_invsqrt2 ↕ X 0 1 PI. 49 | Proof. reflexivity. Qed. 50 | 51 | (* Don't want this to reduce, ever. *) 52 | Global Opaque state_1. 53 | 54 | (** The plus state |+⟩ *) 55 | Definition state_plus : ZX 0 1 := zx_invsqrt2 ↕ Z 0 1 0. 56 | 57 | Lemma state_plus_defn' : 58 | state_plus = zx_invsqrt2 ↕ Z 0 1 0. 59 | Proof. reflexivity. Qed. 60 | 61 | (* Don't want this to reduce, ever. *) 62 | Global Opaque state_plus. 63 | 64 | (** The minus state |-⟩ *) 65 | Definition state_minus : ZX 0 1 := zx_invsqrt2 ↕ Z 0 1 PI. 66 | 67 | Lemma state_minus_defn' : 68 | state_minus = zx_invsqrt2 ↕ Z 0 1 PI. 69 | Proof. reflexivity. Qed. 70 | 71 | (* Don't want this to reduce, ever. *) 72 | Global Opaque state_minus. 73 | 74 | 75 | (** The zero-or-one state | Nat.b2n b ⟩ *) 76 | Definition state_b (b : bool) := if b then state_1 else state_0. 77 | 78 | Lemma state_b_defn' b : state_b b = 79 | zx_invsqrt2 ↕ X 0 1 (if b then PI else 0). 80 | Proof. 81 | unfold state_b. 82 | rewrite state_0_defn', state_1_defn'. 83 | now destruct b. 84 | Qed. 85 | 86 | (** The state |f 0, f 1, ..., f (n-1)⟩ *) 87 | Fixpoint f_to_state n (f : nat -> bool) : ZX 0 n := 88 | match n with 89 | | 0 => ⦰ 90 | | S n' => state_b (f O) ↕ f_to_state n' (fun i => f (1 + i)%nat) 91 | end. 92 | 93 | 94 | 95 | (** The uniform state [∑ x, |x⟩ = [1, 1, ..., 1]⊤] *) 96 | Definition uniform_state n : ZX 0 n := 97 | cast _ _ (eq_sym (Nat.mul_0_r _)) (eq_sym (Nat.mul_1_r _)) 98 | (n_stack n (Z 0 1 0)). -------------------------------------------------------------------------------- /src/CoreRules/CoreAutomation.v: -------------------------------------------------------------------------------- 1 | Require Import ComposeRules. 2 | Require Import CastRules. 3 | Require Import StackRules. 4 | Require Import WireRules. 5 | Require Import StackComposeRules. 6 | 7 | (** Combine stacks of [n_wire] and [—] ([Wire]), restoring 8 | [n_wire 1] to [—] at the end. *) 9 | Ltac bundle_wires := 10 | rewrite ?wire_to_n_wire, ?n_wire_stack, <- 1?wire_to_n_wire. 11 | 12 | #[export] Hint Rewrite 13 | (fun n => @compose_empty_l n) 14 | (fun n => @compose_empty_r n) 15 | (fun n => @stack_empty_l n) 16 | (fun n => @stack_empty_r n) 17 | (fun n => @nwire_removal_l n) 18 | (fun n => @nwire_removal_r n) 19 | @wire_removal_l 20 | @wire_removal_r 21 | X_0_is_wire 22 | Z_0_is_wire 23 | box_compose 24 | (fun n m o p => @nwire_stack_compose_topleft n m o p) 25 | (fun n m o p => @nwire_stack_compose_botleft n m o p) 26 | : cleanup_zx_db. 27 | 28 | (** Simplify the goal by [autorewrite with cleanup_zx_db], solving 29 | as many side-conditions as possible with [lia]. *) 30 | Ltac cleanup_zx := auto_cast_eqn (autorewrite with cleanup_zx_db). 31 | 32 | #[export] Hint Rewrite 33 | (fun n m o p => @cast_colorswap n m o p) 34 | (fun n => @n_wire_colorswap n) 35 | (fun n => @nstack1_colorswap n) 36 | (fun n m o => @nstack_colorswap n m o) 37 | : colorswap_db. 38 | 39 | #[export] Hint Rewrite 40 | (fun n m o p => @cast_transpose n m o p) 41 | (fun n => @n_wire_transpose n) 42 | (fun n => @nstack1_transpose n) 43 | (fun n => @nstack_transpose n) 44 | : transpose_db. 45 | 46 | #[export] Hint Rewrite 47 | (fun n m o p => @cast_adj n m o p) 48 | : adjoint_db. 49 | 50 | (** Solve the goal by showing it is the transpose of the term/lemma [H]. 51 | Specifically, transposes the goal, e.g. by applying [transpose_digrams], 52 | simplifies by [autorewrite with transpose_db] and [simpl], and applies [H]. *) 53 | Ltac transpose_of H := 54 | intros; 55 | first [apply transpose_diagrams 56 | | apply transpose_diagrams_by 57 | | apply transpose_diagrams_eq 58 | | apply transpose_zx]; 59 | repeat (simpl; autorewrite with transpose_db); 60 | apply H. 61 | 62 | (** Solve the goal by showing it is the adjoint of the term [H]. 63 | Specifically, adjoints the goal, e.g. by applying [adjoint_digrams], 64 | simplifies by [autorewrite with adjoint_db] and [simpl], and applies [H]. *) 65 | Ltac adjoint_of H := 66 | intros; 67 | first [apply adjoint_diagrams 68 | | apply adjoint_diagrams_by 69 | | apply adjoint_diagrams_eq 70 | | apply adjoint_zx]; 71 | repeat (simpl; autorewrite with adjoint_db); 72 | apply H. 73 | 74 | (** Solve the goal by showing it is the colorswap of the term [H]. 75 | Specifically, colorswaps the goal, e.g. by applying [colorswap_digrams], 76 | simplifies by [autorewrite with colorswap_db] and [simpl], and applies [H]. *) 77 | Ltac colorswap_of H := 78 | intros; 79 | first [apply colorswap_diagrams 80 | | apply colorswap_diagrams_by 81 | | apply colorswap_diagrams_eq 82 | | apply colorswap_zx]; 83 | repeat (simpl; autorewrite with colorswap_db); 84 | apply H. 85 | -------------------------------------------------------------------------------- /src/CoreRules/ScalarSemanticsComp.v: -------------------------------------------------------------------------------- 1 | Require Import SemanticsComp CoreData GadgetRules ComposeRules CoreAutomation. 2 | 3 | (** Various computational results about explicit ZX-diagrams, using scalars *) 4 | 5 | 6 | Lemma Z_0_2_semantics α : 7 | Z_semantics 0 2 α = make_WF (list2D_to_matrix [[C1];[C0];[C0];[Cexp α]]). 8 | Proof. 9 | prep_matrix_equivalence. 10 | rewrite make_WF_equiv. 11 | by_cell; reflexivity. 12 | Qed. 13 | 14 | Lemma X_2_1_0_semantics : X_semantics 2 1 0 = 15 | make_WF (list2D_to_matrix [[/√2;C0;C0;/√2];[C0;/√2;/√2;C0]]). 16 | Proof. 17 | rewrite X_semantics_equiv. 18 | cbn. 19 | rewrite 4 kron_1_l, Cexp_0, Mscale_1_l by auto_wf. 20 | prep_matrix_equivalence. 21 | rewrite make_WF_equiv. 22 | unfold xbasis_plus, xbasis_minus, braplus, braminus; 23 | autounfold with U_db; cbn; by_cell_no_intros; cbn; 24 | Csimpl; group_radicals; C_field; lca. 25 | Qed. 26 | 27 | Lemma Z_4_1_0_semantics : Z_semantics 4 1 0 = make_WF 28 | (list2D_to_matrix 29 | [[C1;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0]; 30 | [C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0;C0; 31 | C1]]). 32 | Proof. 33 | prep_matrix_equivalence. 34 | rewrite make_WF_equiv. 35 | by_cell; [reflexivity..|]. 36 | rewrite Cexp_0. 37 | reflexivity. 38 | Qed. 39 | 40 | 41 | Lemma hopf_Z_X_rule_base : Z 1 2 0 ⟷ X 2 1 0 ∝= /2 .* (Z 1 0 0 ⟷ X 0 1 0). 42 | Proof. 43 | prep_matrix_equivalence. 44 | rewrite zx_scale_semantics. 45 | cbn. 46 | rewrite X_2_1_0_semantics. 47 | compute_matrix (Z_semantics 1 2 0). 48 | rewrite Cexp_0. 49 | compute_matrix (X_semantics 0 1 0). 50 | rewrite kron_1_l, Cexp_0, 2 Cmult_1_r by auto_wf. 51 | unfold hadamard. 52 | rewrite Cplus_opp_r. 53 | replace (C1 / √ 2 + C1 / √2) with (RtoC (√2)) by (C_field; lca). 54 | compute_matrix (Z_semantics 1 0 0). 55 | rewrite Cexp_0. 56 | rewrite 4 make_WF_equiv. 57 | by_cell; unfold list2D_to_matrix, scale; cbn; Csimpl; C_field. 58 | Qed. 59 | 60 | 61 | 62 | Lemma hopf_Z_X_rule_base_phase α β : Z 1 2 α ⟷ X 2 1 β ∝= 63 | /2 .* (Z 1 0 α ⟷ X 0 1 β). 64 | Proof. 65 | rewrite <- (Rplus_0_r α) at 1. 66 | rewrite <- Z_spider_1_1_fusion. 67 | rewrite <- (Rplus_0_l β) at 1. 68 | rewrite <- X_spider_1_1_fusion. 69 | rewrite compose_assoc, <- (compose_assoc (Z 1 2 0)). 70 | rewrite hopf_Z_X_rule_base. 71 | distribute_zxscale. 72 | rewrite compose_assoc. 73 | rewrite X_spider_1_1_fusion, <- compose_assoc, Z_spider_1_1_fusion. 74 | rewrite Rplus_0_r, Rplus_0_l. 75 | reflexivity. 76 | Qed. 77 | 78 | 79 | Lemma hopf_X_Z_rule_base : X 1 2 0 ⟷ Z 2 1 0 ∝= /2 .* (X 1 0 0 ⟷ Z 0 1 0). 80 | Proof. 81 | colorswap_of (hopf_Z_X_rule_base). 82 | Qed. 83 | 84 | 85 | Lemma hopf_X_Z_rule_base_phase α β : X 1 2 α ⟷ Z 2 1 β ∝= 86 | /2 .* (X 1 0 α ⟷ Z 0 1 β). 87 | Proof. 88 | colorswap_of (hopf_Z_X_rule_base_phase α β). 89 | Qed. 90 | 91 | 92 | Lemma Z_0_1_copy β : Z 0 1 0 ⟷ X 1 1 β ∝= Z 0 1 0. 93 | Proof. 94 | prep_matrix_equivalence. 95 | by_cell; cbn; unfold kron, hadamard; cbn; 96 | rewrite Cexp_0; C_field; lca. 97 | Qed. 98 | 99 | Lemma X_0_1_copy β : X 0 1 0 ⟷ Z 1 1 β ∝= X 0 1 0. 100 | Proof. 101 | colorswap_of (Z_0_1_copy β). 102 | Qed. 103 | 104 | (* @nocheck name *) 105 | Lemma X_0_2_PI_mult_l_to_sum (u v : Matrix 1 2) : WF_Matrix u -> WF_Matrix v -> 106 | u ⊗ v × ⟦ X 0 2 PI ⟧ = 107 | (u × e_i 1 × (v × e_i 0) .+ v × e_i 1 × (u × e_i 0))%M. 108 | Proof. 109 | intros Hu Hv. 110 | prep_matrix_equivalence. 111 | rewrite <- 4 matrix_by_basis by lia. 112 | by_cell. 113 | cbn; 114 | unfold kron, hadamard, Mplus; cbn; Csimpl; 115 | rewrite Cexp_PI'; 116 | C_field; lca. 117 | Qed. -------------------------------------------------------------------------------- /src/Examples/Teleportation.v: -------------------------------------------------------------------------------- 1 | From VyZX Require Import GateDefinitions ZXCore CoreRules Bell. 2 | 3 | Definition bell_state_prep := 4 | (((X 0 1 0) ↕ (X 0 1 0)) ⟷ (□ ↕ —) ⟷ 5 | ((Z 1 2 0 ↕ —) ⟷ (— ↕ X 2 1 0))). 6 | 7 | Definition bell_measurement (a b : nat) := 8 | (_CNOT_ ⟷ (((Z 1 0 ((INR a) * PI))) ↕ (X 1 0 ((INR b) * PI)))). 9 | 10 | Lemma bell_measurement_eq : forall a b, 11 | bell_measurement a b ∝= (Z 1 1 (INR a * PI) ⟷ X 1 1 (INR b * PI)) ↕ — ⟷ ⊃. 12 | Proof. 13 | intros; unfold bell_measurement. 14 | unfold bell_measurement. 15 | rewrite compose_assoc. 16 | rewrite <- (stack_compose_distr Wire (Z 1 0 _) (X 2 1 0)). 17 | rewrite X_spider_1_1_fusion. 18 | rewrite wire_removal_l. 19 | rewrite Rplus_0_l. 20 | assert (H : ((Z 1 0 (INR a * PI) ↕ X 2 0 (INR b * PI))) ∝= 21 | (((Z 1 0 (INR a * PI) ↕ — ↕ —) ⟷ (X 2 0 (INR b * PI))))). 22 | { rewrite stack_assoc. 23 | simpl_casts. 24 | rewrite <- (stack_empty_l (X 2 0 _)) at 2. 25 | rewrite <- (stack_compose_distr (Z 1 0 _) ⦰ (— ↕ —) (X 2 0 _)). 26 | bundle_wires. 27 | cleanup_zx. 28 | reflexivity. } 29 | rewrite H. 30 | rewrite <- compose_assoc. 31 | rewrite <- stack_compose_distr. 32 | assert (H0 : — ∝= n_wire 1). 33 | { 34 | bundle_wires. 35 | reflexivity. 36 | } 37 | rewrite H0. 38 | rewrite (dominated_Z_spider_fusion_top_left 0 0). 39 | simpl. 40 | cleanup_zx. 41 | replace (INR b * PI)%R with (INR b * PI + 0)%R by lra. 42 | rewrite <- (dominated_X_spider_fusion_top_right 1 0 1 0). 43 | rewrite <- cup_X. 44 | rewrite 2 Rplus_0_r. 45 | rewrite <- compose_assoc. 46 | simpl_casts. 47 | bundle_wires. 48 | rewrite <- (stack_compose_distr (Z 1 1 _) (X 1 1 _) (—) (—)). 49 | cleanup_zx. 50 | reflexivity. 51 | Unshelve. 52 | all:lia. Qed. 53 | 54 | Definition teleportation_2 55 | (a b : nat) := 56 | (— ↕ bell_state_prep) ⟷ ((bell_measurement a b) ↕ 57 | (X 1 1 (INR b * PI) ⟷ (Z 1 1 (INR a * PI)))). 58 | 59 | Lemma yank_l_gen {n m} : forall (zx0 : ZX n 1) (zx1 : ZX 1 m), 60 | (zx0 ↕ ⊂) ⟷ (⊃ ↕ zx1) ∝= cast (n + 0) (0 + m) (Nat.add_0_r n) (eq_refl) (zx0 ⟷ zx1). 61 | Proof. 62 | intros. 63 | rewrite <- (compose_empty_l ⊂). 64 | rewrite <- (wire_removal_r zx0). 65 | rewrite stack_compose_distr. 66 | rewrite <- (compose_empty_r ⊃). 67 | rewrite <- (wire_removal_l zx1). 68 | rewrite stack_compose_distr. 69 | repeat rewrite compose_assoc. 70 | rewrite <- (compose_assoc (— ↕ ⊂)). 71 | rewrite yank_l. 72 | cleanup_zx. 73 | rewrite cast_compose_l. 74 | simpl_casts. 75 | reflexivity. Qed. 76 | 77 | Lemma teleportation_2_correct : forall (a b : bool), teleportation_2 a b ∝= —. 78 | Proof. 79 | intros; unfold teleportation_2. 80 | rewrite bell_measurement_eq. 81 | rewrite bell_state_prep_correct. 82 | rewrite <- (wire_removal_l (X 1 1 _ ⟷ Z 1 1 _)). 83 | rewrite stack_compose_distr. 84 | rewrite stack_assoc. 85 | simpl_casts. 86 | rewrite <- compose_assoc. 87 | rewrite <- (stack_compose_distr — (Z 1 1 _ ⟷ X 1 1 _) ⊂ (— ↕ —)). 88 | rewrite wire_removal_l. 89 | bundle_wires. 90 | cleanup_zx. 91 | rewrite yank_l_gen. 92 | simpl_casts. 93 | repeat rewrite compose_assoc. 94 | rewrite <- (compose_assoc (X 1 1 _) (X 1 1 _) (Z 1 1 _)). 95 | rewrite X_spider_1_1_fusion. 96 | replace (INR b * PI + INR b * PI)%R with (INR b * 2 * PI)%R by lra. 97 | rewrite X_2_PI. 98 | cleanup_zx. 99 | rewrite Z_spider_1_1_fusion. 100 | simpl. 101 | replace (INR a * PI + INR a * PI)%R with (INR a * 2 * PI)%R by lra. 102 | rewrite Z_2_PI. 103 | cleanup_zx. 104 | reflexivity. 105 | Unshelve. 106 | all: lia. 107 | Qed. -------------------------------------------------------------------------------- /src/DiagramRules/Bell.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData. 2 | Require Import CoreRules. 3 | 4 | (** Proof of correctness of bell state preparation and teleportation *) 5 | 6 | Definition bell_state_prep := 7 | (((X 0 1 0) ↕ (X 0 1 0)) ⟷ (□ ↕ —) ⟷ 8 | ((Z 1 2 0 ↕ —) ⟷ (— ↕ X 2 1 0))). 9 | 10 | Lemma bell_state_prep_correct : bell_state_prep ∝= ⊂. 11 | Proof. 12 | unfold bell_state_prep. 13 | rewrite <- stack_compose_distr. 14 | assert (X 0 1 0 ⟷ □ ∝= Z 0 1 0) as H. 15 | { 16 | replace (X 0 1 0) with (⊙ (Z 0 1 0)) at 1 by easy. 17 | rewrite colorswap_is_bihadamard; simpl. 18 | cleanup_zx. rewrite cast_id. 19 | rewrite compose_assoc; cleanup_zx; easy. 20 | } 21 | rewrite H; cleanup_zx. 22 | rewrite <- compose_assoc. 23 | rewrite <- (stack_compose_distr (Z 0 1 0) (Z 1 2 0) (X 0 1 0) —); cleanup_zx. 24 | rewrite Z_spider_1_1_fusion. 25 | rewrite <- nwire_stack_compose_botleft. 26 | rewrite compose_assoc. 27 | rewrite <- (n_wire_stack 1 1); rewrite wire_to_n_wire. 28 | rewrite (stack_assoc (n_wire 1) (n_wire 1)); simpl_casts. 29 | rewrite <- (stack_compose_distr (n_wire 1) (n_wire 1) (n_wire 1 ↕ X 0 1 0)). 30 | rewrite (dominated_X_spider_fusion_bot_right 0 0 1). 31 | cleanup_zx; rewrite cast_id. 32 | rewrite Rplus_0_r; rewrite X_0_is_wire. 33 | bundle_wires; cleanup_zx. 34 | rewrite <- cap_Z. 35 | easy. 36 | Unshelve. 37 | all: reflexivity. 38 | Qed. 39 | 40 | Definition teleportation (a b : nat) := 41 | (⊂ ↕ Z 1 2 0) ⟷ ((X 1 1 (b * PI) ⟷ Z 1 1 (a * PI)) ↕ (((X 2 1 0) ↕ (Z 1 0 (a * PI)) ⟷ (□ ⟷ Z 1 0 (b * PI))))). 42 | 43 | Lemma teleportation_correct : forall a b, teleportation a b ∝= —. 44 | Proof. 45 | intros; unfold teleportation. 46 | assert (□ ⟷ Z 1 0 (b * PI) ∝= (X 1 0 (b * PI))). 47 | { 48 | replace (X 1 0 (b * PI)) with (⊙ (Z 1 0 (b * PI))) by easy. 49 | rewrite colorswap_is_bihadamard. 50 | simpl; cleanup_zx; simpl_casts. 51 | easy. 52 | } 53 | rewrite H. 54 | rewrite (stack_empty_r_back (X 1 0 _)). 55 | rewrite cast_id. 56 | rewrite <- (stack_compose_distr (X 2 1 0) (X 1 0 _) (Z 1 0 _) ⦰). 57 | rewrite X_spider_1_1_fusion. 58 | cleanup_zx. 59 | rewrite (stack_assoc_back (X 1 1 _ ⟷ Z 1 1 _) (X 2 0 _) (Z 1 0 _)). 60 | rewrite cast_id. 61 | rewrite <- (nwire_removal_l (X 2 0 _)). 62 | simpl; rewrite stack_empty_r, cast_id. 63 | rewrite stack_compose_distr. 64 | rewrite (stack_assoc_back (X 1 1 _) — —), cast_id. 65 | rewrite <- (compose_empty_r (Z 1 0 _)). 66 | rewrite stack_compose_distr. 67 | rewrite <- compose_assoc. 68 | rewrite (stack_assoc (X 1 1 _ ↕ —) — (Z 1 0 _)), cast_id. 69 | rewrite <- (stack_compose_distr ⊂ (X 1 1 _ ↕ —) (Z 1 2 0) (— ↕ Z 1 0 _)). 70 | rewrite cap_X. 71 | rewrite wire_to_n_wire at 1 2. 72 | rewrite (dominated_X_spider_fusion_top_left 1 0). 73 | rewrite (dominated_Z_spider_fusion_bot_left 0 0 1). 74 | rewrite <- (nwire_removal_l (Z 1 1 _)). 75 | rewrite <- (nwire_removal_r (X 2 0 _)). 76 | rewrite stack_compose_distr. 77 | replace (0 + b * PI)%R with ((b * PI) + 0 +0)%R by lra. 78 | rewrite (X_add_l 1 1). 79 | rewrite stack_nwire_distribute_l. 80 | rewrite (stack_assoc_back (n_wire 1) (X 1 1 _)). 81 | rewrite stack_empty_r, !cast_id. 82 | rewrite compose_assoc. 83 | rewrite <- (compose_assoc (X 0 (1 + 1) _ ↕ Z 1 (1 + 0) _)). 84 | rewrite <- (stack_compose_distr (X 0 (1 + 1) _) (n_wire 1 ↕ X 1 1 _) 85 | (Z 1 (1 + 0) _) (X 1 1 _)). 86 | rewrite (dominated_X_spider_fusion_bot_left 1 0). 87 | replace ((b * PI + (b * PI + 0)))%R with (b * 2 * PI)%R by lra. 88 | rewrite X_2_PI. 89 | rewrite X_0_is_wire. 90 | rewrite <- (nwire_removal_l (X 0 _ _)). 91 | rewrite <- cap_X, <- cup_X. 92 | rewrite stack_compose_distr. 93 | rewrite <- wire_to_n_wire. 94 | repeat rewrite <- compose_assoc. 95 | rewrite (compose_assoc (n_wire 0 ↕ Z 1 (1 + 0) (a * PI + 0))). 96 | rewrite yank_r. 97 | cleanup_zx. rewrite cast_id. 98 | rewrite Z_spider_1_1_fusion. 99 | replace (a * PI + 0 + a * PI)%R with ((a * 2 * PI))%R by lra. 100 | rewrite Z_2_PI. 101 | rewrite Z_0_is_wire. 102 | easy. 103 | Unshelve. 104 | all: reflexivity. 105 | Qed. -------------------------------------------------------------------------------- /.hooks/Search_validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import os 5 | import sys 6 | 7 | MIN_PYTHON = (3, 10) 8 | if sys.version_info < MIN_PYTHON: 9 | print(f"Your python version is {sys.version_info.major}.{sys.version_info.minor}. {MIN_PYTHON[0]}.{MIN_PYTHON[1]} is required") 10 | exit(3) 11 | 12 | args = sys.argv[1:] 13 | 14 | usage = "./Name_validator.py [--interactive]" 15 | 16 | interactive = False 17 | 18 | b_color_green = '\033[92m' 19 | b_color_yellow = '\033[93m' 20 | b_color_reset = '\033[0m' 21 | 22 | 23 | if len(args) > 1: 24 | print(usage) 25 | exit(2) 26 | 27 | if len(args) == 1: 28 | if args[0] == "--interactive": 29 | interactive = True 30 | else: 31 | print(usage) 32 | exit(2) 33 | 34 | curr_dir = os.path.dirname(os.path.realpath(__file__)) 35 | src_dir = f"{curr_dir}/../src" 36 | 37 | search_commands = "Search|Locate|About|Check|SearchPattern|SearchRewrite|Print" 38 | search_regex = re.compile(f"\\s*({search_commands}).*") 39 | ignore_regex = re.compile("\\s*\\(\\*\\s*\\@nocheck\\s+Search\\s*\\*\\)") 40 | 41 | class Violation: 42 | line_no : int = 0 43 | line : str = "" 44 | file : str = "" 45 | keyword : str = "" 46 | 47 | def __init__(self, line_no : int, line : str, file : str, keyword : str): 48 | self.line = line 49 | self.file = file 50 | self.line_no = line_no 51 | self.keyword = keyword 52 | 53 | def _fmt_file(self) -> str: 54 | prefix, _, postfix = self.file.partition(".hooks/../") # strip going into the hooks directory 55 | return prefix + postfix 56 | 57 | def __str__(self) -> str: 58 | return f"{b_color_yellow}Violation found: \"{self.keyword}\" command should not be committed. {b_color_reset}({self._fmt_file()}:{self.line_no} - {self.line})" 59 | pass 60 | 61 | def remove(self): 62 | with open(self.file, "r") as f: 63 | lines = f.readlines() 64 | del lines[self.line_no - 1] 65 | with open(self.file, "w") as f: 66 | lines = "".join(lines) 67 | f.write(lines) 68 | 69 | def ignore(self): 70 | with open(self.file, "r") as f: 71 | lines = f.readlines() 72 | 73 | lines.insert(self.line_no - 1, "(* @nocheck Search *)\n") 74 | 75 | with open(self.file, "w") as f: 76 | lines = "".join(lines) 77 | f.write(lines) 78 | 79 | def validate_file(file) -> list[Violation]: 80 | violations : list[Violation] = list() 81 | with open(file) as lines: 82 | skip_next = False 83 | for (line_no, line) in enumerate(lines, 1): 84 | if re.match(ignore_regex, line): 85 | skip_next = True 86 | continue 87 | match = re.match(search_regex, line) 88 | if match: 89 | if skip_next: 90 | skip_next = False 91 | continue 92 | violations.append(Violation(line_no, line.strip(), file, match.groups()[0])) 93 | return violations 94 | 95 | 96 | print("Checking src/ directory for any files containing search or print statements...") 97 | all_violations : list[Violation] = list() 98 | 99 | for dir, _, files in os.walk(src_dir): 100 | for file in files: 101 | if not file.endswith(".v"): # Make sure we only look at Coq files 102 | continue 103 | all_violations += validate_file(f"{dir}/{file}") 104 | 105 | 106 | if not all_violations: 107 | print("No violations found") 108 | exit(0) 109 | 110 | num_violations = len(all_violations) 111 | 112 | for (n, violation) in enumerate(all_violations, 1): 113 | print(f"({n}/{num_violations}) {violation}") 114 | if not interactive: 115 | continue 116 | while True: # Do until a valid input comes along 117 | option = input(f"What do you want to do? Remove(R)/Skip(S)/Ignore(I) permanently? ").lower() 118 | if option == "r": 119 | violation.remove() 120 | break 121 | elif option == "i": 122 | violation.ignore() 123 | break 124 | elif option == "s": 125 | break 126 | else: 127 | print("Invalid option...") 128 | 129 | if not interactive: 130 | print(f"{b_color_green}Fix issues by running {os.path.realpath(__file__)} --interactive{b_color_reset}") 131 | 132 | exit(1) -------------------------------------------------------------------------------- /src/CoreData/Swaps.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore. 2 | Require Import StrongInduction. 3 | Require Export QuantumLib.Quantum. 4 | Require Export QuantumLib.Permutations. 5 | 6 | Open Scope ZX_scope. 7 | 8 | (** Definitions about generalized swaps *) 9 | 10 | Fixpoint top_to_bottom_helper (n : nat) : ZX (S n) (S n) := 11 | match n with 12 | | 0 => Wire 13 | | S k => Compose (Stack Swap (n_wire k)) (Stack Wire (top_to_bottom_helper k)) 14 | end. 15 | 16 | Definition top_to_bottom (n : nat) : ZX n n := 17 | match n with 18 | | 0 => Empty 19 | | S k => top_to_bottom_helper k 20 | end. 21 | 22 | Definition bottom_to_top (n : nat) : ZX n n := 23 | (top_to_bottom n)⊤. 24 | 25 | Definition a_swap (n : nat) : ZX n n := 26 | match n with 27 | | 0 => Empty 28 | | S k => bottom_to_top (S k) ⟷ (— ↕ top_to_bottom k) 29 | end. 30 | 31 | (* Arbitrary Swap Semantics *) 32 | 33 | (* A linear mapping which takes | x y1 ... yn > -> | y1 .. yn x > *) 34 | Fixpoint top_wire_to_bottom (n : nat) : Square (2 ^ n) := 35 | match n with 36 | | 0 => I 1 37 | | S k => match k with 38 | | 0 => I 2 39 | | S j => (@Mmult _ (2^n) _) ((I 2) ⊗ (top_wire_to_bottom k)) (swap ⊗ (j ⨂ (I 2))) 40 | end 41 | end. 42 | 43 | Open Scope matrix_scope. 44 | Definition bottom_wire_to_top (n : nat) : Square (2 ^ n) := 45 | (top_wire_to_bottom n)⊤. 46 | 47 | (* Well foundedness of semantics *) 48 | 49 | Lemma WF_top_to_bottom (n : nat) : WF_Matrix (top_wire_to_bottom n). 50 | Proof. 51 | destruct n; try auto with wf_db. 52 | induction n. 53 | - simpl; auto with wf_db. 54 | - simpl. try auto with wf_db. 55 | Qed. 56 | 57 | Global Hint Resolve WF_top_to_bottom : wf_db. 58 | 59 | Lemma WF_bottom_to_top (n : nat) : WF_Matrix (bottom_wire_to_top n). 60 | Proof. unfold bottom_wire_to_top. auto with wf_db. Qed. 61 | 62 | Global Hint Resolve WF_bottom_to_top : wf_db. 63 | 64 | Definition a_swap_semantics (n : nat) : Square (2 ^ n) := 65 | match n with 66 | | 0 => I 1 67 | | S k => (@Mmult _ (2 ^ n) _ ((I 2) ⊗ top_wire_to_bottom (k)) ((bottom_wire_to_top (S k)))) 68 | end. 69 | 70 | Lemma WF_a_swap_semantics (n : nat) : 71 | WF_Matrix (a_swap_semantics n). 72 | Proof. 73 | intros. 74 | unfold a_swap_semantics. 75 | destruct n; auto with wf_db. 76 | Qed. 77 | 78 | Global Hint Resolve WF_a_swap_semantics : wf_db. 79 | 80 | Fixpoint n_swap (n : nat) : ZX n n := 81 | match n with 82 | | 0 => ⦰ 83 | | (S n) => bottom_to_top (S n) ⟷ (— ↕ n_swap n) 84 | end. 85 | 86 | Fixpoint n_swap_mat_ind (n : nat) : Matrix (2 ^ n) (2 ^ n) := 87 | match n with 88 | | 0 => I 1 89 | | 1 => I 2 90 | | S (S n) => @Mmult _ (2 ^ (S (S n))) _ (((I 2) ⊗ n_swap_mat_ind n ⊗ (I 2))) (a_swap_semantics (S (S n))) 91 | end. 92 | 93 | Lemma WF_n_swap_mat_ind : forall n, WF_Matrix (n_swap_mat_ind n). 94 | Proof. 95 | intros. 96 | strong induction n. 97 | do 2 (destruct n; [ simpl; auto with wf_db | ]). 98 | assert (n < (S (S n)))%nat by lia. 99 | specialize (H n H0); clear H0. 100 | simpl. 101 | destruct n. 102 | apply WF_mult. 103 | + apply WF_kron; try lia. 104 | apply WF_kron; try lia. 105 | 1-3: auto with wf_db. 106 | + apply WF_mult; [ auto with wf_db | ]. 107 | replace (2 ^ 0 + (2 ^ 0 + 0) + (2 ^ 0 + (2 ^ 0 + 0) + 0))%nat with (2 ^ 2)%nat by (simpl; lia). 108 | auto with wf_db. 109 | + apply WF_mult; auto with wf_db. 110 | apply WF_mult; auto with wf_db. 111 | replace (2 ^ S n + (2 ^ S n + 0) + (2 ^ S n + (2 ^ S n + 0) + 0))%nat with (2 ^ (S (S (S n))))%nat by (simpl; lia). 112 | auto with wf_db. 113 | Qed. 114 | 115 | Fixpoint n_swap_mat (n : nat) : Matrix (2 ^ n) (2 ^ n) := 116 | match n with 117 | | 0 => I 1 118 | | (S n) => (I 2 ⊗ (n_swap_mat n)) × bottom_wire_to_top (S n) 119 | end. 120 | 121 | Lemma WF_n_swap_mat : forall n, WF_Matrix (n_swap_mat n). 122 | Proof. 123 | intros. 124 | induction n; try auto with wf_db. 125 | simpl. 126 | unfold bottom_wire_to_top. 127 | auto with wf_db. 128 | Qed. 129 | 130 | Lemma b_swap_dim : forall n m, (S n + m = 1 + (n + m))%nat. Proof. lia. Qed. 131 | 132 | Fixpoint b_swap (n m : nat) : ZX (n + m) (n + m) := 133 | match n with 134 | | 0 => (n_wire (0 + m)) 135 | | (S n) => (top_to_bottom (S n + m)) ⟷ (— ↕ (b_swap n m)) 136 | end. 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/Permutations/ZXperm.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore Swaps. 2 | Require Import QuantumLib.Permutations. 3 | 4 | Open Scope ZX_scope. 5 | 6 | (** Definition of ZX-diagrams corresponding to permutations, 7 | as well as computing diagrams corresponding to arbitrary permutations *) 8 | 9 | (* @nocheck name *) 10 | Inductive ZXperm : forall {n m}, ZX n m -> Prop := 11 | | PermEmpty : ZXperm Empty 12 | | PermWire : ZXperm Wire 13 | | PermSwap : ZXperm ⨉ 14 | | PermStack {n0 m0 n1 m1} (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) : 15 | ZXperm zx0 -> ZXperm zx1 -> 16 | ZXperm (zx0 ↕ zx1) 17 | | PermComp {n m o} (zx0 : ZX n m) (zx1 : ZX m o) : 18 | ZXperm zx0 -> ZXperm zx1 -> 19 | ZXperm (zx0 ⟷ zx1). 20 | 21 | 22 | 23 | Fixpoint perm_of_zx {n m} (zx : ZX n m) : (nat -> nat) := 24 | let idn := (fun x : nat => x) in 25 | match zx with 26 | | Empty => idn 27 | | Wire => idn 28 | | Swap => swap_2_perm 29 | | @Compose n m o zx0 zx1 => 30 | ((perm_of_zx zx0) ∘ (perm_of_zx zx1))%prg 31 | | @Stack n0 m0 n1 m1 zx0 zx1 => 32 | stack_perms n0 n1 (perm_of_zx zx0) (perm_of_zx zx1) 33 | (* Fake cases: *) 34 | | Cap => idn 35 | | Cup => idn 36 | | Box => idn 37 | | X_Spider _ _ _ => idn 38 | | Z_Spider _ _ _ => idn 39 | end. 40 | 41 | Notation zxperm_to_matrix n zx := (perm_to_matrix n (perm_of_zx zx)). 42 | 43 | Definition bottom_to_top_perm (n : nat) : nat -> nat := 44 | fun k => if n <=? k then k else 45 | match k with 46 | | 0 => (n - 1)%nat 47 | | S k' => k' 48 | end. 49 | 50 | Definition top_to_bottom_perm (n : nat) : nat -> nat := 51 | fun k => if n <=? k then k else 52 | if k =? (n-1) then 0%nat else (k + 1)%nat. 53 | 54 | Definition a_perm (n : nat) : nat -> nat := 55 | swap_perm 0 (n-1) n. 56 | 57 | Lemma zx_to_bot_pf : forall a n, 58 | n = (n - a + Init.Nat.min a n)%nat. 59 | Proof. intros a n; lia. Qed. 60 | 61 | Definition zx_to_bot (a n : nat) : ZX n n := 62 | cast _ _ (zx_to_bot_pf (n-a) n) (zx_to_bot_pf (n-a) n) 63 | ((n_wire (n - (n-a))) ↕ a_swap (min (n-a) n)). 64 | 65 | Lemma zx_to_bot'_pf a n (H : (a < n)%nat) : 66 | n = (a + (n - a))%nat. 67 | Proof. lia. Qed. 68 | 69 | Definition zx_to_bot' (a n : nat) (H : (a < n)%nat) : ZX n n := 70 | cast _ _ (zx_to_bot'_pf a n H) (zx_to_bot'_pf a n H) 71 | (n_wire a ↕ a_swap (n-a)). 72 | 73 | Fixpoint zx_of_swap_list (l : list nat) : ZX (length l) (length l) := 74 | match l with 75 | | [] as l => cast _ _ eq_refl eq_refl ⦰ 76 | | a::l' => 77 | zx_to_bot a (1+length l') 78 | ⟷ (@cast (1+length l') (1+length l') (length l' + 1) (length l' + 1) 79 | (Nat.add_comm _ _) (Nat.add_comm _ _) (zx_of_swap_list l' ↕ —)) 80 | end. 81 | 82 | Definition zx_of_perm_uncast n f := 83 | zx_of_swap_list (insertion_sort_list n (perm_inv n f)). 84 | 85 | (* Need to prove facts about insertion_sort_list first, but in essence: 86 | 87 | Definition zx_of_perm n f := 88 | $ n, n ::: zx_of_perm_uncast n f $ *) 89 | 90 | 91 | (* Now that we have facts about insertion_sort_list, we can define: *) 92 | 93 | Definition zx_of_perm n f := 94 | cast n n 95 | (eq_sym (length_insertion_sort_list n (perm_inv n f))) 96 | (eq_sym (length_insertion_sort_list n (perm_inv n f))) 97 | (zx_of_perm_uncast n f). 98 | 99 | (* Though redundant with cast, this makes for much better 100 | proof statements, e.g. with compose_zx_of_perm_cast. 101 | Since many of our ZXperms are non-square, this is 102 | a common application. *) 103 | Definition zx_of_perm_cast n m f (H : n = m) : ZX n m := 104 | cast n m eq_refl (eq_sym H) (zx_of_perm n f). 105 | 106 | Arguments zx_of_perm_cast : simpl never. 107 | 108 | Notation "'zx_of_perm_cast' n m f '$'" := 109 | (zx_of_perm_cast n m f _) 110 | (at level 10, n at level 9, m at level 9, f at level 9, 111 | only printing) : ZX_scope. 112 | 113 | 114 | Definition zx_comm p q : (ZX (p + q) (q + p)) := 115 | zx_of_perm_cast (p + q) (q + p) (big_swap_perm q p) (Nat.add_comm p q). 116 | 117 | Arguments zx_comm : simpl never. 118 | 119 | 120 | Definition zx_gap_comm p m q : (ZX (p + m + q) (q + m + p)) := 121 | cast _ _ eq_refl (eq_sym (Nat.add_assoc _ _ _)) 122 | (zx_comm (p + m) q ⟷ (n_wire q ↕ zx_comm p m)). 123 | 124 | Arguments zx_gap_comm : simpl never. 125 | 126 | 127 | Lemma zx_mid_comm_prf {a b c d : nat} : 128 | (a + b + (c + d) = a + (b + c) + d)%nat. 129 | Proof. lia. Qed. 130 | Definition zx_mid_comm n0 n1 m0 m1 : 131 | ZX (n0 + n1 + (m0 + m1)) (n0 + m0 + (n1 + m1)) := 132 | (cast _ _ zx_mid_comm_prf zx_mid_comm_prf 133 | (n_wire _ ↕ zx_comm n1 m0 ↕ n_wire m1)). -------------------------------------------------------------------------------- /src/CoreData/Gadgets.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore Proportional. 2 | 3 | From QuantumLib Require Complex Matrix RealAux Polar. 4 | 5 | Import Setoid. 6 | 7 | (** Results about gadgets, i.e. [ZX 0 0]'s, including a definition 8 | [zx_of_const] giving an arbitrary constant as a gadget *) 9 | 10 | (* There are several functions we don't need or want exposed as 11 | part of the main module, as they are just facts about C. If 12 | they were less ZX-specific, they could go in QuantumLib. *) 13 | Module ScalarC. 14 | 15 | Import Polar Modulus. 16 | 17 | Definition prop_lb (z : C) : nat := 18 | (BinInt.Z.to_nat (Int_part (ln (Cmod z / 2) / ln (√2))%R%C) + 1)%nat. 19 | 20 | (* Decomposition assuming |z| <= 2 *) 21 | Definition small_decomp (z : C) : R * R := 22 | let a := acos ((Cmod z)^2 / 2 - 1) in 23 | (a, get_arg (z / (1 + Cexp a))). 24 | 25 | Definition prop_decomp (z : C) : nat * (R * R) := 26 | (prop_lb z, small_decomp (z / (√2 ^ prop_lb z))). 27 | 28 | End ScalarC. 29 | 30 | (* Some specific values as gadgets *) 31 | 32 | Definition zx_sqrt2 : ZX 0 0 := 33 | Z 0 1 0 ⟷ X 1 0 PI. 34 | Lemma zx_sqrt2_defn : zx_sqrt2 = 35 | Z 0 1 0 ⟷ X 1 0 PI. 36 | Proof. reflexivity. Qed. 37 | (* We don't ever want reduction to unfold zx_sqrt2 *) 38 | #[global] 39 | Opaque zx_sqrt2. 40 | 41 | Definition zx_invsqrt2 : ZX 0 0 := 42 | X 0 3 0 ⟷ Z 3 0 0. 43 | Lemma zx_invsqrt2_defn : zx_invsqrt2 = 44 | X 0 3 0 ⟷ Z 3 0 0. 45 | Proof. reflexivity. Qed. 46 | (* We don't ever want reduction to unfold zx_invsqrt2 *) 47 | #[global] 48 | Opaque zx_invsqrt2. 49 | 50 | Definition zx_half : ZX 0 0 := zx_invsqrt2 ↕ zx_invsqrt2. 51 | Lemma zx_half_defn : zx_half = zx_invsqrt2 ↕ zx_invsqrt2. 52 | Proof. reflexivity. Qed. 53 | (* We don't ever want reduction to unfold zx_half *) 54 | #[global] 55 | Opaque zx_half. 56 | 57 | 58 | Definition zx_two : ZX 0 0 := Z 0 0 0. 59 | Lemma zx_two_defn : zx_two = Z 0 0 0. 60 | Proof. reflexivity. Qed. 61 | (* We don't ever want reduction to unfold zx_two *) 62 | #[global] 63 | Opaque zx_two. 64 | 65 | 66 | Definition zx_cexp (r : R) : ZX 0 0 := 67 | X 0 1 r ⟷ Z 1 0 PI ⟷ zx_invsqrt2. 68 | Lemma zx_cexp_defn (r : R) : zx_cexp r = 69 | X 0 1 r ⟷ Z 1 0 PI ⟷ zx_invsqrt2. 70 | Proof. reflexivity. Qed. 71 | (* We don't ever want reduction to unfold zx_cexp *) 72 | #[global] 73 | Opaque zx_cexp. 74 | 75 | (* Gadget representing √2 ^ n as a diagram *) 76 | Fixpoint zx_nsqrt2 (n : nat) : ZX 0 0 := 77 | match n with 78 | | 0 => Empty 79 | | S n' => zx_sqrt2 ⟷ zx_nsqrt2 n' 80 | end. 81 | 82 | Import ScalarC. 83 | 84 | (* Gadget representing the scalar z as a ZX-diagram *) 85 | Definition zx_of_const (z : C) : ZX 0 0 := 86 | zx_nsqrt2 (fst (prop_decomp z)) ⟷ 87 | Z 0 0 (fst (snd (prop_decomp z))) ⟷ 88 | zx_cexp (snd (snd (prop_decomp z))). 89 | 90 | Lemma zx_of_const_defn (z : C) : zx_of_const z = 91 | zx_nsqrt2 (fst (prop_decomp z)) ⟷ 92 | Z 0 0 (fst (snd (prop_decomp z))) ⟷ 93 | zx_cexp (snd (snd (prop_decomp z))). 94 | Proof. reflexivity. Qed. 95 | (* We don't ever want reduction to unfold zx_of_const *) 96 | #[global] 97 | Opaque zx_of_const. 98 | 99 | (* Get the constant associated to a gadget. We will 100 | show this is an inverse to zx_of_const. *) 101 | Definition const_of_zx (zx : ZX 0 0) : C := 102 | ⟦ zx ⟧ O O. 103 | 104 | Add Parametric Morphism : const_of_zx 105 | with signature proportional_by_1 ==> eq as const_of_zx_mor. 106 | Proof. 107 | intros zx zx' Hzx. 108 | unfold const_of_zx. 109 | now rewrite Hzx. 110 | Qed. 111 | 112 | (* A diagram scaling [zx] by [c], so that [⟦ c.* zx ⟧ = c .* ⟦ zx ⟧] *) 113 | Definition zx_scale {n m} (c : C) (zx : ZX n m) : ZX n m := 114 | zx_of_const c ↕ zx. 115 | 116 | Notation "c '.*' zx" := (zx_scale c zx) 117 | (at level 40, left associativity) : ZX_scope. 118 | 119 | Lemma zx_scale_defn {n m} c (zx : ZX n m) : c .* zx = zx_of_const c ↕ zx. 120 | Proof. reflexivity. Qed. 121 | 122 | Lemma zx_scale_fun_defn : @zx_scale = fun n m c zx => zx_of_const c ↕ zx. 123 | Proof. reflexivity. Qed. 124 | 125 | (* We really don't want zx_scale to reduce, as that'll be messy 126 | (especially with dimensions!) *) 127 | #[global] Opaque zx_scale. 128 | 129 | Add Parametric Morphism {n m} c : (@zx_scale n m c) with signature 130 | proportional_by_1 ==> proportional_by_1 as zx_scale_prop_by_1_mor. 131 | Proof. 132 | rewrite zx_scale_fun_defn. 133 | intros zx0 zx1 ->. 134 | reflexivity. 135 | Qed. 136 | 137 | Add Parametric Morphism {n m} c : (@zx_scale n m c) with signature 138 | proportional ==> proportional as zx_scale_mor. 139 | Proof. 140 | rewrite zx_scale_fun_defn. 141 | intros zx0 zx1 ->. 142 | reflexivity. 143 | Qed. 144 | 145 | 146 | 147 | 148 | (* NB: Can be made effective using [Z 0 0 PI] for [0] *) 149 | (* A diagram representing the zero element *) 150 | Definition zx_zero {n m} : ZX n m := 151 | C0 .* Z n m 0. 152 | 153 | Lemma zx_zero_defn n m : zx_zero = C0 .* Z n m 0. 154 | Proof. 155 | reflexivity. 156 | Qed. 157 | 158 | (* Don't unfold zx_zero *) 159 | Global Opaque zx_zero. 160 | 161 | (* May add this back later *) 162 | (* Notation "0" := zx_zero : ZX_scope. *) -------------------------------------------------------------------------------- /.hooks/Z_X_rules_validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import os 5 | import sys 6 | 7 | 8 | MIN_PYTHON = (3, 10) 9 | if sys.version_info < MIN_PYTHON: 10 | print(f"Your python version is {sys.version_info.major}.{sys.version_info.minor}. {MIN_PYTHON[0]}.{MIN_PYTHON[1]} is required") 11 | exit(3) 12 | 13 | 14 | b_color_yellow = '\033[93m' 15 | b_color_reset = '\033[0m' 16 | 17 | curr_dir = os.path.dirname(os.path.realpath(__file__)) 18 | 19 | Z_rules_file_name = "ZRules.v" 20 | X_rules_file_name = "XRules.v" 21 | ZX_rules_file_name = "ZXRules.v" 22 | 23 | print(f"Checking lemmas in {Z_rules_file_name}, {X_rules_file_name}, and {ZX_rules_file_name} for inconsistencies...") 24 | 25 | Z_rules_file = f"{curr_dir}/../src/CoreRules/{Z_rules_file_name}" 26 | X_rules_file = f"{curr_dir}/../src/CoreRules/{X_rules_file_name}" 27 | ZX_rules_file = f"{curr_dir}/../src/CoreRules/{ZX_rules_file_name}" 28 | 29 | 30 | duals : dict[str, str] = { 'X': 'Z','Z': 'X', 'X_Z': 'Z_X', 'Z_X' : 'X_Z' } 31 | 32 | thm_token = "Theorem|Lemma|Fact|Remark|Corollary|Proposition|Property" 33 | exists_thm_regex = re.compile(f".*({thm_token})\\s*(([a-z]|[A-Z]|_)([a-z]|[A-Z]|_|-|\\d)+)") 34 | 35 | ignore_regex = re.compile("\\s*\\(\\*\\s*\\@nocheck\\s+Z\\_X\\s*\\*\\)") 36 | 37 | def is_ignore(line : str) -> bool: 38 | return re.match(ignore_regex, line) 39 | 40 | def get_theorem(line : str) -> str: 41 | match = re.match(exists_thm_regex, line) 42 | if not match: 43 | return "" 44 | return match.groups()[1] 45 | 46 | def check_qualification(thms : set[str], quals : list[str]) -> list[str]: 47 | violations = list() 48 | for thm in thms: 49 | qual_found = False 50 | for qual in quals: 51 | if f"{qual}_" in thm: 52 | qual_found = True 53 | break 54 | if not qual_found: 55 | violations.append(thm) 56 | return violations 57 | 58 | def check_all_in_other(thms : set[str], other : set[str], qual : str) -> list[str]: 59 | violations = list() 60 | for thm in thms: 61 | if thm.replace(qual + "_", duals[qual] + "_") not in other: 62 | violations.append(thm) 63 | return violations 64 | 65 | def check_Z_X_has_duals(thms : set[str]) -> list[str]: 66 | violations = list() 67 | violations += check_all_in_other(thms, thms, 'Z_X') 68 | violations += check_all_in_other(thms, thms, 'X_Z') 69 | restr_thms = set(filter(lambda thm : 'Z_X' not in thm and 'X_Z' not in thm, thms)) 70 | violations += check_all_in_other(restr_thms, restr_thms, 'Z') 71 | violations += check_all_in_other(restr_thms, restr_thms, 'X') 72 | return violations 73 | 74 | def read_thms(file_str) -> set[str]: 75 | thms = set() 76 | with open(file_str) as rules: 77 | skip_next = False 78 | for line in rules: 79 | if is_ignore(line): 80 | skip_next = True 81 | continue 82 | thm = get_theorem(line) 83 | if skip_next: 84 | skip_next = False 85 | continue 86 | if thm != "": 87 | thms.add(thm) 88 | return thms 89 | 90 | Z_rules_thms : set[str] = read_thms(Z_rules_file) 91 | X_rules_thms : set[str] = read_thms(X_rules_file) 92 | ZX_rules_thms : set[str] = read_thms(ZX_rules_file) 93 | 94 | Z_qual_violation = check_qualification(Z_rules_thms, ['Z']) 95 | X_qual_violation = check_qualification(X_rules_thms, ['X']) 96 | Z_total_violation = check_all_in_other(Z_rules_thms, X_rules_thms, 'Z') 97 | X_total_violation = check_all_in_other(X_rules_thms, Z_rules_thms, 'X') 98 | ZX_qual_violations = check_qualification(ZX_rules_thms, duals.keys()) 99 | ZX_duals_violations = check_Z_X_has_duals(ZX_rules_thms) 100 | 101 | print(b_color_yellow, end='') 102 | for violation in Z_qual_violation: 103 | print(f'The lemma "{violation}" in {Z_rules_file_name} violates the rule that each lemma in this file must be described as a Z lemma (i.e., contain "Z_") - suggestion: Rename to Z_{violation}') 104 | 105 | for violation in X_qual_violation: 106 | print(f'The lemma "{violation}" in {X_rules_file_name} violates the rule that each lemma in this file must be described as an X lemma (i.e., contain "X_") - suggestion: Rename to X_{violation}') 107 | 108 | for violation in Z_total_violation: 109 | if violation not in Z_qual_violation: # Can't find anything if lemma is incorrectly named 110 | print(f'The lemma "{violation}" violates the rule that each lemma in {Z_rules_file_name} must also be in {X_rules_file_name} under the same name up to the change of Z_ to X_') 111 | 112 | for violation in X_total_violation: 113 | if violation not in X_qual_violation: # Can't find anything if lemma is incorrectly named 114 | print(f'The lemma "{violation}" violates the rule that each lemma in {X_rules_file_name} must also be in {Z_rules_file_name} under the same name up to the change of X_ to Z_') 115 | 116 | for violation in ZX_qual_violations: 117 | print(f'The lemma "{violation}" in {ZX_rules_file_name} violates the rule that each lemma in this file must be described as an Z, X, Z_X or X_Z lemma - suggestion: Rename to [Z, X, Z_X or X_Z]_{violation}') 118 | 119 | for violation in ZX_duals_violations: 120 | if violation not in ZX_qual_violations: 121 | print(f'The lemma "{violation}" violates the rule that each lemma in {ZX_rules_file_name} must also have its colorswapped version') 122 | print(b_color_reset, end='') 123 | 124 | all_violations = [Z_qual_violation, X_qual_violation, Z_total_violation, X_total_violation, ZX_qual_violations, ZX_duals_violations] 125 | if not any(all_violations): 126 | print("No violations found...") 127 | exit(0) 128 | 129 | print("Done...") 130 | exit(1) 131 | 132 | -------------------------------------------------------------------------------- /src/Quarantine.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData. 2 | Require Import CoreRules. 3 | Require Import Bialgebra. 4 | Require Import Gates. 5 | 6 | Require Import ZXpermFacts. 7 | 8 | Local Open Scope ZX. 9 | 10 | Lemma swap_self_inverse : ⨉ ⟷ ⨉ ∝= n_wire 2. 11 | Proof. 12 | intros. 13 | by_perm_eq. 14 | Qed. 15 | 16 | (* Needs to be diagrammatic *) 17 | Lemma _3_cnot_swap_is_swap : _3_CNOT_SWAP_ ∝[/ (C2 * √2)] ⨉. 18 | Proof. 19 | set (sqrt2 := √ 2). 20 | (* step 1 *) 21 | (* Set Printing Raw Literals. *) 22 | rewrite cnot_is_swapp_notc at 2. 23 | (* step 2 *) 24 | rewrite compose_assoc, <- (compose_assoc _ _ ⨉), 25 | <- (compose_assoc _ ⨉). 26 | rewrite notc_is_notc_r. 27 | (* step 3 *) 28 | rewrite <- ! (compose_assoc (_ ⟷ ⨉)). 29 | zxrewrite bi_algebra_rule_X_over_Z. 30 | fold sqrt2. 31 | rewrite Cdiv_unfold, Cinv_inv, Cinv_mult_distr. 32 | rewrite <- Cmult_assoc, Cinv_l, Cmult_1_r by (subst sqrt2; nonzero). 33 | (* step 4 *) 34 | rewrite <- !compose_assoc. 35 | rewrite (compose_assoc (_ ↕ —)). 36 | rewrite <- (@stack_compose_distr 1 1 2 2 1 1). 37 | rewrite wire_removal_l, wire_removal_r, 38 | (stack_split_diag (Z 1 2 0) (X 2 1 0)). 39 | rewrite <- compose_assoc. 40 | (* step 5 *) 41 | rewrite <- (n_wire_stack 1 1). 42 | change 2%nat with (1 + 1)%nat. 43 | rewrite stack_assoc_back_fwd, cast_id. 44 | rewrite <- (@stack_compose_distr 1 2 3 1 1 1). 45 | rewrite (@dominated_Z_spider_fusion_top_left 2 0 1 1). 46 | rewrite wire_removal_l. 47 | rewrite stack_assoc_fwd, cast_id. 48 | rewrite (compose_assoc _ _ (—↕X 2 1 _)). 49 | rewrite <- (@stack_compose_distr 1 1 1 3 2 1). 50 | rewrite (@dominated_X_spider_fusion_bot_right 2 0 1 1). 51 | rewrite Rplus_0_r. 52 | cbn [Nat.add]. 53 | (* step 6 *) 54 | rewrite wire_removal_r. 55 | pose proof (hopf_rule_Z_X_vert 1 1 1 1 0 0 eq_refl) as Hrw. 56 | rewrite cast_id in Hrw. 57 | zxrewrite Hrw. 58 | rewrite Cdiv_unfold, Cinv_inv, Cinv_l by nonzero. 59 | (* step 7 *) 60 | rewrite Z_is_wire, X_0_is_wire. 61 | bundle_wires. 62 | rewrite nwire_removal_l. 63 | (* step 8 *) 64 | zxrefl. 65 | Qed. 66 | 67 | Lemma n_stack_1_n_stack : forall {n} (zx : ZX 1 1), (n ↑ zx) ∝= (cast _ _ (eq_sym (Nat.mul_1_r _)) (eq_sym (Nat.mul_1_r _)) (n ⇑ zx)). 68 | Proof. 69 | intros. 70 | unfold eq_rect. 71 | destruct (Nat.mul_1_r n). 72 | induction n. 73 | - reflexivity. 74 | - simpl. 75 | rewrite IHn. 76 | reflexivity. 77 | Qed. 78 | 79 | Lemma n_stack_n_stack_1 : forall {n} (zx : ZX 1 1), (n ⇑ zx) ∝= (cast _ _ (Nat.mul_1_r _) (Nat.mul_1_r _) (n ↑ zx)). 80 | Proof. 81 | intros. 82 | symmetry. 83 | unfold eq_sym. 84 | unfold eq_rect. 85 | destruct (Nat.mul_1_r n). 86 | induction n. 87 | - reflexivity. 88 | - simpl. 89 | rewrite IHn. 90 | reflexivity. 91 | Qed. 92 | 93 | Lemma n_stack1_compose : forall (zx0 zx1 : ZX 1 1) {n}, 94 | n ↑ (zx0 ⟷ zx1) ∝= (n ↑ zx0) ⟷ (n ↑ zx1). 95 | Proof. 96 | intros. 97 | induction n. 98 | - unfold n_stack1. 99 | symmetry. 100 | cleanup_zx. 101 | reflexivity. 102 | - simpl. 103 | rewrite <- (stack_compose_distr zx0 zx1). 104 | rewrite IHn. 105 | reflexivity. 106 | Qed. 107 | 108 | Lemma H_H_is_wire : □ ⟷ □ ∝= —. 109 | Proof. 110 | hnf. 111 | simpl. 112 | rewrite MmultHH. 113 | lma. 114 | Qed. 115 | 116 | Lemma n_H_composition : forall {n}, 117 | (n ↑ □) ⟷ (n ↑ □) ∝= n ↑ —. 118 | Proof. 119 | intros. 120 | rewrite <- n_stack1_compose. 121 | rewrite H_H_is_wire. 122 | reflexivity. 123 | Qed. 124 | 125 | Theorem trivial_cap_cup : 126 | ⊂ ⟷ ⊃ ∝[2] ⦰. 127 | Proof. 128 | split; [|nonzero]. 129 | lma'. 130 | Qed. 131 | 132 | Lemma cap_passthrough : forall (zx : ZX 1 1), 133 | (⊂ ⟷ (zx ↕ —)) ∝= (⊂ ⟷ (— ↕ zx⊤)). 134 | Proof. 135 | intros. 136 | hnf. 137 | simpl. 138 | rewrite semantics_transpose_comm. 139 | Msimpl; simpl. 140 | unfold kron, Mmult, I, list2D_to_matrix, Matrix.transpose. 141 | prep_matrix_equality. 142 | do 4 (try destruct x); do 4 (try destruct y). 143 | all: C_field_simplify; try lca. 144 | assert ((S (S (S (S x))) / 2 185 | (— ↕ zx1) ⟷ ⨉ ∝= ⨉ ⟷ (zx1 ↕ —) -> 186 | (— ↕ (zx0 ⟷ zx1)) ⟷ ⨉ ∝= ⨉ ⟷ ((zx0 ⟷ zx1) ↕ —). 187 | Proof. 188 | intros. 189 | rewrite swap_passthrough_1_1. 190 | reflexivity. 191 | Qed. 192 | 193 | Lemma spiders_commute_through_swap_t : forall (zx0 zx1 : ZX 1 1), 194 | (zx0 ↕ —) ⟷ ⨉ ∝= ⨉ ⟷ (— ↕ zx0) -> 195 | (zx1 ↕ —) ⟷ ⨉ ∝= ⨉ ⟷ (— ↕ zx1) -> 196 | ((zx0 ⟷ zx1) ↕ —) ⟷ ⨉ ∝= ⨉ ⟷ (— ↕ (zx0 ⟷ zx1)). 197 | Proof. 198 | intros. 199 | rewrite swap_passthrough_1_1. 200 | reflexivity. 201 | Qed. 202 | 203 | Lemma n_box_passthrough :forall {nIn nOut} (zx : ZX nIn nOut), 204 | (n_box nIn) ⟷ zx ∝= (⊙ zx ⟷ (n_box nOut)). 205 | Proof. 206 | intros. 207 | hnf. 208 | Msimpl. 209 | simpl. 210 | rewrite semantics_colorswap_comm. 211 | rewrite 2 n_box_semantics. 212 | rewrite Mmult_assoc. 213 | rewrite <- Mmult_assoc. 214 | rewrite kron_n_mult. 215 | rewrite MmultHH. 216 | rewrite kron_n_I. 217 | rewrite Mmult_1_l by auto with wf_db. 218 | easy. 219 | Qed. 220 | 221 | Lemma Z_spider_angle_2pi : forall {nIn nOut} α k, Z_Spider nIn nOut α ∝= (Z_Spider nIn nOut (α + IZR (2 * k) * PI)). 222 | Proof. 223 | intros. 224 | hnf. 225 | unfold ZX_semantics, Z_semantics. 226 | rewrite Cexp_add. 227 | rewrite Cexp_2nPI. 228 | rewrite Cmult_1_r. 229 | Msimpl. 230 | reflexivity. 231 | Qed. 232 | 233 | Lemma X_spider_angle_2pi : forall {nIn nOut} α k, X_Spider nIn nOut α ∝= (X_Spider nIn nOut (α + IZR (2 * k) * PI)). 234 | Proof. intros. colorswap_of (@Z_spider_angle_2pi nIn nOut). Qed. 235 | 236 | Require Import DiagramRules. 237 | -------------------------------------------------------------------------------- /src/CoreData/Controlizer.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore Proportional CapCup Stacks ZXperm States Gadgets ZXperm. 2 | Import Setoid. 3 | 4 | (** Definition of controlizers of diagrams, i.e. controlled 5 | versions of the state corresponding (under Choi-Jamiolchosky) 6 | to a given diagram. These are defined following 7 | https://arxiv.org/abs/2202.11386 *) 8 | 9 | (* [zx] is a controlled scalar ([ZX 0 0]) with value [c] *) 10 | Definition is_controlled_scalar c (zx : ZX 1 0) := 11 | state_0 ⟷ zx ∝= ⦰ /\ 12 | state_1 ⟷ zx ∝= c .* ⦰. 13 | 14 | Add Parametric Morphism c : (@is_controlled_scalar c) with signature 15 | proportional_by_1 ==> iff as is_controlled_scalar_mor. 16 | Proof. 17 | unfold is_controlled_scalar. 18 | now intros ? ? ->. 19 | Qed. 20 | 21 | (* [czx] is some controlled state, i.e. [⟦ czx ⟧ |0⟩] is the uniform state *) 22 | Definition is_controlled_state {n} (czx : ZX 1 n) := 23 | state_0 ⟷ czx ∝= uniform_state n. 24 | 25 | Add Parametric Morphism {n} : (@is_controlled_state n) with signature 26 | proportional_by_1 ==> iff as is_controlled_state_mor. 27 | Proof. 28 | unfold is_controlled_state. 29 | now intros ? ? ->. 30 | Qed. 31 | 32 | (* [czx] is a controlled state such that 33 | [⟦ czx ⟧ |1⟩ = √2 ^ (n + m) .* ⟦ proc_to_state zx ⟧] *) 34 | Definition is_controlized {n m} (zx : ZX n m) (czx : ZX 1 (n + m)) := 35 | is_controlled_state czx /\ 36 | zx ∝= (/√2)^ (n + m) .* 37 | state_to_proc (state_1 ⟷ czx). 38 | 39 | Add Parametric Morphism {n m} : (@is_controlized n m) with signature 40 | proportional_by_1 ==> proportional_by_1 ==> iff as is_controlized_mor. 41 | Proof. 42 | unfold is_controlized. 43 | intros ? ? Hrw ? ? ->. 44 | now rewrite Hrw. 45 | Qed. 46 | 47 | (* Controlizers for various diagrams *) 48 | 49 | 50 | Definition controlled_half : ZX 1 0 := 51 | zx_half ↕ (▷ ⟷ Z 1 0 0). 52 | 53 | 54 | Definition box_controlizer : ZX 1 (1 + 1) := 55 | (Z 1 2 0 ⟷ ((X 1 2 PI ⟷ (Z 1 0 (-(PI/4)) ↕ Z 1 0 (PI/4)) ⟷ 56 | Z 0 0 0) ↕ 57 | (X 1 2 PI ⟷ ((◁ ⟷ Z 1 2 0 ⟷ (— ↕ ◁)) ↕ —) ⟷ 58 | (— ↕ (Z 2 1 0 ⟷ □))))). 59 | 60 | 61 | Definition cupcap_controlizer : ZX 1 2 := 62 | Z 1 2 0 ⟷ ((◁ ⟷ Z 1 0 0 ⟷ X 0 1 0 ⟷ Z 1 0 0) ↕ 63 | (▷ ⟷ X 1 2 PI)). 64 | 65 | Definition swap_controlizer : ZX 1 (2 + 2) := 66 | (Z 1 3 0 ⟷ (Z 0 0 0 ↕ (◁ ⟷ Z 1 0 0) ↕ (◁ ⟷ Z 1 0 0) ↕ 67 | (X 1 1 PI ⟷ Z 1 2 0 ⟷ ((◁ ⟷ X 1 2 0) ↕ (◁ ⟷ X 1 2 0)) 68 | ⟷ (— ↕ (⨉ ↕ — ⟷ (— ↕ ⨉)))) )). 69 | 70 | 71 | Definition X_1_0_controlizer β : ZX 1 (1 + 0) := 72 | (Z 1 2 0 ⟷ ((◁ ⟷ Z 1 0 0) ↕ (X 1 1 PI ⟷ ◁ ⟷ X 1 1 β))). 73 | 74 | Definition X_1_2_controlizer : ZX 1 (1 + 2) := 75 | (Z 1 2 0 ⟷ ((◁ ⟷ Z 1 0 0 ⟷ Z 0 0 0) ↕ (▷ ⟷ X 1 3 PI))). 76 | 77 | Lemma comp_conlzr_prf1 {n m k} : (n + m + (m + k))%nat = (n + (m + m) + k)%nat. 78 | Proof. lia. Qed. 79 | 80 | Lemma comp_conlzr_prf2 {n k} : (n + k)%nat = (n + 0 + k)%nat. 81 | Proof. lia. Qed. 82 | 83 | 84 | 85 | Definition compose_controlizer {n m k} (czx0 : ZX 1 (n + m)) 86 | (czx1 : ZX 1 (m + k)) : 87 | ZX 1 (n + k) := 88 | (/2) ^ m .* 89 | Z 1 2 0 ⟷ (czx0 ↕ czx1) ⟷ 90 | cast _ _ comp_conlzr_prf1 comp_conlzr_prf2 91 | (n_wire n ↕ n_cup m ↕ n_wire k). 92 | 93 | 94 | Definition stack_controlizer {n m k l} (czx0 : ZX 1 (n + m)) 95 | (czx1 : ZX 1 (k + l)) : 96 | ZX 1 ((n + k) + (m + l)) := 97 | Z 1 2 0 ⟷ (czx0 ↕ czx1) ⟷ 98 | invassociator (n + m) k l ⟷ 99 | ((associator n m k 100 | ⟷ (n_wire n ↕ zx_comm m k) 101 | ⟷ invassociator n k m) ↕ n_wire l) ⟷ 102 | associator (n + k) m l. 103 | 104 | 105 | Definition wire_controlizer : ZX 1 (1 + 1) := 106 | compose_controlizer box_controlizer box_controlizer. 107 | 108 | 109 | Definition half_controlizer : ZX 1 (0 + 0) := 110 | (zx_invsqrt2 ↕ zx_invsqrt2) ↕ (▷ ⟷ Z 1 0 0). 111 | 112 | Definition two_controlizer : ZX 1 (0 + 0) := 113 | ◁ ⟷ Z 1 0 0. 114 | 115 | Definition empty_controlizer : ZX 1 0 := 116 | stack_controlizer half_controlizer two_controlizer. 117 | 118 | 119 | Fixpoint n_stack_controlizer {n m} k (czx : ZX 1 (n + m)) : ZX 1 (k * n + k * m) := 120 | match k with 121 | | 0 => empty_controlizer 122 | | S k' => stack_controlizer czx (n_stack_controlizer k' czx) 123 | end. 124 | 125 | Fixpoint n_stack1_controlizer k (czx : ZX 1 (1 + 1)) : ZX 1 (k + k) := 126 | match k with 127 | | 0 => empty_controlizer 128 | | S k' => stack_controlizer czx (n_stack1_controlizer k' czx) 129 | end. 130 | 131 | Definition n_wire_controlizer n : ZX 1 (n + n) := 132 | n_stack1_controlizer n wire_controlizer. 133 | 134 | 135 | Definition X_2_1_controlizer : ZX 1 (2 + 1) := X_1_2_controlizer. 136 | 137 | Definition X_0_1_controlizer β : ZX 1 (0 + 1) := X_1_0_controlizer β. 138 | 139 | Fixpoint X_S_0_controlizer n β : ZX 1 (S n + 0) := 140 | match n with 141 | | 0 => X_1_0_controlizer β 142 | | S n' => compose_controlizer 143 | (stack_controlizer X_2_1_controlizer (n_wire_controlizer n')) 144 | (X_S_0_controlizer n' β) 145 | end. 146 | 147 | Fixpoint X_0_S_controlizer n β : ZX 1 (0 + S n) := 148 | match n with 149 | | 0 => X_0_1_controlizer β 150 | | S n' => compose_controlizer 151 | (X_0_S_controlizer n' β) 152 | (stack_controlizer X_1_2_controlizer (n_wire_controlizer n')) 153 | end. 154 | 155 | Definition X_0_n_controlizer n β : ZX 1 n := 156 | match n with 157 | | 0 => 158 | compose_controlizer (X_0_1_controlizer β) 159 | (X_1_0_controlizer 0) 160 | | S n' => X_0_S_controlizer n' β 161 | end. 162 | 163 | Definition X_controlizer n m β : ZX 1 (n + m) := 164 | X_0_n_controlizer (n + m) β. 165 | 166 | Definition Z_controlizer n m β : ZX 1 (n + m) := 167 | compose_controlizer (compose_controlizer 168 | (n_stack1_controlizer n box_controlizer) 169 | (X_controlizer n m β)) 170 | (n_stack1_controlizer m box_controlizer). 171 | 172 | Fixpoint controlizer {n m} (zx : ZX n m) : ZX 1 (n + m) := 173 | match zx with 174 | | ⦰ => empty_controlizer 175 | | — => wire_controlizer 176 | | □ => box_controlizer 177 | | ⊂ => cupcap_controlizer 178 | | ⊃ => cupcap_controlizer 179 | | ⨉ => swap_controlizer 180 | | X n m α => X_controlizer n m α 181 | | Z n m α => Z_controlizer n m α 182 | | zx0 ↕ zx1 => stack_controlizer (controlizer zx0) (controlizer zx1) 183 | | zx0 ⟷ zx1 => compose_controlizer (controlizer zx0) (controlizer zx1) 184 | end. 185 | 186 | 187 | (* The sum of two controlizers/controlled states, so that 188 | [⟦ sum_controlizer c0 c1 ⟧ |1⟩ = ⟦ c0 ⟧ |1⟩ .+ ⟦ c1 ⟧ |1⟩] *) 189 | 190 | Lemma nn_n2 {n:nat} : (n + n = n * 2)%nat. Proof. lia. Qed. 191 | Definition sum_controlizer {n} (c0 c1 : ZX 1 n) : ZX 1 n := 192 | (X 0 1 0 ⟷ Z 1 0 0) ↕ 193 | ( 194 | Z 1 2 0 ⟷ (X 1 2 0 ↕ ◁) ⟷ (— ↕ Z 2 1 0) ⟷ 195 | (c0 ↕ c1) 196 | ) ⟷ 197 | zx_of_perm_cast (n + n) (n * 2) (kron_comm_perm 2 n) nn_n2 ⟷ 198 | n ⇑ Z 2 1 0 ⟷ 199 | cast _ _ (Nat.mul_1_r n) eq_refl (n_wire n). 200 | -------------------------------------------------------------------------------- /src/CoreRules/StackComposeRules.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData.CoreData. 2 | Require Import CastRules. 3 | Require Import SpiderInduction. 4 | Require Export StackRules. 5 | Require Export WireRules. 6 | Require Export ComposeRules. 7 | 8 | (** Rules relating stack and compose *) 9 | 10 | Local Open Scope ZX_scope. 11 | Lemma nwire_stack_compose_topleft : forall {topIn botIn topOut botOut} 12 | (zx0 : ZX botIn botOut) (zx1 : ZX topIn topOut), 13 | ((n_wire topIn) ↕ zx0) ⟷ (zx1 ↕ (n_wire botOut)) ∝= 14 | (zx1 ↕ zx0). 15 | Proof. 16 | intros. 17 | now rewrite <- stack_compose_distr, nwire_removal_l, nwire_removal_r. 18 | Qed. 19 | 20 | Lemma nwire_stack_compose_botleft : forall {topIn botIn topOut botOut} 21 | (zx0 : ZX botIn botOut) (zx1 : ZX topIn topOut), 22 | (zx0 ↕ (n_wire topIn)) ⟷ ((n_wire botOut) ↕ zx1) ∝= 23 | (zx0 ↕ zx1). 24 | Proof. 25 | intros. 26 | now rewrite <- stack_compose_distr, nwire_removal_l, nwire_removal_r. 27 | Qed. 28 | 29 | Lemma stack_split_diag {n m o p} (zx0 : ZX n m) (zx1 : ZX o p) : 30 | zx0 ↕ zx1 ∝= zx0 ↕ n_wire o ⟷ (n_wire m ↕ zx1). 31 | Proof. 32 | now rewrite <- stack_compose_distr, nwire_removal_l, nwire_removal_r. 33 | Qed. 34 | 35 | Lemma stack_split_antidiag {n m o p} (zx0 : ZX n m) (zx1 : ZX o p) : 36 | zx0 ↕ zx1 ∝= (n_wire n ↕ zx1) ⟷ (zx0 ↕ n_wire p). 37 | Proof. 38 | now rewrite <- stack_compose_distr, nwire_removal_l, nwire_removal_r. 39 | Qed. 40 | 41 | Lemma push_out_top : forall {nIn nOut nOutAppendix} 42 | (appendix : ZX 0 nOutAppendix) (zx : ZX nIn nOut), 43 | appendix ↕ zx ∝= zx ⟷ (appendix ↕ (n_wire nOut)). 44 | Proof. 45 | intros. 46 | rewrite <- (stack_empty_l zx) at 2. 47 | rewrite (nwire_stack_compose_topleft zx appendix). 48 | easy. 49 | Qed. 50 | 51 | Lemma push_out_bot : forall {nIn nOut nOutAppendix} 52 | (appendix : ZX 0 nOutAppendix) (zx : ZX nIn nOut) prfn prfm, 53 | zx ↕ appendix ∝= (cast _ _ prfn prfm zx) ⟷ ((n_wire nOut) ↕ appendix). 54 | Proof. 55 | intros. 56 | rewrite <- stack_empty_r. 57 | now rewrite <- stack_compose_distr, compose_empty_l, nwire_removal_r. 58 | Qed. 59 | 60 | Lemma pull_out_top : forall {nIn nOut nInAppendix} 61 | (appendix : ZX nInAppendix 0) (zx : ZX nIn nOut), 62 | appendix ↕ zx ∝= (appendix ↕ (n_wire nIn)) ⟷ zx. 63 | Proof. 64 | intros. 65 | rewrite <- (stack_empty_l zx) at 2. 66 | rewrite (nwire_stack_compose_botleft appendix zx). 67 | easy. 68 | Qed. 69 | 70 | Lemma pull_out_bot : forall {nIn nOut nInAppendix} 71 | (appendix : ZX nInAppendix 0) (zx : ZX nIn nOut) prfn prfm, 72 | zx ↕ appendix ∝= ((n_wire nIn) ↕ appendix) ⟷ (cast _ _ prfn prfm zx). 73 | Proof. 74 | intros. 75 | rewrite <- stack_empty_r. 76 | rewrite <- stack_compose_distr. 77 | now rewrite nwire_removal_l, compose_empty_r. 78 | Qed. 79 | 80 | Lemma disconnected_stack_compose_l : forall {n m} 81 | (zxIn : ZX n 0) (zxOut : ZX 0 m) prfn prfm, 82 | zxIn ↕ zxOut ∝= cast _ _ prfn prfm (zxIn ⟷ zxOut). 83 | Proof. 84 | intros. 85 | rewrite <- (compose_empty_l zxOut) at 1. 86 | rewrite <- (compose_empty_r zxIn) at 1. 87 | rewrite stack_compose_distr. 88 | rewrite stack_empty_l. 89 | auto_cast_eqn (rewrite stack_empty_r). 90 | rewrite cast_compose_l. 91 | simpl_casts. 92 | easy. 93 | Qed. 94 | 95 | Lemma disconnected_stack_compose_r : forall {n m} (zxIn : ZX n 0) (zxOut : ZX 0 m) prfn prfm, 96 | zxOut ↕ zxIn ∝= cast _ _ prfn prfm (zxIn ⟷ zxOut). 97 | Proof. 98 | intros. 99 | rewrite <- (compose_empty_l zxOut) at 1. 100 | rewrite <- (compose_empty_r zxIn) at 1. 101 | rewrite stack_compose_distr. 102 | rewrite stack_empty_l. 103 | auto_cast_eqn (rewrite stack_empty_r). 104 | rewrite cast_compose_r. 105 | simpl_casts. 106 | easy. 107 | Qed. 108 | 109 | 110 | Lemma n_stack_compose {n m o} k (zx0 : ZX n m) (zx1 : ZX m o) : 111 | k ⇑ (zx0 ⟷ zx1) ∝= k ⇑ zx0 ⟷ k ⇑ zx1. 112 | Proof. 113 | induction k. 114 | - simpl; now rewrite compose_empty_l. 115 | - simpl. 116 | rewrite IHk, <- stack_compose_distr. 117 | reflexivity. 118 | Qed. 119 | 120 | 121 | Lemma n_stack1_compose k (zx0 : ZX 1 1) (zx1 : ZX 1 1) : 122 | k ↑ (zx0 ⟷ zx1) ∝= k ↑ zx0 ⟷ k ↑ zx1. 123 | Proof. 124 | induction k. 125 | - simpl; now rewrite compose_empty_l. 126 | - simpl. 127 | rewrite IHk, <- (@stack_compose_distr 1 1 1 k k). 128 | reflexivity. 129 | Qed. 130 | 131 | (* Rules about associator and invassociator *) 132 | 133 | Lemma associator_nat_l {n m o n' m' o'} 134 | (zx0 : ZX n n') (zx1 : ZX m m') (zx2 : ZX o o') : 135 | associator n m o ⟷ (zx0 ↕ (zx1 ↕ zx2)) ∝= 136 | zx0 ↕ zx1 ↕ zx2 ⟷ associator n' m' o'. 137 | Proof. 138 | rewrite stack_assoc_back. 139 | unfold associator. 140 | rewrite cast_compose_eq_mid_join, nwire_removal_l. 141 | rewrite cast_compose_r, cast_id, nwire_removal_r. 142 | reflexivity. 143 | Unshelve. all: lia. 144 | Qed. 145 | 146 | Lemma associator_nat_r {n m o n' m' o'} 147 | (zx0 : ZX n n') (zx1 : ZX m m') (zx2 : ZX o o') : 148 | zx0 ↕ zx1 ↕ zx2 ⟷ associator n' m' o' ∝= 149 | associator n m o ⟷ (zx0 ↕ (zx1 ↕ zx2)). 150 | Proof. 151 | now rewrite associator_nat_l. 152 | Qed. 153 | 154 | 155 | Lemma invassociator_nat_l {n m o n' m' o'} 156 | (zx0 : ZX n n') (zx1 : ZX m m') (zx2 : ZX o o') : 157 | invassociator n m o ⟷ (zx0 ↕ zx1 ↕ zx2) ∝= 158 | (zx0 ↕ (zx1 ↕ zx2)) ⟷ invassociator n' m' o'. 159 | Proof. 160 | rewrite stack_assoc_back. 161 | unfold invassociator. 162 | rewrite cast_compose_eq_mid_join, nwire_removal_r. 163 | rewrite cast_compose_l, cast_id, nwire_removal_l. 164 | reflexivity. 165 | Unshelve. all: lia. 166 | Qed. 167 | 168 | Lemma invassociator_nat_r {n m o n' m' o'} 169 | (zx0 : ZX n n') (zx1 : ZX m m') (zx2 : ZX o o') : 170 | (zx0 ↕ (zx1 ↕ zx2)) ⟷ invassociator n' m' o' ∝= 171 | invassociator n m o ⟷ (zx0 ↕ zx1 ↕ zx2) . 172 | Proof. 173 | now rewrite invassociator_nat_l. 174 | Qed. 175 | 176 | Lemma invassociator_linv n m o : 177 | invassociator n m o ⟷ associator n m o ∝= n_wire _. 178 | Proof. 179 | unfold associator, invassociator. 180 | rewrite cast_compose_eq_mid_join, nwire_removal_r. 181 | rewrite cast_n_wire. 182 | reflexivity. 183 | Qed. 184 | 185 | Lemma invassociator_rinv n m o : 186 | associator n m o ⟷ invassociator n m o ∝= n_wire _. 187 | Proof. 188 | unfold associator, invassociator. 189 | rewrite cast_compose_eq_mid_join, nwire_removal_r. 190 | rewrite cast_id. 191 | reflexivity. 192 | Qed. 193 | 194 | 195 | Lemma cast_to_compose_associator_l {n m o p} (zx : ZX (n + (m + o)) p) prf1 prf2 : 196 | cast (n + m + o) p prf1 prf2 zx ∝= 197 | associator n m o ⟷ zx. 198 | Proof. 199 | unfold associator. 200 | rewrite cast_compose_l, cast_id, nwire_removal_l. 201 | cast_irrelevance. 202 | Qed. 203 | 204 | Lemma cast_to_compose_invassociator_l {n m o p} (zx : ZX (n + m + o) p) prf1 prf2 : 205 | cast (n + (m + o)) p prf1 prf2 zx ∝= 206 | invassociator n m o ⟷ zx. 207 | Proof. 208 | unfold invassociator. 209 | rewrite cast_compose_l, cast_id, nwire_removal_l. 210 | cast_irrelevance. 211 | Qed. -------------------------------------------------------------------------------- /src/CoreRules/ChoiJamiolchosky.v: -------------------------------------------------------------------------------- 1 | Require Export CoreData CoreAutomation 2 | CastRules StackComposeRules CapCupRules. 3 | 4 | (** Results about the Choi-Jamiolshosky isomorphism, i.e. 5 | process/state duality. *) 6 | 7 | Lemma proc_to_state_to_proc {n m} (zx : ZX n m) : 8 | state_to_proc (proc_to_state zx) ∝= zx. 9 | Proof. 10 | unfold state_to_proc, proc_to_state. 11 | rewrite n_cap_pullthrough_bot. 12 | rewrite stack_nwire_distribute_l. 13 | rewrite cast_compose_distribute, compose_assoc. 14 | rewrite stack_assoc_back, cast_contract. 15 | 16 | rewrite (cast_compose_l _ _ _ (_ ↕ _)), cast_id. 17 | rewrite <- stack_nwire_distribute_r. 18 | rewrite n_cup_pullthrough_bot, transpose_involutive_eq. 19 | rewrite stack_nwire_distribute_r. 20 | rewrite cast_compose_distribute, stack_assoc, cast_contract. 21 | rewrite <- compose_assoc. 22 | rewrite cast_compose_eq_mid_join. 23 | rewrite <- stack_compose_distr, nwire_removal_l. 24 | rewrite push_out_bot, cast_compose_distribute, cast_contract. 25 | rewrite compose_assoc, (cast_compose_l _ _ (_ ↕ _)), cast_contract. 26 | rewrite n_wire_stack, nwire_removal_r. 27 | rewrite big_yank_r. 28 | rewrite cast_compose_l. 29 | rewrite 2 cast_contract. 30 | rewrite 2 cast_id, nwire_removal_r. 31 | reflexivity. 32 | Unshelve. all: lia. 33 | Qed. 34 | 35 | 36 | Lemma state_to_proc_to_state {n m} (zx : ZX 0 (n + m)) : 37 | proc_to_state (state_to_proc zx) ∝= zx. 38 | Proof. 39 | unfold state_to_proc, proc_to_state. 40 | rewrite stack_nwire_distribute_l. 41 | rewrite cast_stack_r, stack_assoc_back, cast_contract. 42 | rewrite <- compose_assoc, n_wire_stack. 43 | rewrite cast_compose_r, push_out_bot, <- compose_assoc, 44 | cast_compose_eq_mid_join, nwire_removal_r. 45 | rewrite <- (push_out_bot zx (n_cap n)). 46 | rewrite <- nwire_stack_compose_topleft, cast_compose_distribute, 47 | compose_assoc. 48 | rewrite <- n_wire_stack, stack_assoc_back, cast_contract. 49 | rewrite cast_id. 50 | rewrite (cast_compose_l _ _ (_ ↕ n_wire m)), cast_id. 51 | rewrite (stack_assoc_back (n_wire n) (n_cup n) (n_wire m)), cast_contract. 52 | rewrite cast_stack_distribute, cast_id. 53 | rewrite <- stack_nwire_distribute_r, big_yank_l. 54 | rewrite stack_empty_l, n_wire_stack, nwire_removal_r. 55 | reflexivity. 56 | Unshelve. all: lia. 57 | Qed. 58 | 59 | Lemma colorswap_proc_to_state {n m} (zx : ZX n m) : 60 | ⊙ (proc_to_state zx) ∝= proc_to_state (⊙ zx). 61 | Proof. 62 | unfold proc_to_state; cbn [color_swap]; 63 | autorewrite with colorswap_db. 64 | reflexivity. 65 | Qed. 66 | 67 | Lemma colorswap_state_to_proc {n m} (zx : ZX 0 (n + m)) : 68 | ⊙ (state_to_proc zx) ∝= state_to_proc (⊙ zx). 69 | Proof. 70 | unfold state_to_proc; cbn [color_swap]; 71 | autorewrite with colorswap_db. 72 | cbn [color_swap]. 73 | autorewrite with colorswap_db. 74 | reflexivity. 75 | Qed. 76 | 77 | #[export] Hint Rewrite 78 | @colorswap_proc_to_state @colorswap_state_to_proc : colorswap_db. 79 | 80 | 81 | 82 | 83 | 84 | Lemma proc_to_state_state {n} (zx : ZX 0 n) : 85 | proc_to_state zx ∝= zx. 86 | Proof. 87 | unfold proc_to_state. 88 | rewrite n_cap_0_empty. 89 | cleanup_zx. 90 | reflexivity. 91 | Qed. 92 | 93 | 94 | Lemma state_to_proc_diagrams {n m} (zx zx' : ZX 0 (n + m)) : 95 | state_to_proc zx ∝= state_to_proc zx' -> 96 | zx ∝= zx'. 97 | Proof. 98 | intros H%proc_to_state_mor. 99 | now rewrite 2 state_to_proc_to_state in H. 100 | Qed. 101 | 102 | Lemma proc_to_state_diagrams {n m} (zx zx' : ZX n m) : 103 | proc_to_state zx ∝= proc_to_state zx' -> 104 | zx ∝= zx'. 105 | Proof. 106 | intros H%state_to_proc_mor. 107 | now rewrite 2 proc_to_state_to_proc in H. 108 | Qed. 109 | 110 | Lemma state_to_proc_diagrams_iff {n m} (zx zx' : ZX 0 (n + m)) : 111 | state_to_proc zx ∝= state_to_proc zx' <-> 112 | zx ∝= zx'. 113 | Proof. 114 | split; [apply state_to_proc_diagrams | now intros ->]. 115 | Qed. 116 | 117 | Lemma proc_to_state_diagrams_iff {n m} (zx zx' : ZX n m) : 118 | proc_to_state zx ∝= proc_to_state zx' <-> 119 | zx ∝= zx'. 120 | Proof. 121 | split; [apply proc_to_state_diagrams | now intros ->]. 122 | Qed. 123 | 124 | Lemma state_to_proc_eq_l {n m} (zx : ZX 0 (n + m)) zx' : 125 | state_to_proc zx ∝= zx' <-> zx ∝= proc_to_state zx'. 126 | Proof. 127 | rewrite <- (proc_to_state_to_proc zx') at 1. 128 | apply state_to_proc_diagrams_iff. 129 | Qed. 130 | 131 | Lemma state_to_proc_eq_r {n m} zx (zx' : ZX 0 (n + m)) : 132 | zx ∝= state_to_proc zx' <-> proc_to_state zx ∝= zx'. 133 | Proof. 134 | rewrite <- (proc_to_state_to_proc zx) at 1. 135 | apply state_to_proc_diagrams_iff. 136 | Qed. 137 | 138 | Lemma proc_to_state_eq_l {n m} zx (zx' : ZX 0 (n + m)) : 139 | proc_to_state zx ∝= zx' <-> zx ∝= state_to_proc zx'. 140 | Proof. 141 | rewrite <- (state_to_proc_to_state zx') at 1. 142 | apply proc_to_state_diagrams_iff. 143 | Qed. 144 | 145 | Lemma proc_to_state_eq_r {n m} (zx : ZX 0 (n + m)) zx' : 146 | zx ∝= proc_to_state zx' <-> state_to_proc zx ∝= zx'. 147 | Proof. 148 | rewrite <- (state_to_proc_to_state zx) at 1. 149 | apply proc_to_state_diagrams_iff. 150 | Qed. 151 | 152 | Lemma proc_to_state_n_wire n : proc_to_state (n_wire n) ∝= n_cap n. 153 | Proof. 154 | unfold proc_to_state. 155 | rewrite n_wire_stack, nwire_removal_r. 156 | reflexivity. 157 | Qed. 158 | 159 | Lemma state_to_proc_n_cap n : state_to_proc (n_cap n) ∝= n_wire n. 160 | Proof. 161 | rewrite state_to_proc_eq_l, proc_to_state_n_wire. 162 | reflexivity. 163 | Qed. 164 | 165 | Lemma proc_to_state_alt {n m} (zx : ZX n m) : 166 | proc_to_state zx ∝= n_cap m ⟷ ((zx ⊤) ↕ n_wire m). 167 | Proof. 168 | unfold proc_to_state. 169 | apply n_cap_pullthrough_bot. 170 | Qed. 171 | 172 | Lemma proc_to_state_effect {n} (zx : ZX n 0) : 173 | proc_to_state zx ∝= zx⊤ ↕ ⦰. 174 | Proof. 175 | unfold proc_to_state. 176 | rewrite n_cap_pullthrough_bot, n_cap_0_empty, compose_empty_l. 177 | reflexivity. 178 | Qed. 179 | 180 | Lemma state_to_proc_n_cup n : proc_to_state (n_cup n) ∝= n_cap n ↕ ⦰. 181 | Proof. 182 | apply proc_to_state_effect. 183 | Qed. 184 | 185 | 186 | 187 | Lemma wrap_over_left {n m} (zx zx' : ZX n m) : 188 | n_cap n ⟷ (n_wire n ↕ zx) ∝= n_cap n ⟷ (n_wire n ↕ zx') -> 189 | zx ∝= zx'. 190 | Proof. 191 | intros Heq. 192 | apply proc_to_state_diagrams. 193 | apply Heq. 194 | Qed. 195 | 196 | Lemma wrap_over_right {n m} (zx zx' : ZX n m) : 197 | n_wire m ↕ zx ⟷ n_cup m ∝= n_wire m ↕ zx' ⟷ n_cup m -> 198 | zx ∝= zx'. 199 | Proof. 200 | intros Heq. 201 | apply transpose_prop_by_1_proper in Heq. 202 | cbn -[n_cup] in Heq. 203 | autorewrite with transpose_db in Heq. 204 | apply transpose_diagrams_eq. 205 | now apply wrap_over_left. 206 | Qed. 207 | 208 | Lemma wrap_under_left {n m} (zx zx' : ZX n m) : 209 | n_cap n ⟷ (zx ↕ n_wire n) ∝= n_cap n ⟷ (zx' ↕ n_wire n) -> 210 | zx ∝= zx'. 211 | Proof. 212 | intros Heq. 213 | apply transpose_diagrams_eq. 214 | apply proc_to_state_diagrams. 215 | rewrite 2 proc_to_state_alt. 216 | now rewrite 2 transpose_involutive_eq. 217 | Qed. 218 | 219 | Lemma wrap_under_right {n m} (zx zx' : ZX n m) : 220 | (zx ↕ n_wire m) ⟷ n_cup m ∝= (zx' ↕ n_wire m) ⟷ n_cup m -> 221 | zx ∝= zx'. 222 | Proof. 223 | intros Heq. 224 | apply transpose_prop_by_1_proper in Heq. 225 | cbn -[n_cup] in Heq. 226 | autorewrite with transpose_db in Heq. 227 | apply transpose_diagrams_eq. 228 | now apply wrap_under_left. 229 | Qed. -------------------------------------------------------------------------------- /src/Permutations/ZXpermSemantics.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore. 2 | Require Import CastRules. 3 | Require Export ZXperm. 4 | Require Import ZXpermAutomation. 5 | Require Import QuantumLib.Permutations QuantumLib.Modulus. 6 | Import CoreData.Proportional. 7 | 8 | (** Core proofs of semantics of [ZXperm]s in terms of their 9 | underlying permutations *) 10 | 11 | Local Open Scope nat. 12 | 13 | Lemma zxperm_square {n m} (zx : ZX n m) : 14 | ZXperm zx -> n = m. 15 | Proof. 16 | intros H; induction H; lia. 17 | Qed. 18 | 19 | Lemma zxperm_square_induction 20 | (P : forall {n m : nat}, ZX n m -> Prop) 21 | (Pempty : P Empty) 22 | (Pwire : P Wire) 23 | (Pswap : P Swap) 24 | (Pstack : forall n m (zx0 : ZX n n) (zx1 : ZX m m), 25 | ZXperm zx0 -> ZXperm zx1 -> 26 | P zx0 -> P zx1 -> P (zx0 ↕ zx1)) 27 | (Pcompose : forall n (zx0 zx1 : ZX n n), 28 | ZXperm zx0 -> ZXperm zx1 -> 29 | P zx0 -> P zx1 -> P (zx0 ⟷ zx1)) : 30 | forall {n m} (zx : ZX n m), ZXperm zx -> P zx. 31 | Proof. 32 | intros n m zx Hzx. 33 | induction Hzx; 34 | [assumption..| |]. 35 | - pose proof (zxperm_square zx0 ltac:(auto)) as H0eq. 36 | pose proof (zxperm_square zx1 ltac:(auto)) as H1eq. 37 | gen zx0 zx1. 38 | revert H0eq H1eq. 39 | intros [] []. 40 | auto. 41 | - pose proof (zxperm_square zx0 ltac:(auto)) as H0eq. 42 | pose proof (zxperm_square zx1 ltac:(auto)) as H1eq. 43 | gen zx0 zx1. 44 | revert H0eq H1eq. 45 | intros [] []. 46 | auto. 47 | Qed. 48 | 49 | Lemma perm_of_zx_permutation {n m} (zx : ZX n m) : 50 | ZXperm zx -> permutation n (perm_of_zx zx). 51 | Proof. 52 | intros H. 53 | induction H using zxperm_square_induction; 54 | show_permutation. 55 | Qed. 56 | 57 | #[export] Hint Resolve perm_of_zx_permutation : perm_db. 58 | #[export] Hint Extern 4 (permutation _ (perm_of_zx _)) => 59 | apply perm_of_zx_permutation; 60 | solve [auto with zxperm_db] : perm_db. 61 | 62 | #[export] Hint Constructors ZXperm : zxperm_db. 63 | 64 | Lemma empty_permutation_semantics : ⟦ Empty ⟧ = zxperm_to_matrix 0 Empty. 65 | Proof. lma'. Qed. 66 | 67 | Lemma wire_permutation_semantics : ⟦ Wire ⟧ = zxperm_to_matrix 1 Wire. 68 | Proof. lma'. Qed. 69 | 70 | Lemma swap_2_perm_semantics : ⟦ Swap ⟧ = zxperm_to_matrix 2 Swap. 71 | Proof. lma'. Qed. 72 | 73 | Lemma if_dist2 {T1 T2 T3 : Type} (f : T1 -> T2 -> T3) 74 | (b1 b2 : bool) x1 x2 x3 x4 : 75 | f (if b1 then x1 else x2) (if b2 then x3 else x4) = 76 | if b1 && b2 then f x1 x3 else 77 | (if b1 then f x1 x4 else 78 | (if b2 then f x2 x3 else f x2 x4)). 79 | Proof. 80 | now destruct b1, b2. 81 | Qed. 82 | 83 | Lemma stack_perms_semantics {n0 n1 m0 m1} 84 | {zx0 : ZX n0 m0} {zx1 : ZX n1 m1} (H0 : n0 = m0) (H1 : n1 = m1) 85 | (Hzx0 : ⟦ zx0 ⟧ = zxperm_to_matrix n0 zx0) 86 | (Hzx1 : ⟦ zx1 ⟧ = zxperm_to_matrix n1 zx1) 87 | (Hzx0perm : permutation n0 (perm_of_zx zx0)) 88 | (Hzx1perm : permutation n1 (perm_of_zx zx1)) : 89 | ⟦ zx0 ↕ zx1 ⟧ = zxperm_to_matrix (n0 + n1) (zx0 ↕ zx1). 90 | Proof. 91 | simpl. 92 | subst. 93 | rewrite perm_to_matrix_of_stack_perms by easy. 94 | now f_equal. 95 | Qed. 96 | 97 | Lemma compose_permutation_semantics {n m o} {zx0 : ZX n m} {zx1 : ZX m o} 98 | (H0 : n = m) 99 | (Hzx0 : ⟦ zx0 ⟧ = zxperm_to_matrix n zx0) 100 | (Hzx1 : ⟦ zx1 ⟧ = zxperm_to_matrix m zx1) 101 | (Hzx0perm : permutation n (perm_of_zx zx0)) 102 | (Hzx1perm : permutation m (perm_of_zx zx1)) : 103 | ⟦ zx0 ⟷ zx1 ⟧ = zxperm_to_matrix n (zx0 ⟷ zx1). 104 | Proof. 105 | simpl. 106 | subst. 107 | rewrite perm_to_matrix_compose by auto with perm_db. 108 | now rewrite Hzx0, Hzx1. 109 | Qed. 110 | 111 | Lemma cast_permutations_semantics {n0 n1} {zx : ZX n0 n0} 112 | (Hn : n1 = n0) 113 | (Hzx : ⟦ zx ⟧ = zxperm_to_matrix n1 zx) : 114 | ⟦ cast _ _ Hn Hn zx ⟧ = zxperm_to_matrix n1 (cast _ _ Hn Hn zx). 115 | Proof. subst; easy. Qed. 116 | 117 | Lemma perm_of_zx_permutation_semantics {n m} (zx : ZX n m) : 118 | ZXperm zx -> ⟦ zx ⟧ = zxperm_to_matrix n zx. 119 | Proof. 120 | intros H. 121 | induction H using zxperm_square_induction. 122 | - apply empty_permutation_semantics. 123 | - apply wire_permutation_semantics. 124 | - apply swap_2_perm_semantics. 125 | - eapply stack_perms_semantics; auto with perm_db. 126 | - apply compose_permutation_semantics; auto with perm_db. 127 | Qed. 128 | 129 | (* ... which enables the main result: *) 130 | 131 | Lemma prop_eq_of_equal_perm {n m} {zx0 zx1 : ZX n m} 132 | (Hzx0 : ZXperm zx0) (Hzx1 : ZXperm zx1) 133 | (Hperm : perm_of_zx zx0 = perm_of_zx zx1) : 134 | zx0 ∝= zx1. 135 | Proof. 136 | hnf. 137 | rewrite (perm_of_zx_permutation_semantics zx0 Hzx0), 138 | (perm_of_zx_permutation_semantics zx1 Hzx1). 139 | f_equal; easy. 140 | Qed. 141 | 142 | Lemma prop_eq_of_perm_eq {n m} {zx0 zx1 : ZX n m} 143 | (Hzx0 : ZXperm zx0) (Hzx1 : ZXperm zx1) 144 | (Hperm : perm_eq n (perm_of_zx zx0) (perm_of_zx zx1)) : 145 | zx0 ∝= zx1. 146 | Proof. 147 | pose proof (zxperm_square zx0 Hzx0); subst. 148 | hnf. 149 | rewrite (perm_of_zx_permutation_semantics zx0 Hzx0), 150 | (perm_of_zx_permutation_semantics zx1 Hzx1). 151 | now apply perm_to_matrix_eq_of_perm_eq. 152 | Qed. 153 | 154 | (* TODO: split intro prop_perm_eq and prop_perm_eqΩ *) 155 | 156 | Ltac to_prop_eq_then tac := 157 | lazymatch goal with 158 | | |- _ ∝ _ => 159 | apply proportional_of_by_1; tac 160 | | |- _ ∝[_] _ => 161 | zxrefl; only 1: tac 162 | | |- _ ∝= _ => tac 163 | | |- _ => tac 164 | end. 165 | 166 | Ltac prop_perm_eq_nosimpl_base := 167 | intros; 168 | (* Goal: zx0 ∝= zx1 *) 169 | apply prop_eq_of_equal_perm; [ 170 | (* New goals: *) 171 | (*1: ZXperm _ zx0 *) auto 10 with zxperm_db | 172 | (*2: ZXperm _ zx1*) auto 10 with zxperm_db | 173 | (*3: perm_of_zx zx0 = perm_of_zx zx1*) 174 | ]. 175 | 176 | Ltac prop_perm_eq_nosimpl := 177 | to_prop_eq_then prop_perm_eq_nosimpl_base. 178 | 179 | Ltac prop_perm_eq_base := 180 | intros; 181 | autounfold with zxperm_db; 182 | simpl_casts; 183 | simpl_permlike_zx; 184 | (* __cast_prop_sides_to_square; *) 185 | (* Goal: zx0 ∝ zx1 *) 186 | apply prop_eq_of_equal_perm; [ 187 | (* New goals: *) 188 | (*1: ZXperm _ zx0 *) auto 10 with zxperm_db | 189 | (*2: ZXperm _ zx1*) auto 10 with zxperm_db | 190 | (*3: perm_of_zx zx0 = perm_of_zx zx1*) cleanup_perm_of_zx; try easy; try lia 191 | ]. 192 | 193 | Ltac prop_perm_eq := 194 | to_prop_eq_then prop_perm_eq_base. 195 | 196 | (* TODO: switch all over to this: *) 197 | Ltac by_perm_eq_base := 198 | intros; 199 | autounfold with zxperm_db; 200 | simpl_casts; 201 | simpl_permlike_zx; 202 | (* __cast_prop_sides_to_square; *) 203 | (* Goal: zx0 ∝ zx1 *) 204 | apply prop_eq_of_perm_eq; [ 205 | (* New goals: *) 206 | (*1: ZXperm _ zx0 *) auto 100 with zxperm_db | 207 | (*2: ZXperm _ zx1*) auto 100 with zxperm_db | 208 | (*3: forall k, k < n -> perm_of_zx zx0 k = perm_of_zx zx1 k *) 209 | cleanup_perm_of_zx; try easy; try lia 210 | ]. 211 | 212 | Ltac by_perm_eq := to_prop_eq_then by_perm_eq_base. 213 | 214 | Ltac by_perm_eq_nosimpl_base := 215 | intros; 216 | autounfold with zxperm_db; 217 | (* Goal: zx0 ∝ zx1 *) 218 | apply prop_eq_of_perm_eq; [ 219 | (* New goals: *) 220 | (*1: ZXperm _ zx0 *) auto 100 with zxperm_db | 221 | (*2: ZXperm _ zx1*) auto 100 with zxperm_db | 222 | 223 | ]. 224 | 225 | Ltac by_perm_eq_nosimpl := to_prop_eq_then by_perm_eq_nosimpl_base. 226 | 227 | -------------------------------------------------------------------------------- /.hooks/Name_validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import re 3 | import os 4 | import sys 5 | import sys 6 | 7 | 8 | MIN_PYTHON = (3, 10) 9 | if sys.version_info < MIN_PYTHON: 10 | print(f"Your python version is {sys.version_info.major}.{sys.version_info.minor}. {MIN_PYTHON[0]}.{MIN_PYTHON[1]} is required") 11 | exit(3) 12 | 13 | 14 | args = sys.argv[1:] 15 | 16 | usage = "./Name_validator.py [--interactive]" 17 | 18 | interactive = False 19 | 20 | b_color_green = '\033[92m' 21 | b_color_yellow = '\033[93m' 22 | b_color_reset = '\033[0m' 23 | 24 | 25 | if len(args) > 1: 26 | print(usage) 27 | exit(2) 28 | 29 | if len(args) == 1: 30 | if args[0] == "--interactive": 31 | interactive = True 32 | else: 33 | print(usage) 34 | exit(2) 35 | 36 | 37 | curr_dir = os.path.dirname(os.path.realpath(__file__)) 38 | src_dir = f"{curr_dir}/../src" 39 | 40 | thm_token = "Theorem|Lemma|Fact|Remark|Corollary|Proposition|Property|Variable|Hypothesis" 41 | def_token = "Definition|Fixpoint|Inductive|Example" 42 | exists_thm_regex = re.compile(f".*({thm_token}|{def_token})\\s*(([a-z]|[A-Z]|_)([a-z]|[A-Z]|_|-|\\d)+)") 43 | def_name_ignore_regex = re.compile("\\s*\\(\\*\\s*\\@nocheck\\s+name\\s*\\*\\)") 44 | 45 | acceptable_upper_case = ["Z","X","WF","H","Rz","Rx","S"] 46 | acceptable_upper_case_regex = "|".join(acceptable_upper_case) 47 | 48 | snake_case_regex = re.compile(f"ZX|(_?((({acceptable_upper_case_regex})|(([a-z]|[0-9])*))_)*(({acceptable_upper_case_regex})|(([a-z]|[0-9])*)))") 49 | 50 | 51 | camel_case_to_snake_case_regex = re.compile(r'(? str: 65 | prefix, _, postfix = self.file.partition(".hooks/../") # strip going into the hooks directory 66 | return prefix + postfix 67 | 68 | def __str__(self) -> str: 69 | if (not self.line_no) or (not self.def_type): # File global violation 70 | return f"{b_color_yellow}Violation found: {self.name} is a disallowed file name. Should be PascalCase (where only the beginning can have multiple uppercase letters in row) {b_color_reset}({self._fmt_file()})" 71 | acceptable_upper_case_str = ", ".join(map(lambda x: '\"' + x + '\"', acceptable_upper_case)) 72 | suggestion = self.fix_snake_case() 73 | suggestion_info = f" Suggestion: {suggestion} " if suggestion != None else "" 74 | return f"{b_color_yellow}Violation found: {self.def_type} \"{self.name}\" should be snake_case and lower case following standard library's convention (except for qualifiers: {acceptable_upper_case_str}.{suggestion_info}{b_color_reset}({self._fmt_file()}:{self.line_no})" 75 | 76 | def fix_snake_case(self) -> (str | None): 77 | snake_split = self.name.replace("-","_").split("_") 78 | results = list() 79 | for component in snake_split: 80 | if component not in acceptable_upper_case: 81 | component_is_upper = component == component.upper() 82 | if component_is_upper and (component not in acceptable_upper_case): 83 | component = component.lower() 84 | else: 85 | component = camel_case_to_snake_case_regex \ 86 | .sub('_', component) \ 87 | .lower() 88 | 89 | results.append(component) 90 | snake_cased_name = "_".join(results) 91 | if snake_cased_name.startswith("zx_") or snake_cased_name.startswith("ZX_"): 92 | snake_cased_name = snake_cased_name[3:] 93 | if (self.name == snake_cased_name) or not snake_case_regex.fullmatch(snake_cased_name): # Guard against bad suggestions 94 | return None 95 | return snake_cased_name 96 | 97 | def replace_in_all(self, files : list[str], change_to : (str | None) = None): 98 | for file in files: 99 | with open(file, "r") as f: 100 | content = f.read() 101 | 102 | if change_to == None: 103 | change_to = self.fix_snake_case() 104 | 105 | content = re.sub(f'\\b@?{self.name}\\b', change_to, content) 106 | 107 | with open(file, "w") as f: 108 | f.write(content) 109 | 110 | def ignore(self, reason : str): 111 | with open(self.file, "r") as f: 112 | lines = f.readlines() 113 | 114 | insertion = "(* @nocheck name *)\n" 115 | if len(reason.strip()) > 0: 116 | insertion += f"(* {reason} *)\n" 117 | lines.insert(self.line_no - 1, insertion) 118 | 119 | with open(self.file, "w") as f: 120 | lines = "".join(lines) 121 | f.write(lines) 122 | 123 | def validate_file(file) -> list[Violation]: 124 | violations : list[Violation] = list() 125 | with open(file) as lines: 126 | skip_next = False 127 | for (line_no, line) in enumerate(lines, 1): 128 | if re.match(def_name_ignore_regex, line): 129 | skip_next = True 130 | continue 131 | match = re.match(exists_thm_regex, line) 132 | if match: 133 | if skip_next: 134 | skip_next = False 135 | continue 136 | def_type = match.groups()[0] 137 | name = match.groups()[1] 138 | name_matches_rules = re.fullmatch(snake_case_regex, name) 139 | if not name_matches_rules: 140 | violations.append(Violation(line_no, file, name, def_type)) 141 | return violations 142 | 143 | 144 | file_name_regex = re.compile("[A-Z]*([A-Z][a-z])+") 145 | file_name_ignore_regex = re.compile("\\s*\\(\\*\\s*\\@nocheck\\s+filename\\s*\\*\\)") 146 | 147 | def check_file_name(file_name : str, file_path : str) -> (Violation | None): 148 | if ".Old" in file_path: 149 | return None 150 | with open(file_path) as lines: 151 | first_line = lines.readline() 152 | if first_line: 153 | is_ignored = re.match(file_name_ignore_regex, first_line) 154 | if is_ignored: 155 | return None 156 | if re.match(file_name_regex,file_name): 157 | return None 158 | return Violation(None, file_path, file_name, None) 159 | 160 | 161 | 162 | print("Checking src/ directory for comforming theorem names...") 163 | name_violations : list[Violation] = list() 164 | file_name_violations: list[Violation] = list() 165 | 166 | all_files : list[str] = list() 167 | 168 | for dir, _, files in os.walk(src_dir): 169 | if ".Old" in dir: 170 | continue 171 | for file in files: 172 | if not file.endswith(".v"): # Make sure we only look at Coq files 173 | continue 174 | all_files.append(f"{dir}/{file}") 175 | file_name_violation = check_file_name(file, f"{dir}/{file}") 176 | if file_name_violation: 177 | file_name_violations.append(file_name_violation) 178 | name_violations += validate_file(f"{dir}/{file}") 179 | 180 | 181 | if not name_violations and not file_name_violations: 182 | print("No violations found") 183 | exit(0) 184 | 185 | all_violations = file_name_violations + name_violations 186 | n_violations = len(all_violations) 187 | 188 | for (n, violation) in enumerate(all_violations, 1): 189 | print(f"({n}/{n_violations}) - {violation}") 190 | if not interactive: # If not interactive, just print the violations 191 | continue 192 | has_suggestion = violation.fix_snake_case() != None 193 | auto_fix_info = " Auto Fix(F)/" if has_suggestion else "" 194 | while True: # Do until a valid input comes along 195 | option = input(f"What do you want to do? {auto_fix_info}Manually Fix(M)/Skip(S)/Ignore(I) permanently? ").lower() 196 | if option == "f" and has_suggestion: 197 | violation.replace_in_all(all_files) 198 | break 199 | if option == "m": 200 | change_to = input('Input desired new name: ') 201 | violation.replace_in_all(all_files, change_to) 202 | break 203 | elif option == "i": 204 | reason = input("Please type in the reason for ignoring (for documentation): ") 205 | violation.ignore(reason) 206 | break 207 | elif option == "s": 208 | break 209 | else: 210 | print("Invalid option...") 211 | 212 | if not interactive: 213 | print(f"{b_color_green}Fix issues by running {os.path.realpath(__file__)} --interactive{b_color_reset}") 214 | 215 | exit(1) -------------------------------------------------------------------------------- /src/CoreRules/StackRules.v: -------------------------------------------------------------------------------- 1 | Require Export CoreData.CoreData. 2 | Require Import CastRules. 3 | Require Import SpiderInduction. 4 | 5 | Local Open Scope ZX_scope. 6 | 7 | (** Results about stacks of diagrams *) 8 | 9 | Lemma stack_assoc : 10 | forall {n0 n1 n2 m0 m1 m2} 11 | (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) (zx2 : ZX n2 m2) prfn prfm, 12 | (zx0 ↕ zx1) ↕ zx2 ∝= 13 | cast _ _ prfn prfm (zx0 ↕ (zx1 ↕ zx2)). 14 | Proof. 15 | intros. 16 | unfold proportional_by_1. 17 | simpl_cast_semantics. 18 | cbn. 19 | restore_dims. 20 | now rewrite kron_assoc by auto_wf. 21 | Qed. 22 | 23 | Lemma stack_assoc_back : 24 | forall {n0 n1 n2 m0 m1 m2} 25 | (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) (zx2 : ZX n2 m2) prfn prfm, 26 | zx0 ↕ (zx1 ↕ zx2) ∝= 27 | cast (n0 + (n1 + n2)) (m0 + (m1 + m2)) prfn prfm 28 | ((zx0 ↕ zx1) ↕ zx2). 29 | Proof. 30 | intros. 31 | unfold proportional_by_1. 32 | simpl_cast_semantics. 33 | cbn. 34 | restore_dims. 35 | now rewrite kron_assoc by auto_wf. 36 | Qed. 37 | 38 | Lemma stack_empty_l : forall {nIn nOut} (zx : ZX nIn nOut), 39 | ⦰ ↕ zx ∝= zx. 40 | Proof. 41 | intros. 42 | unfold proportional_by_1. 43 | cbn. 44 | restore_dims. 45 | now rewrite kron_1_l by auto_wf. 46 | Qed. 47 | 48 | Lemma stack_empty_r : forall {n m : nat} (zx : ZX n m) prfn prfm, 49 | zx ↕ ⦰ ∝= 50 | cast (n + 0) (m + 0) prfn prfm zx. 51 | Proof. 52 | intros. 53 | unfold proportional_by_1. 54 | simpl_cast_semantics. 55 | cbn. 56 | restore_dims. 57 | now rewrite kron_1_r by auto_wf. 58 | Qed. 59 | 60 | Lemma stack_empty_r_back : forall {n m : nat} (zx : ZX n m) prfn prfm, 61 | zx ∝= 62 | cast _ _ prfn prfm (zx ↕ ⦰). 63 | Proof. 64 | intros. 65 | unfold proportional_by_1. 66 | simpl_cast_semantics. 67 | cbn. 68 | restore_dims. 69 | now rewrite kron_1_r by auto_wf. 70 | Qed. 71 | 72 | Lemma stack_simplify_eq : forall {n1 m1 n2 m2} 73 | (zx1 zx3 : ZX n1 m1) (zx2 zx4 : ZX n2 m2), 74 | zx1 ∝= zx3 -> zx2 ∝= zx4 -> zx1 ↕ zx2 ∝= zx3 ↕ zx4. 75 | Proof. 76 | now intros * -> ->. 77 | Qed. 78 | 79 | Lemma stack_simplify : forall {n1 m1 n2 m2} 80 | (zx1 zx3 : ZX n1 m1) (zx2 zx4 : ZX n2 m2), 81 | zx1 ∝ zx3 -> zx2 ∝ zx4 -> zx1 ↕ zx2 ∝ zx3 ↕ zx4. 82 | Proof. 83 | now intros * -> ->. 84 | Qed. 85 | 86 | Lemma stack_transpose : forall {n1 m1 n2 m2} (zx1 : ZX n1 m1) (zx2 : ZX n2 m2), 87 | (zx1 ↕ zx2) ⊤ = (zx1⊤ ↕ zx2⊤). 88 | Proof. 89 | reflexivity. 90 | Qed. 91 | 92 | 93 | 94 | Lemma stack_empty_r_fwd {n m} (zx : ZX n m) : 95 | zx ↕ ⦰ ∝= 96 | cast _ _ (Nat.add_0_r _) (Nat.add_0_r _) zx. 97 | Proof. apply stack_empty_r. Qed. 98 | 99 | Lemma cast_stack_l_fwd {n0 m0 n0' m0' n1 m1} 100 | (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) prfn prfm : 101 | cast n0' m0' prfn prfm zx0 ↕ zx1 ∝= 102 | cast _ _ (f_equal (fun k => k + n1)%nat prfn) 103 | (f_equal (fun k => k + m1)%nat prfm) 104 | (zx0 ↕ zx1). 105 | Proof. now subst. Qed. 106 | 107 | Lemma cast_stack_r_fwd {n0 m0 n1 m1 n1' m1'} 108 | (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) prfn prfm : 109 | zx0 ↕ cast n1' m1' prfn prfm zx1 ∝= 110 | cast _ _ (f_equal (Nat.add n0) prfn) 111 | (f_equal (Nat.add m0) prfm) 112 | (zx0 ↕ zx1). 113 | Proof. now subst. Qed. 114 | 115 | Lemma stack_assoc_fwd {n0 n1 n2 m0 m1 m2} 116 | (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) (zx2 : ZX n2 m2) : 117 | zx0 ↕ zx1 ↕ zx2 ∝= 118 | cast _ _ (eq_sym (Nat.add_assoc _ _ _)) 119 | (eq_sym (Nat.add_assoc _ _ _)) 120 | (zx0 ↕ (zx1 ↕ zx2)). 121 | Proof. apply stack_assoc. Qed. 122 | 123 | Lemma stack_assoc_back_fwd {n0 n1 n2 m0 m1 m2} 124 | (zx0 : ZX n0 m0) (zx1 : ZX n1 m1) (zx2 : ZX n2 m2) : 125 | zx0 ↕ (zx1 ↕ zx2) ∝= 126 | cast _ _ (Nat.add_assoc _ _ _) 127 | (Nat.add_assoc _ _ _) 128 | (zx0 ↕ zx1 ↕ zx2). 129 | Proof. apply stack_assoc_back. Qed. 130 | 131 | 132 | Lemma nstack1_colorswap : forall n (zx : ZX 1 1), ⊙(n ↑ zx) = (n ↑ (⊙ zx)). 133 | Proof. 134 | intros. 135 | induction n. 136 | - easy. 137 | - simpl. 138 | rewrite IHn. 139 | easy. 140 | Qed. 141 | 142 | Lemma nstack_transpose : forall k {n m} (zx : ZX n m), (k ⇑ zx)⊤ = (k ⇑ zx⊤). 143 | Proof. 144 | intros. 145 | induction k. 146 | - easy. 147 | - simpl. 148 | rewrite IHk. 149 | easy. 150 | Qed. 151 | 152 | Lemma nstack_colorswap : forall n {n' m'} (zx : ZX n' m'), ⊙(n ⇑ zx) = (n ⇑ (⊙ zx)). 153 | Proof. 154 | intros. 155 | induction n. 156 | - easy. 157 | - simpl. 158 | rewrite IHn. 159 | easy. 160 | Qed. 161 | 162 | Lemma n_stack1_succ_l : forall n (zx : ZX 1 1), 163 | (S n) ↑ zx = zx ↕ (n ↑ zx). 164 | Proof. easy. Qed. 165 | 166 | Lemma n_stack1_succ_r : forall n (zx : ZX 1 1) prfn prfm, 167 | (S n) ↑ zx ∝= 168 | cast (S n) (S n) prfn prfm ((n ↑ zx) ↕ zx). 169 | Proof. 170 | intros. 171 | induction n. 172 | - cbn. 173 | now rewrite stack_empty_r, 2!cast_id_eq, stack_empty_l. 174 | - rewrite n_stack1_succ_l. 175 | rewrite IHn at 1. 176 | rewrite cast_stack_r. 177 | simpl. 178 | simpl_casts. 179 | rewrite stack_assoc_back. 180 | simpl_casts. 181 | easy. 182 | Unshelve. 183 | all: lia. 184 | Qed. 185 | 186 | Lemma stack_wire_distribute_l : forall {n m o} (zx0 : ZX n m) (zx1 : ZX m o), 187 | — ↕ (zx0 ⟷ zx1) ∝= (— ↕ zx0) ⟷ (— ↕ zx1). 188 | Proof. 189 | intros. 190 | unfold proportional_by_1. 191 | simpl; Msimpl; easy. 192 | Qed. 193 | 194 | Lemma stack_wire_distribute_r : forall {n m o} (zx0 : ZX n m) (zx1 : ZX m o), 195 | (zx0 ⟷ zx1) ↕ — ∝= (zx0 ↕ —) ⟷ (zx1 ↕ —). 196 | Proof. 197 | intros. 198 | unfold proportional_by_1. 199 | simpl; Msimpl; easy. 200 | Qed. 201 | 202 | Lemma stack_nwire_distribute_l : forall {n m o p} (zx0 : ZX n m) (zx1 : ZX m o), 203 | n_wire p ↕ (zx0 ⟷ zx1) ∝= (n_wire p ↕ zx0) ⟷ (n_wire p ↕ zx1). 204 | Proof. 205 | intros. 206 | unfold proportional_by_1. 207 | cbn; rewrite n_wire_semantics; Msimpl; reflexivity. 208 | Qed. 209 | 210 | Lemma stack_nwire_distribute_r : forall {n m o p} (zx0 : ZX n m) (zx1 : ZX m o), 211 | (zx0 ⟷ zx1) ↕ n_wire p ∝= (zx0 ↕ n_wire p) ⟷ (zx1 ↕ n_wire p). 212 | Proof. 213 | intros. 214 | unfold proportional_by_1. 215 | cbn; rewrite n_wire_semantics; Msimpl; reflexivity. 216 | Qed. 217 | 218 | (* Lemma n_wire_collapse_r : forall {n0 n1 m1} (zx0 : ZX n0 0) (zx1 : ZX n1 m1), 219 | (zx0 ↕ n_wire n1) ⟷ zx1 ∝ zx0 ↕ zx1. *) 220 | 221 | Lemma nstack1_split : forall n m (zx : ZX 1 1), 222 | (n + m) ↑ zx ∝= 223 | (n ↑ zx) ↕ (m ↑ zx). 224 | Proof. 225 | intros. 226 | induction n. 227 | - simpl. rewrite stack_empty_l. easy. 228 | - simpl. 229 | rewrite IHn. 230 | rewrite (stack_assoc zx). 231 | simpl_casts. 232 | reflexivity. 233 | Unshelve. 234 | all: lia. 235 | Qed. 236 | 237 | Lemma nstack_split : forall n m {nIn mOut} (zx : ZX nIn mOut) prfn prfm, 238 | (n + m) ⇑ zx ∝= 239 | cast _ _ prfn prfm ((n ⇑ zx) ↕ (m ⇑ zx)). 240 | Proof. 241 | intros. 242 | dependent induction n. 243 | - simpl. simpl_casts. 244 | rewrite stack_empty_l. easy. 245 | - simpl. 246 | rewrite IHn. 247 | simpl. 248 | simpl_casts. 249 | rewrite stack_assoc. 250 | simpl_casts. 251 | reflexivity. 252 | Unshelve. 253 | all: lia. 254 | Qed. 255 | 256 | Lemma nstack1_1 : forall zx, 1 ↑ zx ∝= zx. 257 | Proof. 258 | intros. 259 | simpl. 260 | rewrite stack_empty_r. 261 | simpl_casts. 262 | easy. 263 | Unshelve. 264 | all: lia. 265 | Qed. 266 | 267 | Lemma nstack1_0 : forall zx, 0 ↑ zx = ⦰. 268 | Proof. easy. Qed. 269 | 270 | Lemma n_stack_mul {n m} k l (zx : ZX n m) : 271 | (k * l) ⇑ zx ∝= 272 | cast _ _ (eq_sym (Nat.mul_assoc _ _ _)) (eq_sym (Nat.mul_assoc _ _ _)) 273 | (k ⇑ (l ⇑ zx)). 274 | Proof. 275 | induction k. 276 | - simpl. 277 | now rewrite cast_id. 278 | - simpl. 279 | rewrite nstack_split, IHk. 280 | simpl_casts. 281 | reflexivity. 282 | Unshelve. all: lia. 283 | Qed. 284 | 285 | Lemma n_stack_semantics {n m} (zx : ZX n m) k : 286 | ⟦ k ⇑ zx ⟧ = k ⨂ ⟦ zx ⟧. 287 | Proof. 288 | induction k; [easy|]. 289 | rewrite kron_n_assoc by auto_wf. 290 | simpl. 291 | rewrite IHk. 292 | f_equal; rewrite <- Nat.pow_mul_r; f_equal; lia. 293 | Qed. 294 | 295 | 296 | Lemma n_stack1_semantics (zx : ZX 1 1) k : 297 | ⟦ k ↑ zx ⟧ = k ⨂ ⟦ zx ⟧. 298 | Proof. 299 | induction k; [easy|]. 300 | rewrite kron_n_assoc by auto_wf. 301 | simpl. 302 | rewrite IHk. 303 | f_equal; rewrite <- Nat.pow_mul_r; f_equal; lia. 304 | Qed. 305 | 306 | 307 | 308 | 309 | Lemma n_stack_1 {n m} (zx : ZX n m) : 1 ⇑ zx ∝= 310 | cast _ _ (Nat.mul_1_l _) (Nat.mul_1_l _) zx. 311 | Proof. 312 | simpl. 313 | rewrite stack_empty_r. 314 | reflexivity. 315 | Qed. 316 | 317 | Lemma n_stack_1' {n m} (zx : ZX n m) prfn prfm : cast _ _ prfn prfm (1 ⇑ zx) ∝= 318 | zx. 319 | Proof. 320 | now rewrite n_stack_1, cast_contract, cast_id. 321 | Unshelve. all: reflexivity. 322 | Qed. 323 | 324 | -------------------------------------------------------------------------------- /src/Permutations/ZXpermAutomation.v: -------------------------------------------------------------------------------- 1 | Require Import ZXCore. 2 | Require CastRules ComposeRules. 3 | Require Export ZXperm. 4 | 5 | (** Automation for [ZXperm]'s *) 6 | 7 | #[export] Hint Extern 100 (WF_Matrix _) => 8 | apply WF_Matrix_dim_change : wf_db. 9 | 10 | Create HintDb perm_of_zx_cleanup_db. 11 | Create HintDb zxperm_db. 12 | #[export] Hint Constructors ZXperm : zxperm_db. 13 | 14 | Ltac cleanup_perm_of_zx := 15 | autounfold with zxperm_db; 16 | autorewrite with perm_of_zx_cleanup_db perm_inv_db perm_cleanup_db; 17 | auto with perm_of_zx_cleanup_db perm_inv_db perm_cleanup_db 18 | perm_db perm_bounded_db WF_Perm_db. 19 | 20 | (* Hack to get auto to apply PermStack where it obviously should 21 | (like to ZXperm (S n) (— ↕ zx), where zx : ZX n n; it doesn't work 22 | here because apply doesn't see that S n = 1 + n, but if we tell it 23 | to look for 1 + n, it will find S n). *) 24 | Ltac __cleanup_stack_perm zx0 zx1 := 25 | match type of zx0 with ZX ?n0 ?n0 => 26 | match type of zx1 with ZX ?n1 ?n1 => 27 | apply (PermStack (n0:=n0) (n1:=n1)) 28 | end end. 29 | 30 | #[export] Hint Extern 0 (ZXperm (?zx0 ↕ ?zx1)) => 31 | __cleanup_stack_perm zx0 zx1 : zxperm_db. 32 | 33 | #[export] Hint Extern 0 (ZXperm (@Stack ?n0 ?m0 ?n1 ?m1 ?zx0 ?zx1)) => 34 | apply (@PermStack n0 m0 n1 m1 zx0 zx1) : zxperm_db. 35 | 36 | 37 | (* Making proportional_of_eq_perm usable, mostly through a series of tactics to 38 | deal with the absolute nightmare that is definitional equality casts. *) 39 | Lemma prop_iff_double_cast : forall {n0 m0} n1 m1 (zx0 zx1 : ZX n0 m0) 40 | (prfn: n1 = n0) (prfm : m1 = m0), 41 | Proportional.proportional zx0 zx1 <-> 42 | Proportional.proportional (cast n1 m1 prfn prfm zx0) (cast _ _ prfn prfm zx1). 43 | Proof. 44 | intros. 45 | subst. 46 | reflexivity. 47 | Qed. 48 | 49 | (* Ltac __cast_prop_sides_to_square := 50 | match goal with 51 | | |- Proportional.proportional ?zx0 ?zx1 => 52 | match type of zx0 with 53 | | ZX ?n ?n => idtac 54 | | ZX ?n ?m => 55 | let Hm0n := fresh "Hm0n" in 56 | assert (Hm0n : n = m) by lia; 57 | rewrite (prop_iff_double_cast n n zx0 zx1 (eq_refl) (Hm0n)) 58 | end 59 | end. *) 60 | 61 | Lemma cast_compose_eq : forall n0 n1 m o0 o1 (zx0 : ZX n0 m) (zx1 : ZX m o0) Hn0n1 Ho0o1, 62 | cast n1 o1 Hn0n1 Ho0o1 (zx0 ⟷ zx1) = 63 | (cast n1 m Hn0n1 (@eq_refl _ m) zx0) ⟷ (cast m o1 (@eq_refl _ m) Ho0o1 zx1). 64 | Proof. 65 | intros. 66 | subst. 67 | reflexivity. 68 | Qed. 69 | 70 | Lemma cast_cast_eq : forall n0 m0 n1 m1 n2 m2 (zx : ZX n0 m0) Hn0n1 Hm0m1 Hn1n2 Hm1m2, 71 | let Hn0n2 := eq_trans Hn1n2 Hn0n1 in 72 | let Hm0m2 := eq_trans Hm1m2 Hm0m1 in 73 | cast n2 m2 Hn1n2 Hm1m2 (cast n1 m1 Hn0n1 Hm0m1 zx) = 74 | cast n2 m2 Hn0n2 Hm0m2 zx. 75 | Proof. 76 | intros; subst. 77 | reflexivity. 78 | Qed. 79 | 80 | Lemma cast_id_eq : forall n m (prfn : n = n) (prfm : m = m) zx, 81 | cast n m prfn prfm zx = zx. 82 | Proof. 83 | intros; subst. 84 | rewrite (Eqdep_dec.UIP_refl_nat n prfn). (* Replace prfn with (@eq_refl nat n) *) 85 | rewrite (Eqdep_dec.UIP_refl_nat m prfm). (* Replace prfn with (@eq_refl nat m) *) 86 | reflexivity. 87 | Qed. 88 | 89 | Lemma zxperm_iff_cast' n m n' m' 90 | (zx : ZX n m) (Hn : n' = n) (Hm : m' = m) : 91 | ZXperm (cast n' m' Hn Hm zx) <-> ZXperm zx. 92 | Proof. 93 | intros. 94 | now subst. 95 | Qed. 96 | 97 | #[export] Hint Resolve <- zxperm_iff_cast' : zxperm_db. 98 | 99 | Ltac simpl_permlike_zx := 100 | let simpl_casts_eq := first [ 101 | rewrite cast_id_eq | 102 | rewrite cast_cast_eq ] 103 | in 104 | repeat (match goal with 105 | | |- context[?zx ⟷ cast ?m' ?o' ?prfm ?prfo (n_wire ?o)] => 106 | rewrite (@CastRules.cast_compose_r _ _ _ _ _ prfm prfo zx _); 107 | rewrite (@ComposeRules.nwire_removal_r o) 108 | | |- context[cast ?n' ?m' ?prfn ?prfm (n_wire ?n) ⟷ ?zx] => 109 | rewrite (@CastRules.cast_compose_l _ _ _ _ _ prfn prfm _ zx); 110 | rewrite (@ComposeRules.nwire_removal_l n) 111 | | |- context[@cast ?n' ?m' ?n ?m ?prfn ?prfm ?zx ⟷ cast ?m' ?o' ?prfom ?prfo (n_wire ?o)] => 112 | rewrite (@CastRules.cast_compose_l n n' m m' o' prfn prfm zx (cast m' o' prfom prfo (n_wire o))); 113 | rewrite (cast_cast_eq _ _ _ _ _ _ (n_wire o)); 114 | try rewrite (cast_id_eq _ _ _ _ (zx ⟷ _)) 115 | | |- context[cast ?n ?m' ?prfn ?prfmn (n_wire ?n') ⟷ @cast ?m' ?o' ?m ?o ?prfm ?prfo ?zx] => 116 | rewrite (@CastRules.cast_compose_r n m m' o o' prfm prfo (cast n m prfn prfmn (n_wire n')) zx); 117 | rewrite (cast_cast_eq _ _ _ _ _ _ (n_wire n')); 118 | try rewrite (cast_id_eq _ _ _ _ (zx ⟷ _)) 119 | | |- context[cast ?n1 ?m _ _ ?zx0 ⟷ cast ?m ?o1 _ _ ?zx1] => 120 | rewrite <- (cast_compose_eq _ n1 m _ o1 zx0 zx1) 121 | | |- context[ @cast ?n1 ?m1 ?n0 ?m0 ?prfn0 ?prfm0 ?zx0 ⟷ cast ?m1 ?o1 ?prfm1 ?prfo1 ?zx1 ] => 122 | rewrite (CastRules.cast_compose_mid m0 (eq_sym prfm0) (eq_sym prfm0) (cast n1 m1 prfn0 prfm0 zx0) (cast m1 o1 prfm1 prfo1 zx1)); 123 | rewrite 124 | (cast_cast_eq _ _ _ _ _ _ zx0), (cast_cast_eq _ _ _ _ _ _ zx1), 125 | (cast_id_eq _ _ _ _ zx0) 126 | end; repeat simpl_casts_eq) 127 | || (repeat simpl_casts_eq). 128 | 129 | #[export] Hint Extern 2 => 130 | (repeat first [rewrite cast_id_eq | rewrite cast_cast_eq]) : zxperm_db. 131 | 132 | Ltac __one_round_cleanup_zxperm_of_cast := 133 | match goal with 134 | | |- ZXperm _ (cast ?n2 ?m2 ?Hn1n2 ?Hm1m2 (@cast ?n1 ?m1 ?n0 ?m0 ?Hn0n1 ?Hm0m1 ?zx)) => (* idtac "clean_cast_cast"; *) 135 | rewrite (cast_cast_eq n0 m0 n1 m1 n2 m2 zx Hn0n1 Hm0m1 Hn1n2 Hm1m2) 136 | | |- ZXperm ?n (@cast ?n ?n ?n ?n _ _ ?zx) => (* idtac "clean_id"; *) 137 | rewrite (cast_id_eq n n _ _ zx) 138 | | |- ZXperm ?n (@cast ?n ?n ?n' ?m' _ _ (?zx0 ⟷ ?zx1)) => (* idtac "clean_comp"; *) 139 | rewrite (cast_compose_eq _ _ _ _ _ zx0 zx1) by lia; 140 | apply PermComp 141 | | |- ZXperm ?n (@cast ?n ?n ?n' ?m' _ _ (?zx0 ↕ ?zx1)) => (* idtac "clean_stack"; *) 142 | match type of zx0 with ZX ?n0 ?n0 => 143 | match type of zx1 with ZX ?n1 ?n1 => 144 | rewrite <- (zxperm_iff_cast' (n) (n0 + n1) (ltac:(lia)) (ltac:(lia))) 145 | end end 146 | end. 147 | 148 | (* #[export] Hint Extern 3 (ZXperm (cast _ _ _ _ _)) => __one_round_cleanup_zxperm_of_cast : zxperm_db. *) 149 | 150 | (* Lemma perm_of_cast_compose_each_square : forall n m a b c d 151 | (zx0 : ZX n n) (zx1 : ZX m m) prfa0 prfb0 prfb1 prfc1 prfd1 prfd2, 152 | ZXperm n zx0 -> ZXperm m zx1 -> 153 | ZXperm d (cast d d prfd1 prfd2 154 | (cast a b prfa0 prfb0 zx0 ⟷ cast b c prfb1 prfc1 zx1)). 155 | Proof. 156 | intros. 157 | subst. 158 | auto with zxperm_db. 159 | Qed. 160 | 161 | #[export] Hint Resolve perm_of_cast_compose_each_square : zxperm_db. *) 162 | 163 | (* I don't know if these actually ever help: *) 164 | (* Lemma perm_of_cast_compose_each_square_l : forall n m c d 165 | (zx0 : ZX n n) (zx1 : ZX m m) prfb1 prfc1 prfd1 prfd2, 166 | ZXperm n zx0 -> ZXperm m zx1 -> 167 | ZXperm d (cast d d prfd1 prfd2 168 | (zx0 ⟷ cast n c prfb1 prfc1 zx1)). 169 | Proof. 170 | intros. 171 | subst. 172 | auto with zxperm_db. 173 | Qed. 174 | 175 | Lemma perm_of_cast_compose_each_square_r : forall n m a d 176 | (zx0 : ZX n n) (zx1 : ZX m m) prfa0 prfm0 prfd1 prfd2, 177 | ZXperm n zx0 -> ZXperm m zx1 -> 178 | ZXperm d (cast d d prfd1 prfd2 179 | (cast a m prfa0 prfm0 zx0 ⟷ zx1)). 180 | Proof. 181 | intros. 182 | subst. 183 | auto with zxperm_db. 184 | Qed. *) 185 | 186 | 187 | (* #[export] Hint Resolve perm_of_cast_compose_each_square_l 188 | perm_of_cast_compose_each_square_r : zxperm_db. *) 189 | 190 | 191 | (* This can't be here because proportional_of_eq_perm is defined later, but keeping 192 | for reference. (This is put in ZXpermSemantics, right after proportional_of_eq_perm.) *) 193 | 194 | (* 195 | Ltac prop_perm_eq := 196 | intros; 197 | simpl_casts; 198 | simpl_permlike_zx; 199 | __cast_prop_sides_to_square; 200 | (* Goal: zx0 ∝ zx1 *) 201 | apply proportional_of_eq_perm; [ 202 | (* New goals: *) 203 | (*1: ZXperm _ zx0 *) auto with zxperm_db | 204 | (*2: ZXperm _ zx1*) auto with zxperm_db | 205 | (*3: perm_of_zx zx0 = perm_of_zx zx1*) cleanup_perm_of_zx; try easy; try lia 206 | ]. 207 | *) 208 | 209 | 210 | (* For VyZX lemmas which create a ton of shelved goals, this solves 211 | them immediately (and ensures they *are* solvable, 212 | unlike auto_cast_eqn) *) 213 | Tactic Notation "clean_eqns" tactic(tac) := 214 | unshelve (tac); [reflexivity + lia..|]. 215 | 216 | Ltac print_hyps := 217 | try (match reverse goal with | H : ?p |- _ => idtac H ":" p; fail end). 218 | 219 | Ltac print_goal := 220 | match reverse goal with |- ?P => idtac P; idtac "" end. 221 | 222 | Ltac print_state := 223 | print_hyps; 224 | idtac "---------------------------------------------------------"; 225 | print_goal. 226 | 227 | (* TODO: Move to QuantumLib *) 228 | Ltac by_perm_cell := 229 | let i := fresh "i" in 230 | let Hi := fresh "Hi" in 231 | intros i Hi; try solve_end; 232 | repeat 233 | (destruct i as [| i]; [ | apply <- Nat.succ_lt_mono in Hi ]; 234 | try solve_end). 235 | 236 | Arguments Nat.leb !_ !_ /. 237 | 238 | (* FIXME: Move to Qlib *) 239 | Ltac auto_perm_to n := 240 | auto n with perm_db perm_bounded_db WF_Perm_db perm_inv_db. 241 | 242 | Ltac auto_perm := 243 | auto 6 with perm_db perm_bounded_db WF_Perm_db perm_inv_db. 244 | 245 | Tactic Notation "auto_perm" int_or_var(n) := 246 | auto_perm_to n. 247 | 248 | Tactic Notation "auto_perm" := 249 | auto_perm 6. 250 | 251 | Ltac auto_zxperm_to n := 252 | auto n with zxperm_db perm_db perm_bounded_db WF_Perm_db perm_inv_db. 253 | 254 | Ltac auto_zxperm n := 255 | auto 6 with zxperm_db perm_db perm_bounded_db WF_Perm_db perm_inv_db. 256 | 257 | Tactic Notation "auto_zxperm" int_or_var(n) := 258 | auto_zxperm_to n. 259 | 260 | Tactic Notation "auto_zxperm" := 261 | auto_zxperm 6. 262 | -------------------------------------------------------------------------------- /src/Gates/GateRules.v: -------------------------------------------------------------------------------- 1 | Require Import QuantumLib.Quantum. 2 | Require Export ZXCore. 3 | Require Export GateDefinitions. 4 | Require Export DiagramRules. 5 | Require Export CoreRules. 6 | 7 | Local Open Scope ZX_scope. 8 | Local Open Scope matrix_scope. 9 | 10 | (** Rules for manipulating gates *) 11 | 12 | Lemma Z_is_Z : ⟦ _Z_ ⟧ = σz. 13 | Proof. 14 | apply z_1_1_pi_σz. 15 | Qed. 16 | 17 | Lemma X_is_X : ⟦ _X_ ⟧ = σx. 18 | Proof. 19 | apply x_1_1_pi_σx. 20 | Qed. 21 | 22 | Lemma _H_is_box : _H_ ∝[Cexp (PI/4)] □. 23 | Proof. 24 | apply prop_by_iff_zx_scale. 25 | split; [|nonzero]. 26 | rewrite box_decomposition_Z_X_Z. 27 | distribute_zxscale. 28 | rewrite zx_scale_eq_1_l; [reflexivity|]. 29 | rewrite Cexp_PI4. 30 | C_field; lca. 31 | Qed. 32 | 33 | Lemma _Rz_is_Rz : forall α, ⟦ _Rz_ α ⟧ = phase_shift α. 34 | Proof. 35 | intros. 36 | lma'. 37 | Qed. 38 | 39 | Lemma cnot_l_is_cnot : ⟦ _CNOT_ ⟧ = (/ (√ 2)%R) .* cnot. 40 | Proof. 41 | prep_matrix_equivalence. 42 | cbn. 43 | rewrite X_2_1_0_semantics. 44 | restore_dims. 45 | compute_matrix (/ √ 2 .* cnot). 46 | compute_matrix (Z_semantics 1 2 0). 47 | rewrite Cexp_0. 48 | rewrite 2!make_WF_equiv. 49 | rewrite Kronecker.kron_I_l, Kronecker.kron_I_r. 50 | by_cell; lazy; lca. 51 | Qed. 52 | 53 | Lemma cnot_involutive : _CNOT_R ⟷ _CNOT_ ∝[/ C2] n_wire 2. 54 | Proof. 55 | rewrite <- compose_assoc. 56 | rewrite (compose_assoc (— ↕ (X 1 2 0))). 57 | rewrite <- (stack_compose_distr (Z 2 1 0) (Z 1 2 0) — —). 58 | rewrite Z_spider_1_1_fusion. 59 | cleanup_zx. 60 | rewrite (X_wrap_over_top_left 1 1). 61 | rewrite (X_wrap_over_top_right 1 1) at 1. 62 | rewrite <- wire_to_n_wire. 63 | rewrite <- (wire_removal_l —) at 1. 64 | rewrite <- (wire_removal_l —) at 6. 65 | rewrite 2 stack_compose_distr. 66 | rewrite (stack_assoc_back — — (X 1 2 0)). 67 | rewrite (stack_assoc_back — — (X 2 1 0)). 68 | rewrite !cast_id. 69 | change (n_wire 2) with (— ↕ n_wire (0 + 1)). 70 | rewrite <- wire_to_n_wire, wire_to_n_wire, 2!n_wire_stack, 71 | <- wire_to_n_wire. 72 | change (1 + (0 + 1))%nat with 2%nat. 73 | rewrite (compose_assoc (— ↕ (⊂ ↕ —))). 74 | rewrite wire_to_n_wire at 3. 75 | rewrite (nwire_stack_compose_topleft (X 2 1 0) (Z 2 2 (0 + 0))). 76 | rewrite <- (nwire_stack_compose_botleft (Z 2 2 (0 + 0)) (X 2 1 0)). 77 | repeat rewrite <- compose_assoc. 78 | rewrite (compose_assoc _ (n_wire 2 ↕ (X 2 1 0))). 79 | rewrite <- (stack_compose_distr (n_wire 2) (n_wire (1 + 1)) (X 2 1 0) (X 1 2 0)). 80 | rewrite X_spider_1_1_fusion. 81 | rewrite Rplus_0_r. 82 | rewrite nwire_removal_l. 83 | cbn. 84 | rewrite stack_empty_r_fwd, cast_id. 85 | rewrite (compose_assoc _ (— ↕ — ↕ X 2 2 _)). 86 | rewrite stack_assoc. (* simpl_casts. *) 87 | rewrite cast_id. 88 | rewrite <- (stack_compose_distr — — (— ↕ X 2 2 _)). 89 | rewrite wire_removal_l. 90 | rewrite wire_to_n_wire at 7. 91 | rewrite <- X_wrap_over_top_left. 92 | rewrite (stack_assoc_back — ⊂ —). 93 | rewrite (stack_assoc_back _ — —). 94 | rewrite !cast_id. 95 | rewrite <- (stack_compose_distr (— ↕ ⊂) (Z 2 2 _ ↕ —) — —). 96 | rewrite wire_removal_l. 97 | rewrite wire_to_n_wire at 1. 98 | erewrite <- (cast_id _ _ (n_wire 1 ↕ ⊂)). 99 | rewrite <- Z_wrap_under_bot_left. 100 | change (2 + 1)%nat with (1 + 2)%nat. 101 | 102 | rewrite wire_to_n_wire. 103 | rewrite grow_Z_bot_right. 104 | rewrite grow_X_top_left. 105 | rewrite stack_nwire_distribute_r. 106 | rewrite stack_nwire_distribute_l. 107 | repeat rewrite <- compose_assoc. 108 | rewrite (compose_assoc _ (n_wire 1 ↕ Z 1 2 0 ↕ n_wire 1)). 109 | rewrite stack_assoc. 110 | rewrite cast_id. 111 | rewrite <- wire_to_n_wire. 112 | rewrite <- (stack_compose_distr — — (Z 1 2 0 ↕ —)). 113 | rewrite <- stack_compose_distr. 114 | rewrite wire_removal_l. 115 | zxrewrite hopf_rule_Z_X. 116 | rewrite wire_to_n_wire. 117 | rewrite stack_nwire_distribute_r. 118 | rewrite stack_nwire_distribute_l. 119 | repeat rewrite <- compose_assoc. 120 | rewrite stack_assoc_back. 121 | rewrite cast_id. 122 | rewrite <- (stack_nwire_distribute_r (Z 1 (1 + 1) 0) (n_wire 1 ↕ Z 1 0 0 )). 123 | rewrite <- grow_Z_bot_right. 124 | rewrite compose_assoc. 125 | rewrite <- stack_nwire_distribute_l. 126 | rewrite <- X_appendix_rot_l. 127 | rewrite Rplus_0_r. 128 | rewrite Z_0_is_wire, X_0_is_wire. 129 | rewrite <- wire_to_n_wire. 130 | rewrite <- (stack_compose_distr — — — —). 131 | cleanup_zx. 132 | zxrefl. 133 | Unshelve. 134 | all: reflexivity. 135 | Qed. 136 | 137 | Lemma cnot_is_cnot_r : _CNOT_ ∝= _CNOT_R. 138 | Proof. 139 | intros. 140 | remember (— ↕ X 1 2 0 ⟷ (Z 2 1 0 ↕ —)) as RHS. 141 | rewrite (Z_wrap_under_bot_left 1 1). 142 | rewrite (X_wrap_over_top_left 1 1). 143 | rewrite cast_id. 144 | rewrite wire_to_n_wire. 145 | rewrite stack_nwire_distribute_l. 146 | rewrite stack_nwire_distribute_r. 147 | repeat rewrite <- compose_assoc. 148 | rewrite (compose_assoc _ (Z (1 + 1) 1 0 ↕ (n_wire _) ↕ _)). 149 | rewrite stack_assoc. 150 | rewrite cast_id. 151 | rewrite n_wire_stack. 152 | rewrite (nwire_stack_compose_botleft (Z (1 + 1) 1 0) (n_wire 1 ↕ X 1 2 0)). 153 | rewrite <- (nwire_stack_compose_topleft (n_wire 1 ↕ X 1 2 0)). 154 | rewrite <- compose_assoc. 155 | rewrite stack_assoc_back. 156 | rewrite cast_id. 157 | rewrite n_wire_stack. 158 | rewrite <- (stack_compose_distr ((n_wire 1) ↕ ⊂) (n_wire 3) (n_wire 1) (X 1 2 0)). 159 | rewrite nwire_removal_l, nwire_removal_r. 160 | rewrite <- nwire_stack_compose_topleft. 161 | rewrite compose_assoc. 162 | rewrite nwire_stack_compose_botleft. 163 | rewrite <- (nwire_stack_compose_topleft (⊃ ↕ n_wire 1)). 164 | rewrite <- compose_assoc. 165 | rewrite (compose_assoc _ (n_wire 1 ↕ ⊂ ↕ n_wire 2) _). 166 | cbn; rewrite stack_empty_r_fwd, cast_id. 167 | (* cbn; cleanup_zx; simpl_casts. *) 168 | rewrite 2 (@stack_assoc 1 _ _ 1), 2 cast_id. 169 | rewrite <- stack_wire_distribute_l. 170 | rewrite (@stack_assoc_back 1 2 1 1 0 1), 171 | (@stack_assoc_back 0 1 1 2 1 1), 2 cast_id. 172 | rewrite <- (stack_wire_distribute_r (⊂ ↕ —) (— ↕ ⊃)). 173 | rewrite yank_r. 174 | bundle_wires. 175 | rewrite nwire_removal_r. 176 | subst. 177 | easy. 178 | Unshelve. 179 | all: reflexivity. 180 | Qed. 181 | 182 | Import Setoid. 183 | Import Kronecker. 184 | Require Import ZXpermFacts. 185 | Import CoreRules. 186 | 187 | Local Open Scope matrix_scope. 188 | 189 | Add Parametric Morphism n : (zx_of_perm n) with signature 190 | perm_eq n ==> eq as zx_of_perm_proper. 191 | Proof. 192 | intros. 193 | now apply zx_of_perm_eq_of_perm_eq. 194 | Qed. 195 | 196 | Lemma cnot_states_b b0 b1 : 197 | state_b b0 ↕ state_b b1 ⟷ _CNOT_ ∝= 198 | /√2 .* (state_b b0 ↕ state_b (b0 ⊕ b1)). 199 | Proof. 200 | rewrite <- compose_assoc. 201 | rewrite <- stack_compose_distr, wire_removal_r. 202 | rewrite Z_1_2_state_b, Cexp_0, Tauto.if_same, zx_scale_1_l. 203 | rewrite (@stack_assoc_fwd 0 0 0 1 1 1), cast_id, 204 | <- (@stack_compose_distr 0 1 1 0 2 1). 205 | rewrite X_2_1_states_b, wire_removal_r. 206 | rewrite Rplus_0_l. 207 | rewrite (state_b_defn' (xorb _ _)). 208 | rewrite gadget_is_scaled_empty, const_of_zx_invsqrt2; distribute_zxscale. 209 | rewrite zx_scale_stack_distr_r, zx_scale_assoc. 210 | rewrite stack_empty_l. 211 | apply zx_scale_simplify_eq_l; C_field. 212 | Qed. 213 | 214 | Lemma cnot_inv_is_colorswap_cnot : 215 | _CNOT_inv_ ∝= ⊙ _CNOT_. 216 | Proof. 217 | now rewrite colorswap_is_bihadamard, ! compose_assoc. 218 | Qed. 219 | 220 | Lemma cnot_inv_states_b b0 b1 : 221 | state_b b0 ↕ state_b b1 ⟷ _CNOT_inv_ ∝= 222 | /√2 .* (state_b (b0 ⊕ b1) ↕ state_b b1). 223 | Proof. 224 | rewrite cnot_inv_is_colorswap_cnot. 225 | cbn. 226 | rewrite <- compose_assoc. 227 | rewrite <- (@stack_compose_distr 0 1 2 0 1 1). 228 | rewrite X_1_n_state_b, wire_removal_r, Rplus_0_r. 229 | 230 | distribute_zxscale. 231 | rewrite zx_scale_compose_distr_l. 232 | apply zx_scale_simplify_eq_r. 233 | destruct b0. 234 | - rewrite xorb_true_l, X_0_2_PI_to_cup_not, cup_pullthrough_bot_1. 235 | rewrite not_defn; cbn [transpose]; rewrite <- not_defn. 236 | rewrite wire_removal_r. 237 | rewrite <- (nwire_removal_l (state_b b1)) at 1. 238 | rewrite stack_compose_distr. 239 | rewrite (@stack_assoc_fwd 1 1 0 1 1 1), cast_id. 240 | rewrite compose_assoc. 241 | rewrite <- (@stack_compose_distr 1 1 1 1 2 1). 242 | rewrite wire_removal_r. 243 | rewrite (stack_split_antidiag NOT). 244 | rewrite <- compose_assoc. 245 | rewrite stack_nwire_distribute_l, <- compose_assoc. 246 | rewrite (@stack_assoc_back_fwd 1 1 0 1 1 1), cast_id. 247 | rewrite wire_to_n_wire, n_wire_stack. 248 | rewrite <- (stack_split_diag ⊂ (state_b b1)). 249 | rewrite (stack_split_antidiag ⊂). 250 | rewrite (compose_assoc (n_wire 0 ↕ state_b _)). 251 | rewrite <- wire_to_n_wire at 2. 252 | rewrite <- Z_wrap_over_top_right. 253 | rewrite stack_empty_l. 254 | rewrite Z_1_2_state_b, Cexp_0, Tauto.if_same, zx_scale_1_l. 255 | rewrite <- (@stack_compose_distr 0 1 1 0 1 1). 256 | rewrite not_state_b, nwire_removal_r. 257 | reflexivity. 258 | - rewrite xorb_false_l, <- cap_X. 259 | rewrite stack_split_antidiag, compose_assoc. 260 | rewrite <- Z_wrap_over_top_right. 261 | rewrite stack_empty_l. 262 | rewrite Z_1_2_state_b, Cexp_0, Tauto.if_same, zx_scale_1_l. 263 | reflexivity. 264 | Qed. 265 | 266 | Lemma cnot_inv_is_swapped_cnot : _CNOT_inv_ ∝= ⨉ ⟷ _CNOT_ ⟷ ⨉. 267 | Proof. 268 | apply prop_eq_by_eq_on_states_b_step. 269 | intros b0. 270 | apply prop_eq_by_eq_on_state_b_1_n. 271 | intros b1. 272 | rewrite <- 2 (compose_assoc (state_b b1)), <- push_out_top. 273 | rewrite cnot_inv_states_b. 274 | rewrite (compose_assoc ⨉), <- (compose_assoc (state_b _ ↕ state_b _)). 275 | rewrite swap_commutes_r, zx_comm_0_0, compose_empty_l. 276 | rewrite <- compose_assoc. 277 | rewrite cnot_states_b. 278 | distribute_zxscale. 279 | rewrite swap_commutes_r, zx_comm_0_0, compose_empty_l. 280 | now rewrite xorb_comm. 281 | Qed. 282 | 283 | Lemma notc_is_swapp_cnot : _NOTC_ ∝= ⨉ ⟷ _CNOT_ ⟷ ⨉. 284 | Proof. 285 | rewrite <- cnot_inv_is_swapped_cnot. 286 | rewrite compose_assoc. 287 | rewrite <- colorswap_is_bihadamard. 288 | rewrite cnot_is_cnot_r. 289 | easy. 290 | Qed. 291 | 292 | Lemma cnot_is_swapp_notc : _CNOT_ ∝= ⨉ ⟷ _NOTC_ ⟷ ⨉. 293 | Proof. 294 | rewrite notc_is_swapp_cnot. 295 | rewrite compose_assoc, (compose_assoc _ ⨉). 296 | rewrite swap_compose, nwire_removal_r. 297 | rewrite <- compose_assoc. 298 | now rewrite swap_compose, nwire_removal_l. 299 | Qed. 300 | 301 | Lemma notc_r_is_swapp_cnot_r : _NOTC_R ∝= ⨉ ⟷ _CNOT_R ⟷ ⨉. 302 | Proof. 303 | rewrite <- cnot_is_cnot_r. 304 | rewrite <- cnot_inv_is_swapped_cnot. 305 | rewrite compose_assoc. 306 | rewrite <- colorswap_is_bihadamard. 307 | easy. 308 | Qed. 309 | 310 | Lemma notc_is_notc_r : _NOTC_ ∝= _NOTC_R. 311 | Proof. 312 | rewrite notc_is_swapp_cnot. 313 | rewrite cnot_is_cnot_r. 314 | rewrite <- notc_r_is_swapp_cnot_r. 315 | easy. 316 | Qed. -------------------------------------------------------------------------------- /src/CoreRules/SwapRules.v: -------------------------------------------------------------------------------- 1 | Require Import QuantumLib.Kronecker QuantumLib.Modulus. 2 | Require Import CoreData. 3 | Require Import WireRules. 4 | Require Import CoreAutomation. 5 | Require Import StackComposeRules. 6 | Require Import CastRules. 7 | Require Import ZXpermFacts. 8 | 9 | (** Rules for manipulating swaps *) 10 | 11 | Lemma swap_compose : 12 | ⨉ ⟷ ⨉ ∝= n_wire 2. 13 | Proof. 14 | by_perm_eq_nosimpl; by_perm_cell; reflexivity. 15 | Qed. 16 | 17 | Global Hint Rewrite swap_compose : cleanup_zx_db. 18 | 19 | Lemma top_wire_to_bottom_ind : forall n, top_wire_to_bottom (S (S n)) = 20 | @Mmult _ (2 ^ (S (S n))) _ ((I 2) ⊗ top_wire_to_bottom (S n)) (swap ⊗ (I (2 ^ n))). 21 | Proof. 22 | intros. 23 | induction n. 24 | - Msimpl. 25 | simpl. 26 | Msimpl. 27 | easy. 28 | - rewrite IHn. 29 | simpl. 30 | apply Mmult_simplify. 31 | + apply kron_simplify; easy. 32 | + apply kron_simplify; [easy | ]. 33 | rewrite kron_n_I. 34 | rewrite id_kron. 35 | replace (2 ^ n + (2 ^ n + 0))%nat with (2 ^ n * 2)%nat by lia. 36 | easy. 37 | Qed. 38 | 39 | 40 | 41 | (* Proving correctness of conversion *) 42 | 43 | Lemma top_to_bottom_correct : forall n, ⟦ top_to_bottom n ⟧ = top_wire_to_bottom n. 44 | Proof. 45 | intros. 46 | destruct n; [ reflexivity | ]. 47 | destruct n; [ easy | ]. 48 | induction n. 49 | - easy. 50 | - cbn. 51 | simpl in IHn. 52 | rewrite <- IHn. 53 | fold (n_wire n). 54 | rewrite n_wire_semantics. 55 | rewrite kron_n_I. 56 | rewrite 2 id_kron. 57 | replace (2 * 2 ^ n)%nat with (2 ^ n * 2)%nat by lia. 58 | easy. 59 | Qed. 60 | 61 | Lemma bottom_to_top_correct : forall n, ⟦ bottom_to_top n ⟧ = bottom_wire_to_top n. 62 | Proof. 63 | intros. 64 | unfold bottom_to_top. 65 | unfold bottom_wire_to_top. 66 | rewrite semantics_transpose_comm. 67 | rewrite top_to_bottom_correct. 68 | easy. 69 | Qed. 70 | 71 | Lemma a_swap_correct : forall n, ⟦ a_swap n ⟧ = a_swap_semantics n. 72 | Proof. 73 | intros. 74 | unfold a_swap_semantics. 75 | destruct n; [ reflexivity | ]. 76 | rewrite <- bottom_to_top_correct. 77 | rewrite <- top_to_bottom_correct. 78 | simpl. 79 | easy. 80 | Qed. 81 | 82 | Lemma swap_spec' : swap = ((ket 0 × bra 0) ⊗ (ket 0 × bra 0) .+ (ket 0 × bra 1) ⊗ (ket 1 × bra 0) 83 | .+ (ket 1 × bra 0) ⊗ (ket 0 × bra 1) .+ (ket 1 × bra 1) ⊗ (ket 1 × bra 1))%M. 84 | Proof. 85 | prep_matrix_equivalence. 86 | by_cell; lazy; lca. 87 | Qed. 88 | 89 | Lemma top_to_bottom_grow_l : forall n, 90 | top_to_bottom (S (S n)) = (⨉ ↕ n_wire n) ⟷ (— ↕ top_to_bottom (S n)). 91 | Proof. reflexivity. Qed. 92 | 93 | Lemma top_to_bottom_grow_r : forall n prf prf', 94 | top_to_bottom (S (S n)) ∝= 95 | cast _ _ prf' prf' (top_to_bottom (S n) ↕ —) ⟷ 96 | (cast _ _ prf prf (n_wire n ↕ ⨉)). 97 | Proof. 98 | intros. 99 | by_perm_eq_nosimpl. 100 | rewrite perm_of_top_to_bottom_eq. 101 | cbn. 102 | rewrite 2!perm_of_zx_cast. 103 | cbn. 104 | rewrite perm_of_top_to_bottom_helper_eq, perm_of_n_wire. 105 | intros i Hi. 106 | rewrite stack_perms_WF_idn by cleanup_perm. 107 | rewrite stack_perms_idn_f. 108 | unfold compose. 109 | bdestructΩ'; 110 | unfold top_to_bottom_perm; [bdestructΩ'|]. 111 | unfold swap_2_perm, swap_perm. 112 | do 2 simplify_bools_lia_one_kernel. 113 | bdestructΩ'. 114 | Qed. 115 | 116 | 117 | 118 | Lemma offset_swaps_comm_top_left : 119 | ⨉ ↕ — ⟷ (— ↕ ⨉) ∝= 120 | — ↕ ⨉ ⟷ (⨉ ↕ —) ⟷ (— ↕ ⨉) ⟷ (⨉ ↕ —). 121 | Proof. 122 | by_perm_eq_nosimpl. 123 | by_perm_cell; reflexivity. 124 | Qed. 125 | 126 | Lemma offset_swaps_comm_bot_right : 127 | — ↕ ⨉ ⟷ (⨉ ↕ —) ∝= 128 | ⨉ ↕ — ⟷ (— ↕ ⨉) ⟷ (⨉ ↕ —) ⟷ (— ↕ ⨉). 129 | Proof. 130 | by_perm_eq_nosimpl. 131 | by_perm_cell; reflexivity. 132 | Qed. 133 | 134 | Lemma bottom_wire_to_top_ind : forall n, 135 | bottom_wire_to_top (S (S n)) = 136 | @Mmult _ (2 ^ (S (S n))) _ (swap ⊗ (I (2 ^ n))) 137 | ((I 2) ⊗ bottom_wire_to_top (S n)). 138 | Proof. 139 | intros. 140 | apply transpose_matrices. 141 | unfold bottom_wire_to_top. 142 | rewrite Mmult_transpose. 143 | restore_dims. 144 | rewrite Matrix.transpose_involutive. 145 | restore_dims. 146 | rewrite (kron_transpose 2 2 (2 ^ (S n)) (2 ^ S n)). 147 | replace (Nat.pow 2 (S (S n)))%nat with ((2 * 2) * (2 ^ n))%nat by (simpl; lia). 148 | rewrite (kron_transpose (2 * 2) (2 * 2) (2 ^ n) (2 ^ n) swap (I (2 ^ n))). 149 | rewrite 2 id_transpose_eq. 150 | rewrite swap_transpose. 151 | rewrite Matrix.transpose_involutive. 152 | restore_dims. 153 | rewrite (top_wire_to_bottom_ind n). 154 | easy. 155 | Qed. 156 | 157 | Lemma bottom_to_top_grow_r : forall n, 158 | bottom_to_top (S (S n)) = (— ↕ bottom_to_top (S n)) ⟷ (⨉ ↕ n_wire n). 159 | Proof. 160 | intros. 161 | unfold bottom_to_top. 162 | simpl. 163 | rewrite n_wire_transpose. 164 | easy. 165 | Qed. 166 | 167 | 168 | Lemma bottom_to_top_grow_l : forall n prf prf', 169 | bottom_to_top (S (S n)) ∝= cast _ _ prf' prf'((cast _ _ prf prf (n_wire n ↕ ⨉)) ⟷ (bottom_to_top (S n) ↕ —)). 170 | Proof. 171 | intros. 172 | apply transpose_diagrams_eq. 173 | unfold bottom_to_top. 174 | rewrite cast_transpose. 175 | cbn -[top_to_bottom]. 176 | repeat rewrite cast_transpose. 177 | cbn -[top_to_bottom]. 178 | rewrite n_wire_transpose. 179 | repeat rewrite Proportional.transpose_involutive. 180 | rewrite top_to_bottom_grow_r. 181 | rewrite cast_compose_distribute. 182 | simpl_casts. 183 | erewrite (cast_compose_mid (S (n + 1))). 184 | simpl_casts. 185 | apply compose_simplify_eq; cast_irrelevance. 186 | Unshelve. 187 | all: lia. 188 | Qed. 189 | 190 | Lemma top_to_bottom_transpose : forall n, (top_to_bottom n)⊤ = bottom_to_top n. 191 | Proof. 192 | reflexivity. 193 | Qed. 194 | 195 | Lemma bottom_to_top_transpose : forall n, (bottom_to_top n)⊤ = top_to_bottom n. 196 | Proof. 197 | intros. 198 | unfold bottom_to_top. 199 | rewrite Proportional.transpose_involutive_eq. 200 | easy. 201 | Qed. 202 | 203 | Lemma a_swap_grow : forall n, a_swap (S (S (S n))) ∝= 204 | (⨉ ↕ n_wire (S n)) ⟷ (— ↕ a_swap (S (S n))) ⟷ (⨉ ↕ n_wire (S n)). 205 | Proof. 206 | intros. 207 | by_perm_eq_nosimpl. 208 | cbn -[a_swap n_stack1]. 209 | rewrite 2!perm_of_a_swap, perm_of_n_wire. 210 | rewrite 2!swap_perm_defn by lia. 211 | rewrite (stack_perms_defn 1). 212 | rewrite stack_perms_WF_idn by cleanup_perm. 213 | unfold swap_2_perm, swap_perm. 214 | intros i Hi. 215 | unfold compose at 1. 216 | bdestructΩ'; unfold compose; bdestructΩ'. 217 | Qed. 218 | 219 | Lemma a_swap_2_is_swap : a_swap 2 ∝= ⨉. 220 | Proof. 221 | by_perm_eq_nosimpl; by_perm_cell; reflexivity. 222 | Qed. 223 | 224 | 225 | Lemma a_swap_3_order_indep : 226 | I 2 ⊗ swap × (swap ⊗ I 2) × (I 2 ⊗ swap) = 227 | (swap ⊗ I 2) × (I 2 ⊗ swap) × (swap ⊗ I 2). 228 | Proof. 229 | rewrite swap_eq_kron_comm. 230 | change 2%nat with (2^1)%nat. 231 | rewrite <- perm_to_matrix_idn. 232 | rewrite kron_comm_pows2_eq_perm_to_matrix_big_swap. 233 | restore_dims. 234 | rewrite <- !perm_to_matrix_of_stack_perms by auto with perm_db. 235 | restore_dims. 236 | rewrite <- !perm_to_matrix_compose by auto with perm_db. 237 | apply perm_to_matrix_eq_of_perm_eq. 238 | by_perm_cell; reflexivity. 239 | Qed. 240 | 241 | Lemma a_swap_semantics_ind : forall n, a_swap_semantics (S (S (S n))) = 242 | swap ⊗ (I (2 ^ (S n))) × (I 2 ⊗ a_swap_semantics (S (S n))) × (swap ⊗ (I (2 ^ (S n)))). 243 | Proof. 244 | intros n. 245 | rewrite <- a_swap_correct. 246 | rewrite <- n_wire_semantics. 247 | change (I 2) with (⟦ — ⟧). 248 | rewrite <- a_swap_correct. 249 | change (swap ⊗ ⟦n_wire (S n)⟧) with 250 | (⟦ ⨉ ↕ n_wire (S n)⟧). 251 | restore_dims. 252 | change (⟦ a_swap (S (S (S n))) ⟧ = ⟦ 253 | (⨉ ↕ n_wire (S n)) ⟷ ((— ↕ a_swap (S (S n))) 254 | ⟷ (⨉ ↕ n_wire (S n))) ⟧). 255 | rewrite 2!perm_of_zx_permutation_semantics by auto_zxperm. 256 | apply perm_to_matrix_eq_of_perm_eq. 257 | cbn [perm_of_zx]. 258 | rewrite perm_of_n_wire, 2!perm_of_a_swap. 259 | rewrite swap_perm_defn by lia. 260 | rewrite stack_perms_idn_f, stack_perms_WF_idn by auto_perm. 261 | unfold swap_2_perm. 262 | intros k Hk. 263 | rewrite <- Combinators.compose_assoc. 264 | unfold compose at 1. 265 | bdestruct (k =? 0); 266 | [unfold swap_perm; bdestructΩ'; 267 | unfold compose; bdestructΩ'|]. 268 | bdestruct (k =? 1); 269 | [unfold swap_perm; bdestructΩ'; 270 | unfold compose; bdestructΩ'|]. 271 | unfold swap_perm. 272 | simplify_bools_lia_one_kernel. 273 | unfold compose. 274 | bdestructΩ'. 275 | Qed. 276 | 277 | Lemma a_swap_transpose : forall n, 278 | (a_swap n) ⊤ ∝= a_swap n. 279 | Proof. 280 | by_perm_eq_nosimpl. 281 | rewrite perm_of_zx_transpose by auto with zxperm_db. 282 | rewrite perm_of_a_swap. 283 | bdestruct (n =? 0); [subst; now intros i Hi|]. 284 | rewrite swap_perm_inv' by lia. 285 | easy. 286 | Qed. 287 | 288 | (* n_swap proofs *) 289 | 290 | Opaque a_swap a_swap_semantics. (* For n_swap proofs we don't want a_swap to unfold, instead we use lemmata from above*) 291 | 292 | Lemma n_swap_2_is_swap : n_swap 2 ∝= ⨉. 293 | Proof. 294 | by_perm_eq_nosimpl. 295 | by_perm_cell; reflexivity. 296 | Qed. 297 | 298 | Lemma n_swap_1_is_wire : n_swap 1 ∝= —. 299 | Proof. 300 | by_perm_eq_nosimpl. 301 | by_perm_cell; reflexivity. 302 | Qed. 303 | 304 | Lemma n_swap_grow_l : forall n, 305 | n_swap (S n) ∝= bottom_to_top (S n) ⟷ (— ↕ n_swap n). 306 | Proof. 307 | induction n. 308 | - simpl. 309 | cleanup_zx. 310 | easy. 311 | - reflexivity. 312 | Qed. 313 | 314 | Lemma n_swap_grow_r : forall n, 315 | n_swap (S n) ∝= (— ↕ n_swap n) ⟷ top_to_bottom (S n). 316 | Proof. 317 | by_perm_eq. 318 | rewrite !reflect_perm_defn, stack_perms_defn. 319 | change (S n) with (1 + n)%nat. 320 | rewrite (rotr_add_l 1 n). 321 | unfold big_swap_perm, compose. 322 | intros i Hi. 323 | bdestructΩ'. 324 | Qed. 325 | 326 | Lemma n_swap_transpose : forall n, 327 | (n_swap n) ⊤ ∝= n_swap n. 328 | Proof. 329 | intros. 330 | by_perm_eq. 331 | Qed. 332 | 333 | #[export] Hint Rewrite 334 | (fun n => @bottom_to_top_transpose n) 335 | (fun n => @top_to_bottom_transpose n) 336 | (fun n => @n_swap_transpose n) 337 | (fun n => @a_swap_transpose n) 338 | : transpose_db. 339 | 340 | Lemma top_to_bottom_colorswap : forall n, 341 | ⊙ (top_to_bottom n) = top_to_bottom n. 342 | Proof. 343 | intros n. 344 | now rewrite zxperm_colorswap_eq by auto with zxperm_db. 345 | Qed. 346 | 347 | Lemma bottom_to_top_colorswap : forall n, 348 | ⊙ (bottom_to_top n) = bottom_to_top n. 349 | Proof. 350 | intros n. 351 | now rewrite zxperm_colorswap_eq by auto with zxperm_db. 352 | Qed. 353 | 354 | Lemma a_swap_colorswap : forall n, 355 | ⊙ (a_swap n) = a_swap n. 356 | Proof. 357 | intros n. 358 | now rewrite zxperm_colorswap_eq by auto with zxperm_db. 359 | Qed. 360 | 361 | Lemma n_swap_colorswap : forall n, 362 | ⊙ (n_swap n) = n_swap n. 363 | Proof. 364 | intros n. 365 | now rewrite zxperm_colorswap_eq by auto with zxperm_db. 366 | Qed. 367 | 368 | #[export] Hint Rewrite 369 | (fun n => @bottom_to_top_colorswap n) 370 | (fun n => @top_to_bottom_colorswap n) 371 | (fun n => @a_swap_colorswap n) 372 | (fun n => @n_swap_colorswap n) 373 | : colorswap_db. 374 | 375 | Lemma swap_pullthrough_top_right_Z_1_1 : forall α, (Z 1 1 α) ↕ — ⟷ ⨉ ∝= ⨉ ⟷ (— ↕ (Z 1 1 α)). 376 | Proof. 377 | intros. 378 | rewrite <- zx_comm_1_1_swap. 379 | now rewrite zx_comm_commutes_r. 380 | Qed. 381 | 382 | 383 | Lemma swap_pullthrough_top_right_X_1_1 : forall α, 384 | (X 1 1 α) ↕ — ⟷ ⨉ ∝= ⨉ ⟷ (— ↕ (X 1 1 α)). 385 | Proof. intros. colorswap_of swap_pullthrough_top_right_Z_1_1. Qed. 386 | 387 | -------------------------------------------------------------------------------- /src/CoreRules/StateRules.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData GadgetRules CoreAutomation StackComposeRules. 2 | 3 | Open Scope ZX_scope. 4 | 5 | (** Rules about states *) 6 | 7 | Lemma state_0_defn : 8 | state_0 ∝= /√2 .* X 0 1 0. 9 | Proof. 10 | rewrite state_0_defn'. 11 | rewrite gadget_is_scaled_empty; distribute_zxscale. 12 | rewrite stack_empty_l, const_of_zx_invsqrt2. 13 | reflexivity. 14 | Qed. 15 | 16 | Lemma state_0_semantics : ⟦ state_0 ⟧ = ∣0⟩. 17 | Proof. 18 | prep_matrix_equivalence. 19 | rewrite state_0_defn. 20 | rewrite zx_scale_semantics. 21 | compute_matrix (⟦ X 0 1 0 ⟧). 22 | rewrite kron_1_l by auto_wf. 23 | rewrite Cexp_0; Csimpl. 24 | unfold hadamard; simpl. 25 | rewrite make_WF_equiv. 26 | by_cell; autounfold with U_db; unfold list2D_to_matrix; simpl; 27 | [C_field; lca | lca]. 28 | Qed. 29 | 30 | 31 | Lemma state_1_defn : 32 | state_1 ∝= /√2 .* X 0 1 PI. 33 | Proof. 34 | rewrite state_1_defn'. 35 | rewrite gadget_is_scaled_empty; distribute_zxscale. 36 | rewrite stack_empty_l, const_of_zx_invsqrt2. 37 | reflexivity. 38 | Qed. 39 | 40 | Lemma state_1_semantics : ⟦ state_1 ⟧ = ∣1⟩. 41 | Proof. 42 | prep_matrix_equivalence. 43 | rewrite state_1_defn. 44 | rewrite zx_scale_semantics. 45 | compute_matrix (⟦ X 0 1 PI ⟧). 46 | rewrite kron_1_l by auto_wf. 47 | rewrite Cexp_PI. 48 | unfold hadamard; simpl. 49 | rewrite make_WF_equiv. 50 | by_cell; autounfold with U_db; unfold list2D_to_matrix; simpl; 51 | [lca | C_field; lca]. 52 | Qed. 53 | 54 | Lemma state_b_defn'' b : 55 | state_b b ∝= / √ 2 .* X 0 1 (if b then PI else 0). 56 | Proof. 57 | rewrite state_b_defn'. 58 | rewrite gadget_is_scaled_empty, const_of_zx_invsqrt2. 59 | distribute_zxscale. 60 | now rewrite stack_empty_l. 61 | Qed. 62 | 63 | Lemma state_plus_defn : 64 | state_plus ∝= /√2 .* Z 0 1 0. 65 | Proof. 66 | rewrite state_plus_defn'. 67 | rewrite gadget_is_scaled_empty; distribute_zxscale. 68 | rewrite stack_empty_l, const_of_zx_invsqrt2. 69 | reflexivity. 70 | Qed. 71 | 72 | Lemma state_plus_semantics : ⟦ state_plus ⟧ = ∣+⟩. 73 | Proof. 74 | prep_matrix_equivalence. 75 | rewrite state_plus_defn. 76 | rewrite zx_scale_semantics. 77 | compute_matrix (⟦ Z 0 1 0 ⟧). 78 | rewrite Cexp_0. 79 | rewrite make_WF_equiv. 80 | unfold xbasis_plus; 81 | by_cell; autounfold with U_db; unfold list2D_to_matrix; simpl; lca. 82 | Qed. 83 | 84 | Lemma state_minus_defn : 85 | state_minus ∝= /√2 .* Z 0 1 PI. 86 | Proof. 87 | rewrite state_minus_defn'. 88 | rewrite gadget_is_scaled_empty; distribute_zxscale. 89 | rewrite stack_empty_l, const_of_zx_invsqrt2. 90 | reflexivity. 91 | Qed. 92 | 93 | Lemma state_minus_semantics : ⟦ state_minus ⟧ = ∣-⟩. 94 | Proof. 95 | prep_matrix_equivalence. 96 | rewrite state_minus_defn. 97 | rewrite zx_scale_semantics. 98 | compute_matrix (⟦ Z 0 1 PI ⟧). 99 | rewrite Cexp_PI. 100 | rewrite make_WF_equiv. 101 | unfold xbasis_minus; 102 | by_cell; autounfold with U_db; unfold list2D_to_matrix; simpl; lca. 103 | Qed. 104 | 105 | 106 | Lemma state_0_colorswap : ⊙ state_0 ∝= state_plus. 107 | Proof. 108 | rewrite state_0_defn, state_plus_defn. 109 | rewrite zx_scale_colorswap. 110 | reflexivity. 111 | Qed. 112 | 113 | Lemma state_1_colorswap : ⊙ state_1 ∝= state_minus. 114 | Proof. 115 | rewrite state_1_defn, state_minus_defn. 116 | rewrite zx_scale_colorswap. 117 | reflexivity. 118 | Qed. 119 | 120 | Lemma state_plus_colorswap : ⊙ state_plus ∝= state_0. 121 | Proof. 122 | apply colorswap_diagrams_eq. 123 | rewrite colorswap_involutive. 124 | now rewrite state_0_colorswap. 125 | Qed. 126 | 127 | Lemma state_minus_colorswap : ⊙ state_minus ∝= state_1. 128 | Proof. 129 | apply colorswap_diagrams_eq. 130 | rewrite colorswap_involutive. 131 | now rewrite state_1_colorswap. 132 | Qed. 133 | 134 | #[export] Hint Rewrite state_0_colorswap state_1_colorswap 135 | state_plus_colorswap state_minus_colorswap : colorswap_db. 136 | 137 | 138 | 139 | 140 | Lemma semantics_compose_state_0_l {n} (zx : ZX 1 n) : 141 | ⟦ state_0 ⟷ zx ⟧ = get_col (⟦ zx ⟧) 0. 142 | Proof. 143 | simpl. 144 | rewrite state_0_semantics. 145 | rewrite qubit0_to_ei. 146 | now rewrite matrix_by_basis by lia. 147 | Qed. 148 | 149 | Lemma semantics_compose_state_1_l {n} (zx : ZX 1 n) : 150 | ⟦ state_1 ⟷ zx ⟧ = get_col (⟦ zx ⟧) 1. 151 | Proof. 152 | simpl. 153 | rewrite state_1_semantics. 154 | rewrite qubit1_to_ei. 155 | now rewrite matrix_by_basis by lia. 156 | Qed. 157 | 158 | 159 | 160 | Lemma semantics_by_states_1_n {n} (zx : ZX 1 n) : 161 | ⟦ zx ⟧ = smash (⟦ state_0 ⟷ zx ⟧) (⟦ state_1 ⟷ zx ⟧). 162 | Proof. 163 | prep_matrix_equivalence. 164 | rewrite semantics_compose_state_0_l, semantics_compose_state_1_l. 165 | intros i j Hi Hj. 166 | unfold smash, get_col. 167 | simpl in *. 168 | destruct j; [|replace j with O in * by lia]; 169 | Modulus.bdestructΩ'. 170 | Qed. 171 | 172 | Lemma prop_eq_by_eq_on_states_1_n {n} (zx zx' : ZX 1 n) : 173 | state_0 ⟷ zx ∝= state_0 ⟷ zx' -> 174 | state_1 ⟷ zx ∝= state_1 ⟷ zx' -> 175 | zx ∝= zx'. 176 | Proof. 177 | intros H0 H1. 178 | prep_matrix_equivalence. 179 | rewrite 2 semantics_by_states_1_n. 180 | rewrite H0, H1. 181 | reflexivity. 182 | Qed. 183 | 184 | Lemma prop_eq_by_eq_on_states_step {n m} (zx zx' : ZX (S n) m) : 185 | state_0 ↕ n_wire n ⟷ zx ∝= state_0 ↕ n_wire n ⟷ zx' -> 186 | state_1 ↕ n_wire n ⟷ zx ∝= state_1 ↕ n_wire n ⟷ zx' -> 187 | zx ∝= zx'. 188 | Proof. 189 | intros H0 H1. 190 | prep_matrix_equivalence. 191 | intros i j Hi Hj. 192 | bdestruct (j 220 | zx ∝= zx'. 221 | Proof. 222 | intros Hb. 223 | apply prop_eq_by_eq_on_states_1_n. 224 | - apply (Hb false). 225 | - apply (Hb true). 226 | Qed. 227 | 228 | 229 | 230 | Lemma prop_eq_by_eq_on_states_b_step {n m} (zx zx' : ZX (S n) m) : 231 | (forall b, state_b b ↕ n_wire n ⟷ zx ∝= state_b b ↕ n_wire n ⟷ zx') -> 232 | zx ∝= zx'. 233 | Proof. 234 | intros Hb. 235 | apply prop_eq_by_eq_on_states_step. 236 | - apply (Hb false). 237 | - apply (Hb true). 238 | Qed. 239 | 240 | 241 | Lemma prop_eq_by_eq_on_states {n m} (zx zx' : ZX n m) : 242 | (forall f, f_to_state n f ⟷ zx ∝= f_to_state n f ⟷ zx') -> 243 | zx ∝= zx'. 244 | Proof. 245 | induction n. 246 | - intros Hf. 247 | specialize (Hf (fun _ => false)). 248 | simpl in Hf. 249 | now rewrite 2 compose_empty_l in Hf. 250 | - intros Hf. 251 | apply prop_eq_by_eq_on_states_b_step. 252 | intros b. 253 | apply IHn. 254 | intros f. 255 | rewrite <- 2 compose_assoc. 256 | rewrite <- push_out_top. 257 | generalize (Hf (fun n => match n with | O => b | S n' => f n' end)). 258 | intros Heq; apply Heq. 259 | Qed. 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | Lemma state_0_to_b : state_0 = state_b false. 273 | Proof. reflexivity. Qed. 274 | 275 | Lemma state_1_to_b : state_1 = state_b true. 276 | Proof. reflexivity. Qed. 277 | 278 | Lemma state_b_semantics b : 279 | ⟦ state_b b ⟧ = ket b. 280 | Proof. 281 | destruct b. 282 | - apply state_1_semantics. 283 | - apply state_0_semantics. 284 | Qed. 285 | 286 | 287 | Lemma state_b_state_b_transpose b b' : 288 | state_b b ⟷ (state_b b') ⊤ ∝= 289 | (b2R (eqb b b')) .* ⦰. 290 | Proof. 291 | prep_matrix_equivalence. 292 | rewrite zx_compose_spec, semantics_transpose_comm, 293 | 2 state_b_semantics, zx_scale_semantics. 294 | by_cell. 295 | destruct b, b'; lca. 296 | Qed. 297 | 298 | Lemma f_to_state_semantics n f : 299 | ⟦ f_to_state n f ⟧ = f_to_vec n f. 300 | Proof. 301 | revert f; 302 | induction n; intros f. 303 | - reflexivity. 304 | - cbn [f_to_state]. 305 | rewrite (@zx_stack_spec 0 1 0 n). 306 | rewrite state_b_semantics. 307 | rewrite (f_to_vec_split'_eq 1 n). 308 | rewrite IHn. 309 | f_equal. 310 | simpl. 311 | now rewrite kron_1_l by auto_wf. 312 | Qed. 313 | 314 | Lemma f_to_state_split n m f : 315 | f_to_state (n + m) f ∝= f_to_state n f ↕ f_to_state m (fun i => f (n + i)%nat). 316 | Proof. 317 | prep_matrix_equivalence. 318 | cbn. 319 | rewrite 3 f_to_state_semantics. 320 | now rewrite f_to_vec_split'_eq. 321 | Qed. 322 | 323 | Lemma f_to_state_merge n m f g : 324 | f_to_state m f ↕ f_to_state n g ∝= 325 | f_to_state (m + n) (fun x => if x O -> 399 | k ⇑ (@zx_zero n m) ∝= zx_zero. 400 | Proof. 401 | intros H. 402 | destruct k; [easy|]. 403 | simpl. 404 | now rewrite stack_0_l. 405 | Qed. 406 | 407 | (* Lemma n_compose_zx_zero k n : k <> O -> 408 | n_compose k (@zx_zero n n) ∝= zx_zero. 409 | Proof. 410 | intros Hk. 411 | destruct k; [easy|]. 412 | simpl. 413 | now rewrite compose_0_l. 414 | Qed. *) 415 | 416 | Lemma zx_zero_transpose n m : (@zx_zero n m) ⊤ ∝= zx_zero. 417 | Proof. 418 | rewrite zx_zero_defn. 419 | distribute_zxscale. 420 | now rewrite zx_scale_0_l. 421 | Qed. 422 | 423 | Lemma zx_zero_adjoint n m : (@zx_zero n m) † ∝= zx_zero. 424 | Proof. 425 | rewrite zx_zero_defn. 426 | distribute_zxscale. 427 | now rewrite Cconj_R, zx_scale_0_l. 428 | Qed. 429 | 430 | Lemma zx_zero_colorswap n m : ⊙ (@zx_zero n m) ∝= zx_zero. 431 | Proof. 432 | rewrite zx_zero_defn. 433 | distribute_zxscale. 434 | now rewrite zx_scale_0_l. 435 | Qed. 436 | 437 | #[export] Hint Rewrite zx_zero_transpose : transpose_db. 438 | #[export] Hint Rewrite zx_zero_adjoint : adjoint_db. 439 | #[export] Hint Rewrite zx_zero_colorswap : colorswap_db. 440 | 441 | -------------------------------------------------------------------------------- /src/CoreRules/ZXRules.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData.CoreData. 2 | Require Import CoreRules.WireRules. 3 | Require Import CoreRules.CastRules. 4 | Require Import CoreRules.StackComposeRules. 5 | Require Import CoreRules.CoreAutomation. 6 | Require Export CoreRules.ZRules. 7 | Require Export CoreRules.XRules. 8 | 9 | (** Rules relating Z and X spiders *) 10 | 11 | Theorem X_state_copy_phase_0 : forall (r n : nat) prfn prfm, 12 | (X 0 1 (r * PI) ⟷ Z 1 n 0) 13 | ∝[(√2 * (/√2 ^ n))%R] 14 | cast 0%nat n prfn prfm (n ⇑ (X 0 1 (r * PI))). 15 | Proof. 16 | intros. 17 | assert (X_state_copy_ind : (X 0 1 (r * PI) ⟷ Z 1 2 0) ∝[/(√2)%R] 18 | X 0 1 (r * PI) ↕ X 0 1 (r * PI)). 19 | { 20 | zxsymmetry. 21 | split; [|C_field]. 22 | symmetry. 23 | prep_matrix_equivalence. 24 | Msimpl; simpl. 25 | unfold X_semantics, Z_semantics. 26 | rewrite Cexp_0. 27 | destruct (INR_pi_exp r); rewrite H; 28 | cbv delta [kron_n kron hadamard Mmult scale I]; 29 | by_cell; simpl; C_field; lca. 30 | } 31 | induction n; [| destruct n]. 32 | - simpl. (* n = 0 --> √2 *) 33 | simpl_casts. 34 | split; [|nonzero]. 35 | prep_matrix_equivalence. 36 | by_cell. 37 | unfold X_semantics, Z_semantics, Mmult, 38 | kron_n, kron, hadamard, I, scale; 39 | simpl. 40 | Csimpl. 41 | rewrite Rinv_1, Rmult_1_r. 42 | C_field. 43 | destruct (INR_pi_exp r); rewrite H; 44 | autorewrite with Cexp_db; lca. 45 | - simpl. (* n = 1 --> 1 *) 46 | rewrite Z_0_is_wire. 47 | rewrite cast_id. 48 | rewrite stack_empty_r. 49 | rewrite cast_id. 50 | cleanup_zx. 51 | zxrefl. 52 | rewrite Rmult_1_r. 53 | rewrite Rinv_r by nonzero. 54 | reflexivity. 55 | - eapply (cast_diagrams_by (S (S n) * 0) (S (S n) * 1)). 56 | rewrite cast_contract. 57 | rewrite cast_compose_distribute. 58 | rewrite cast_X, cast_Z, cast_id. 59 | simpl. 60 | eapply (@cast_simplify_by 0 (S n * 0)%nat (S n) (S n * 1)%nat) in IHn. 61 | rewrite cast_compose_distribute in IHn. 62 | rewrite cast_Z in IHn. 63 | rewrite cast_X in IHn. 64 | rewrite cast_contract in IHn. 65 | simpl in IHn. 66 | rewrite cast_id in IHn. 67 | rewrite grow_Z_top_right. 68 | rewrite <- compose_assoc. 69 | zxrewrite IHn. 70 | rewrite <- (stack_compose_distr 71 | (X 0 1 (r * PI)) (Z 1 2 0) (n ⇑ X 0 1 (r * PI)) (n_wire (n * 1))). 72 | zxrewrite X_state_copy_ind. 73 | cleanup_zx. 74 | rewrite (stack_assoc (X 0 1 (r * PI)) (X 0 1 (r * PI))). 75 | simpl_casts. 76 | zxrefl. 77 | autorewrite with RtoC_db. 78 | C_field. 79 | Unshelve. 80 | all: lia. 81 | Qed. 82 | 83 | Theorem Z_state_copy_phase_0 : forall (r n : nat) prfn prfm, 84 | (Z 0 1 (r * PI) ⟷ X 1 n 0) 85 | ∝[(√2 * (/√2 ^ n))%R] 86 | cast 0%nat n prfn prfm (n ⇑ (Z 0 1 (r * PI))). 87 | Proof. 88 | intros r n prfn prfm. 89 | colorswap_of (X_state_copy_phase_0 r n prfn prfm). 90 | Qed. 91 | 92 | Theorem X_state_copy : forall (r n : nat) (a : R) prfn prfm, 93 | (X 0 1 (r * PI) ⟷ Z 1 n a) 94 | ∝[((/√2 ^ S n))%R * 95 | (((C1 + Cexp (r * PI)) * (C1 - Cexp a) + 2 * Cexp a))] 96 | cast 0%nat n prfn prfm (n ⇑ (X 0 1 (r * PI))). 97 | Proof. 98 | assert (X_Z_phase_value' : forall (a b : R), 99 | (⟦ X 0 1 a ⟷ Z 1 0 b ⟧ = 100 | (((C1 + Cexp a) * (C1 - Cexp b) + 2 * Cexp b) / √2) .* I 1)%M). 1: { 101 | intros a b. 102 | prep_matrix_equivalence. 103 | by_cell. 104 | cbn; unfold kron, scale; cbn. 105 | Csimpl. 106 | C_field_simplify; [|nonzero]. 107 | lca. 108 | } 109 | intros r n a prfn prfm. 110 | replace (((/√2 ^ S n))%R * (((C1 + Cexp (r * PI)) * (C1 - Cexp a) + 2 * Cexp a))) 111 | with (((/√2 ^ n))%R * (((C1 + Cexp (r * PI)) * (C1 - Cexp a) + 2 * Cexp a) / √2)) 112 | by (simpl; unfold Cdiv; rewrite Rinv_mult, Cmult_assoc, Cmult_comm, 113 | Cmult_assoc, RtoC_mult, !RtoC_inv; reflexivity). 114 | replace (Z 1 n a) with (Z 1 n (a + 0)) by (f_equal; lra). 115 | rewrite Z_appendix_rot_r. 116 | rewrite <- compose_assoc. 117 | zxrewrite X_state_copy_phase_0. 118 | simpl. 119 | rewrite cast_compose_l. 120 | erewrite <- (cast_stack_r (nBot' := n * 1) (mBot' := n) 121 | _ _ _ _ (Z 1 0 a) (n_wire n)). 122 | rewrite <- (stack_compose_distr (X 0 1 _) (Z 1 0 a) (n ⇑ X 0 1 _) 123 | ($ n * 1, n ::: n_wire n $)). 124 | erewrite (cast_stack_distribute (n':=0) (m' := 0) (o' := 0) (p' := n) 125 | _ _ _ _ _ _ (X 0 1 (r * PI) ⟷ Z 1 0 a) 126 | ((n ⇑ X 0 1 (r * PI) ⟷ $ n * 1, n ::: n_wire n $))). 127 | rewrite cast_id. 128 | zxsymmetry. 129 | rewrite <- stack_empty_l. 130 | erewrite (proportional_by_trans_iff_l _ _ _ 1). 131 | - apply (stack_prop_by_compat_l 132 | ⦰ (X 0 1 (r * PI) ⟷ Z 1 0 a) 133 | ($ 0, n ::: n ⇑ X 0 1 (r * PI) ⟷ $ n * 1, n ::: n_wire n $ $)). 134 | assert (Hnz : ((C1 + Cexp (r * PI)) * (C1 - Cexp a) + C2 * Cexp a) <> C0). 1: { 135 | rewrite Cmult_plus_distr_r. 136 | unfold Cminus at 1. 137 | rewrite Cmult_plus_distr_l. 138 | Csimpl. 139 | rewrite Cplus_comm, Cplus_assoc. 140 | replace (C2 * Cexp a + (C1 + - Cexp a)) with (C1 + Cexp a) by lca. 141 | destruct (INR_pi_exp r) as [-> | ->]. 142 | - Csimpl. 143 | rewrite <- Cplus_assoc, (Cplus_comm (Cexp a)). 144 | unfold Cminus. 145 | rewrite <- Cplus_assoc, Cplus_opp_l. 146 | intros H%(f_equal fst); simpl in H; lra. 147 | - pose proof (Cexp_nonzero a) as Hnz. 148 | replace (C1 + Cexp a + -1 * (C1 - Cexp a)) with (C2 * Cexp a) by lca. 149 | apply Cmult_nonzero_iff. 150 | split; nonzero. 151 | } 152 | split. 153 | + rewrite X_Z_phase_value'. 154 | prep_matrix_equivalence. 155 | by_cell. 156 | unfold scale; 157 | cbn. 158 | Csimpl. 159 | rewrite Cdiv_1_r. 160 | unfold Cdiv. 161 | rewrite Cinv_mult_distr. 162 | rewrite <- 2!Cmult_assoc. 163 | rewrite Cinv_l by (apply Cdiv_nonzero_iff; split; assumption + nonzero). 164 | Csimpl. 165 | rewrite Rinv_mult, <- Rmult_assoc, Rinv_r, Rmult_1_l by nonzero. 166 | symmetry. 167 | apply Cinv_r. 168 | rewrite RtoC_inv, <- RtoC_pow. 169 | apply nonzero_div_nonzero. 170 | nonzero. 171 | + apply Cdiv_nonzero; [|nonzero]. 172 | apply Cmult_nonzero_iff; split; [nonzero|]. 173 | apply nonzero_div_nonzero. 174 | apply Cmult_nonzero_iff; split; [nonzero|]. 175 | apply Cdiv_nonzero_iff; split; [nonzero|assumption]. 176 | - zxrefl. 177 | rewrite 2!stack_empty_l. 178 | rewrite cast_compose_r, nwire_removal_r. 179 | rewrite 2!cast_contract. 180 | cast_irrelevance. 181 | Unshelve. 182 | all: lia. 183 | Qed. 184 | 185 | Theorem Z_state_copy : forall (r n : nat) (a : R) prfn prfm, 186 | (Z 0 1 (r * PI) ⟷ X 1 n a) 187 | ∝[((/√2 ^ S n))%R * 188 | (((C1 + Cexp (r * PI)) * (C1 - Cexp a) + 2 * Cexp a))] 189 | cast 0%nat n prfn prfm (n ⇑ (Z 0 1 (r * PI))). 190 | Proof. 191 | intros r n a prfn prfm. 192 | colorswap_of (X_state_copy r n a prfn prfm). 193 | Qed. 194 | 195 | Theorem X_state_pi_copy : forall n prfn prfm, 196 | X 0 1 PI ⟷ Z 1 n 0 ∝[(√2 * (/√2 ^ n))%R] 197 | cast 0 n prfn prfm (n ⇑ (X 0 1 PI)). 198 | Proof. 199 | intros. 200 | replace (PI)%R with (1 * PI)%R by lra. 201 | replace (1)%R with (INR 1)%R by reflexivity. 202 | (* rewrite (X_state_copy_phase_0 1). *) 203 | zxrewrite X_state_copy_phase_0. 204 | zxrefl. 205 | Qed. 206 | 207 | Theorem X_state_0_copy : forall (n : nat) prfn prfm, 208 | X 0 1 0 ⟷ Z 1 n 0 ∝[(√2 * (/√2 ^ n))%R] 209 | cast 0 n prfn prfm (n ⇑ (X 0 1 0)). 210 | Proof. 211 | intros. 212 | replace (0)%R with (0 * PI)%R at 1 by lra. 213 | replace (0)%R with (INR 0)%R by reflexivity. 214 | zxrewrite X_state_copy_phase_0. 215 | rewrite Rmult_0_l. 216 | zxrefl. 217 | Qed. 218 | 219 | Theorem Z_state_pi_copy : forall (n : nat) prfn prfm, 220 | Z 0 1 PI ⟷ X 1 n 0 ∝[(√2 * (/√2 ^ n))%R] 221 | cast 0 n prfn prfm (n ⇑ (Z 0 1 PI)). 222 | Proof. 223 | intros. 224 | replace (PI)%R with (INR 1 * PI)%R by (simpl; lra). 225 | zxrewrite Z_state_copy_phase_0. 226 | zxrefl. 227 | Qed. 228 | 229 | Theorem Z_state_0_copy : forall (n : nat) prfn prfm, 230 | Z 0 1 0 ⟷ X 1 n 0 ∝[(√2 * (/√2 ^ n))%R] 231 | cast 0 n prfn prfm (n ⇑ (Z 0 1 0)). 232 | Proof. 233 | intros. 234 | replace (0)%R with (0 * PI)%R at 1 by lra. 235 | replace (0)%R with (INR 0)%R by reflexivity. 236 | zxrewrite Z_state_copy_phase_0. 237 | rewrite Rmult_0_l. 238 | zxrefl. 239 | Qed. 240 | 241 | Lemma Z_copy : forall (n r : nat), 242 | Z 1 1 (r * PI) ⟷ X 1 n 0 ∝= 243 | X 1 n 0 ⟷ n ↑ Z 1 1 (r * PI). 244 | Proof. 245 | intros. 246 | assert (Z_copy_ind : (Z 1 1 (r * PI) ⟷ X 1 2 0) ∝= 247 | X 1 2 0 ⟷ (Z 1 1 (r * PI) ↕ Z 1 1 (r * PI))). 248 | { 249 | prep_matrix_equivalence. 250 | change (X 1 2 0) with ((X 2 1 0) ⊤). 251 | rewrite 2 zx_compose_spec. 252 | rewrite semantics_transpose_comm. 253 | simpl. 254 | compute_matrix (Z_semantics 1 1 (r * PI)). 255 | rewrite X_2_1_0_semantics. 256 | rewrite !make_WF_equiv. 257 | destruct (INR_pi_exp r) as [H|H]; rewrite H; by_cell; 258 | cbv [kron_n kron hadamard Mmult scale I Matrix.transpose 259 | list2D_to_matrix nth Nat.div Nat.modulo Nat.divmod Nat.mul 260 | Nat.sub fst snd big_sum]; lca. 261 | } 262 | induction n; [ | destruct n]. 263 | - simpl. 264 | rewrite compose_empty_r. 265 | prep_matrix_equivalence. 266 | simpl. 267 | unfold X_semantics, Z_semantics; 268 | rewrite Cexp_0; 269 | cbv [kron_n kron hadamard Mmult scale I]; 270 | by_cell; simpl; C_field; lca. 271 | - simpl. 272 | repeat rewrite X_0_is_wire. 273 | cleanup_zx. 274 | now rewrite cast_id. 275 | - simpl. 276 | rewrite grow_X_top_right. 277 | simpl in IHn. 278 | rewrite <- compose_assoc. 279 | rewrite IHn by lia. 280 | rewrite compose_assoc. 281 | rewrite <- (stack_compose_distr 282 | (Z 1 1 (r * PI)) (X 1 2 0) 283 | (n ↑ (Z 1 1 (r * PI))) (n_wire n)). 284 | rewrite Z_copy_ind. 285 | rewrite nwire_removal_r. 286 | rewrite <- (nwire_removal_l (n ↑ Z 1 1 (r * PI))) at 1. 287 | rewrite stack_compose_distr. 288 | rewrite compose_assoc. 289 | rewrite (stack_assoc (Z 1 1 (r * PI))). 290 | rewrite cast_id. 291 | easy. 292 | Unshelve. 293 | all: reflexivity. 294 | Qed. 295 | 296 | Lemma X_copy : forall (n r : nat), 297 | X 1 1 (r * PI) ⟷ Z 1 n 0 ∝= 298 | Z 1 n 0 ⟷ n ↑ X 1 1 (r * PI). 299 | Proof. 300 | intros n r. 301 | colorswap_of (Z_copy n r). 302 | Qed. 303 | 304 | Lemma Z_0_copy : forall (n : nat), 305 | Z 1 1 0 ⟷ X 1 n 0 ∝= 306 | X 1 n 0 ⟷ n ↑ Z 1 1 0. 307 | Proof. 308 | intros. 309 | specialize (Z_copy n 0). 310 | intros. 311 | simpl in H. 312 | rewrite Rmult_0_l in H. 313 | apply H. 314 | Qed. 315 | 316 | Lemma Z_pi_copy : forall (n : nat), 317 | Z 1 1 PI ⟷ X 1 n 0 ∝= 318 | X 1 n 0 ⟷ n ↑ Z 1 1 PI. 319 | Proof. 320 | intros. 321 | specialize (Z_copy n 1). 322 | intros. 323 | simpl in H. 324 | rewrite Rmult_1_l in H. 325 | apply H. 326 | Qed. 327 | 328 | Lemma X_0_copy : forall (n : nat), 329 | X 1 1 0 ⟷ Z 1 n 0 ∝= 330 | Z 1 n 0 ⟷ n ↑ X 1 1 0. 331 | Proof. 332 | intros. 333 | specialize (X_copy n 0). 334 | intros. 335 | simpl in H. 336 | rewrite Rmult_0_l in H. 337 | apply H. 338 | Qed. 339 | 340 | Lemma X_pi_copy : forall (n : nat), 341 | X 1 1 PI ⟷ Z 1 n 0 ∝= 342 | Z 1 n 0 ⟷ n ↑ X 1 1 PI. 343 | Proof. 344 | intros. 345 | specialize (X_copy n 1). 346 | intros. 347 | simpl in H. 348 | rewrite Rmult_1_l in H. 349 | apply H. 350 | Qed. 351 | 352 | 353 | Lemma Z_pi_copy_1_1_gen α : 354 | Z 1 1 PI ⟷ X 1 1 α ∝[Cexp α] X 1 1 (-α) ⟷ Z 1 1 PI. 355 | Proof. 356 | split; [|nonzero]. 357 | prep_matrix_equivalence. 358 | simpl. 359 | unfold X_semantics. 360 | rewrite kron_n_1 by auto_wf. 361 | compute_matrix (Z_semantics 1 1 α). 362 | compute_matrix (Z_semantics 1 1 (-α)). 363 | rewrite <- Mscale_mult_dist_r, <- Mscale_mult_dist_l, 364 | <- Mscale_mult_dist_r. 365 | rewrite scalar_make_WF. 366 | unfold scale. 367 | let t := type of (@Mscale_list2D_to_matrix) in 368 | let lem := eval unfold scale in t in 369 | rewrite (@Mscale_list2D_to_matrix : lem). 370 | cbn [map]. 371 | Csimpl. 372 | rewrite <- Cexp_add, Rplus_opp_r, Cexp_0. 373 | compute_matrix (Z_semantics 1 1 PI). 374 | rewrite Cexp_PI', 2 make_WF_equiv. 375 | by_cell; lca. 376 | Qed. 377 | 378 | Lemma X_pi_copy_1_1_gen α : 379 | X 1 1 PI ⟷ Z 1 1 α ∝[Cexp α] Z 1 1 (-α) ⟷ X 1 1 PI. 380 | Proof. 381 | colorswap_of (Z_pi_copy_1_1_gen α). 382 | Qed. 383 | 384 | Lemma Z_pi_copy_gen n α : 385 | Z 1 1 PI ⟷ X 1 n α ∝[Cexp α] X 1 n (-α) ⟷ 386 | n ↑ Z 1 1 PI. 387 | Proof. 388 | rewrite <- (Rplus_0_r α). 389 | rewrite <- (X_absolute_fusion (m:=0)), <- compose_assoc. 390 | zxrewrite Z_pi_copy_1_1_gen. 391 | rewrite Rplus_0_r, Cdiv_unfold, Cinv_r by nonzero. 392 | rewrite compose_assoc, Z_pi_copy, <- compose_assoc. 393 | rewrite X_absolute_fusion, Rplus_0_r. 394 | zxrefl. 395 | Qed. 396 | 397 | Lemma X_pi_copy_gen n α : 398 | X 1 1 PI ⟷ Z 1 n α ∝[Cexp α] Z 1 n (-α) ⟷ 399 | n ↑ X 1 1 PI. 400 | Proof. 401 | colorswap_of (Z_pi_copy_gen n α). 402 | Qed. -------------------------------------------------------------------------------- /src/CoreRules/SpiderInduction.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData.CoreData. 2 | 3 | Open Scope ZX_scope. 4 | 5 | (* Spider Induction *) 6 | 7 | (* The first part that is necessary to prove spider edge count induction is the 8 | ability to split spiders off to the side. We only need to prove this one, 9 | the others follow through transposes *) 10 | 11 | Lemma grow_Z_left_2_1 : forall {n} α, 12 | Z (S (S n)) 1 α ∝= 13 | (Z 2 1 0 ↕ n_wire n) ⟷ Z (S n) 1 α. 14 | Proof. 15 | assert ( pow2Pos : forall n, exists m, (2^n = S m)%nat ). 16 | { intros n. 17 | enough (2 ^ n <> O)%nat. 18 | + destruct (2 ^ n)%nat; [easy | eexists; easy]. 19 | + apply Modulus.pow2_nonzero. } 20 | assert ( eqb_succ_f : forall j, (j =? S j)%nat = false ). 21 | { intros. Modulus.bdestructΩ'. } 22 | assert ( div_1_comp : forall i, ((S (i + i) / S i) = 1)%nat). 23 | { intros. 24 | rewrite Kronecker.div_eq_iff; lia. } 25 | assert ( div_3_comp : forall i, 26 | ((S (S (S (i + i + (i + i)))) / S i) = 3)%nat). 27 | { intros. 28 | rewrite Kronecker.div_eq_iff; lia. } 29 | assert ( mod_2_comp : forall i, ((S (i + i)) mod (S i) = i)%nat ). 30 | { intros. 31 | rewrite plus_n_Sm. 32 | rewrite Modulus.mod_add_n_r. 33 | apply Nat.mod_small; lia. } 34 | assert ( mod_4_comp : forall i, 35 | ((S (S (S (i + i + (i + i))))) mod (S i) = i)%nat ). 36 | { intros. 37 | replace (S (S (S (i + i + (i + i))))) 38 | with (i + S i + S i + S i)%nat by lia. 39 | rewrite !Modulus.mod_add_n_r. 40 | apply Nat.mod_small; lia. } 41 | intros. 42 | unfold proportional_by_1. 43 | simpl. 44 | rewrite n_wire_semantics. 45 | unfold Mmult. 46 | prep_matrix_equality. 47 | destruct (pow2Pos n) as [m Hm]. 48 | assert (mltSm : (m < S m)%nat) by lia. 49 | apply Nat.ltb_lt in mltSm. 50 | unfold Z_semantics. 51 | simpl. 52 | rewrite Hm. 53 | rewrite Nat.add_0_r. 54 | rewrite <- plus_n_Sm. 55 | simpl. 56 | rewrite Nat.add_0_r. 57 | repeat rewrite <- plus_n_Sm. 58 | bdestruct (x =? 1)%nat; bdestruct (y =? S (S (S (m + m + (m + m)))))%nat. 59 | - rewrite H, H0. 60 | simpl. 61 | rewrite big_sum_0_bounded by 62 | (intros; 63 | apply Nat.lt_lt_succ_r in H1; 64 | apply Nat.lt_neq in H1; 65 | rewrite <- Nat.eqb_neq in H1; 66 | rewrite H1; 67 | lca). 68 | rewrite eqb_succ_f. 69 | rewrite Cmult_0_l. 70 | rewrite Nat.eqb_refl. 71 | rewrite Cplus_0_l. 72 | unfold kron. 73 | rewrite div_1_comp. 74 | rewrite div_3_comp. 75 | rewrite mod_2_comp. 76 | rewrite mod_4_comp. 77 | rewrite Cexp_0. 78 | unfold I. 79 | repeat rewrite Nat.eqb_refl. 80 | rewrite mltSm. 81 | lca. 82 | - simpl. 83 | rewrite H. 84 | rewrite big_sum_0_bounded by 85 | (intros; apply Nat.lt_lt_succ_r in H1; 86 | apply Nat.lt_neq in H1; 87 | rewrite <- Nat.eqb_neq in H1; 88 | rewrite H1; 89 | lca). 90 | rewrite eqb_succ_f. 91 | rewrite Nat.eqb_refl. 92 | C_field_simplify. 93 | unfold kron. 94 | rewrite div_1_comp. 95 | rewrite Nat.eqb_refl. 96 | rewrite mod_2_comp. 97 | unfold I. 98 | bdestruct (y / S m =? 3)%nat; bdestruct (m =? y mod S m)%nat; try lca. 99 | contradict H0. 100 | rewrite (Nat.div_mod_eq y (S m)). 101 | rewrite H1, <- H2; lia. 102 | - simpl. 103 | rewrite H0. 104 | unfold kron. 105 | unfold I. 106 | rewrite div_1_comp, div_3_comp, mod_2_comp, mod_4_comp. 107 | repeat rewrite Nat.eqb_refl. 108 | rewrite big_sum_0_bounded. 109 | + rewrite mltSm. 110 | destruct x; [ | lca ]. 111 | destruct m; lca. 112 | + intros. 113 | destruct x, x0; lca. 114 | - simpl. 115 | unfold kron, I. 116 | rewrite div_1_comp, mod_2_comp. 117 | destruct x,y,m; try lca. 118 | + repeat rewrite Cmult_0_l. 119 | replace (S m + S m)%nat with (S (S (m + m)))%nat by lia. 120 | rewrite <- big_sum_extend_l. 121 | simpl. 122 | repeat rewrite Nat.sub_diag. 123 | simpl. 124 | rewrite big_sum_0; intros; lca. 125 | + rewrite Cmult_0_l. 126 | rewrite Nat.div_1_r. 127 | lca. 128 | + rewrite big_sum_0; try lca. 129 | intros. 130 | destruct x,y. 131 | * simpl. 132 | rewrite Nat.sub_diag. 133 | replace (match m with 134 | | 0 => S m 135 | | S l => m - l 136 | end)%nat with 1%nat by (destruct m; lia). 137 | lca. 138 | * destruct (S (S y) / (S (S m)))%nat eqn:E; try lca. 139 | rewrite Nat.div_small_iff in E by auto. 140 | rewrite (Nat.mod_small (S (S y))) by auto. 141 | cbn. 142 | rewrite Nat.sub_diag. 143 | cbn. 144 | lca. 145 | * lca. 146 | * lca. 147 | + rewrite big_sum_0; intros; lca. 148 | + rewrite big_sum_0; intros; lca. 149 | Qed. 150 | 151 | Lemma grow_Z_right_1_2 : forall {n} α, 152 | Z 1 (S (S n)) α ∝= 153 | Z 1 (S n) α ⟷ (Z 1 2 0 ↕ n_wire n). 154 | Proof. 155 | intros. 156 | replace (Z_Spider 1 (S (S n))%nat α) 157 | with ((Z_Spider (S (S n))%nat 1 α)⊤) by reflexivity. 158 | rewrite grow_Z_left_2_1. 159 | simpl. 160 | rewrite n_wire_transpose. 161 | reflexivity. 162 | Qed. 163 | 164 | Lemma grow_Z_right_bot_1_2_base : forall α, 165 | Z 1 3 α ∝= Z 1 2 α ⟷ (— ↕ Z 1 2 0). 166 | Proof. 167 | intros. 168 | unfold proportional_by_1. 169 | lma'. 170 | unfold Z_semantics, kron; 171 | cbn. 172 | rewrite Cexp_0. 173 | lca. 174 | Qed. 175 | 176 | Lemma Z_wrap_over_top_right_base : forall n α, 177 | (— ↕ Z n 2 α) ⟷ (Cap ↕ —) ∝= Z (S n) 1 α. 178 | Proof. 179 | intros. 180 | prep_matrix_equivalence. 181 | cbn [ZX_semantics]. 182 | rewrite Kronecker.kron_I_l, Kronecker.kron_I_r. 183 | intros i j Hi Hj. 184 | unfold Mmult. 185 | unfold Z_semantics at 2. 186 | destruct i as [|[]]; [..|cbn in Hi; lia]. 187 | - rewrite Nat.Div0.mod_0_l. 188 | cbn [Nat.add]. 189 | change (0 =? 2 ^ 1 - 1) with false. 190 | rewrite andb_false_l. 191 | destruct j. 192 | + apply big_sum_unique. 193 | exists O. 194 | split; [pose proof (Modulus.pow2_nonzero 3); lia|]. 195 | rewrite !Nat.Div0.div_0_l, !Nat.Div0.mod_0_l, Nat.eqb_refl. 196 | split; [cbn; destruct n; lca|]. 197 | intros k Hk Hknz. 198 | destruct k; [easy|]. 199 | do 7 (try destruct k; cbn; [cbn; lca|]). 200 | cbn in *; lia. 201 | + apply (@big_sum_0_bounded C). 202 | intros k Hk. 203 | rewrite Nat.Div0.div_0_l. 204 | cbn [Nat.pow Nat.mul Nat.add] in *. 205 | do 8 (try destruct k); try apply Cmult_0_l; [..|lia]; 206 | rewrite Modulus.if_true by reflexivity. 207 | * rewrite !Nat.Div0.div_0_l, Nat.Div0.mod_0_l. 208 | rewrite Nat.eqb_sym. 209 | Modulus.bdestructΩ'; [|lca]. 210 | rewrite Nat.div_small_iff in * by Modulus.show_nonzero. 211 | rewrite Nat.mod_small by easy. 212 | apply Cmult_1_l. 213 | * change (6 / 4)%nat with 1%nat; change (4 / 2)%nat with 2%nat. 214 | change (6 mod 4) with (2)%nat. 215 | Modulus.bdestructΩ'; apply Cmult_0_r. 216 | - rewrite Nat.eqb_refl, andb_true_l. 217 | bdestruct (j =? 2 ^ (1 + n) - 1). 218 | + apply big_sum_unique. 219 | assert (j / 2 ^ n < 2)%nat by 220 | (apply Nat.Div0.div_lt_upper_bound; cbn in *; lia). 221 | destruct (j / 2 ^ n)%nat as [|one] eqn:e; 222 | [rewrite Nat.div_small_iff in e; cbn in *; lia|]. 223 | destruct one; [|lia]. 224 | exists 7%nat. 225 | split; [cbn; lia|]. 226 | rewrite 2!Modulus.if_true by reflexivity. 227 | change (7 mod 2 ^ 2) with 3%nat. 228 | rewrite Modulus.mod_n_to_2n by (cbn in *; lia). 229 | subst j. 230 | split; [cbn; Modulus.bdestructΩ'; lca|]. 231 | intros k Hk Hk7. 232 | cbn [Nat.pow Nat.mul Nat.add Nat.sub] in *. 233 | do 8 (try destruct k); try apply Cmult_0_l; [..|lia]; 234 | rewrite Modulus.if_true by reflexivity; [|easy]. 235 | apply Cmult_0_r. 236 | + apply (@big_sum_0_bounded C). 237 | intros k Hk. 238 | cbn [Nat.pow Nat.mul Nat.add Nat.sub] in *. 239 | do 8 (try destruct k); try apply Cmult_0_l; [..|lia]; 240 | rewrite Modulus.if_true by reflexivity; rewrite Cmult_1_l; 241 | Modulus.bdestructΩ'. 242 | change (7 mod 4) with 3%nat. 243 | assert (~ (j < 2 ^ n)%nat) by 244 | (rewrite <- Nat.div_small_iff by Modulus.show_nonzero; 245 | replace <- (j / 2 ^ n)%nat; easy). 246 | cbn. 247 | rewrite Modulus.mod_n_to_2n by lia. 248 | Modulus.bdestructΩ'. 249 | Qed. 250 | 251 | Lemma Z_wrap_over_top_right_0 : forall n α, 252 | (— ↕ Z n 1 α) ⟷ Cap ∝= Z (S n) 0 α. 253 | Proof. 254 | intros. 255 | unfold proportional_by_1. 256 | cbn. 257 | unfold Z_semantics, kron, Mmult. 258 | prep_matrix_equality. 259 | replace (2 ^ S n)%nat with (2 ^ n + 2 ^ n)%nat by (simpl; lia). 260 | remember (2 ^ n)%nat as m. 261 | assert (Hm : (m <> 0)%nat). 262 | { rewrite Heqm. apply Nat.pow_nonzero. easy. } 263 | assert (Hm_div : (((m + m - 1) / m) = 1)%nat). 264 | { 265 | replace (m + m - 1)%nat with (1 * m + (m - 1))%nat by lia. 266 | rewrite Nat.div_add_l by assumption. 267 | rewrite Nat.div_small by lia. 268 | lia. 269 | } 270 | assert (Hm_mod : ((m + m - 1) mod m = m - 1)%nat). 271 | { 272 | replace (m + m - 1)%nat with (m + (m - 1))%nat by lia. 273 | rewrite Nat.Div0.add_mod by auto. 274 | rewrite Nat.Div0.mod_same by auto. 275 | simpl. 276 | repeat rewrite Nat.mod_small; lia. 277 | } 278 | bdestruct (x =? 0)%nat; bdestruct (y =? m + m - 1)%nat. 279 | - rewrite H, H0. 280 | simpl. 281 | rewrite Hm_mod. 282 | rewrite Hm_div. 283 | rewrite Nat.eqb_refl. 284 | simpl. 285 | unfold list2D_to_matrix, I. 286 | simpl. 287 | Csimpl. 288 | destruct m; [ contradict Hm; lia | ]. 289 | simpl. 290 | rewrite <- plus_n_Sm. 291 | lca. 292 | - rewrite H. 293 | simpl. 294 | unfold list2D_to_matrix, I. 295 | simpl. 296 | bdestruct (y / m =? 1)%nat; bdestruct (y mod m =? m - 1)%nat. 297 | + rewrite H1. 298 | simpl. 299 | contradict H0. 300 | specialize (Nat.div_mod_eq y m); intros. 301 | rewrite H0. 302 | rewrite H1, H2. 303 | lia. 304 | + rewrite H1. 305 | Csimpl. 306 | destruct y; [ contradict H1 | ]. 307 | rewrite Nat.Div0.div_0_l. 308 | lia. 309 | lca. 310 | + destruct (y / m)%nat eqn:E; try lca. 311 | Csimpl. 312 | destruct y. 313 | * rewrite Nat.Div0.mod_0_l. 314 | destruct n; auto. 315 | * destruct (S y mod m) eqn:Ey. 316 | assert (contra : (S y <> 0)%nat) by lia. 317 | contradict contra. 318 | specialize (Nat.div_mod_eq (S y) m). 319 | intros. 320 | rewrite H3. 321 | rewrite Ey, E. 322 | lia. 323 | lca. 324 | * Csimpl. 325 | destruct n0; [ contradict H1; easy | ]. 326 | simpl. 327 | destruct y; [|lca]. 328 | contradict E. 329 | rewrite Nat.Div0.div_0_l. 330 | lia. 331 | + Csimpl. 332 | destruct y. 333 | * rewrite Nat.Div0.div_0_l, Nat.Div0.mod_0_l. 334 | destruct n; lca. 335 | * specialize (Nat.div_mod_eq (S y) m); intros. 336 | destruct (S y / m)%nat, (S y mod m)%nat; try lca. 337 | lia. 338 | - destruct x. 339 | + rewrite H0. 340 | simpl. 341 | unfold list2D_to_matrix, I. 342 | simpl. 343 | rewrite Hm_div, Hm_mod. 344 | simpl. 345 | destruct m; simpl. 346 | * lia. 347 | * rewrite Nat.sub_0_r. 348 | rewrite <- plus_n_Sm. 349 | rewrite Nat.eqb_refl. 350 | lca. 351 | + simpl. 352 | Csimpl. 353 | rewrite H0. 354 | rewrite Hm_div. 355 | rewrite Hm_mod. 356 | rewrite Nat.eqb_refl. 357 | destruct x; lca. 358 | - rewrite andb_false_r. 359 | destruct x,y. 360 | + simpl. 361 | unfold list2D_to_matrix, I. 362 | simpl. 363 | rewrite Nat.Div0.div_0_l, Nat.Div0.mod_0_l; lia. 364 | + simpl. 365 | unfold list2D_to_matrix, I. 366 | simpl. 367 | Csimpl. 368 | specialize (Nat.div_mod_eq (S y) m). 369 | intros. 370 | bdestruct (S y / m =? 0)%nat; bdestruct (S y mod m =? 0); exfalso; lia. 371 | + destruct x; lca. 372 | + destruct x; lca. 373 | Qed. 374 | 375 | Lemma Z_wrap_over_top_left_0 : forall n α, 376 | Cup ⟷ (— ↕ Z 1 n α) ∝= Z 0 (S n) α. 377 | Proof. 378 | intros. 379 | apply transpose_diagrams_eq. 380 | simpl. 381 | apply Z_wrap_over_top_right_0. 382 | Qed. 383 | 384 | (** Inducts on [n] and specializes the case where [n = 1]. Useful for 385 | induction on spiders where both the [n = 0] and [n = 1] cases are 386 | special, whereas normal induction has only [n = 0] as base case. *) 387 | Ltac spider_induction n := induction n; [ | destruct n ]. 388 | -------------------------------------------------------------------------------- /src/CoreData/QlibTemp.v: -------------------------------------------------------------------------------- 1 | From QuantumLib Require Import Matrix. 2 | From QuantumLib Require Import Quantum. 3 | Require Import QuantumLib.VectorStates. 4 | Require Import QuantumLib.Permutations. 5 | 6 | Import Setoid. 7 | 8 | (* Results that will eventually go into QuantumLib *) 9 | 10 | (* FIXME: Move to Prelim.v *) 11 | Lemma symmetry_iff {A} {R : relation A} `{Symmetric A R} (x y : A) : 12 | R x y <-> R y x. 13 | Proof. 14 | split; apply symmetry. 15 | Qed. 16 | 17 | (* @nocheck name *) 18 | Lemma Cpow_1_l k : C1 ^ k = C1. 19 | Proof. 20 | induction k; [|simpl; rewrite IHk]; lca. 21 | Qed. 22 | 23 | (* @nocheck name *) 24 | (* Conventional name *) 25 | Lemma Cdiv_0_l c : 0 / c = 0. 26 | Proof. apply Cmult_0_l. Qed. 27 | 28 | (* @nocheck name *) 29 | (* Conventional name *) 30 | Lemma Cdiv_nonzero_iff (c d : C) : 31 | d / c <> 0 <-> c <> 0 /\ d <> 0. 32 | Proof. 33 | rewrite Cdiv_integral_iff. 34 | tauto. 35 | Qed. 36 | 37 | (* @nocheck name *) 38 | (* Conventional name *) 39 | Lemma Cdiv_nonzero_iff_r (c d : C) : c <> 0 -> 40 | d / c <> 0 <-> d <> 0. 41 | Proof. 42 | intros Hc. 43 | rewrite Cdiv_nonzero_iff. 44 | tauto. 45 | Qed. 46 | 47 | (* @nocheck name *) 48 | (* Conventional name *) 49 | Lemma Cmult_nonzero_iff (c d : C) : 50 | c * d <> 0 <-> c <> 0 /\ d <> 0. 51 | Proof. 52 | rewrite Cmult_integral_iff. 53 | tauto. 54 | Qed. 55 | 56 | (* @nocheck name *) 57 | (* Conventional name *) 58 | Lemma Cinv_div (c d : C) : 59 | / (c / d) = d / c. 60 | Proof. 61 | unfold Cdiv. 62 | rewrite Cinv_mult_distr, Cinv_inv. 63 | apply Cmult_comm. 64 | Qed. 65 | 66 | (* @nocheck name *) 67 | (* Conventional name *) 68 | Lemma Cdiv_div (b c d : C) : 69 | b / (c / d) = b * d / c. 70 | Proof. 71 | unfold Cdiv at 1. 72 | rewrite Cinv_div. 73 | apply Cmult_assoc. 74 | Qed. 75 | 76 | (* @nocheck name *) 77 | Lemma Cexp_PI' : Cexp PI = - C1. 78 | Proof. rewrite Cexp_PI; lca. Qed. 79 | 80 | Local Open Scope nat_scope. 81 | 82 | 83 | 84 | (* @nocheck name *) 85 | (* Conventional name *) 86 | Lemma Mmult_vec_comm {n} (v u : Vector n) : WF_Matrix u -> WF_Matrix v -> 87 | v ⊤%M × u = u ⊤%M × v. 88 | Proof. 89 | intros Hu Hv. 90 | prep_matrix_equivalence. 91 | by_cell. 92 | apply big_sum_eq_bounded. 93 | intros k Hk. 94 | unfold transpose. 95 | lca. 96 | Qed. 97 | 98 | Lemma kron_f_to_vec_eq {n m p q : nat} (A : Matrix (2^n) (2^m)) 99 | (B : Matrix (2^p) (2^q)) (f : nat -> bool) : WF_Matrix A -> WF_Matrix B -> 100 | A ⊗ B × f_to_vec (m + q) f 101 | = A × f_to_vec m f ⊗ (B × f_to_vec q (fun k : nat => f (m + k))). 102 | Proof. 103 | intros. 104 | prep_matrix_equivalence. 105 | apply kron_f_to_vec. 106 | Qed. 107 | 108 | (* @nocheck name *) 109 | Lemma Forall_seq {start len : nat} f : 110 | Forall f (seq start len) <-> forall k, k < len -> f (start + k). 111 | Proof. 112 | revert start; 113 | induction len; intros start; 114 | [split; constructor + lia|]. 115 | simpl. 116 | rewrite Forall_cons_iff. 117 | split. 118 | - intros [Hfk H]. 119 | rewrite IHlen in H. 120 | intros k Hk. 121 | destruct k. 122 | + rewrite Nat.add_0_r; easy. 123 | + specialize (H k). 124 | rewrite Nat.add_succ_r. 125 | apply H. 126 | lia. 127 | - intros H. 128 | rewrite IHlen; split. 129 | + specialize (H 0). 130 | rewrite Nat.add_0_r in H. 131 | apply H; lia. 132 | + intros k Hk; specialize (H (S k)). 133 | rewrite Nat.add_succ_r in H. 134 | apply H. 135 | lia. 136 | Qed. 137 | 138 | Lemma mat_equiv_iff_conj {n m} (A B : Matrix n m) : 139 | A ≡ B <-> fold_right (fun i P => 140 | fold_right (fun j => and (A i j = B i j)) P (seq 0 m)) 141 | True (seq 0 n). 142 | Proof. 143 | transitivity (Forall (fun i => Forall (fun j => 144 | (A i j) = (B i j)) (seq 0 m)) 145 | (seq 0 n)). 146 | - rewrite Forall_seq. 147 | setoid_rewrite Forall_seq. 148 | unfold mat_equiv. 149 | cbn. 150 | intuition auto. 151 | - rewrite Forall_fold_right. 152 | unfold Matrix in A, B. 153 | generalize (seq 0 n) as l. 154 | intros l. 155 | induction l; [reflexivity|]. 156 | cbn. 157 | rewrite IHl. 158 | rewrite Forall_fold_right. 159 | generalize 160 | (fold_right (fun i P => 161 | fold_right (fun j => and (A i j = B i j)) P (seq 0 m)) True l). 162 | intros P. 163 | generalize (seq 0 m) as l'. 164 | intros l'. 165 | induction l'; cbn; intuition fail. 166 | Qed. 167 | 168 | Lemma equal_on_basis_states_implies_equal' : (* FIXME: Replace 169 | equal_on_basis_states_implies_equal with this *) 170 | forall {m dim : nat} (A B : Matrix m (2 ^ dim)), 171 | WF_Matrix A -> WF_Matrix B -> 172 | (forall f : nat -> bool, A × f_to_vec dim f = B × f_to_vec dim f) -> 173 | A = B. 174 | Proof. 175 | intros m dim A B HA HB HAB. 176 | prep_matrix_equivalence. 177 | intros i j Hi Hj. 178 | rewrite 2!(get_entry_with_e_i _ i j) by lia. 179 | rewrite 2!Mmult_assoc. 180 | rewrite <- (basis_vector_eq_e_i _ j) by assumption. 181 | rewrite basis_f_to_vec_alt by assumption. 182 | now rewrite HAB. 183 | Qed. 184 | 185 | Lemma equal_on_conj_basis_states_implies_equal {n m} 186 | (A B : Matrix (2 ^ n) (2 ^ m)) : WF_Matrix A -> WF_Matrix B -> 187 | (forall f g, (f_to_vec n g) ⊤%M × (A × f_to_vec m f) = 188 | (f_to_vec n g) ⊤%M × (B × f_to_vec m f)) -> A = B. 189 | Proof. 190 | intros HA HB HAB. 191 | apply equal_on_basis_states_implies_equal'; [auto..|]. 192 | intros f. 193 | apply transpose_matrices. 194 | apply equal_on_basis_states_implies_equal'; [auto_wf..|]. 195 | intros g. 196 | apply transpose_matrices. 197 | rewrite Mmult_transpose, transpose_involutive, HAB. 198 | rewrite Mmult_transpose, transpose_involutive. 199 | reflexivity. 200 | Qed. 201 | 202 | Lemma equal_on_basis_states_implies_equal_l {dim n} 203 | (A B : Matrix (2^dim) n) : WF_Matrix A -> WF_Matrix B -> 204 | (forall f, (f_to_vec dim f) ⊤%M × A = (f_to_vec dim f) ⊤%M × B) -> 205 | A = B. 206 | Proof. 207 | intros HA HB HAB. 208 | apply transpose_matrices. 209 | apply equal_on_basis_states_implies_equal; [auto_wf..|]. 210 | intros f. 211 | apply transpose_matrices. 212 | rewrite 2 Mmult_transpose, 2 transpose_involutive. 213 | apply HAB. 214 | Qed. 215 | 216 | 217 | Lemma e_i_transpose_adjoint n i : 218 | (@e_i n i) ⊤%M = (e_i i) †%M. 219 | Proof. 220 | prep_matrix_equality. 221 | unfold transpose, adjoint, e_i. 222 | rewrite (if_dist C C). 223 | now rewrite 2 Cconj_R. 224 | Qed. 225 | 226 | (* @nocheck name *) 227 | Lemma Mmult_f_to_vec_l_is_get_row {dim m} (A : Matrix (2^dim) m) f : 228 | WF_Matrix A -> 229 | (f_to_vec dim f) ⊤%M × A = get_row A (funbool_to_nat dim f). 230 | Proof. 231 | intros HA. 232 | rewrite basis_f_to_vec, basis_vector_eq_e_i by apply funbool_to_nat_bound. 233 | rewrite e_i_transpose_adjoint. 234 | rewrite <- matrix_by_basis_adjoint by apply funbool_to_nat_bound. 235 | reflexivity. 236 | Qed. 237 | 238 | (* FIXME: Move (I guess to vectorstates?? But b2R shouldn't go there either...) *) 239 | (* @nocheck name *) 240 | Lemma b2R_mult b c : (b2R b * b2R c = b2R (b && c))%R. 241 | Proof. 242 | destruct b, c; cbn; lra. 243 | Qed. 244 | 245 | 246 | (* FIXME: Move to Qlib *) 247 | (* @nocheck name *) 248 | Lemma Mmult_n_1 {n} (A : Square n) : WF_Matrix A -> 249 | Mmult_n 1 A = A. 250 | Proof. 251 | intros; 252 | simpl; now Msimpl. 253 | Qed. 254 | (* @nocheck name *) 255 | Lemma Mmult_n_add {n} k l (A : Square n) : WF_Matrix A -> 256 | Mmult_n (k + l) A = Mmult_n k A × Mmult_n l A. 257 | Proof. 258 | intros HA. 259 | induction k. 260 | - simpl. 261 | now Msimpl. 262 | - simpl. 263 | rewrite IHk. 264 | now rewrite Mmult_assoc. 265 | Qed. 266 | (* @nocheck name *) 267 | Lemma Mmult_n_transpose {n} (k : nat) (A : Square n) : WF_Matrix A -> 268 | ((Mmult_n k A) ⊤)%M = Mmult_n k (A ⊤)%M. 269 | Proof. 270 | intros HA. 271 | induction k. 272 | - apply id_transpose_eq. 273 | - simpl. 274 | rewrite Mmult_transpose, IHk. 275 | rewrite <- (Mmult_n_1 (A ⊤)%M) at 2 3 by auto_wf. 276 | rewrite <- 2 Mmult_n_add by auto_wf. 277 | now rewrite Nat.add_comm. 278 | Qed. 279 | 280 | 281 | Lemma mat_eq_dec_WF {n m} {A B : Matrix n m} 282 | (HA : WF_Matrix A) (HB : WF_Matrix B) : 283 | {A = B} + {A <> B}. 284 | Proof. 285 | destruct (mat_equiv_dec A B) as [Heq | Hneq]. 286 | - left. 287 | apply mat_equiv_eq; assumption. 288 | - right. 289 | intros ->. 290 | apply Hneq. 291 | reflexivity. 292 | (* Opaque because mat_equiv_dec is *) 293 | Qed. 294 | 295 | 296 | (* FIXME: Move, perhaps to Qlib.PermutationsBase? *) 297 | Lemma forall_nat_lt_add n m (P : nat -> Prop) : 298 | (forall k, k < n + m -> P k) <-> 299 | (forall k, k < n -> P k) /\ (forall k, k < m -> P (n + k)). 300 | Proof. 301 | split; [auto with zarith|]. 302 | intros [Hlow Hhigh] k Hk. 303 | bdestruct (k WF_Perm n g -> f = g. 312 | Proof. 313 | intros Hf Hg. 314 | now eq_by_WF_perm_eq n. 315 | Qed. 316 | 317 | Import Modulus. 318 | 319 | (* FIXME: Move to Qlib, in some Permutation* file *) 320 | Lemma big_swap_perm_left p q a : a < p -> 321 | big_swap_perm p q a = a + q. 322 | Proof. unfold big_swap_perm; Modulus.bdestructΩ'. Qed. 323 | 324 | Lemma big_swap_perm_right p q a : p <= a < p + q -> 325 | big_swap_perm p q a = a - p. 326 | Proof. unfold big_swap_perm; Modulus.bdestructΩ'. Qed. 327 | 328 | (* FIXME: Move to Qlib.Modulus *) 329 | Lemma div_add_n_r a n (Hn : n <> 0) : 330 | (a + n) / n = a / n + 1. 331 | Proof. 332 | pose proof (Nat.div_mod_eq (a + n) n). 333 | rewrite Modulus.mod_add_n_r in H. 334 | pose proof (Nat.div_mod_eq a n). 335 | nia. 336 | Qed. 337 | 338 | Lemma kron_comm_perm_2_n_succ_alt p : 339 | perm_eq (2 * (S p)) (kron_comm_perm 2 (S p)) 340 | ( stack_perms 1 (p + S p) idn (stack_perms (S p) p (big_swap_perm 1 p) idn) 341 | ∘ stack_perms 2 (2 * p) idn (kron_comm_perm 2 p))%prg. 342 | Proof. 343 | rewrite 2!kron_comm_perm_defn. 344 | intros k Hk. 345 | unfold compose at 1. 346 | bdestruct (k | ->]. 350 | + rewrite stack_perms_left by lia. 351 | lia. 352 | + rewrite stack_perms_right by lia. 353 | rewrite stack_perms_left by lia. 354 | rewrite big_swap_perm_left by lia. 355 | lia. 356 | - rewrite (stack_perms_right (k := k)) by lia. 357 | assert (Hkge : 2 <= k) by auto. 358 | destruct (le_ex_diff_r _ _ Hkge) as [l Hl]. 359 | subst k. 360 | rewrite add_sub' by lia. 361 | assert (Hl : l < 2 * p) by lia. 362 | rewrite (Nat.add_comm 2 l). 363 | rewrite mod_add_n_r, div_add_n_r by auto. 364 | assert (l mod 2 < 2) by show_moddy_lt. 365 | assert (l / 2 < p) by show_moddy_lt. 366 | assert (l mod 2 * p + l / 2 < 2 * p) by show_moddy_lt. 367 | rewrite stack_perms_right by lia. 368 | destruct (ltac:(lia) : l mod 2 = 0 \/ l mod 2 = 1) as [Hlmod | Hlmod]; 369 | rewrite Hlmod. 370 | + rewrite stack_perms_left by lia. 371 | rewrite big_swap_perm_right by lia. 372 | lia. 373 | + rewrite stack_perms_right by lia. 374 | lia. 375 | Qed. 376 | 377 | 378 | (* FIXME: Move *) 379 | (* @nocheck name *) 380 | Lemma Mmult_kron_e_i_I_r {n m1 m2} (A : Matrix n (m1 * m2)) k : 381 | WF_Matrix A -> (k < m1)%nat -> 382 | A × ((e_i k) ⊗ I m2) = 383 | make_WF (fun i j => A i (m2 * k + j)%nat). 384 | Proof. 385 | intros HA Hk. 386 | prep_matrix_equivalence. 387 | rewrite make_WF_equiv. 388 | intros i j Hi Hj. 389 | unfold Mmult, kron. 390 | apply (@big_sum_unique C). 391 | exists (m2 * k + j)%nat. 392 | split; [Modulus.show_moddy_lt|]. 393 | split. 394 | - unfold e_i, I. 395 | rewrite Nat.mul_comm, Nat.div_add_l by lia. 396 | rewrite Nat.div_small by lia. 397 | rewrite Nat.add_0_r. 398 | Modulus.simplify_bools_lia_one_kernel. 399 | Modulus.simplify_bools_lia_one_kernel. 400 | rewrite Cmult_1_l. 401 | rewrite Modulus.mod_add_l. 402 | rewrite Nat.eqb_refl. 403 | Modulus.simpl_bools. 404 | Modulus.simplify_bools_moddy_lia_one_kernel. 405 | lca. 406 | - intros l Hl Hlne. 407 | unfold e_i, I. 408 | Modulus.simplify_bools_moddy_lia_one_kernel. 409 | Modulus.simplify_bools_moddy_lia_one_kernel. 410 | rewrite (Nat.div_small j), (Nat.mod_small j) by lia. 411 | rewrite Nat.eqb_refl; Modulus.simpl_bools. 412 | bdestruct_all; try lca. 413 | exfalso; apply Hlne. 414 | subst k j. 415 | pose proof (Nat.div_mod_eq l m2). 416 | lia. 417 | Qed. 418 | 419 | Lemma qubit0_to_ei : qubit0 = e_i 0. 420 | Proof. 421 | lma'. 422 | Qed. 423 | 424 | Lemma qubit1_to_ei : qubit1 = e_i 1. 425 | Proof. 426 | lma'. 427 | Qed. -------------------------------------------------------------------------------- /src/CoreRules/AdditionRules.v: -------------------------------------------------------------------------------- 1 | Require Import CoreData CapCupRules StackRules StateRules ZXStateRules 2 | ChoiJamiolchosky GadgetRules ControlizerRules. 3 | Import Setoid. 4 | 5 | (** Rules about the addition of ZX-diagrams, including the 6 | correctness of [zx_of_matrix], proving universality *) 7 | 8 | Lemma zx_plus_defn' {n m} (zx0 zx1 : ZX n m) : 9 | zx0 .+ zx1 ∝= (/√2)^(n+m) .* 10 | state_to_proc (state_1 ⟷ 11 | sum_controlizer (controlizer zx0) (controlizer zx1)). 12 | Proof. 13 | rewrite zx_plus_defn. 14 | rewrite gadget_is_scaled_empty, zx_scale_stack_distr_l, stack_empty_l. 15 | rewrite const_of_zx_n_stack, const_of_zx_invsqrt2. 16 | reflexivity. 17 | Qed. 18 | 19 | Lemma zx_plus_semantics {n m} (zx0 zx1 : ZX n m) : 20 | ⟦ zx0 .+ zx1 ⟧ = 21 | (⟦ zx0 ⟧ .+ ⟦ zx1 ⟧)%M. 22 | Proof. 23 | rewrite zx_plus_defn'. 24 | rewrite zx_scale_semantics. 25 | unfold state_to_proc. 26 | rewrite zx_compose_spec, zx_stack_spec. 27 | simpl_cast_semantics. 28 | rewrite zx_stack_spec, 2 n_wire_semantics. 29 | rewrite sum_controlizer_state_1_semantics by (apply zx_is_controlized). 30 | rewrite 2 controlizer_state_1. 31 | rewrite 2 zx_scale_semantics. 32 | rewrite <- Mscale_plus_distr_r. 33 | distribute_scale. 34 | restore_dims. 35 | unify_pows_two. 36 | rewrite Mscale_mult_dist_r, Mscale_assoc. 37 | rewrite <- Cpow_mul_l, Cinv_l, Cpow_1_l, Mscale_1_l by nonzero. 38 | distribute_plus. 39 | restore_dims. 40 | unify_pows_two. 41 | rewrite Mmult_plus_distr_l. 42 | etransitivity. 2:{ 43 | rewrite <- (proc_to_state_to_proc zx0), <- (proc_to_state_to_proc zx1). 44 | unfold state_to_proc. 45 | unfold state_to_proc. 46 | rewrite 2 zx_compose_spec, zx_stack_spec. 47 | simpl_cast_semantics. 48 | rewrite 2 zx_stack_spec, 2 n_wire_semantics. 49 | reflexivity. 50 | } 51 | reflexivity. 52 | Qed. 53 | 54 | 55 | 56 | Lemma zx_plus_0_l {n m} (zx : ZX n m) : 57 | zx_zero .+ zx ∝= zx. 58 | Proof. 59 | prep_matrix_equivalence. 60 | rewrite zx_plus_semantics, zx_zero_semantics, Mplus_0_l. 61 | reflexivity. 62 | Qed. 63 | 64 | Lemma zx_plus_0_r {n m} (zx : ZX n m) : 65 | zx .+ zx_zero ∝= zx. 66 | Proof. 67 | prep_matrix_equivalence. 68 | rewrite zx_plus_semantics, zx_zero_semantics, Mplus_0_r. 69 | reflexivity. 70 | Qed. 71 | 72 | (* TODO: Other distributivities *) 73 | 74 | Lemma compose_plus_distr_l {n m o} (zx zx' : ZX n m) (zx1 : ZX m o) : 75 | (zx .+ zx') ⟷ zx1 ∝= zx ⟷ zx1 .+ zx' ⟷ zx1. 76 | Proof. 77 | prep_matrix_equivalence. 78 | rewrite zx_plus_semantics, 3 zx_compose_spec, zx_plus_semantics. 79 | now rewrite Mmult_plus_distr_l by auto_wf. 80 | Qed. 81 | 82 | Lemma compose_plus_distr_r {n m o} (zx : ZX n m) (zx1 zx1' : ZX m o) : 83 | zx ⟷ (zx1 .+ zx1') ∝= zx ⟷ zx1 .+ zx ⟷ zx1'. 84 | Proof. 85 | prep_matrix_equivalence. 86 | rewrite zx_plus_semantics, 3 zx_compose_spec, zx_plus_semantics. 87 | now rewrite Mmult_plus_distr_r by auto_wf. 88 | Qed. 89 | 90 | Lemma stack_plus_distr_l {n m o p} (zx zx' : ZX n m) (zx1 : ZX o p) : 91 | (zx .+ zx') ↕ zx1 ∝= zx ↕ zx1 .+ zx' ↕ zx1. 92 | Proof. 93 | prep_matrix_equivalence. 94 | rewrite zx_plus_semantics, 3 zx_stack_spec, zx_plus_semantics. 95 | now rewrite kron_plus_distr_r by auto_wf. 96 | Qed. 97 | 98 | Lemma stack_plus_distr_r {n m o p} (zx : ZX n m) (zx1 zx1' : ZX o p) : 99 | zx ↕ (zx1 .+ zx1') ∝= zx ↕ zx1 .+ zx ↕ zx1'. 100 | Proof. 101 | prep_matrix_equivalence. 102 | rewrite zx_plus_semantics, 3 zx_stack_spec, zx_plus_semantics. 103 | now rewrite kron_plus_distr_l by auto_wf. 104 | Qed. 105 | 106 | Lemma zx_scale_plus_distr_r {n m} c (zx0 zx1 : ZX n m) : 107 | c .* (zx0 .+ zx1) ∝= c .* zx0 .+ c .* zx1. 108 | Proof. 109 | prep_matrix_equivalence. 110 | rewrite zx_plus_semantics, 3 zx_scale_semantics, zx_plus_semantics. 111 | now rewrite Mscale_plus_distr_r. 112 | Qed. 113 | 114 | Lemma zx_scale_plus_distr_l {n m} c d (zx : ZX n m) : 115 | (c + d) .* zx ∝= c .* zx .+ d .* zx. 116 | Proof. 117 | prep_matrix_equivalence. 118 | rewrite zx_plus_semantics, 3 zx_scale_semantics. 119 | now rewrite Mscale_plus_distr_l. 120 | Qed. 121 | 122 | 123 | 124 | Lemma zx_plus_comm {n m} (zx0 zx1 : ZX n m) : 125 | zx0 .+ zx1 ∝= zx1 .+ zx0. 126 | Proof. 127 | prep_matrix_equivalence. 128 | rewrite 2 zx_plus_semantics, Mplus_comm. 129 | reflexivity. 130 | Qed. 131 | 132 | Lemma zx_plus_assoc {n m} (zx0 zx1 zx2 : ZX n m) : 133 | zx0 .+ (zx1 .+ zx2) ∝= zx0 .+ zx1 .+ zx2. 134 | Proof. 135 | prep_matrix_equivalence. 136 | rewrite 4 zx_plus_semantics, Mplus_assoc. 137 | reflexivity. 138 | Qed. 139 | 140 | (* TODO: Other comm/assoc helpers... *) 141 | 142 | 143 | 144 | 145 | Lemma zx_sum_S {n m} (f : nat -> ZX n m) k : 146 | zx_sum f (S k) ∝= zx_sum f k .+ f k. 147 | Proof. 148 | destruct k; [|reflexivity]. 149 | simpl. 150 | now rewrite zx_plus_0_l. 151 | Qed. 152 | 153 | 154 | 155 | (* TODO: Other morphism instance (proportionality) *) 156 | Add Parametric Morphism {n m} : (@zx_sum n m) with signature 157 | Morphisms.pointwise_relation nat proportional_by_1 ==> eq ==> proportional_by_1 158 | as zx_sum_mor. 159 | Proof. 160 | intros f g Hfg. 161 | intros k. 162 | induction k; [reflexivity|]. 163 | now rewrite 2 zx_sum_S, IHk, Hfg. 164 | Qed. 165 | 166 | Lemma zx_sum_semantics {n m} (f : nat -> ZX n m) k : 167 | ⟦ zx_sum f k ⟧ = big_sum (fun i => ⟦ f i ⟧) k. 168 | Proof. 169 | induction k. 170 | - apply zx_zero_semantics. 171 | - rewrite zx_sum_S. 172 | cbn. 173 | rewrite zx_plus_semantics, IHk. 174 | reflexivity. 175 | Qed. 176 | 177 | Lemma state_of_vector_semantics {n} (v : Vector (2^n)) : WF_Matrix v -> 178 | ⟦ state_of_vector v ⟧ = v. 179 | Proof. 180 | intros Hv. 181 | prep_matrix_equivalence. 182 | intros i j Hi Hj. 183 | replace j with O in * by (simpl in Hj; lia); clear j Hj. 184 | unfold state_of_vector. 185 | rewrite zx_sum_semantics, Msum_Csum. 186 | apply big_sum_unique. 187 | exists i. 188 | split; [auto|]. 189 | split. 190 | - rewrite zx_scale_semantics, f_to_state_semantics. 191 | rewrite <- basis_f_to_vec_alt by auto. 192 | rewrite basis_vector_eq_e_i by auto. 193 | unfold scale, e_i. 194 | bdestructΩ'; lca. 195 | - intros j Hj Hji. 196 | rewrite zx_scale_semantics, f_to_state_semantics. 197 | rewrite <- basis_f_to_vec_alt by auto. 198 | rewrite basis_vector_eq_e_i by auto. 199 | unfold scale, e_i. 200 | bdestructΩ'; lca. 201 | Qed. 202 | 203 | Lemma zx_of_matrix_semantics {n m} (A : Matrix (2^m) (2^n)) : WF_Matrix A -> 204 | ⟦ zx_of_matrix A ⟧ = A. 205 | Proof. 206 | intros HA. 207 | prep_matrix_equivalence. 208 | unfold zx_of_matrix. 209 | (* TODO: Lemma state_to_proc_semantics *) 210 | unfold state_to_proc. 211 | rewrite zx_compose_spec. 212 | simpl_cast_semantics. 213 | rewrite (zx_stack_spec _ _ _ _ (n_wire n)). 214 | rewrite state_of_vector_semantics by auto_wf. 215 | rewrite n_wire_semantics, kron_id_dist_l by auto_wf. 216 | restore_dims. 217 | rewrite <- kron_assoc, id_kron by auto_wf. 218 | unify_pows_two. 219 | rewrite <- Mmult_assoc. 220 | rewrite zx_stack_spec, n_wire_semantics. 221 | restore_dims. 222 | rewrite <- kron_split_diag by auto_wf. 223 | rewrite (kron_split_antidiag _ A), kron_1_l by auto_wf. 224 | rewrite <- (Mmult_1_r _ _ A) at 2 by auto_wf. 225 | unify_pows_two. 226 | rewrite Mmult_assoc. 227 | (* rewrite Nat.add_0_r. *) 228 | apply mmult_mat_equiv_morph; [reflexivity|]. 229 | generalize (big_yank_r n (Nat.add_assoc _ _ _) eq_refl (Nat.add_0_r _)). 230 | unfold proportional_by_1. 231 | cbn [Nat.add]. 232 | simpl_cast_semantics. 233 | intros H. 234 | rewrite <- n_wire_semantics. 235 | etransitivity; [|now rewrite <- H]. 236 | rewrite zx_compose_spec. 237 | simpl_cast_semantics. 238 | rewrite zx_stack_spec. 239 | restore_dims. 240 | pose proof (zx_stack_spec _ _ _ _ (n_cup n) (n_wire n)) as Hrw. 241 | cbn [Nat.add] in Hrw. 242 | rewrite Hrw. 243 | unify_pows_two. 244 | reflexivity. 245 | Qed. 246 | 247 | 248 | Require Import ZXpermFacts. 249 | 250 | 251 | Lemma zx_of_matrix'_semantics {n m} (A : Matrix (2^m) (2^n)) : WF_Matrix A -> 252 | ⟦ zx_of_matrix' A ⟧ = A. 253 | Proof. 254 | intros HA. 255 | prep_matrix_equivalence. 256 | unfold zx_of_matrix'. 257 | rewrite zx_sum_semantics. 258 | erewrite big_sum_eq_bounded. 2:{ 259 | intros i Hi. 260 | rewrite zx_sum_semantics. 261 | eapply big_sum_eq_bounded. 262 | intros j Hj. 263 | rewrite zx_scale_semantics. 264 | rewrite zx_compose_spec, semantics_transpose_comm. 265 | rewrite 2 f_to_state_semantics, <- 2 basis_f_to_vec_alt by easy. 266 | rewrite 2 basis_vector_eq_e_i by easy. 267 | reflexivity. 268 | } 269 | intros i' j' Hi' Hj'. 270 | rewrite Msum_Csum. 271 | erewrite big_sum_eq_bounded. 2:{ 272 | intros i Hi. 273 | rewrite Msum_Csum. 274 | erewrite big_sum_eq_bounded. 2:{ 275 | intros j Hj. 276 | unfold scale. 277 | cbn. 278 | unfold Matrix.transpose. 279 | rewrite Cplus_0_l. 280 | unfold e_i. 281 | cbn. 282 | replace_bool_lia (i'