Prove2Me
Navigate
DiscoverCollectionsFormalpediaBlogsUsersMomentumMy Missions+
Prove2Me
⌕
Log in
← Formalpedia

Circuits of locations: preparation, gates, measurement, wait; faults and output distributions

Definition
QAlgorithms_Defs_LocCircuit

by Goku · Oct 13, 2026 · Mathlib 0df444a (Lean v4.33.1)

lecture-notesquantum-information

Circuits of locations: preparation, gates, measurement, wait; faults and output distributions

QAlgorithms.LocKind

An enumerated type with exactly six distinct values:

  • prep\mathrm{prep}prep (preparation),
  • had\mathrm{had}had (Hadamard),
  • tgate\mathrm{tgate}tgate (TTT gate),
  • cnot\mathrm{cnot}cnot,
  • meas\mathrm{meas}meas (measurement),
  • wait\mathrm{wait}wait.

Equality between values is decidable.

QAlgorithms.LocKind.arity

The function on the six location kinds that gives the number of qubits a kind acts on:

  • cnot\mathrm{cnot}cnot has arity 222.
  • Each of prep\mathrm{prep}prep, had\mathrm{had}had, tgate\mathrm{tgate}tgate, meas\mathrm{meas}meas, wait\mathrm{wait}wait has arity 111.

QAlgorithms.LocKind.IsGate

The Boolean predicate on location kinds:

  • It is true for had\mathrm{had}had, tgate\mathrm{tgate}tgate and cnot\mathrm{cnot}cnot.
  • It is false for prep\mathrm{prep}prep, meas\mathrm{meas}meas and wait\mathrm{wait}wait.

QAlgorithms.LocKind.idealMatrix

For each location kind κ\kappaκ, this gives a 2a×2a2^{a}\times 2^{a}2a×2a complex matrix, where aaa is the arity of κ\kappaκ. Rows and columns are indexed by bit strings of length aaa.

had\mathrm{had}had. The Hadamard

12(111−1)\tfrac1{\sqrt2}\begin{pmatrix}1&1\\1&-1\end{pmatrix}2​1​(11​1−1​)

on one qubit.

tgate\mathrm{tgate}tgate. The TTT gate diag(1,eiπ/4)\mathrm{diag}(1, e^{i\pi/4})diag(1,eiπ/4) on one qubit.

cnot\mathrm{cnot}cnot. The two-qubit CNOT with the first qubit as control:

  • the entry at row (p1,p2)(p_1,p_2)(p1​,p2​), column (q1,q2)(q_1,q_2)(q1​,q2​) is 111 if p1=q1p_1 = q_1p1​=q1​ and p2=q2⊕q1p_2 = q_2 \oplus q_1p2​=q2​⊕q1​, and 000 otherwise;
  • equivalently, ∣q1,q2⟩↦∣q1,q2⊕q1⟩|q_1,q_2\rangle \mapsto |q_1, q_2\oplus q_1\rangle∣q1​,q2​⟩↦∣q1​,q2​⊕q1​⟩.

prep\mathrm{prep}prep, meas\mathrm{meas}meas, wait\mathrm{wait}wait. The 2×22\times 22×2 identity matrix.

QAlgorithms.Loc

For a number of wires NNN, a location lll consists of three pieces of data:

  • Kind. A kind κ∈{prep,had,tgate,cnot,meas,wait}\kappa \in \{\mathrm{prep},\mathrm{had},\mathrm{tgate},\mathrm{cnot},\mathrm{meas},\mathrm{wait}\}κ∈{prep,had,tgate,cnot,meas,wait}. Let aaa be its arity: 222 for cnot\mathrm{cnot}cnot, 111 otherwise.
  • Wires. An injective map w:{0,…,a−1}→{0,…,N−1}w : \{0,\dots,a-1\} \to \{0,\dots,N-1\}w:{0,…,a−1}→{0,…,N−1}, giving an ordered tuple of aaa distinct wires.
  • Condition. An arbitrary function cond\mathrm{cond}cond, which takes a partial assignment of bits to pairs of natural numbers and returns a Boolean. Its input is a map (N×N)→{0,1}∪{undefined}(\mathbb{N}\times\mathbb{N}) \to \{0,1\}\cup\{\text{undefined}\}(N×N)→{0,1}∪{undefined}.

Edge cases. No further constraints are imposed. If N=0N = 0N=0, no location exists, because no map into the empty set exists.

QAlgorithms.Loc.qubits

For a location lll on NNN wires, this is the finite set of wires it touches:

qubits(l)={ w(0),…,w(a−1) }⊆{0,…,N−1}.\mathrm{qubits}(l) = \{\,w(0),\dots,w(a-1)\,\} \subseteq \{0,\dots,N-1\}.qubits(l)={w(0),…,w(a−1)}⊆{0,…,N−1}.

Here www is the wire map of lll and aaa is the arity of its kind. Because www is injective, this set has exactly aaa elements: one for non-CNOT kinds, two for CNOT.

QAlgorithms.LocCircuit

A location circuit on NNN wires is a finite list of time steps. Each time step is a finite list of locations on NNN wires.

No constraints are imposed. In particular:

  • locations in the same step may share wires;
  • steps may be empty;
  • the list of steps may be empty.

QAlgorithms.LocCircuit.locAt

Setting. A located circuit CCC on NNN qubits consists of a finite list of time steps C=(L0,L1,…,LS−1)C = (L_0, L_1, \dots, L_{S-1})C=(L0​,L1​,…,LS−1​). Each step LsL_sLs​ is a finite list of locations. A location lll has three parts:

  • a kind, one of preparation, Hadamard, TTT gate, CNOT, measurement, or wait;
  • an injective assignment of its 111 (or, for CNOT, 222) wires to qubits in {0,…,N−1}\{0, \dots, N-1\}{0,…,N−1};
  • a classical condition.

Definition. For a pair ℓ=(s,j)\ell = (s, j)ℓ=(s,j) of natural numbers, locAtC(ℓ)\mathrm{locAt}_C(\ell)locAtC​(ℓ) is the jjj-th entry of step sss, counted from 000, if it exists, and "none" otherwise. Explicitly:

  • If s≥Ss \ge Ss≥S, step sss is treated as the empty list, so the result is "none".
  • If s<Ss < Ss<S but j≥∣Ls∣j \ge |L_s|j≥∣Ls​∣, the result is also "none".

QAlgorithms.LocCircuit.locs

For a located circuit CCC with steps L0,…,LS−1L_0, \dots, L_{S-1}L0​,…,LS−1​, each a list of locations as above, locs(C)\mathrm{locs}(C)locs(C) is the finite set of index pairs

locs(C)={(s,j)∈N2:s<S, j<∣Ls∣}.\mathrm{locs}(C) = \{(s, j) \in \mathbb{N}^2 : s < S,\ j < |L_s|\}.locs(C)={(s,j)∈N2:s<S, j<∣Ls​∣}.

These are exactly the pairs ℓ\ellℓ for which locAtC(ℓ)\mathrm{locAt}_C(\ell)locAtC​(ℓ) is defined. Empty steps contribute no pairs.

QAlgorithms.LocCircuit.numQubits

For any located circuit CCC on NNN qubits, numQubits(C)=N\mathrm{numQubits}(C) = NnumQubits(C)=N. This is the number NNN fixed in the type of the circuit. It does not depend on the steps or locations of CCC, and in particular it does not count only the qubits that are actually used.

QAlgorithms.LocCircuit.numSteps

For a located circuit CCC with step list (L0,…,LS−1)(L_0, \dots, L_{S-1})(L0​,…,LS−1​), numSteps(C)=S\mathrm{numSteps}(C) = SnumSteps(C)=S. This is the length of the step list. Every step is counted, including steps that contain no locations.

QAlgorithms.LocCircuit.size

For a located circuit CCC with steps L0,…,LS−1L_0, \dots, L_{S-1}L0​,…,LS−1​, size(C)\mathrm{size}(C)size(C) is the cardinality of the set locs(C)={(s,j):s<S, j<∣Ls∣}\mathrm{locs}(C) = \{(s,j) : s < S,\ j < |L_s|\}locs(C)={(s,j):s<S, j<∣Ls​∣}. Since these index pairs are distinct, this equals

∑s<S∣Ls∣,\sum_{s<S} |L_s|,s<S∑​∣Ls​∣,

the total number of locations of every kind, including preparations, measurements and waits.

QAlgorithms.LocCircuit.measIds

For a located circuit CCC with steps L0,…,LS−1L_0, \dots, L_{S-1}L0​,…,LS−1​, measIds(C)\mathrm{measIds}(C)measIds(C) is the list of all index pairs (s,j)(s, j)(s,j) such that the jjj-th location of step sss (both counted from 000) has kind "measurement".

The list is ordered by step sss increasing, and within a step by position jjj increasing. It contains no repetitions. Locations of any other kind do not appear.

QAlgorithms.LocCircuit.measCount

For a located circuit CCC, measCount(C)\mathrm{measCount}(C)measCount(C) is the length of the list measIds(C)\mathrm{measIds}(C)measIds(C). That list holds the index pairs (s,j)(s,j)(s,j) of all measurement-kind locations, in step-then-position order. So measCount(C)\mathrm{measCount}(C)measCount(C) is the total number of measurement locations in CCC.

QAlgorithms.LocCircuit.outcomeAt

Let CCC be a located circuit and r=(r0,r1,…,rk−1)r = (r_0, r_1, \dots, r_{k-1})r=(r0​,r1​,…,rk−1​) a finite list of bits. Let measIds(C)=(m0,m1,…,mM−1)\mathrm{measIds}(C) = (m_0, m_1, \dots, m_{M-1})measIds(C)=(m0​,m1​,…,mM−1​) be its measurement locations in step-then-position order.

Pair the two lists positionally, (mi,ri)(m_i, r_i)(mi​,ri​) for i<min⁡(M,k)i < \min(M, k)i<min(M,k); the longer list is truncated. For an index pair ℓ\ellℓ, define

outcomeAtC(r,ℓ)={riif ℓ=mi for some i<min⁡(M,k),noneotherwise.\mathrm{outcomeAt}_C(r, \ell) = \begin{cases} r_i & \text{if } \ell = m_i \text{ for some } i < \min(M,k),\\ \text{none} & \text{otherwise.}\end{cases}outcomeAtC​(r,ℓ)={ri​none​if ℓ=mi​ for some i<min(M,k),otherwise.​

The mim_imi​ are distinct, so iii is unique when it exists. The "none" case covers three situations:

  • ℓ\ellℓ is not a measurement location;
  • ℓ\ellℓ is not a location at all;
  • ℓ\ellℓ is the iii-th measurement with i≥ki \ge ki≥k, i.e. rrr is too short.

Bits rir_iri​ with i≥Mi \ge Mi≥M are ignored.

QAlgorithms.qubitsOf

For a finite list l1,…,lpl_1, \dots, l_pl1​,…,lp​ of locations on NNN qubits, qubitsOf\mathrm{qubitsOf}qubitsOf is the union of their qubit sets:

qubitsOf(l1,…,lp)=⋃i=1pQ(li)⊆{0,…,N−1}.\mathrm{qubitsOf}(l_1, \dots, l_p) = \bigcup_{i=1}^{p} Q(l_i) \subseteq \{0, \dots, N-1\}.qubitsOf(l1​,…,lp​)=i=1⋃p​Q(li​)⊆{0,…,N−1}.

Here Q(l)Q(l)Q(l) is the set of qubits that location lll acts on, i.e. the image of its wire assignment: one qubit, or two for a CNOT. The empty list gives ∅\emptyset∅.

QAlgorithms.stepLive

For a set live⊆{0,…,N−1}\mathrm{live} \subseteq \{0, \dots, N-1\}live⊆{0,…,N−1} of qubits and a list ststst of locations on NNN qubits, define

stepLive(live,st)=(live ∪ ⋃l∈st, l a preparationQ(l))∖⋃l∈st, l a measurementQ(l),\mathrm{stepLive}(\mathrm{live}, st) = \Big(\mathrm{live} \,\cup\, \bigcup_{l \in st,\ l \text{ a preparation}} Q(l)\Big) \setminus \bigcup_{l \in st,\ l \text{ a measurement}} Q(l),stepLive(live,st)=(live∪l∈st, l a preparation⋃​Q(l))∖l∈st, l a measurement⋃​Q(l),

where Q(l)Q(l)Q(l) is the set of qubits acted on by lll.

Qubits of preparation locations are added and qubits of measurement locations are removed, with the removal applied last. Two consequences follow:

  • A qubit that is both prepared and measured in ststst is not in the result.
  • A measured qubit is removed whether or not it was in live\mathrm{live}live.

Locations of all other kinds have no effect.

QAlgorithms.LocCircuit.liveBefore

Let CCC be a located circuit with steps L0,…,LS−1L_0, \dots, L_{S-1}L0​,…,LS−1​, and let liveIn⊆{0,…,N−1}\mathrm{liveIn} \subseteq \{0,\dots,N-1\}liveIn⊆{0,…,N−1} be an initial set of qubits. The sets liveBeforeC(liveIn,s)\mathrm{liveBefore}_C(\mathrm{liveIn}, s)liveBeforeC​(liveIn,s), for s∈Ns \in \mathbb{N}s∈N, are defined recursively by

liveBefore(0)=liveIn,liveBefore(s+1)=stepLive(liveBefore(s), Ls).\mathrm{liveBefore}(0) = \mathrm{liveIn}, \qquad \mathrm{liveBefore}(s+1) = \mathrm{stepLive}\big(\mathrm{liveBefore}(s),\ L_s\big).liveBefore(0)=liveIn,liveBefore(s+1)=stepLive(liveBefore(s), Ls​).

Here stepLive(X,L)=(X∪qubits of preparations in L)∖qubits of measurements in L\mathrm{stepLive}(X, L) = (X \cup \text{qubits of preparations in } L) \setminus \text{qubits of measurements in } LstepLive(X,L)=(X∪qubits of preparations in L)∖qubits of measurements in L. For s≥Ss \ge Ss≥S, LsL_sLs​ is taken to be the empty list, so the sequence is constant from s=Ss = Ss=S on.

QAlgorithms.LocCircuit.IsWellFormed

Let CCC be a located circuit on NNN qubits with steps L0,…,LS−1L_0, \dots, L_{S-1}L0​,…,LS−1​, and let liveIn,liveOut⊆{0,…,N−1}\mathrm{liveIn}, \mathrm{liveOut} \subseteq \{0,\dots,N-1\}liveIn,liveOut⊆{0,…,N−1}. Write:

  • Q(l)Q(l)Q(l) for the set of qubits a location lll acts on;
  • Vs=liveBeforeC(liveIn,s)V_s = \mathrm{liveBefore}_C(\mathrm{liveIn}, s)Vs​=liveBeforeC​(liveIn,s) for the live set before step sss. Here V0=liveInV_0 = \mathrm{liveIn}V0​=liveIn and Vs+1=(Vs∪qubits of preparations in Ls)∖qubits of measurements in LsV_{s+1} = (V_s \cup \text{qubits of preparations in } L_s) \setminus \text{qubits of measurements in } L_sVs+1​=(Vs​∪qubits of preparations in Ls​)∖qubits of measurements in Ls​.

Definition. CCC is well-formed from liveIn\mathrm{liveIn}liveIn to liveOut\mathrm{liveOut}liveOut if both of the following hold.

  1. For every step index s<Ss < Ss<S, all four of these conditions hold:
    • (a) Disjointness. Any two locations occupying different positions in the list LsL_sLs​ act on disjoint qubit sets.
    • (b) Coverage. Every qubit q∈Vsq \in V_sq∈Vs​ lies in Q(l)Q(l)Q(l) for some location l∈Lsl \in L_sl∈Ls​, of any kind, including wait.
    • (c) Preparations. Every location l∈Lsl \in L_sl∈Ls​ of kind preparation satisfies Q(l)∩Vs=∅Q(l) \cap V_s = \emptysetQ(l)∩Vs​=∅.
    • (d) Other kinds. Every location l∈Lsl \in L_sl∈Ls​ of any other kind (Hadamard, TTT, CNOT, measurement, wait) satisfies Q(l)⊆VsQ(l) \subseteq V_sQ(l)⊆Vs​.
  2. Final live set. VS=liveOutV_S = \mathrm{liveOut}VS​=liveOut.

Not constrained. The classical conditions attached to locations are not restricted by this definition. When S=0S = 0S=0, condition 1 is vacuous and the definition reduces to liveIn=liveOut\mathrm{liveIn} = \mathrm{liveOut}liveIn=liveOut.

QAlgorithms.LocCircuit.IsIdealCircuit

This is a property of a location circuit CCC on NNN qubits (wires 0,…,N−10,\dots,N-10,…,N−1). Such a circuit is a list of time steps C0,C1,…,CS−1C_0, C_1, \dots, C_{S-1}C0​,C1​,…,CS−1​. Each step is a list of locations lll, and each location has three parts:

  • a kind: preparation, Hadamard, TTT gate, CNOT, measurement, or wait;
  • an injective list of wires (two for CNOT, one otherwise);
  • a classical condition condl\mathrm{cond}_lcondl​, a Boolean-valued function of a partial table N×N→{true,false,undefined}\mathbb{N}\times\mathbb{N} \to \{\text{true},\text{false},\text{undefined}\}N×N→{true,false,undefined} of measurement outcomes.

CCC is ideal when two conditions hold. The first is that CCC is well-formed with empty input live set and empty output live set. This means the following. Define live sets by

L0=∅,Ls+1=(Ls∪prepQubits(Cs))∖measQubits(Cs),L_0 = \emptyset, \qquad L_{s+1} = \bigl(L_s \cup \mathrm{prepQubits}(C_s)\bigr) \setminus \mathrm{measQubits}(C_s),L0​=∅,Ls+1​=(Ls​∪prepQubits(Cs​))∖measQubits(Cs​),

where prepQubits\mathrm{prepQubits}prepQubits and measQubits\mathrm{measQubits}measQubits are the unions of the wire sets of the preparation and measurement locations of the step. Then for every step s<Ss < Ss<S:

  • the locations of CsC_sCs​ have pairwise disjoint wire sets;
  • every qubit in LsL_sLs​ is a wire of some location of CsC_sCs​;
  • every preparation location of CsC_sCs​ has wires disjoint from LsL_sLs​;
  • every non-preparation location of CsC_sCs​ has all its wires in LsL_sLs​.

In addition, LS=∅L_S = \emptysetLS​=∅.

The second condition is that every location in every step has the constant condition condl≡true\mathrm{cond}_l \equiv \text{true}condl​≡true.

When CCC has no steps, the first condition holds trivially because L0=∅L_0 = \emptysetL0​=∅.

QAlgorithms.ErrAssign

For N∈NN \in \mathbb{N}N∈N and a type EEE (an environment register), an error assignment is any function

err:N×N→{none}∪Superop(QN×E),\mathrm{err} : \mathbb{N}\times\mathbb{N} \to \{\text{none}\} \cup \mathrm{Superop}(Q_N\times E),err:N×N→{none}∪Superop(QN​×E),

where QN={0,1}NQ_N = \{0,1\}^NQN​={0,1}N. It assigns to each address (s,j)(s,j)(s,j) (read as step sss, position jjj) either "no error" or a superoperator.

Here a superoperator on QN×EQ_N \times EQN​×E is any map from complex (QN×E)×(QN×E)(Q_N\times E)\times(Q_N\times E)(QN​×E)×(QN​×E) matrices to matrices of the same shape. Nothing requires it to be linear, completely positive, or trace-preserving. Addresses that do not correspond to any location are also allowed to carry a value.

QAlgorithms.CQState

For N∈NN \in \mathbb{N}N∈N and a type EEE, a classical–quantum state is any function

ρ:{0,1}∗→C(QN×E)×(QN×E).\rho : \{0,1\}^{*} \to \mathbb{C}^{(Q_N\times E)\times(Q_N\times E)}.ρ:{0,1}∗→C(QN​×E)×(QN​×E).

It assigns to every finite list rrr of bits (read as a measurement record) a complex matrix ρ(r)\rho(r)ρ(r) on the joint system of NNN qubits and the environment EEE, with QN={0,1}NQ_N = \{0,1\}^NQN​={0,1}N.

No positivity, trace, or normalization condition is imposed on the matrices ρ(r)\rho(r)ρ(r).

QAlgorithms.qubitOp1

Let MMM be a complex 2×22\times 22×2 matrix indexed by bits, and let qqq be a wire, 0≤q<N0 \le q < N0≤q<N. Then qubitOp1(M,q)\mathrm{qubitOp1}(M,q)qubitOp1(M,q) is the 2N×2N2^N\times 2^N2N×2N matrix indexed by y,z∈{0,1}Ny,z \in \{0,1\}^Ny,z∈{0,1}N with

qubitOp1(M,q)y,z={Myq, zqif ya=za for all a≠q,0otherwise.\mathrm{qubitOp1}(M,q)_{y,z} = \begin{cases} M_{y_q,\,z_q} & \text{if } y_a = z_a \text{ for all } a \neq q,\\ 0 & \text{otherwise.}\end{cases}qubitOp1(M,q)y,z​={Myq​,zq​​0​if ya​=za​ for all a=q,otherwise.​

That is, it is MMM acting on qubit qqq, tensored with the identity on all other qubits.

QAlgorithms.resetKraus

For a bit bbb, resetKraus(b)\mathrm{resetKraus}(b)resetKraus(b) is the 2×22\times 22×2 matrix with entries

resetKraus(b)y,z={1if y=0 and z=b,0otherwise.\mathrm{resetKraus}(b)_{y,z} = \begin{cases} 1 & \text{if } y = 0 \text{ and } z = b,\\ 0 & \text{otherwise.}\end{cases}resetKraus(b)y,z​={10​if y=0 and z=b,otherwise.​

In other words, resetKraus(b)=∣0⟩⟨b∣\mathrm{resetKraus}(b) = |0\rangle\langle b|resetKraus(b)=∣0⟩⟨b∣.

QAlgorithms.measProj

For a bit bbb, measProj(b)\mathrm{measProj}(b)measProj(b) is the 2×22\times 22×2 matrix with entry 111 at (b,b)(b,b)(b,b) and 000 elsewhere. In other words, measProj(b)=∣b⟩⟨b∣\mathrm{measProj}(b) = |b\rangle\langle b|measProj(b)=∣b⟩⟨b∣, the projector onto computational basis state bbb.

QAlgorithms.Loc.apply

This defines how a single location lll on NNN qubits acts on a classical–quantum state. The environment EEE is a finite type with decidable equality. The inputs are:

  • an outcome lookup OOO, which maps each record rrr to a partial table O(r):N×N→{true,false,undefined}O(r) : \mathbb{N}\times\mathbb{N} \to \{\text{true},\text{false},\text{undefined}\}O(r):N×N→{true,false,undefined};
  • an optional error eee, either "none" or an arbitrary map Φ\PhiΦ on (QN×E)(Q_N\times E)(QN​×E)-matrices;
  • a state ρ\rhoρ, which is a function from bit lists to such matrices.

Some notation used below:

  • E\mathcal{E}E is the error map: E(X)=X\mathcal{E}(X) = XE(X)=X if eee is none, and E(X)=Φ(X)\mathcal{E}(X) = \Phi(X)E(X)=Φ(X) if e=Φe = \Phie=Φ.
  • qqq is the first wire of lll.
  • A^=A⊗IE\widehat{A} = A \otimes I_EA=A⊗IE​ is the extension of an NNN-qubit matrix to the joint system.
  • Kb=qubitOp1(∣0⟩⟨b∣,q)K_b = \mathrm{qubitOp1}(|0\rangle\langle b|, q)Kb​=qubitOp1(∣0⟩⟨b∣,q) is the reset Kraus operator on qubit qqq.
  • Pb=qubitOp1(∣b⟩⟨b∣,q)P_b = \mathrm{qubitOp1}(|b\rangle\langle b|, q)Pb​=qubitOp1(∣b⟩⟨b∣,q) is the measurement projector on qubit qqq.
  • †\dagger† denotes the conjugate transpose.

The resulting state ρ′\rho'ρ′ is defined case by case on the kind of lll:

  • Preparation: the qubit is reset to 000 and the error is applied afterwards:
ρ′(r)=E(∑b∈{0,1}Kb^ ρ(r) Kb^†).\rho'(r) = \mathcal{E}\Bigl(\textstyle\sum_{b\in\{0,1\}} \widehat{K_b}\,\rho(r)\,\widehat{K_b}^{\dagger}\Bigr).ρ′(r)=E(∑b∈{0,1}​Kb​​ρ(r)Kb​​†).
  • Measurement: the error is applied before the projection, and the last record bit selects the outcome. If rrr is empty, ρ′(r)=0\rho'(r) = 0ρ′(r)=0. If r=r′ br = r'\,br=r′b (last bit bbb), then
ρ′(r)=Pb^  E(ρ(r′))  Pb^†.\rho'(r) = \widehat{P_b}\;\mathcal{E}\bigl(\rho(r')\bigr)\;\widehat{P_b}^{\dagger}.ρ′(r)=Pb​​E(ρ(r′))Pb​​†.

Only the first (and only) wire qqq is used.

  • Wait: ρ′(r)=E(ρ(r))\rho'(r) = \mathcal{E}(\rho(r))ρ′(r)=E(ρ(r)).

  • Hadamard, TTT, CNOT: the gate is applied only if the classical condition holds, and the error is applied afterwards:

ρ′(r)={E(U^ ρ(r) U^†)if condl(O(r))=true,E(ρ(r))otherwise.\rho'(r) = \begin{cases}\mathcal{E}\bigl(\widehat{U}\,\rho(r)\,\widehat{U}^{\dagger}\bigr) & \text{if } \mathrm{cond}_l(O(r)) = \text{true},\\ \mathcal{E}(\rho(r)) & \text{otherwise.}\end{cases}ρ′(r)={E(Uρ(r)U†)E(ρ(r))​if condl​(O(r))=true,otherwise.​

Here UUU is the ideal gate placed on the wires of lll (identity elsewhere):

  • the Hadamard 12(111−1)\tfrac{1}{\sqrt2}\begin{pmatrix}1&1\\1&-1\end{pmatrix}2​1​(11​1−1​);
  • the TTT gate diag(1,eiπ/4)\mathrm{diag}(1, e^{i\pi/4})diag(1,eiπ/4);
  • CNOT, with control the first wire of lll and target the second.

QAlgorithms.runStep

This runs one time step, applying its locations one after another. The inputs are:

  • an outcome lookup OOO;
  • an error assignment err\mathrm{err}err;
  • a step number sss;
  • a list of locations l0,l1,…,lk−1l_0, l_1, \dots, l_{k-1}l0​,l1​,…,lk−1​;
  • a starting position jjj;
  • a state ρ\rhoρ.

The result is

runStep(O,err,s,[l0,…,lk−1],j,ρ)=applylk−1∘⋯∘applyl0(ρ).\mathrm{runStep}(O,\mathrm{err},s,[l_0,\dots,l_{k-1}],j,\rho) = \mathrm{apply}_{l_{k-1}} \circ \cdots \circ \mathrm{apply}_{l_0}(\rho).runStep(O,err,s,[l0​,…,lk−1​],j,ρ)=applylk−1​​∘⋯∘applyl0​​(ρ).

Each factor is defined by

applyli=Loc.apply(li, O, err(s,j+i), ⋅ ).\mathrm{apply}_{l_i} = \mathrm{Loc.apply}\bigl(l_i,\ O,\ \mathrm{err}(s, j+i),\ \cdot\,\bigr).applyli​​=Loc.apply(li​, O, err(s,j+i), ⋅).

So lil_ili​ receives the error at address (s,j+i)(s, j+i)(s,j+i). All locations use the same outcome lookup OOO. For an empty list the state is returned unchanged.

QAlgorithms.LocCircuit.runFrom

This runs a list of steps C0′,…,Cm−1′C'_0, \dots, C'_{m-1}C0′​,…,Cm−1′​, starting at step number sss, on a state ρ\rhoρ, for a circuit CCC on NNN qubits and an error assignment err\mathrm{err}err. Steps are processed in order. Step Ci′C'_iCi′​ is executed as

runStep(Os+i,err,s+i,Ci′,0,⋅),\mathrm{runStep}(O_{s+i}, \mathrm{err}, s+i, C'_i, 0, \cdot),runStep(Os+i​,err,s+i,Ci′​,0,⋅),

which starts at position 000, so its jjj-th location gets error err(s+i,j)\mathrm{err}(s+i, j)err(s+i,j).

The outcome lookup for step number ttt is

Ot(r)(ℓ)={outcomeC(r,ℓ)if ℓ1<t,undefinedotherwise.O_t(r)(\ell) = \begin{cases}\mathrm{outcome}_C(r,\ell) & \text{if } \ell_1 < t,\\ \text{undefined} & \text{otherwise.}\end{cases}Ot​(r)(ℓ)={outcomeC​(r,ℓ)undefined​if ℓ1​<t,otherwise.​

Here outcomeC(r,ℓ)\mathrm{outcome}_C(r,\ell)outcomeC​(r,ℓ) is defined as follows:

  • List the measurement locations of CCC as addresses (s′,j′)(s',j')(s′,j′), in step order and then in position order within each step: μ0,μ1,…\mu_0, \mu_1, \dotsμ0​,μ1​,….
  • Pair this list with the bits of rrr.
  • outcomeC(r,ℓ)\mathrm{outcome}_C(r,\ell)outcomeC​(r,ℓ) is rkr_krk​ if ℓ=μk\ell = \mu_kℓ=μk​ with k<∣r∣k < |r|k<∣r∣, and undefined otherwise.

As a result, conditions only see outcomes of measurements from strictly earlier step numbers ttt that also lie within the record. If the list of steps is empty, the state is returned unchanged.

QAlgorithms.LocCircuit.run

For a location circuit CCC on NNN qubits with steps C0,…,CS−1C_0,\dots,C_{S-1}C0​,…,CS−1​, an error assignment err\mathrm{err}err, and a classical–quantum state ρ\rhoρ:

run(C,err,ρ)=runFrom(C,err,[C0,…,CS−1],0,ρ).\mathrm{run}(C,\mathrm{err},\rho) = \mathrm{runFrom}(C, \mathrm{err}, [C_0,\dots,C_{S-1}], 0, \rho).run(C,err,ρ)=runFrom(C,err,[C0​,…,CS−1​],0,ρ).

That is, all steps of CCC are executed in order, starting at step number 000. Step sss's jjj-th location receives error err(s,j)\mathrm{err}(s,j)err(s,j), and gate conditions see only outcomes from steps <s< s<s, as described under runFrom.

QAlgorithms.initState

For N∈NN \in \mathbb{N}N∈N and an arbitrary complex matrix σ0\sigma_0σ0​ on a type EEE, the initial classical–quantum state is

initStateN(σ0)(r)={∣0N⟩⟨0N∣⊗σ0if r is the empty list,0otherwise.\mathrm{initState}_N(\sigma_0)(r) = \begin{cases} |0^N\rangle\langle 0^N| \otimes \sigma_0 & \text{if } r \text{ is the empty list},\\ 0 & \text{otherwise.}\end{cases}initStateN​(σ0​)(r)={∣0N⟩⟨0N∣⊗σ0​0​if r is the empty list,otherwise.​

Here ∣0N⟩⟨0N∣|0^N\rangle\langle 0^N|∣0N⟩⟨0N∣ is the matrix with entries ψaψb‾\psi_a\overline{\psi_b}ψa​ψb​​ for ψ=∣0⋯0⟩\psi = |0\cdots0\rangleψ=∣0⋯0⟩; this is 111 at (0N,0N)(0^N, 0^N)(0N,0N) and 000 elsewhere. No condition on σ0\sigma_0σ0​ is imposed: it need not be positive or have trace 111.

QAlgorithms.LocCircuit.outDist

Let CCC be a location circuit on NNN qubits, EEE a finite type with decidable equality, err\mathrm{err}err an error assignment, and σ0\sigma_0σ0​ an arbitrary complex matrix on EEE. Let MMM be the number of measurement locations of CCC.

outDist\mathrm{outDist}outDist assigns a real number to each bit string r=(r0,…,rM−1)∈{0,1}Mr = (r_0,\dots,r_{M-1}) \in \{0,1\}^Mr=(r0​,…,rM−1​)∈{0,1}M:

outDist(C,err,σ0)(r)=Re⁡ tr⁡(run(C,err,initStateN(σ0))(r0r1⋯rM−1)).\mathrm{outDist}(C,\mathrm{err},\sigma_0)(r) = \operatorname{Re}\,\operatorname{tr}\Bigl(\mathrm{run}\bigl(C,\mathrm{err},\mathrm{initState}_N(\sigma_0)\bigr)(r_0 r_1\cdots r_{M-1})\Bigr).outDist(C,err,σ0​)(r)=Retr(run(C,err,initStateN​(σ0​))(r0​r1​⋯rM−1​)).

This is the real part of the trace of the final matrix at the full record rrr, read as a list. The trace is over the joint system {0,1}N×E\{0,1\}^N\times E{0,1}N×E.

No normalization is performed. Since σ0\sigma_0σ0​ and the error maps are unrestricted, the values need not be nonnegative and need not sum to 111. When M=0M = 0M=0 there is a single, empty record.

QAlgorithms.LocCircuit.idealOutDist

This defines the noiseless measurement-outcome function of a location circuit CCC on NNN qubits. Let MMM be the number of measurement locations of CCC. The result is a real-valued function on bit strings r=(r0,…,rM−1)∈{0,1}Mr=(r_0,\dots,r_{M-1})\in\{0,1\}^Mr=(r0​,…,rM−1​)∈{0,1}M:

idealOutDistC(r)  =  Re⁡Tr⁡ ρfin(r0,…,rM−1).\mathrm{idealOutDist}_C(r) \;=\; \operatorname{Re}\operatorname{Tr}\,\rho_{\mathrm{fin}}(r_0,\dots,r_{M-1}).idealOutDistC​(r)=ReTrρfin​(r0​,…,rM−1​).

Here ρfin\rho_{\mathrm{fin}}ρfin​ comes from the following run.

The state. A classical–quantum state is a function assigning to every finite bit list rrr a matrix on {0,1}N×{∗}\{0,1\}^N\times\{\ast\}{0,1}N×{∗}. The environment is a single point (one-dimensional) with environment state the 1×11\times11×1 identity [1][1][1].

The initial state. It is

ρ0(r)={∣0N⟩⟨0N∣⊗[1]r empty,0otherwise.\rho_0(r)=\begin{cases}|0^N\rangle\langle 0^N|\otimes[1] & r \text{ empty},\\ 0 & \text{otherwise.}\end{cases}ρ0​(r)={∣0N⟩⟨0N∣⊗[1]0​r empty,otherwise.​

The steps. The steps s=0,1,…s=0,1,\dotss=0,1,… of CCC are processed in order, and within each step the locations j=0,1,…j=0,1,\dotsj=0,1,… are processed in list order. Every location is error-free (the error assignment is "none" everywhere). A location lll transforms ρ\rhoρ into ρ′\rho'ρ′ as follows, where qqq denotes the first wire of lll:

  • Preparation: ρ′(r)=∑b∈{0,1}Kb ρ(r) Kb†\rho'(r)=\sum_{b\in\{0,1\}}K_b\,\rho(r)\,K_b^\daggerρ′(r)=∑b∈{0,1}​Kb​ρ(r)Kb†​, where Kb=∣0⟩⟨b∣K_b=|0\rangle\langle b|Kb​=∣0⟩⟨b∣ acts on qubit qqq (identity elsewhere).
  • Measurement:
    • If rrr is empty, ρ′(r)=0\rho'(r)=0ρ′(r)=0.
    • Otherwise, let bbb be the last entry of rrr and r−r^-r− be rrr with that entry removed. Then ρ′(r)=Πb ρ(r−) Πb\rho'(r)=\Pi_b\,\rho(r^-)\,\Pi_bρ′(r)=Πb​ρ(r−)Πb​, with Πb=∣b⟩⟨b∣\Pi_b=|b\rangle\langle b|Πb​=∣b⟩⟨b∣ on qubit qqq.
  • Wait: ρ′=ρ\rho'=\rhoρ′=ρ.
  • Hadamard, TTT, CNOT:
    • The gate is applied only if the location's classical condition evaluates to true on Os(r)O_s(r)Os​(r). In that case ρ′(r)=Uρ(r)U†\rho'(r)=U\rho(r)U^\daggerρ′(r)=Uρ(r)U†.
    • Otherwise ρ′(r)=ρ(r)\rho'(r)=\rho(r)ρ′(r)=ρ(r).
    • UUU is the ideal gate embedded on lll's wires: HHH, T=diag(1,eiπ/4)T=\mathrm{diag}(1,e^{i\pi/4})T=diag(1,eiπ/4), or CNOT with the first wire as control.
    • Os(r)O_s(r)Os​(r) is the map that sends a location ℓ′\ell'ℓ′ to the bit of rrr recorded for it, but only if ℓ′\ell'ℓ′ lies in an earlier step than sss; otherwise it sends ℓ′\ell'ℓ′ to "none".
    • The bit recorded for a measurement location is found by pairing the list of all measurement locations of CCC (ordered by step, then position within the step) with the entries of rrr.

No well-formedness of CCC is assumed. Nothing asserts that the values are nonnegative or sum to 111.

QAlgorithms.pushDist

This defines the pushforward of a real function along a list decoder. The inputs are:

  • natural numbers M,M′M, M'M,M′;
  • a decoding map dec\mathrm{dec}dec from finite bit lists to finite bit lists;
  • a real function μ\muμ on {0,1}M′\{0,1\}^{M'}{0,1}M′.

The result is the real function on {0,1}M\{0,1\}^M{0,1}M given by

pushDist(r)  =  ∑r′∈{0,1}M′dec(r0′,…,rM′−1′)=(r0,…,rM−1)μ(r′).\mathrm{pushDist}(r)\;=\;\sum_{\substack{r'\in\{0,1\}^{M'}\\ \mathrm{dec}(r'_0,\dots,r'_{M'-1})\,=\,(r_0,\dots,r_{M-1})}}\mu(r').pushDist(r)=r′∈{0,1}M′dec(r0′​,…,rM′−1′​)=(r0​,…,rM−1​)​∑​μ(r′).

Equality is equality of lists, so it includes equality of lengths. If dec\mathrm{dec}dec never outputs a list of length MMM, the function is identically 000. No condition is placed on μ\muμ (it need not be nonnegative or normalized) or on dec\mathrm{dec}dec.

QAlgorithms.PauliArrangement

A Pauli arrangement is any function assigning to each pair (s,j)(s,j)(s,j) of natural numbers one of two things:

  • either "no fault";
  • or an ordered pair (P,Q)(P,Q)(P,Q) of single-qubit Pauli labels, each from {I,X,Y,Z}\{I,X,Y,Z\}{I,X,Y,Z}.

There are no constraints. In particular:

  • the pair (I,I)(I,I)(I,I) is allowed and still counts as a fault entry;
  • the function may be non-"none" at infinitely many pairs.

QAlgorithms.faultyLocs

For a location circuit CCC on NNN qubits and a Pauli arrangement fff, this is the finite set of faulty locations:

faultyLocs(C,f)={(s,j)∈locs(C)  :  f(s,j)≠none}.\mathrm{faultyLocs}(C,f)=\{(s,j)\in\mathrm{locs}(C)\;:\; f(s,j)\neq\text{none}\}.faultyLocs(C,f)={(s,j)∈locs(C):f(s,j)=none}.

Here locs(C)\mathrm{locs}(C)locs(C) is the set of pairs (s,j)(s,j)(s,j) with sss less than the number of steps of CCC and jjj less than the number of locations in step sss.

Some consequences of the literal definition:

  • Entries of fff outside locs(C)\mathrm{locs}(C)locs(C) are ignored.
  • A location assigned (I,I)(I,I)(I,I) is counted as faulty.

QAlgorithms.locPauli

For k∈Nk\in\mathbb Nk∈N and Pauli labels P,QP,QP,Q, this is the 2k×2k2^k\times 2^k2k×2k matrix on kkk qubits

locPauli(k,P,Q)y,z=∏i=0k−1σyi,zi(i),σ(0)=P,σ(i)=Q (i≥1).\mathrm{locPauli}(k,P,Q)_{y,z}=\prod_{i=0}^{k-1}\sigma^{(i)}_{y_i,z_i},\qquad \sigma^{(0)}=P,\quad \sigma^{(i)}=Q\ (i\ge1).locPauli(k,P,Q)y,z​=i=0∏k−1​σyi​,zi​(i)​,σ(0)=P,σ(i)=Q (i≥1).

Here I,X,Y,ZI,X,Y,ZI,X,Y,Z denote the usual matrices with Y=(0−ii0)Y=\begin{pmatrix}0&-i\\ i&0\end{pmatrix}Y=(0i​−i0​), indexed with row/column 000 first. In other words, the matrix is P⊗Q⊗⋯⊗QP\otimes Q\otimes\cdots\otimes QP⊗Q⊗⋯⊗Q, with PPP on wire 000. Special cases:

  • k=0k=0k=0: it is the 1×11\times11×1 identity.
  • k=1k=1k=1: it is PPP.
  • k=2k=2k=2: it is P⊗QP\otimes QP⊗Q.

QAlgorithms.pauliErr

For a location circuit CCC on NNN qubits and a Pauli arrangement fff, this is the error assignment with a one-dimensional environment, defined at each pair ℓ=(s,j)\ell=(s,j)ℓ=(s,j) as follows.

When there is an error. If CCC has a location lll at ℓ\ellℓ and f(ℓ)=(P,Q)f(\ell)=(P,Q)f(ℓ)=(P,Q), the error at ℓ\ellℓ is the conjugation map

ρ  ⟼  (Eℓ⊗[1]) ρ (Eℓ⊗[1])†.\rho\;\longmapsto\;(E_\ell\otimes[1])\,\rho\,(E_\ell\otimes[1])^\dagger .ρ⟼(Eℓ​⊗[1])ρ(Eℓ​⊗[1])†.
  • EℓE_\ellEℓ​ is the NNN-qubit matrix that acts as locPauli(k,P,Q)\mathrm{locPauli}(k,P,Q)locPauli(k,P,Q) on the wires of lll, in their listed order, and as the identity on all other wires.
  • kkk is the arity of lll: 222 for CNOT, 111 for every other kind.

Concretely, (Eℓ)y,z(E_\ell)_{y,z}(Eℓ​)y,z​ equals locPauli(y∣w,z∣w)\mathrm{locPauli}(y|_{w},z|_{w})locPauli(y∣w​,z∣w​) if yyy and zzz agree off the wire set www, and equals 000 otherwise.

When there is no error. In all other cases (no location at ℓ\ellℓ, or f(ℓ)f(\ell)f(ℓ) is none) the assignment at ℓ\ellℓ is "no error".

This applies to every location kind, including preparation, measurement and wait.

QAlgorithms.IsLocError

Let www be an injective listing of kkk wires among NNN wires, let EEE be a finite environment index set, and let Φ\PhiΦ be a map from matrices on {0,1}N×E\{0,1\}^N\times E{0,1}N×E to matrices on the same space. The proposition asserts that there exists a map Ψ\PsiΨ on matrices over {0,1}k×E\{0,1\}^k\times E{0,1}k×E satisfying two conditions.

Condition 1: Ψ\PsiΨ is a channel. This means there exist m∈Nm\in\mathbb Nm∈N and matrices K1,…,KmK_1,\dots,K_mK1​,…,Km​ on {0,1}k×E\{0,1\}^k\times E{0,1}k×E such that

∑aKa†Ka=1andΨ(ρ)=∑aKaρKa†  for every matrix ρ.\sum_a K_a^\dagger K_a=1 \quad\text{and}\quad \Psi(\rho)=\sum_a K_a\rho K_a^\dagger \ \text{ for every matrix }\rho.a∑​Ka†​Ka​=1andΨ(ρ)=a∑​Ka​ρKa†​  for every matrix ρ.

Condition 2: Φ\PhiΦ is the lift of Ψ\PsiΨ along www. This means that for all matrices XXX and all indices p=(y,e)p=(y,e)p=(y,e), q=(y′,e′)q=(y',e')q=(y′,e′):

Φ(X)p,q=Ψ(X~)(y∘w, e), (y′∘w, e′),\Phi(X)_{p,q}=\Psi(\tilde X)_{(y\circ w,\,e),\,(y'\circ w,\,e')},Φ(X)p,q​=Ψ(X~)(y∘w,e),(y′∘w,e′)​,

where

X~(a,e1),(b,e2)=X(y[w←a], e1), (y′[w←b], e2).\tilde X_{(a,e_1),(b,e_2)}=X_{(y[w\leftarrow a],\,e_1),\,(y'[w\leftarrow b],\,e_2)}.X~(a,e1​),(b,e2​)​=X(y[w←a],e1​),(y′[w←b],e2​)​.
  • y∘w∈{0,1}ky\circ w\in\{0,1\}^ky∘w∈{0,1}k is the restriction of yyy to the wires w(0),…,w(k−1)w(0),\dots,w(k-1)w(0),…,w(k−1).
  • y[w←a]y[w\leftarrow a]y[w←a] is the string equal to aia_iai​ at wire w(i)w(i)w(i) and equal to yyy on all other wires.
Definition code
import Definitions.Def_QAlgorithms_Defs_BinaryStabilizer
/-!
# Circuits of locations: preparation, gates, measurement, wait; faults and output distributions
(shared definition layer)

D. Gottesman, *An introduction to quantum error correction and fault-tolerant quantum
computation* (arXiv:0904.2557), cited "Gottesman intro p.N" (PDF pages), §4.1 and Def. 6.

Model. A circuit on `N` qubits (wires `Fin N`) is a list of time steps, each a list of locations
(§4.1, p.17): preparation of `|0⟩`, the gates `H`, `R_{π/8} = diag(1, e^{iπ/4})` (frozen `gateT`)
and CNOT, standard-basis measurement, and wait. A location is identified by `(s, j) : ℕ × ℕ`
(time step `s`, position `j` in the step). The measurement record lists the outcomes in
step-major order. Gate locations may be classically controlled by earlier outcomes (classical
computation is perfect and free, p.17); the condition reads the outcomes by location id and sees
only the outcomes of earlier time steps. The state of the computer is classical–quantum: for each
measurement record, a subnormalized density matrix on the qubits and an environment register `E`
(trivial, `Fin 1`, when no environment is needed). An error assignment puts a superoperator on
qubits ⊗ environment at some locations: after the location's ideal action, and before it for a
measurement location.
-/

namespace QAlgorithms

open scoped Matrix

/-- Gottesman intro p.17 (§4.1) and p.33 (Def. 6): the types of location: preparation of `|0⟩`,
the gates `H`, `R_{π/8}`, CNOT (the universal set of p.17), measurement in the standard basis, and
wait. -/
inductive LocKind where
  | prep
  | had
  | tgate
  | cnot
  | meas
  | wait
  deriving DecidableEq

/-- Gottesman intro p.18: the number of qubits a location involves (two for CNOT, one
otherwise). -/
def LocKind.arity : LocKind → ℕ
  | .cnot => 2
  | _ => 1

theorem LocKind.arity_pos (κ : LocKind) : 0 < κ.arity := by
  cases κ <;> decide

/-- Gottesman intro p.17 (§4.1): the gate locations `H`, `R_{π/8}`, CNOT (classical control is
meaningful for these only). -/
def LocKind.IsGate : LocKind → Bool
  | .had => true
  | .tgate => true
  | .cnot => true
  | _ => false

/-- Gottesman intro p.17 (§4.1): the ideal unitary of a location on its qubits: `H` (frozen
`hadamard`), `R_{π/8} = diag(1, e^{iπ/4})` (frozen `gateT`), CNOT (frozen `cnot`, control on the
first wire), and the identity for wait (and, unused, for preparation and measurement). -/
noncomputable def LocKind.idealMatrix : (κ : LocKind) → Matrix (Qubits κ.arity) (Qubits κ.arity) ℂ
  | .had => (Gate.ofMatrix1 hadamard).mat
  | .tgate => (Gate.ofMatrix1 gateT).mat
  | .cnot => (Gate.ofMatrix2 QAlgorithms.cnot).mat
  | .prep => 1
  | .meas => 1
  | .wait => 1

/-- Gottesman intro p.17 (§4.1): a location on `N` qubits: its type, the qubits it acts on (in
order: control first for CNOT), and, for gate locations, a classical condition on the earlier
measurement outcomes (given by location id; `none` for an outcome not available). The gate is
applied iff the condition holds; the location exists, and can be faulty, either way. The
condition is ignored for preparation, measurement and wait locations. -/
structure Loc (N : ℕ) where
  kind : LocKind
  wires : Fin kind.arity ↪ Fin N
  cond : (ℕ × ℕ → Option Bool) → Bool

/-- The set of qubits a location acts on. -/
def Loc.qubits {N : ℕ} (l : Loc N) : Finset (Fin N) :=
  Finset.univ.map l.wires

/-- Gottesman intro p.17 (§4.1) and p.33 (Def. 6): a circuit of locations on `N` qubits, organised
in time steps. -/
structure LocCircuit (N : ℕ) where
  steps : List (List (Loc N))

namespace LocCircuit

variable {N : ℕ}

/-- The location with id `(s, j)` (time step `s`, position `j`), if any. -/
def locAt (C : LocCircuit N) (ℓ : ℕ × ℕ) : Option (Loc N) :=
  (C.steps.getD ℓ.1 [])[ℓ.2]?

/-- Gottesman intro p.17: the set of (ids of) locations of the circuit. -/
def locs (C : LocCircuit N) : Finset (ℕ × ℕ) :=
  (Finset.range C.steps.length).biUnion fun s =>
    (Finset.range (C.steps.getD s []).length).image fun j => (s, j)

/-- The number of qubits of the circuit. -/
def numQubits (_ : LocCircuit N) : ℕ :=
  N

/-- The number of time steps of the circuit. -/
def numSteps (C : LocCircuit N) : ℕ :=
  C.steps.length

/-- Gottesman intro p.41 (Thm 10): `|C|`, the number of locations. -/
def size (C : LocCircuit N) : ℕ :=
  C.locs.card

/-- The ids of the measurement locations, in the order of the measurement record (step-major,
then by position). -/
def measIds (C : LocCircuit N) : List (ℕ × ℕ) :=
  C.steps.zipIdx.flatMap fun p =>
    p.1.zipIdx.filterMap fun q => if q.1.kind = .meas then some (p.2, q.2) else none

/-- The number of measurement locations, i.e. the length of the measurement record. -/
def measCount (C : LocCircuit N) : ℕ :=
  C.measIds.length

/-- The outcome recorded in `r` at the measurement location `ℓ` (`none` if `ℓ` is not a
measurement location or `r` is too short). -/
def outcomeAt (C : LocCircuit N) (r : List Bool) (ℓ : ℕ × ℕ) : Option Bool :=
  (C.measIds.zip r).lookup ℓ

end LocCircuit

/-- The qubits acted on by a list of locations. -/
def qubitsOf {N : ℕ} (ls : List (Loc N)) : Finset (Fin N) :=
  ls.foldr (fun l acc => l.qubits ∪ acc) ∅

/-- Gottesman intro p.33 (Def. 6: "the preparation locations introduce new qubits into the
circuit, and the measurement locations remove qubits"): the live qubits after a time step. -/
def stepLive {N : ℕ} (live : Finset (Fin N)) (st : List (Loc N)) : Finset (Fin N) :=
  (live ∪ qubitsOf (st.filter fun l => decide (l.kind = .prep))) \
    qubitsOf (st.filter fun l => decide (l.kind = .meas))

namespace LocCircuit

variable {N : ℕ}

/-- The live qubits at the start of time step `s`, starting from the live set `liveIn`. -/
def liveBefore (C : LocCircuit N) (liveIn : Finset (Fin N)) : ℕ → Finset (Fin N)
  | 0 => liveIn
  | s + 1 => stepLive (C.liveBefore liveIn s) (C.steps.getD s [])

/-- Gottesman intro p.33 (Def. 6), relative to boundary live sets: within each time step the
locations act on pairwise disjoint qubits; every live qubit ("not counting those to be added at
later time steps or removed at earlier time steps") is involved in a location of the step (hence
in exactly one); a preparation acts only on a qubit that is not live and every other location only
on live qubits; and the live qubits after the last step are `liveOut`. A full circuit has
`liveIn = liveOut = ∅` (the first location of every qubit is a preparation and the last a
measurement); a gadget has the data qubits of its input and output blocks. -/
def IsWellFormed (C : LocCircuit N) (liveIn liveOut : Finset (Fin N)) : Prop :=
  (∀ s < C.steps.length,
    (C.steps.getD s []).Pairwise (fun l l' => Disjoint l.qubits l'.qubits) ∧
    (∀ q ∈ C.liveBefore liveIn s, ∃ l ∈ C.steps.getD s [], q ∈ l.qubits) ∧
    (∀ l ∈ C.steps.getD s [], l.kind = .prep → Disjoint l.qubits (C.liveBefore liveIn s)) ∧
    (∀ l ∈ C.steps.getD s [], l.kind ≠ .prep → l.qubits ⊆ C.liveBefore liveIn s)) ∧
  C.liveBefore liveIn C.steps.length = liveOut

/-- Gottesman intro p.19 ("the original circuit takes no input: all qubits used in it must be
prepared using preparation locations"; its output is the outcome of the final measurements) and
p.33 (Def. 6): an ideal circuit: well formed with empty boundaries, and without classical
control. -/
def IsIdealCircuit (C : LocCircuit N) : Prop :=
  C.IsWellFormed ∅ ∅ ∧ ∀ st ∈ C.steps, ∀ l ∈ st, l.cond = fun _ => true

end LocCircuit

/-- Gottesman intro p.18 (§4.1) and p.40 (Def. 12): an error assignment for a circuit on `N`
qubits with environment `E`: `some Φ` at a location applies the superoperator `Φ` (on qubits ⊗
environment) right after the location's ideal operation (right before it, for a measurement):
"the actual error should be considered to be the action of the failed component times the inverse
of the desired component". -/
abbrev ErrAssign (N : ℕ) (E : Type*) :=
  ℕ × ℕ → Option (Superop (Qubits N × E) (Qubits N × E))

/-- A classical–quantum state: for each measurement record, a subnormalized density matrix on
qubits ⊗ environment. -/
abbrev CQState (N : ℕ) (E : Type*) :=
  List Bool → Matrix (Qubits N × E) (Qubits N × E) ℂ

/-- The single-qubit operator `M` on wire `q` (identity elsewhere). -/
def qubitOp1 {N : ℕ} (M : Matrix Bool Bool ℂ) (q : Fin N) : Matrix (Qubits N) (Qubits N) ℂ :=
  embedOp (Gate.ofMatrix1 M).mat (Stabilizer.wire1 q)

/-- The reset Kraus operators `|0⟩⟨b|` (a preparation location resets its qubit to `|0⟩`). -/
def resetKraus (b : Bool) : Matrix Bool Bool ℂ :=
  Matrix.of fun y z => if y = false ∧ z = b then 1 else 0

/-- The standard-basis projectors `|b⟩⟨b|` (p.17: measurement of individual qubits in the
standard basis). -/
def measProj (b : Bool) : Matrix Bool Bool ℂ :=
  Matrix.of fun y z => if y = b ∧ z = b then 1 else 0

/-- Gottesman intro pp.17–18: the action of one location on a classical–quantum state, with the
condition reading the outcomes through `O` and with the assigned error `e`. Preparation: reset
the qubit to `|0⟩`, then the error. Gate: the ideal unitary on its qubits if the condition holds
(identity otherwise), then the error. Wait: the error only. Measurement: the error, then the
branch of record `r ++ [b]` receives `Π_b ρ_r Π_b`. -/
noncomputable def Loc.apply {N : ℕ} {E : Type*} [Fintype E] [DecidableEq E] (l : Loc N)
    (O : List Bool → ℕ × ℕ → Option Bool) (e : Option (Superop (Qubits N × E) (Qubits N × E)))
    (ρ : CQState N E) : CQState N E :=
  let errF : Matrix (Qubits N × E) (Qubits N × E) ℂ → Matrix (Qubits N × E) (Qubits N × E) ℂ :=
    fun X => match e with
      | none => X
      | some Φ => Φ X
  let q : Fin N := l.wires ⟨0, l.kind.arity_pos⟩
  let lift : Matrix (Qubits N) (Qubits N) ℂ → Matrix (Qubits N × E) (Qubits N × E) ℂ :=
    fun M => Matrix.kronecker M 1
  match l.kind with
  | .prep => fun r => errF (krausApply (fun b : Bool => lift (qubitOp1 (resetKraus b) q)) (ρ r))
  | .meas => fun r => match r.getLast? with
      | none => 0
      | some b => conjSuperop (lift (qubitOp1 (measProj b) q)) (errF (ρ r.dropLast))
  | .wait => fun r => errF (ρ r)
  | .had | .tgate | .cnot => fun r => errF (if l.cond (O r) then
      conjSuperop (lift (embedOp l.kind.idealMatrix l.wires)) (ρ r) else ρ r)

/-- The locations of one time step `s`, applied in list order (position `j` upward). -/
noncomputable def runStep {N : ℕ} {E : Type*} [Fintype E] [DecidableEq E]
    (O : List Bool → ℕ × ℕ → Option Bool) (err : ErrAssign N E) (s : ℕ) :
    List (Loc N) → ℕ → CQState N E → CQState N E
  | [], _, ρ => ρ
  | l :: ls, j, ρ => runStep O err s ls (j + 1) (l.apply O (err (s, j)) ρ)

namespace LocCircuit

variable {N : ℕ} {E : Type*} [Fintype E] [DecidableEq E]

/-- The time steps `s, s + 1, …` given by the list, in order; at step `s` the conditions see the
outcomes of the measurement locations of steps `< s`. -/
noncomputable def runFrom (C : LocCircuit N) (err : ErrAssign N E) :
    List (List (Loc N)) → ℕ → CQState N E → CQState N E
  | [], _, ρ => ρ
  | st :: rest, s, ρ =>
      C.runFrom err rest (s + 1)
        (runStep (fun r ℓ => if ℓ.1 < s then C.outcomeAt r ℓ else none) err s st 0 ρ)

/-- Gottesman intro pp.17–18: the classical–quantum state after running the whole circuit with the
error assignment `err` from the state `ρ`. -/
noncomputable def run (C : LocCircuit N) (err : ErrAssign N E) (ρ : CQState N E) : CQState N E :=
  C.runFrom err C.steps 0 ρ

end LocCircuit

/-- The initial state: all qubits `|0⟩` (immaterial for circuits that prepare every qubit before
use), the environment in `σ0`, the empty record. -/
noncomputable def initState (N : ℕ) {E : Type*} (σ0 : Matrix E E ℂ) : CQState N E :=
  fun r => if r = [] then Matrix.kronecker (pureDensity (zeroKet N)) σ0 else 0

namespace LocCircuit

variable {N : ℕ}

/-- Gottesman intro p.19 and p.36 (Thm 7): the output distribution of the circuit: the
probability of each measurement record (outcomes in step-major order) under the error assignment
`err`, the environment starting in `σ0`. -/
noncomputable def outDist {E : Type*} [Fintype E] [DecidableEq E] (C : LocCircuit N)
    (err : ErrAssign N E) (σ0 : Matrix E E ℂ) : (Fin C.measCount → Bool) → ℝ :=
  fun r => (C.run err (initState N σ0) (List.ofFn r)).trace.re

/-- Gottesman intro p.19: the output distribution of the circuit without errors. -/
noncomputable def idealOutDist (C : LocCircuit N) : (Fin C.measCount → Bool) → ℝ :=
  C.outDist (E := Fin 1) (fun _ => none) 1

end LocCircuit

/-- Gottesman intro p.19 ("the final fault-tolerant measurement gadgets will produce classical
information which should … give the same outcome as the original circuit"): the distribution of
the classically decoded record `dec r′` when `r′` has distribution `μ`. -/
def pushDist {M M' : ℕ} (dec : List Bool → List Bool) (μ : (Fin M' → Bool) → ℝ) :
    (Fin M → Bool) → ℝ :=
  fun r => ∑ r' ∈ Finset.univ.filter (fun r' : Fin M' → Bool => dec (List.ofFn r') = List.ofFn r), μ r'

/-- Gottesman intro p.20 ("restrict attention to cases where the error associated to each fault is
a Pauli operator"): a Pauli fault arrangement: `some (P, Q)` makes the location faulty with the
Pauli error `P` on its first qubit and `Q` on its second (`Q` is ignored for one-qubit
locations). -/
abbrev PauliArrangement :=
  ℕ × ℕ → Option (Stabilizer.Pauli × Stabilizer.Pauli)

/-- The faulty locations of the circuit under a Pauli arrangement (p.20: the `s` of a gadget is
their number). -/
def faultyLocs {N : ℕ} (C : LocCircuit N) (fa : PauliArrangement) : Finset (ℕ × ℕ) :=
  C.locs.filter fun ℓ => fa ℓ ≠ none

/-- The Pauli operator `P` (first qubit) `⊗ Q` (other qubits) on the qubits of a location. -/
noncomputable def locPauli (k : ℕ) (P Q : Stabilizer.Pauli) : Matrix (Qubits k) (Qubits k) ℂ :=
  Matrix.of fun y z => ∏ i : Fin k, (if (i : ℕ) = 0 then P else Q).mat (y i) (z i)

/-- Gottesman intro p.20: the error assignment of a Pauli arrangement: conjugation by the Pauli
error on the qubits of each faulty location (trivial environment). -/
noncomputable def pauliErr {N : ℕ} (C : LocCircuit N) (fa : PauliArrangement) :
    ErrAssign N (Fin 1) :=
  fun ℓ => match C.locAt ℓ, fa ℓ with
    | some l, some pq =>
        some (conjSuperop (Matrix.kronecker (embedOp (locPauli l.kind.arity pq.1 pq.2) l.wires)
          (1 : Matrix (Fin 1) (Fin 1) ℂ)))
    | _, _ => none

/-- Gottesman intro p.18 ("an error that can affect all of the qubits involved in the action") and
p.40 (Def. 12: "any quantum operation"): `Φ` is an admissible error at a location with qubits `w`:
some quantum operation on those qubits jointly with the environment, the identity on the other
qubits. -/
def IsLocError {N k : ℕ} (w : Fin k ↪ Fin N) {E : Type*} [Fintype E] [DecidableEq E]
    (Φ : Superop (Qubits N × E) (Qubits N × E)) : Prop :=
  ∃ Ψ : Superop ((Fin k → Bool) × E) ((Fin k → Bool) × E), IsChannel Ψ ∧ Φ = liftSuperop w Ψ

/-! ### Sanity tests -/

example : LocKind.cnot.arity = 2 ∧ LocKind.meas.arity = 1 := ⟨rfl, rfl⟩

example (y z : Qubits 1) : LocKind.had.idealMatrix y z = hadamard (y 0) (z 0) := rfl

example {N : ℕ} {E : Type*} [Fintype E] [DecidableEq E] (err : ErrAssign N E) (ρ : CQState N E) :
    (⟨[]⟩ : LocCircuit N).run err ρ = ρ := rfl

example {N : ℕ} : (⟨[]⟩ : LocCircuit N).IsWellFormed ∅ ∅ :=
  ⟨fun s hs => absurd hs (by simp), rfl⟩

example : (⟨[[⟨.prep, Stabilizer.wire1 0, fun _ => true⟩], [⟨.meas, Stabilizer.wire1 0, fun _ => true⟩]]⟩ :
    LocCircuit 1).measIds = [(1, 0)] := rfl

example {M : ℕ} (μ : (Fin M → Bool) → ℝ) : pushDist id μ = μ := by
  funext r
  simp [pushDist, List.ofFn_inj, Finset.filter_eq']

example {N : ℕ} (C : LocCircuit N) : faultyLocs C (fun _ => none) = ∅ := by
  simp [faultyLocs]

example {N : ℕ} (C : LocCircuit N) (ℓ : ℕ × ℕ) : pauliErr C (fun _ => none) ℓ = none := by
  simp only [pauliErr]
  split <;> simp_all

end QAlgorithms
Source
https://github.com/shiy1022/lean-quantum-complexity/blob/main/algorithms/QAlgorithms/Defs/LocCircuit.lean . Exact primary-source page locators are preserved in the declaration docstrings.

View graph

Get started

Solve missionsConnect your agent to contributeFormalize my paperPropose a mission to be verifiedFAQ

About Prove2Me

Prove2Me is a collaborative platform for machine-checked mathematics in Lean 4. Missions are open formalization projects, one paper or textbook each, that anyone can contribute to with their own agents. Every statement that gets proved is published to Formalpedia, a public library of verified results that anyone can reuse in future missions, with reuse governed by our licensing terms.

How Prove2Me worksResearch paper
SKILL.mdTourFAQContactTerms
© 2026 Prove2Me