def test_ccnot_circuit_evolve() -> None: rho0 = qf.random_state(3).asdensity() gate = qf.CCNot(0, 1, 2) circ = qf.Circuit(qf.translate_ccnot_to_cnot(gate)) rho1 = gate.evolve(rho0) rho2 = circ.evolve(rho0) assert qf.densities_close(rho1, rho2)
def test_evolve() -> None: rho0 = qf.random_state(3).asdensity() rho1 = qf.CCNot(0, 1, 2).evolve(rho0) dag = qf.DAGCircuit(qf.translate_ccnot_to_cnot(qf.CCNot(0, 1, 2))) rho2 = dag.evolve(rho0) assert qf.densities_close(rho1, rho2)
def identities(): """Return a list of circuit identities, each consisting of a name, and two equivalent Circuits.""" circuit_identities = [] # Pick random parameter # theta = np.pi * np.random.uniform() # t = np.random.uniform() theta = syms["theta"] t = syms["t"] tx = syms["tx"] ty = syms["ty"] tz = syms["tz"] # Single qubit gate identities name = "Hadamard is own inverse" circ0 = Circuit([H(0), H(0)]) circ1 = Circuit([I(0)]) circuit_identities.append([name, circ0, circ1]) name = "Hadamards convert X to Z" circ0 = Circuit([H(0), X(0), H(0)]) circ1 = Circuit([Z(0)]) circuit_identities.append([name, circ0, circ1]) name = "Hadamards convert Z to X" circ0 = Circuit([H(0), Z(0), H(0)]) circ1 = Circuit([X(0)]) circuit_identities.append([name, circ0, circ1]) name = "S sandwich converts X to Y" circ0 = Circuit([S(0).H, X(0), S(0)]) circ1 = Circuit([Y(0)]) circuit_identities.append([name, circ0, circ1]) name = "S sandwich converts Y to X" circ0 = Circuit([S(0), Y(0), S(0).H]) circ1 = Circuit([X(0)]) circuit_identities.append([name, circ0, circ1]) name = "Hadamards convert Rz to Rx" circ0 = Circuit([H(0), Rz(theta, 0), H(0)]) circ1 = Circuit([Rx(theta, 0)]) circuit_identities.append([name, circ0, circ1]) # Simplified from Cirq's "_potential_cross_whole_w" # "_potential_cross_partial_w" is essentially same identity # X and ZPow commute name = "X-sandwich inverts ZPow" circ0 = Circuit([X(0), ZPow(t, 0), X(0)]) circ1 = Circuit([ZPow(-t, 0)]) circuit_identities.append([name, circ0, circ1]) # Same relation as previous name = "Commute X past ZPow" circ0 = Circuit([X(0), ZPow(t, 0)]) circ1 = Circuit([ZPow(-t, 0), X(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute X past YPow" circ0 = Circuit([X(0), YPow(t, 0)]) circ1 = Circuit([YPow(-t, 0), X(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute V past ZPow" circ0 = Circuit([V(0), ZPow(t, 0)]) circ1 = Circuit([YPow(t, 0), V(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute V past YPow" circ0 = Circuit([V(0), YPow(t, 0)]) circ1 = Circuit([ZPow(-t, 0), V(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute V.H past ZPow" circ0 = Circuit([V(0).H, ZPow(t, 0)]) circ1 = Circuit([YPow(-t, 0), V(0).H]) circuit_identities.append([name, circ0, circ1]) name = "Commute V.H past YPow" circ0 = Circuit([V(0).H, YPow(t, 0)]) circ1 = Circuit([ZPow(t, 0), V(0).H]) circuit_identities.append([name, circ0, circ1]) name = "Couumte S.H past XPow" circ0 = Circuit([S(0).H, XPow(t, 0)]) circ1 = Circuit([YPow(t, 0), S(0).H]) circuit_identities.append([name, circ0, circ1]) name = "Commute S past XPow" circ0 = Circuit([S(0), XPow(t, 0)]) circ1 = Circuit([YPow(-t, 0), S(0)]) circuit_identities.append([name, circ0, circ1]) name = "Y to ZX" circ0 = Circuit([Y(0)]) circ1 = Circuit([Z(0), X(0)]) circuit_identities.append([name, circ0, circ1]) # ZYZ Decompositions name = "Hadamard ZYZ decomposition" circ0 = Circuit([H(0)]) circ1 = Circuit([Z(0), Y(0)**0.5]) circuit_identities.append([name, circ0, circ1]) # CNot identities name = "CZ to CNot" circ0 = Circuit([CZ(0, 1)]) circ1 = Circuit([H(1), CNot(0, 1), H(1)]) circuit_identities.append([name, circ0, circ1]) name = "CZ to CNot (2)" circ0 = Circuit([CZ(0, 1)]) circ1 = Circuit([YPow(+0.5, 1), CNot(0, 1), YPow(-0.5, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Swap to 3 CNots" circ0 = Circuit([Swap(0, 1)]) circ1 = Circuit([CNot(0, 1), CNot(1, 0), CNot(0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Swap to 3 CZs" circ0 = Circuit([Swap(0, 1)]) circ1 = Circuit( [CZ(0, 1), H(0), H(1), CZ(1, 0), H(0), H(1), CZ(0, 1), H(0), H(1)]) circuit_identities.append([name, circ0, circ1]) name = "ISwap decomposition to Swap and CNot" circ0 = Circuit([ISwap(0, 1)]) circ1 = Circuit([Swap(0, 1), H(1), CNot(0, 1), H(1), S(0), S(1)]) circuit_identities.append([name, circ0, circ1]) name = "ISwap decomposition to Swap and CZ" # This makes it clear why you can commute Rz's across ISwap circ0 = Circuit([ISwap(0, 1)]) circ1 = Circuit([Swap(0, 1), CZ(0, 1), S(0), S(1)]) circuit_identities.append([name, circ0, circ1]) # http://info.phys.unm.edu/~caves/courses/qinfo-f14/lectures/lectures21-23.pdf name = "CNot sandwich with X on control" circ0 = Circuit([CNot(0, 1), X(0), CNot(0, 1)]) circ1 = Circuit([X(0), X(1)]) circuit_identities.append([name, circ0, circ1]) # http://info.phys.unm.edu/~caves/courses/qinfo-f14/lectures/lectures21-23.pdf name = "CNot sandwich with Z on target" circ0 = Circuit([CNot(0, 1), Z(1), CNot(0, 1)]) circ1 = Circuit([Z(0), Z(1)]) circuit_identities.append([name, circ0, circ1]) name = "DCNot (Double-CNot) to iSwap" circ0 = Circuit([CNot(0, 1), CNot(1, 0)]) circ1 = Circuit([H(0), S(0).H, S(1).H, ISwap(0, 1), H(1)]) circuit_identities.append([name, circ0, circ1]) # Commuting single qubit gates across 2 qubit games name = "Commute X on CNot target" circ0 = Circuit([X(1), CNot(0, 1)]) circ1 = Circuit([CNot(0, 1), X(1)]) circuit_identities.append([name, circ0, circ1]) name = "Commute X on CNot control" circ0 = Circuit([X(0), CNot(0, 1)]) circ1 = Circuit([CNot(0, 1), X(0), X(1)]) circuit_identities.append([name, circ0, circ1]) name = "Commute Z on CNot target" circ0 = Circuit([Z(1), CNot(0, 1)]) circ1 = Circuit([CNot(0, 1), Z(0), Z(1)]) circuit_identities.append([name, circ0, circ1]) name = "Commute Z on CNot control" circ0 = Circuit([Z(0), CNot(0, 1)]) circ1 = Circuit([CNot(0, 1), Z(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute X with CZ" circ0 = Circuit([X(0), CZ(0, 1)]) circ1 = Circuit([CZ(0, 1), X(0), Z(1)]) circuit_identities.append([name, circ0, circ1]) name = "Commute X with XX" circ0 = Circuit([X(0), XX(t, 0, 1)]) circ1 = Circuit([ XX(t, 0, 1), X(0), ]) circuit_identities.append([name, circ0, circ1]) name = "Commute X with YY" circ0 = Circuit([X(0), YY(t, 0, 1)]) circ1 = Circuit([ YY(-t, 0, 1), X(0), ]) circuit_identities.append([name, circ0, circ1]) name = "Commute X with ZZ" circ0 = Circuit([X(0), ZZ(t, 0, 1)]) circ1 = Circuit([ ZZ(-t, 0, 1), X(0), ]) circuit_identities.append([name, circ0, circ1]) name = "Commute X with Canonical" circ0 = Circuit([X(0), Can(tx, ty, tz, 0, 1)]) circ1 = Circuit([Can(tx, -ty, -tz, 0, 1), X(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute Y with Canonical" circ0 = Circuit([Y(0), Can(tx, ty, tz, 0, 1)]) circ1 = Circuit([Can(-tx, ty, -tz, 0, 1), Y(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute Z with Canonical" circ0 = Circuit([Z(0), Can(tx, ty, tz, 0, 1)]) circ1 = Circuit([Can(-tx, -ty, tz, 0, 1), Z(0)]) circuit_identities.append([name, circ0, circ1]) name = "Commute Sqrt(X) with Canonical switches ty and tz arguments" circ0 = Circuit([V(0), V(1), Can(tx, ty, tz, 0, 1)]) circ1 = Circuit([Can(tx, tz, ty, 0, 1), V(0), V(1)]) circuit_identities.append([name, circ0, circ1]) # Canonical decompositions name = "Canonical gates: CZ to ZZ" circ0 = Circuit([CZ(0, 1), S(0), S(1)]) circ1 = Circuit([ZZ(0.5, 0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Canonical gates: XX to ZZ" circ0 = Circuit([H(0), H(1), XX(0.5, 0, 1), H(0), H(1)]) circ1 = Circuit([ZZ(0.5, 0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Canonical gates: CNot to XX" circ0 = Circuit([CNot(0, 1)]) circ1 = Circuit([H(0), XX(0.5, 0, 1), H(0), H(1), S(0).H, S(1).H, H(1)]) circuit_identities.append([name, circ0, circ1]) name = "Canonical gates: Swap to Canonical" circ0 = Circuit([Swap(0, 1)]) circ1 = Circuit([Can(0.5, 0.5, 0.5, 0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "ISwap to Canonical" circ0 = Circuit([ISwap(0, 1)]) circ1 = Circuit([Can(-0.5, -0.5, 0.0, 0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "ISwap to Canonical in Weyl chamber" circ0 = Circuit([ISwap(0, 1)]) circ1 = Circuit([X(0), Can(0.5, 0.5, 0.0, 0, 1), X(1)]) circuit_identities.append([name, circ0, circ1]) name = "ISwap conjugate to ISwap" circ0 = Circuit([ISwap(0, 1).H]) circ1 = Circuit([X(0), ISwap(0, 1), X(1)]) circuit_identities.append([name, circ0, circ1]) name = "DCNot to Canonical" circ0 = Circuit([CNot(0, 1), CNot(1, 0)]) circ1 = Circuit( [H(0), S(0).H, S(1).H, X(0), Can(0.5, 0.5, 0.0, 0, 1), X(1), H(1)]) circuit_identities.append([name, circ0, circ1]) # Multi-qubit circuits name = "CNot controls commute" circ0 = Circuit([CNot(1, 0), CNot(1, 2)]) circ1 = Circuit([CNot(1, 2), CNot(1, 0)]) circuit_identities.append([name, circ0, circ1]) name = "CNot targets commute" circ0 = Circuit([CNot(0, 1), CNot(2, 1)]) circ1 = Circuit([CNot(2, 1), CNot(0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Commutation of CNot target/control" circ0 = Circuit([CNot(0, 1), CNot(1, 2)]) circ1 = Circuit([CNot(1, 2), CNot(0, 2), CNot(0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Indirect CNot and 4 CNotS with intermediate qubit" circ0 = Circuit([CNot(0, 2), I(1)]) circ1 = Circuit([CNot(0, 1), CNot(1, 2), CNot(0, 1), CNot(1, 2)]) circuit_identities.append([name, circ0, circ1]) name = "CZs with shared shared qubit commute" circ0 = Circuit([CZ(0, 1), CZ(1, 2)]) circ1 = Circuit([CZ(1, 2), CZ(0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "Z's shift ZZ by one unit" circ0 = Circuit([ZZ(t, 0, 1)]) circ1 = Circuit([ZZ(t + 1, 0, 1), Z(0), Z(1)]) circuit_identities.append([name, circ0, circ1]) name = "Z's shift ZZ by one unit" circ0 = Circuit([XX(t, 0, 1)]) circ1 = Circuit([XX(t + 1, 0, 1), X(0), X(1)]) circuit_identities.append([name, circ0, circ1]) # Parametric circuits name = "ZZ to CNots" # 1108.4318 circ0 = Circuit([ZZ(theta / pi, 0, 1)]) circ1 = Circuit([CNot(0, 1), Rz(theta, 1), CNot(0, 1)]) circuit_identities.append([name, circ0, circ1]) name = "XX to CNots" # 1108.4318 circ0 = Circuit([XX(theta / pi, 0, 1)]) circ1 = Circuit( [H(0), H(1), CNot(0, 1), Rz(theta, 1), CNot(0, 1), H(0), H(1)]) circuit_identities.append([name, circ0, circ1]) name = "XX to CNots (2)" circ0 = Circuit([XX(theta / pi, 0, 1)]) circ1 = Circuit([ Y(0)**0.5, Y(1)**0.5, CNot(0, 1), Rz(theta, 1), CNot(0, 1), Y(0)**-0.5, Y(1)**-0.5, ]) circuit_identities.append([name, circ0, circ1]) name = "YY to CNots" circ0 = Circuit([YY(theta / pi, 0, 1)]) circ1 = Circuit([ X(0)**0.5, X(1)**0.5, CNot(0, 1), Rz(theta, 1), CNot(0, 1), X(0)**-0.5, X(1)**-0.5, ]) circuit_identities.append([name, circ0, circ1]) def cphase_to_zz(gate: CPhase): t = -gate.param("theta") / (2 * pi) q0, q1 = gate.qubits circ = Circuit([ZZ(t, q0, q1), ZPow(-t, q0), ZPow(-t, q1)]) return circ def cphase00_to_zz(gate: CPhase00): t = -gate.param("theta") / (2 * pi) q0, q1 = gate.qubits circ = Circuit([ X(0), X(1), ZZ(t, q0, q1), ZPow(-t, q0), ZPow(-t, q1), X(0), X(1) ]) return circ def cphase01_to_zz(gate: CPhase00): t = -gate.param("theta") / (2 * pi) q0, q1 = gate.qubits circ = Circuit([X(0), ZZ(t, q0, q1), ZPow(-t, q0), ZPow(-t, q1), X(0)]) return circ def cphase10_to_zz(gate: CPhase00): t = -gate.param("theta") / (2 * pi) q0, q1 = gate.qubits circ = Circuit([X(1), ZZ(t, q0, q1), ZPow(-t, q0), ZPow(-t, q1), X(1)]) return circ name = "CPhase to ZZ" gate = CPhase(theta, 0, 1) circ0 = Circuit([gate]) circ1 = cphase_to_zz(gate) circuit_identities.append([name, circ0, circ1]) name = "CPhase00 to ZZ" gate = CPhase00(theta, 0, 1) circ0 = Circuit([gate]) circ1 = cphase00_to_zz(gate) circuit_identities.append([name, circ0, circ1]) name = "CPhase01 to ZZ" gate = CPhase01(theta, 0, 1) circ0 = Circuit([gate]) circ1 = cphase01_to_zz(gate) circuit_identities.append([name, circ0, circ1]) name = "CPhase10 to ZZ" gate = CPhase10(theta, 0, 1) circ0 = Circuit([gate]) circ1 = cphase10_to_zz(gate) circuit_identities.append([name, circ0, circ1]) name = "PSwap to Canonical" gate = PSwap(theta, 0, 1) circ0 = Circuit([gate]) circ1 = Circuit() circ1 += YPow(1, 0) circ1 += Can(0.5, 0.5, 0.5 - theta / pi, 0, 1) circ1 += YPow(1, 1) circuit_identities.append([name, circ0, circ1]) # Three qubit gates name = "Toffoli gate CNot decomposition" circ0 = Circuit([CCNot(0, 1, 2)]) circ1 = translate_ccnot_to_cnot(CCNot(0, 1, 2)) circuit_identities.append([name, circ0, circ1]) name = "CCZ to CNots, respecting adjacency" gate = CCZ(0, 1, 2) circ0 = Circuit([gate]) circ1 = Circuit(translate_ccz_to_adjacent_cnot(gate)) circuit_identities.append([name, circ0, circ1]) name = "CCNot to CCZ" gate = CCNot(0, 1, 2) circ0 = Circuit([gate]) circ1 = Circuit(translate_ccnot_to_ccz(gate)) circuit_identities.append([name, circ0, circ1]) name = "CSwap to CCNot" gate = CSwap(0, 1, 2) circ0 = Circuit([gate]) circ1 = Circuit(translate_cswap_to_ccnot(gate)) circuit_identities.append([name, circ0, circ1]) name = "CSwap to CNot" gate = CSwap(0, 1, 2) circ0 = Circuit([gate]) circ1 = Circuit(translate_cswap_to_cnot(gate)) circuit_identities.append([name, circ0, circ1]) name = "CSwap to CNot (control between targets)" gate = CSwap(1, 0, 2) circ0 = Circuit([gate]) circ1 = Circuit(translate_cswap_inside_to_cnot(gate)) circuit_identities.append([name, circ0, circ1]) name = "CH to Clifford+T" gate = CH(0, 1) circ0 = Circuit([gate]) circ1 = Circuit(translate_ch_to_cpt(gate)) circuit_identities.append([name, circ0, circ1]) name = "CV to Clifford+T" gate = CV(0, 1) circ0 = Circuit([gate]) circ1 = Circuit(translate_cv_to_cpt(gate)) circuit_identities.append([name, circ0, circ1]) name = "CV_H to Clifford+T" gate = CV_H(0, 1) circ0 = Circuit([gate]) circ1 = Circuit(translate_cvh_to_cpt(gate)) circuit_identities.append([name, circ0, circ1]) # from sympy import Symbol, pi name = "CNotPow to ZZ" gate = CNotPow(t, 0, 1) circ0 = Circuit([gate]) circ1 = Circuit(translate_cnotpow_to_zz(gate)) circuit_identities.append([name, circ0, circ1]) # name = "PISwap to XY" # gate = PISwap(theta, 0, 1) # circ0 = Circuit([gate]) # circ1 = Circuit(translate_piswap_to_xy(gate)) # circuit_identities.append([name, circ0, circ1]) name = "Powers of iSwap to CNot sandwich" gate = ISwap(0, 1)**t trans = [translate_xy_to_can, translate_can_to_cnot] circ0 = Circuit([gate]) circ1 = circuit_translate(circ0, trans) circuit_identities.append([name, circ0, circ1]) name = "Commute ZPow past multiple CNots" gate = ZPow(t, 1) circ0 = Circuit([gate, CNot(0, 1), CNot(1, 2), CNot(0, 1)]) circ1 = Circuit([CNot(0, 1), CNot(1, 2), CNot(0, 1), gate]) circuit_identities.append([name, circ0, circ1]) return circuit_identities