def test_controlled_op_to_gates_omits_negligible_global_phase(): qc = ops.QubitId() qt = ops.QubitId() operations = decompositions.controlled_op_to_native_gates( control=qc, target=qt, operation=ops.H.matrix(), tolerance=0.0001) assert operations == [ops.Y(qt)**-0.25, ops.CZ(qc, qt), ops.Y(qt)**0.25]
def _with_parameterized_layers( circuit: 'cirq.Circuit', qubits: Sequence['cirq.Qid'], needs_init_layer: bool, ) -> 'cirq.Circuit': """Return a copy of the input circuit with parameterized single-qubit rotations. These rotations flank the circuit: the initial two layers of X and Y gates are given parameter names "{qubit}-Xi" and "{qubit}-Yi" and are used to set up the initial state. If `needs_init_layer` is False, these two layers of gates are omitted. The final two layers of X and Y gates are given parameter names "{qubit}-Xf" and "{qubit}-Yf" and are use to change the frame of the qubit before measurement, effectively measuring in bases other than Z. """ x_beg_mom = ops.Moment([ops.X(q)**sympy.Symbol(f'{q}-Xi') for q in qubits]) y_beg_mom = ops.Moment([ops.Y(q)**sympy.Symbol(f'{q}-Yi') for q in qubits]) x_end_mom = ops.Moment([ops.X(q)**sympy.Symbol(f'{q}-Xf') for q in qubits]) y_end_mom = ops.Moment([ops.Y(q)**sympy.Symbol(f'{q}-Yf') for q in qubits]) meas_mom = ops.Moment([ops.measure(*qubits, key='z')]) if needs_init_layer: total_circuit = circuits.Circuit([x_beg_mom, y_beg_mom]) total_circuit += circuit.copy() else: total_circuit = circuit.copy() total_circuit.append([x_end_mom, y_end_mom, meas_mom]) return total_circuit
def nonoptimal_toffoli_circuit(q0: 'cirq.Qid', q1: 'cirq.Qid', q2: 'cirq.Qid') -> circuits.Circuit: ret = circuits.Circuit( ops.Y(q2)**0.5, ops.X(q2), ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.Z(q1)**0.25, ops.CNOT(q0, q1), ops.Z(q0)**0.25, ops.Z(q1)**-0.25, ops.CNOT(q0, q1), ops.Y(q2)**0.5, ops.X(q2), ) return ret
def known_two_q_operations_to_sycamore_operations( qubit_a: ops.Qid, qubit_b: ops.Qid, op: ops.Operation, tabulation: Optional[GateTabulation] = None, ) -> ops.OP_TREE: """ Synthesize a known gate operation to a sycamore operation This function dispatches based on gate type Args: qubit_a: first qubit of GateOperation qubit_b: second qubit of GateOperation op: operation to decompose tabulation: A tabulation for the Sycamore gate to use for decomposing gates. Returns: New operations iterable object """ gate = op.gate if isinstance(gate, ops.PhasedISwapPowGate): if math.isclose(gate.exponent, 1): return decompose_phased_iswap_into_syc(gate.phase_exponent, qubit_a, qubit_b) elif math.isclose(gate.phase_exponent, 0.25): return decompose_phased_iswap_into_syc_precomputed( gate.exponent * np.pi / 2, qubit_a, qubit_b) else: raise ValueError( "To decompose PhasedISwapPowGate, it must have a phase_exponent" " of .25 OR an exponent of 1.0, but got: {!r}".format(op)) if isinstance(gate, ops.CNotPowGate): return [ ops.Y(qubit_b)**-0.5, cphase(gate.exponent * np.pi, qubit_a, qubit_b), ops.Y(qubit_b)**0.5, ] elif isinstance(gate, ops.CZPowGate): if math.isclose(gate.exponent, 1): # check if CZ or CPHASE return decompose_cz_into_syc(qubit_a, qubit_b) else: # because CZPowGate == diag([1, 1, 1, e^{i pi phi}]) return cphase(gate.exponent * np.pi, qubit_a, qubit_b) elif isinstance(gate, ops.SwapPowGate) and math.isclose(gate.exponent, 1): return decompose_swap_into_syc(qubit_a, qubit_b) elif isinstance(gate, ops.ISwapPowGate) and math.isclose(gate.exponent, 1): return decompose_iswap_into_syc(qubit_a, qubit_b) elif isinstance(gate, ops.ZZPowGate): return rzz(gate.exponent * np.pi / 2, *op.qubits) elif protocols.unitary(gate, None) is not None: if tabulation: return decompose_arbitrary_into_syc_tabulation( qubit_a, qubit_b, op, tabulation) else: return decompose_arbitrary_into_syc_analytic(qubit_a, qubit_b, op) else: raise ValueError("Unrecognized gate: {!r}".format(op))
def _decompose_(self, qubits): from cirq import ops a, b = qubits return [ ops.GlobalPhaseOperation(self.global_phase), ops.MatrixGate(self.single_qubit_operations_before[0]).on(a), ops.MatrixGate(self.single_qubit_operations_before[1]).on(b), np.exp(1j * ops.X(a) * ops.X(b) * self.interaction_coefficients[0]), np.exp(1j * ops.Y(a) * ops.Y(b) * self.interaction_coefficients[1]), np.exp(1j * ops.Z(a) * ops.Z(b) * self.interaction_coefficients[2]), ops.MatrixGate(self.single_qubit_operations_after[0]).on(a), ops.MatrixGate(self.single_qubit_operations_after[1]).on(b), ]
def test_two_qubit_state_tomography(): # Check that the density matrices of the four Bell states closely match # the ideal cases. In addition, check that the output states of # single-qubit rotations (H, H), (X/2, Y/2), (Y/2, X/2) have the correct # density matrices. simulator = sim.Simulator() q_0 = GridQubit(0, 0) q_1 = GridQubit(0, 1) circuit_00 = circuits.Circuit.from_ops(ops.H(q_0), ops.CNOT(q_0, q_1)) circuit_01 = circuits.Circuit.from_ops(ops.X(q_1), ops.H(q_0), ops.CNOT(q_0, q_1)) circuit_10 = circuits.Circuit.from_ops(ops.X(q_0), ops.H(q_0), ops.CNOT(q_0, q_1)) circuit_11 = circuits.Circuit.from_ops(ops.X(q_0), ops.X(q_1), ops.H(q_0), ops.CNOT(q_0, q_1)) circuit_hh = circuits.Circuit.from_ops(ops.H(q_0), ops.H(q_1)) circuit_xy = circuits.Circuit.from_ops(ops.X(q_0)**0.5, ops.Y(q_1)**0.5) circuit_yx = circuits.Circuit.from_ops(ops.Y(q_0)**0.5, ops.X(q_1)**0.5) act_rho_00 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_00, 1000).data act_rho_01 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_01, 1000).data act_rho_10 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_10, 1000).data act_rho_11 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_11, 1000).data act_rho_hh = two_qubit_state_tomography(simulator, q_0, q_1, circuit_hh, 1000).data act_rho_xy = two_qubit_state_tomography(simulator, q_0, q_1, circuit_xy, 1000).data act_rho_yx = two_qubit_state_tomography(simulator, q_0, q_1, circuit_yx, 1000).data tar_rho_00 = np.outer([1.0, 0, 0, 1.0], [1.0, 0, 0, 1.0]) * 0.5 tar_rho_01 = np.outer([0, 1.0, 1.0, 0], [0, 1.0, 1.0, 0]) * 0.5 tar_rho_10 = np.outer([1.0, 0, 0, -1.0], [1.0, 0, 0, -1.0]) * 0.5 tar_rho_11 = np.outer([0, 1.0, -1.0, 0], [0, 1.0, -1.0, 0]) * 0.5 tar_rho_hh = np.outer([0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5]) tar_rho_xy = np.outer([0.5, 0.5, -0.5j, -0.5j], [0.5, 0.5, 0.5j, 0.5j]) tar_rho_yx = np.outer([0.5, -0.5j, 0.5, -0.5j], [0.5, 0.5j, 0.5, 0.5j]) np.testing.assert_almost_equal(act_rho_00, tar_rho_00, decimal=1) np.testing.assert_almost_equal(act_rho_01, tar_rho_01, decimal=1) np.testing.assert_almost_equal(act_rho_10, tar_rho_10, decimal=1) np.testing.assert_almost_equal(act_rho_11, tar_rho_11, decimal=1) np.testing.assert_almost_equal(act_rho_hh, tar_rho_hh, decimal=1) np.testing.assert_almost_equal(act_rho_xy, tar_rho_xy, decimal=1) np.testing.assert_almost_equal(act_rho_yx, tar_rho_yx, decimal=1)
def test_controlled_op_to_gates_concrete_case(): qc = ops.QubitId() qt = ops.QubitId() operations = decompositions.controlled_op_to_native_gates( control=qc, target=qt, operation=np.array([[1, 1j], [1j, 1]]) * np.sqrt(0.5), tolerance=0.0001) assert operations == [ ops.Y(qt)**-0.5, ops.CZ(qc, qt)**1.5, ops.Z(qc)**0.25, ops.Y(qt)**0.5 ]
def test_to_from_braket_common_one_qubit_gates(): """These gates should stay the same (i.e., not get decomposed) when converting Cirq -> Braket -> Cirq. """ rots = [ops.rx, ops.ry, ops.rz] angles = [1 / 5, 3 / 5, -4 / 5] qubit = LineQubit(0) cirq_circuit = Circuit( # Paulis. ops.X(qubit), ops.Y(qubit), ops.Z(qubit), # Single-qubit rotations. [rot(angle).on(qubit) for rot, angle in zip(rots, angles)], # Rz alter egos. ops.T(qubit), ops.T(qubit)**-1, ops.S(qubit), ops.S(qubit)**-1, # Rx alter egos. ops.X(qubit)**0.5, ops.X(qubit)**-0.5, ) test_circuit = from_braket(to_braket(cirq_circuit)) assert _equal(test_circuit, cirq_circuit, require_qubit_equality=True)
def test_equality(): a = ops.QubitId() b = ops.QubitId() c = ops.QubitId() d = ops.QubitId() eq = EqualsTester() # Default is empty. Iterables get frozen into tuples. eq.add_equality_group(Moment(), Moment([]), Moment(())) eq.add_equality_group( Moment([ops.X(d)]), Moment((ops.X(d),))) # Equality depends on gate and qubits. eq.add_equality_group(Moment([ops.X(a)])) eq.add_equality_group(Moment([ops.X(b)])) eq.add_equality_group(Moment([ops.Y(a)])) # Equality depends on order. eq.add_equality_group(Moment([ops.X(a), ops.X(b)])) eq.add_equality_group(Moment([ops.X(b), ops.X(a)])) # Two qubit gates. eq.make_equality_pair(lambda: Moment([ops.CZ(c, d)])) eq.make_equality_pair(lambda: Moment([ops.CZ(a, c)])) eq.make_equality_pair(lambda: Moment([ops.CZ(a, b), ops.CZ(c, d)])) eq.make_equality_pair(lambda: Moment([ops.CZ(a, c), ops.CZ(b, d)]))
def _cpmg_circuit(qubit: devices.GridQubit, delay_var: sympy.Symbol, max_pulses: int) -> 'cirq.Circuit': """Creates a CPMG circuit for a given qubit. The circuit will look like: sqrt(Y) - wait(delay_var) - X - wait(2*delay_var) - ... - wait(delay_var) with max_pulses number of X gates. The X gates are paramterizd by 'pulse_N' symbols so that pulses can be turned on and off. This is done to combine circuits with different pulses into the same paramterized circuit. """ circuit = circuits.Circuit( ops.Y(qubit)**0.5, ops.WaitGate(value.Duration(nanos=delay_var))(qubit), ops.X(qubit)) for n in range(max_pulses): pulse_n_on = sympy.Symbol(f'pulse_{n}') circuit.append( ops.WaitGate(value.Duration(nanos=2 * delay_var * pulse_n_on))(qubit)) circuit.append(ops.X(qubit)**pulse_n_on) circuit.append(ops.WaitGate(value.Duration(nanos=delay_var))(qubit)) return circuit
def test_text_diagrams(): a = ops.NamedQubit('a') b = ops.NamedQubit('b') circuit = Circuit.from_ops(ops.SWAP(a, b), ops.X(a), ops.Y(a), ops.Z(a), ops.CZ(a, b), ops.CNOT(a, b), ops.CNOT(b, a), ops.H(a)) assert circuit.to_text_diagram().strip() == """ a: ───×───X───Y───Z───@───@───X───H─── │ │ │ │ b: ───×───────────────@───X───@─────── """.strip()
def test_clears_known_empties_even_at_zero_tolerance(): m = circuits.DropNegligible(0.001) q = ops.QubitId() q2 = ops.QubitId() c = circuits.Circuit.from_ops( ops.Z(q)**0, ops.Y(q)**0.0000001, ops.X(q)**-0.0000001, ops.CZ(q, q2)**0) m.optimize_circuit(c) assert c == circuits.Circuit([circuits.Moment()] * 4)
def _two_qubit_clifford_mixers(q_0: 'cirq.Qid', q_1: 'cirq.Qid', idx_2: int, cliffords: Cliffords ) -> Iterator['cirq.OP_TREE']: """Fulfills parts (b-d) for two-qubit Cliffords.""" s1 = cliffords.s1 s1_x = cliffords.s1_x s1_y = cliffords.s1_y if idx_2 == 1: yield ops.CZ(q_0, q_1) yield ops.Y(q_0)**-0.5 yield ops.Y(q_1)**0.5 yield ops.CZ(q_0, q_1) yield ops.Y(q_0)**0.5 yield ops.Y(q_1)**-0.5 yield ops.CZ(q_0, q_1) yield ops.Y(q_1)**0.5 elif 2 <= idx_2 <= 10: yield ops.CZ(q_0, q_1) idx_3 = int((idx_2 - 2) / 3) idx_4 = (idx_2 - 2) % 3 yield _single_qubit_gates(s1[idx_3], q_0) yield _single_qubit_gates(s1_y[idx_4], q_1) elif idx_2 >= 11: yield ops.CZ(q_0, q_1) yield ops.Y(q_0)**0.5 yield ops.X(q_1)**-0.5 yield ops.CZ(q_0, q_1) idx_3 = int((idx_2 - 11) / 3) idx_4 = (idx_2 - 11) % 3 yield _single_qubit_gates(s1_y[idx_3], q_0) yield _single_qubit_gates(s1_x[idx_4], q_1)
def _xx_yy_interaction_via_full_czs(q0: 'cirq.Qid', q1: 'cirq.Qid', x: float, y: float): a = x * -2 / np.pi b = y * -2 / np.pi yield ops.X(q0) ** 0.5 yield ops.H(q1) yield ops.CZ(q0, q1) yield ops.H(q1) yield ops.X(q0) ** a yield ops.Y(q1) ** b yield ops.H(q1) yield ops.CZ(q0, q1) yield ops.H(q1) yield ops.X(q0) ** -0.5
def test_works_with_basic_gates(): a = ops.NamedQubit('a') b = ops.NamedQubit('b') basics = [ ops.X(a), ops.Y(a)**0.5, ops.Z(a), ops.CZ(a, b)**-0.25, ops.CNOT(a, b), ops.H(b), ops.SWAP(a, b) ] assert list(ops.inverse_of_invertible_op_tree(basics)) == [ ops.SWAP(a, b), ops.H(b), ops.CNOT(a, b), ops.CZ(a, b)**0.25, ops.Z(a), ops.Y(a)**-0.5, ops.X(a), ]
def nonoptimal_toffoli_circuit( q0: 'cirq.Qid', q1: 'cirq.Qid', q2: 'cirq.Qid', device: devices.Device = devices.UNCONSTRAINED_DEVICE, ) -> circuits.Circuit: ret = circuits.Circuit( ops.Y(q2) ** 0.5, ops.X(q2), ops.CNOT(q1, q2), ops.Z(q2) ** -0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2) ** 0.25, ops.CNOT(q1, q2), ops.Z(q2) ** -0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2) ** 0.25, ops.Z(q1) ** 0.25, ops.CNOT(q0, q1), ops.Z(q0) ** 0.25, ops.Z(q1) ** -0.25, ops.CNOT(q0, q1), ops.Y(q2) ** 0.5, ops.X(q2), ) ret._device = device return ret
def swap_to_sqrt_iswap(a, b, turns): """Implement the evolution of the hopping term using two sqrt_iswap gates and single-qubit operations. Output unitary: [[1, 0, 0, 0], [0, g·c, -i·g·s, 0], [0, -i·g·s, g·c, 0], [0, 0, 0, 1]] where c = cos(theta) and s = sin(theta). Args: a: the first qubit b: the second qubit theta: The rotational angle that specifies the gate, where c = cos(π·t/2), s = sin(π·t/2), g = exp(i·π·t/2). """ if not isinstance(turns, sympy.Basic) and _near_mod_n(turns, 1.0, 2): # Decomposition for cirq.SWAP yield ops.Y(a)**0.5 yield ops.Y(b)**0.5 yield SQRT_ISWAP(a, b) yield ops.Y(a)**-0.5 yield ops.Y(b)**-0.5 yield SQRT_ISWAP(a, b) yield ops.X(a)**-0.5 yield ops.X(b)**-0.5 yield SQRT_ISWAP(a, b) yield ops.X(a)**0.5 yield ops.X(b)**0.5 return yield ops.Z(a)**1.25 yield ops.Z(b)**-0.25 yield ops.ISWAP(a, b)**-0.5 yield ops.Z(a)**(-turns / 2 + 1) yield ops.Z(b)**(turns / 2) yield ops.ISWAP(a, b)**-0.5 yield ops.Z(a)**(turns / 2 - 0.25) yield ops.Z(b)**(turns / 2 + 0.25) yield ops.CZ.on(a, b)**(-turns)
def test_combines_sequence(): m = MergeRotations(0.000001) q = ops.QubitId() c = circuits.Circuit([ circuits.Moment([ops.X(q)**0.5]), circuits.Moment([ops.Z(q)**0.5]), circuits.Moment([ops.X(q)**-0.5]), ]) assert (m.optimization_at(c, 0, c.operation_at( q, 0)) == circuits.PointOptimizationSummary(clear_span=3, clear_qubits=[q], new_operations=ops.Y(q)**0.5))
def nonoptimal_toffoli_circuit( q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, device: devices.Device = devices.UNCONSTRAINED_DEVICE ) -> circuits.Circuit: return circuits.Circuit.from_ops(ops.Y(q2)**0.5, ops.X(q2), ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.Z(q1)**0.25, ops.CNOT(q0, q1), ops.Z(q0)**0.25, ops.Z(q1)**-0.25, ops.CNOT(q0, q1), ops.Y(q2)**0.5, ops.X(q2), device=device)
def test_single_qubit_state_tomography(): # Check that the density matrices of the output states of X/2, Y/2 and # H + Y gates closely match the ideal cases. simulator = sim.Simulator() qubit = GridQubit(0, 0) circuit_1 = circuits.Circuit(ops.X(qubit)**0.5) circuit_2 = circuits.Circuit(ops.Y(qubit)**0.5) circuit_3 = circuits.Circuit(ops.H(qubit), ops.Y(qubit)) act_rho_1 = single_qubit_state_tomography(simulator, qubit, circuit_1, 1000).data act_rho_2 = single_qubit_state_tomography(simulator, qubit, circuit_2, 1000).data act_rho_3 = single_qubit_state_tomography(simulator, qubit, circuit_3, 1000).data tar_rho_1 = np.array([[0.5, 0.5j], [-0.5j, 0.5]]) tar_rho_2 = np.array([[0.5, 0.5], [0.5, 0.5]]) tar_rho_3 = np.array([[0.5, -0.5], [-0.5, 0.5]]) np.testing.assert_almost_equal(act_rho_1, tar_rho_1, decimal=1) np.testing.assert_almost_equal(act_rho_2, tar_rho_2, decimal=1) np.testing.assert_almost_equal(act_rho_3, tar_rho_3, decimal=1)
def nonoptimal_toffoli_circuit( q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, device: devices.Device = devices.UnconstrainedDevice ) -> circuits.Circuit: return circuits.Circuit.from_ops(ops.Y(q2)**0.5, ops.X(q2), ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.Z(q1)**0.25, ops.CNOT(q0, q1), ops.Z(q0)**0.25, ops.Z(q1)**-0.25, ops.CNOT(q0, q1), ops.Y(q2)**0.5, ops.X(q2), device=device)
def single_qubit_state_tomography( sampler: 'cirq.Sampler', qubit: 'cirq.Qid', circuit: 'cirq.AbstractCircuit', repetitions: int = 1000, ) -> TomographyResult: """Single-qubit state tomography. The density matrix of the output state of a circuit is measured by first doing projective measurements in the z-basis, which determine the diagonal elements of the matrix. A X/2 or Y/2 rotation is then added before the z-basis measurement, which determines the imaginary and real parts of the off-diagonal matrix elements, respectively. See Vandersypen and Chuang, Rev. Mod. Phys. 76, 1037 for details. Args: sampler: The quantum engine or simulator to run the circuits. qubit: The qubit under test. circuit: The circuit to execute on the qubit before tomography. repetitions: The number of measurements for each basis rotation. Returns: A TomographyResult object that stores and plots the density matrix. """ circuit_z = circuit + circuits.Circuit(ops.measure(qubit, key='z')) results = sampler.run(circuit_z, repetitions=repetitions) rho_11 = np.mean(results.measurements['z']) rho_00 = 1.0 - rho_11 circuit_x = circuits.Circuit(circuit, ops.X(qubit)**0.5, ops.measure(qubit, key='z')) results = sampler.run(circuit_x, repetitions=repetitions) rho_01_im = np.mean(results.measurements['z']) - 0.5 circuit_y = circuits.Circuit(circuit, ops.Y(qubit)**-0.5, ops.measure(qubit, key='z')) results = sampler.run(circuit_y, repetitions=repetitions) rho_01_re = 0.5 - np.mean(results.measurements['z']) rho_01 = rho_01_re + 1j * rho_01_im rho_10 = np.conj(rho_01) rho = np.array([[rho_00, rho_01], [rho_10, rho_11]]) return TomographyResult(rho)
def _xx_yy_zz_interaction_via_full_czs(q0: 'cirq.Qid', q1: 'cirq.Qid', x: float, y: float, z: float): a = x * -2 / np.pi + 0.5 b = y * -2 / np.pi + 0.5 c = z * -2 / np.pi + 0.5 yield ops.X(q0)**0.5 yield ops.H(q1) yield ops.CZ(q0, q1) yield ops.H(q1) yield ops.X(q0)**a yield ops.Y(q1)**b yield ops.H.on(q0) yield ops.CZ(q1, q0) yield ops.H(q0) yield ops.X(q1)**-0.5 yield ops.Z(q1)**c yield ops.H(q1) yield ops.CZ(q0, q1) yield ops.H(q1)
def default_decompose(self, qubits: Sequence[ops.QubitId]) -> ops.OP_TREE: q0, q1 = qubits a = self.x * -2 / np.pi + 0.5 b = self.y * -2 / np.pi + 0.5 c = self.z * -2 / np.pi + 0.5 yield self.before0(q0) yield self.before1(q1) yield ops.X(q0)**0.5 yield ops.CNOT(q0, q1) yield ops.X(q0)**a yield ops.Y(q1)**b yield ops.CNOT(q1, q0) yield ops.X(q1)**-0.5 yield ops.Z(q1)**c yield ops.CNOT(q0, q1) yield self.after0(q0) yield self.after1(q1)
def test_from_braket_non_parameterized_single_qubit_gates(): braket_circuit = BKCircuit() instructions = [ Instruction(braket_gates.I(), target=0), Instruction(braket_gates.X(), target=1), Instruction(braket_gates.Y(), target=2), Instruction(braket_gates.Z(), target=3), Instruction(braket_gates.H(), target=0), Instruction(braket_gates.S(), target=1), Instruction(braket_gates.Si(), target=2), Instruction(braket_gates.T(), target=3), Instruction(braket_gates.Ti(), target=0), Instruction(braket_gates.V(), target=1), Instruction(braket_gates.Vi(), target=2), ] for instr in instructions: braket_circuit.add_instruction(instr) cirq_circuit = from_braket(braket_circuit) for i, op in enumerate(cirq_circuit.all_operations()): assert np.allclose( instructions[i].operator.to_matrix(), protocols.unitary(op) ) qreg = LineQubit.range(4) expected_cirq_circuit = Circuit( ops.I(qreg[0]), ops.X(qreg[1]), ops.Y(qreg[2]), ops.Z(qreg[3]), ops.H(qreg[0]), ops.S(qreg[1]), ops.S(qreg[2]) ** -1, ops.T(qreg[3]), ops.T(qreg[0]) ** -1, ops.X(qreg[1]) ** 0.5, ops.X(qreg[2]) ** -0.5, ) assert _equal(cirq_circuit, expected_cirq_circuit)
def _decompose_(self, qubits: Sequence[ops.Qid]) -> ops.OP_TREE: q0, q1 = qubits x, y, z = self.kak.interaction_coefficients a = x * -2 / np.pi + 0.5 b = y * -2 / np.pi + 0.5 c = z * -2 / np.pi + 0.5 b0, b1 = self.kak.single_qubit_operations_before yield QasmUGate.from_matrix(b0).on(q0) yield QasmUGate.from_matrix(b1).on(q1) yield ops.X(q0)**0.5 yield ops.CNOT(q0, q1) yield ops.X(q0)**a yield ops.Y(q1)**b yield ops.CNOT(q1, q0) yield ops.X(q1)**-0.5 yield ops.Z(q1)**c yield ops.CNOT(q0, q1) a0, a1 = self.kak.single_qubit_operations_after yield QasmUGate.from_matrix(a0).on(q0) yield QasmUGate.from_matrix(a1).on(q1)
def t2_decay( sampler: work.Sampler, *, qubit: devices.GridQubit, experiment_type: 'ExperimentType' = ExperimentType.RAMSEY, num_points: int, max_delay: 'cirq.DURATION_LIKE', min_delay: 'cirq.DURATION_LIKE' = None, repetitions: int = 1000, delay_sweep: Optional[study.Sweep] = None, ) -> 'cirq.experiments.T2DecayResult': """Runs a t2 transverse relaxation experiment. Initializes a qubit into a superposition state, evolves the system using rules determined by the experiment type and by the delay parameters, then rotates back for measurement. This will measure the phase decoherence decay. This experiment has three types of T2 metrics, each which measure a different slice of the noise spectrum. For the Ramsey experiment type (often denoted T2*), the state will be prepared with a square root Y gate (`cirq.Y ** 0.5`) and then waits for a variable amount of time. After this time, it will do basic state tomography to measure the expectation of the Pauli-X and Pauli-Y operators by performing either a `cirq.Y ** -0.5` or `cirq.X ** -0.5`. The square of these two measurements is summed to determine the length of the Bloch vector. This experiment measures the phase decoherence of the system under free evolution. For the Hahn echo experiment (often denoted T2 or spin echo), the state will also be prepared with a square root Y gate (`cirq.Y ** 0.5`). However, during the mid-point of the delay time being measured, a pi-pulse (`cirq.X`) gate will be applied to cancel out inhomogeneous dephasing. The same method of measuring the final state as Ramsey experiment is applied after the second half of the delay period. CPMG, or the Carr-Purcell-Meiboom-Gill sequence, is currently not implemented. Args: sampler: The quantum engine or simulator to run the circuits. qubit: The qubit under test. experiment_type: The type of T2 test to run. num_points: The number of evenly spaced delays to test. max_delay: The largest delay to test. min_delay: The smallest delay to test. Defaults to no delay. repetitions: The number of repetitions of the circuit for each delay and for each tomography result. delay_sweep: Optional range of time delays to sweep across. This should be a SingleSweep using the 'delay_ns' with values in integer number of nanoseconds. If specified, this will override the max_delay and min_delay parameters. If not specified, the experiment will sweep from min_delay to max_delay with linear steps. Returns: A T2DecayResult object that stores and can plot the data. """ min_delay_dur = value.Duration(min_delay) max_delay_dur = value.Duration(max_delay) # Input validation if repetitions <= 0: raise ValueError('repetitions <= 0') if max_delay_dur < min_delay_dur: raise ValueError('max_delay < min_delay') if min_delay_dur < 0: raise ValueError('min_delay < 0') # Initialize values used in sweeps delay_var = sympy.Symbol('delay_ns') inv_x_var = sympy.Symbol('inv_x') inv_y_var = sympy.Symbol('inv_y') if not delay_sweep: delay_sweep = study.Linspace(delay_var, start=min_delay_dur.total_nanos(), stop=max_delay_dur.total_nanos(), length=num_points) if delay_sweep.keys != ['delay_ns']: raise ValueError('delay_sweep must be a SingleSweep ' 'with delay_ns parameter') if experiment_type == ExperimentType.RAMSEY: # Ramsey T2* experiment # Use sqrt(Y) to flip to the equator. # Evolve the state for a given amount of delay time # Then measure the state in both X and Y bases. circuit = circuits.Circuit( ops.Y(qubit)**0.5, ops.WaitGate(value.Duration(nanos=delay_var))(qubit), ops.X(qubit)**inv_x_var, ops.Y(qubit)**inv_y_var, ops.measure(qubit, key='output'), ) tomography_sweep = study.Zip( study.Points('inv_x', [0.0, -0.5]), study.Points('inv_y', [-0.5, 0.0]), ) sweep = study.Product(delay_sweep, tomography_sweep) elif experiment_type == ExperimentType.HAHN_ECHO: # Hahn / Spin Echo T2 experiment # Use sqrt(Y) to flip to the equator. # Evolve the state for half the given amount of delay time # Flip the state using an X gate # Evolve the state for half the given amount of delay time # Then measure the state in both X and Y bases. circuit = circuits.Circuit( ops.Y(qubit)**0.5, ops.WaitGate(value.Duration(nanos=0.5 * delay_var))(qubit), ops.X(qubit), ops.WaitGate(value.Duration(nanos=0.5 * delay_var))(qubit), ops.X(qubit)**inv_x_var, ops.Y(qubit)**inv_y_var, ops.measure(qubit, key='output'), ) tomography_sweep = study.Zip( study.Points('inv_x', [0.0, 0.5]), study.Points('inv_y', [-0.5, 0.0]), ) sweep = study.Product(delay_sweep, tomography_sweep) else: raise ValueError(f'Experiment type {experiment_type} not supported') # Tabulate measurements into a histogram results = sampler.sample(circuit, params=sweep, repetitions=repetitions) y_basis_measurements = results[abs(results.inv_y) > 0] x_basis_measurements = results[abs(results.inv_x) > 0] x_basis_tabulation = pd.crosstab( x_basis_measurements.delay_ns, x_basis_measurements.output).reset_index() y_basis_tabulation = pd.crosstab( y_basis_measurements.delay_ns, y_basis_measurements.output).reset_index() # If all measurements are 1 or 0, fill in the missing column with all zeros. for tab in [x_basis_tabulation, y_basis_tabulation]: for col_index, name in [(1, 0), (2, 1)]: if name not in tab: tab.insert(col_index, name, [0] * tab.shape[0]) # Return the results in a container object return T2DecayResult(x_basis_tabulation, y_basis_tabulation)
def _two_qubit_clifford(q_0: devices.GridQubit, q_1: devices.GridQubit, idx: int, cliffords: Cliffords) -> Iterator[ops.OP_TREE]: """Generates a two-qubit Clifford gate. An integer (idx) from 0 to 11519 is used to generate a two-qubit Clifford gate which is constructed with single-qubit X and Y rotations and CZ gates. The decomposition of the Cliffords follow those described in the appendix of Barends et al., Nature 508, 500. The integer idx is first decomposed into idx_0 (which ranges from 0 to 23), idx_1 (ranging from 0 to 23) and idx_2 (ranging from 0 to 19). idx_0 and idx_1 determine the two single-qubit rotations which happen at the beginning of all two-qubit Clifford gates. idx_2 determines the subsequent gates in the following: a) If idx_2 = 0, do nothing so the Clifford is just two single-qubit Cliffords (total of 24*24 = 576 possibilities). b) If idx_2 = 1, perform a CZ, followed by -Y/2 on q_0 and Y/2 on q_1, followed by another CZ, followed by Y/2 on q_0 and -Y/2 on q_1, followed by one more CZ and finally a Y/2 on q_1. The Clifford is then a member of the SWAP-like class (total of 24*24 = 576 possibilities). c) If 2 <= idx_2 <= 10, perform a CZ followed by a member of the S_1 group on q_0 and a member of the S_1^(Y/2) group on q_1. The Clifford is a member of the CNOT-like class (a total of 3*3*24*24 = 5184 possibilities). d) If 11 <= idx_2 <= 19, perform a CZ, followed by Y/2 on q_0 and -X/2 on q_1, followed by another CZ, and finally a member of the S_1^(Y/2) group on q_0 and a member of the S_1^(X/2) group on q_1. The Clifford is a member of the iSWAP-like class (a total of 3*3*24*24 = 5184 possibilities). Through the above process, all 11520 members of the two-qubit Clifford group may be generated. Args: q_0: The first qubit under test. q_1: The second qubit under test. idx: An integer from 0 to 11519. cliffords: A NamedTuple that contains single-qubit Cliffords from the C1, S1, S_1^(X/2) and S_1^(Y/2) groups. """ c1 = cliffords.c1_in_xy s1 = cliffords.s1 s1_x = cliffords.s1_x s1_y = cliffords.s1_y idx_0 = int(idx / 480) idx_1 = int((idx % 480) / 20) idx_2 = idx - idx_0 * 480 - idx_1 * 20 yield _single_qubit_gates(c1[idx_0], q_0) yield _single_qubit_gates(c1[idx_1], q_1) if idx_2 == 1: yield ops.CZ(q_0, q_1) yield ops.Y(q_0)**-0.5 yield ops.Y(q_1)**0.5 yield ops.CZ(q_0, q_1) yield ops.Y(q_0)**0.5 yield ops.Y(q_1)**-0.5 yield ops.CZ(q_0, q_1) yield ops.Y(q_1)**0.5 elif 2 <= idx_2 <= 10: yield ops.CZ(q_0, q_1) idx_3 = int((idx_2 - 2) / 3) idx_4 = (idx_2 - 2) % 3 yield _single_qubit_gates(s1[idx_3], q_0) yield _single_qubit_gates(s1_y[idx_4], q_1) elif idx_2 >= 11: yield ops.CZ(q_0, q_1) yield ops.Y(q_0)**0.5 yield ops.X(q_1)**-0.5 yield ops.CZ(q_0, q_1) idx_3 = int((idx_2 - 11) / 3) idx_4 = (idx_2 - 11) % 3 yield _single_qubit_gates(s1_y[idx_3], q_0) yield _single_qubit_gates(s1_x[idx_4], q_1)
def t2_decay( sampler: 'cirq.Sampler', *, qubit: 'cirq.Qid', experiment_type: 'ExperimentType' = ExperimentType.RAMSEY, num_points: int, max_delay: 'cirq.DURATION_LIKE', min_delay: 'cirq.DURATION_LIKE' = None, repetitions: int = 1000, delay_sweep: Optional[study.Sweep] = None, num_pulses: List[int] = None ) -> Union['cirq.experiments.T2DecayResult', List['cirq.experiments.T2DecayResult']]: """Runs a t2 transverse relaxation experiment. Initializes a qubit into a superposition state, evolves the system using rules determined by the experiment type and by the delay parameters, then rotates back for measurement. This will measure the phase decoherence decay. This experiment has three types of T2 metrics, each which measure a different slice of the noise spectrum. For the Ramsey experiment type (often denoted T2*), the state will be prepared with a square root Y gate (`cirq.Y ** 0.5`) and then waits for a variable amount of time. After this time, it will do basic state tomography to measure the expectation of the Pauli-X and Pauli-Y operators by performing either a `cirq.Y ** -0.5` or `cirq.X ** 0.5`. The square of these two measurements is summed to determine the length of the Bloch vector. This experiment measures the phase decoherence of the system under free evolution. For the Hahn echo experiment (often denoted T2 or spin echo), the state will also be prepared with a square root Y gate (`cirq.Y ** 0.5`). However, during the mid-point of the delay time being measured, a pi-pulse (`cirq.X`) gate will be applied to cancel out inhomogeneous dephasing. The same method of measuring the final state as Ramsey experiment is applied after the second half of the delay period. See the animation on the wiki page https://en.wikipedia.org/wiki/Spin_echo for a visual illustration of this experiment. CPMG, or the Carr-Purcell-Meiboom-Gill sequence, involves using a sqrt(Y) followed by a sequence of pi pulses (X gates) in a specific timing pattern: π/2, t, π, 2t, π, ... 2t, π, t The first pulse, a sqrt(Y) gate, will put the qubit's state on the Bloch equator. After a delay, successive X gates will refocus dehomogenous phase effects by causing them to precess in opposite directions and averaging their effects across the entire pulse train. This pulse pattern has two variables that can be adjusted. The first, denoted as 't' in the above sequence, is delay, which can be specified with `delay_min` and `delay_max` or by using a `delay_sweep`, similar to the other experiments. The second variable is the number of pi pulses (X gates). This can be specified as a list of integers using the `num_pulses` parameter. If multiple different pulses are specified, the data will be presented in a data frame with two indices (delay_ns and num_pulses). See the following reference for more information about CPMG pulse trains: Meiboom, S., and D. Gill, “Modified spin-echo method for measuring nuclear relaxation times”, Rev. Sci. Inst., 29, 688–691 (1958). https://doi.org/10.1063/1.1716296 Note that interpreting T2 data is fairly tricky and subtle, as it can include other effects that need to be accounted for. For instance, amplitude damping (T1) will present as T2 noise and needs to be appropriately compensated for to find a true measure of T2. Due to this subtlety and lack of standard way to interpret the data, the fitting of the data to an exponential curve and the extrapolation of an actual T2 time value is left as an exercise to the reader. Args: sampler: The quantum engine or simulator to run the circuits. qubit: The qubit under test. experiment_type: The type of T2 test to run. num_points: The number of evenly spaced delays to test. max_delay: The largest delay to test. min_delay: The smallest delay to test. Defaults to no delay. repetitions: The number of repetitions of the circuit for each delay and for each tomography result. delay_sweep: Optional range of time delays to sweep across. This should be a SingleSweep using the 'delay_ns' with values in integer number of nanoseconds. If specified, this will override the max_delay and min_delay parameters. If not specified, the experiment will sweep from min_delay to max_delay with linear steps. num_pulses: For CPMG, a list of the number of pulses to use. If multiple pulses are specified, each will be swept on. Returns: A T2DecayResult object that stores and can plot the data. """ min_delay_dur = value.Duration(min_delay) max_delay_dur = value.Duration(max_delay) # Input validation if repetitions <= 0: raise ValueError('repetitions <= 0') if max_delay_dur < min_delay_dur: raise ValueError('max_delay < min_delay') if min_delay_dur < 0: raise ValueError('min_delay < 0') if num_pulses and experiment_type != ExperimentType.CPMG: raise ValueError('num_pulses is only valid for CPMG experiments.') # Initialize values used in sweeps delay_var = sympy.Symbol('delay_ns') inv_x_var = sympy.Symbol('inv_x') inv_y_var = sympy.Symbol('inv_y') max_pulses = max(num_pulses) if num_pulses else 0 if not delay_sweep: delay_sweep = study.Linspace(delay_var, start=min_delay_dur.total_nanos(), stop=max_delay_dur.total_nanos(), length=num_points) if delay_sweep.keys != ['delay_ns']: raise ValueError('delay_sweep must be a SingleSweep ' 'with delay_ns parameter') if experiment_type == ExperimentType.RAMSEY: # Ramsey T2* experiment # Use sqrt(Y) to flip to the equator. # Evolve the state for a given amount of delay time # Then measure the state in both X and Y bases. circuit = circuits.Circuit( ops.Y(qubit)**0.5, ops.wait(qubit, nanos=delay_var), ) else: if experiment_type == ExperimentType.HAHN_ECHO: # Hahn / Spin Echo T2 experiment # Use sqrt(Y) to flip to the equator. # Evolve the state for the given amount of delay time # Flip the state using an X gate # Evolve the state for the given amount of delay time # Then measure the state in both X and Y bases. num_pulses = [0] # This is equivalent to a CPMG experiment with zero pulses # and will follow the same code path. # Carr-Purcell-Meiboom-Gill sequence. # Performs the following sequence # π/2 - wait(t) - π - wait(2t) - ... - π - wait(t) # There will be N π pulses (X gates) # where N sweeps over the values of num_pulses # if not num_pulses: raise ValueError('At least one value must be given ' 'for num_pulses in a CPMG experiment') circuit = _cpmg_circuit(qubit, delay_var, max_pulses) # Add simple state tomography circuit.append(ops.X(qubit)**inv_x_var) circuit.append(ops.Y(qubit)**inv_y_var) circuit.append(ops.measure(qubit, key='output')) tomography_sweep = study.Zip( study.Points('inv_x', [0.0, 0.5]), study.Points('inv_y', [-0.5, 0.0]), ) if num_pulses and max_pulses > 0: pulse_sweep = _cpmg_sweep(num_pulses) sweep = study.Product(delay_sweep, pulse_sweep, tomography_sweep) else: sweep = study.Product(delay_sweep, tomography_sweep) # Tabulate measurements into a histogram results = sampler.sample(circuit, params=sweep, repetitions=repetitions) y_basis_measurements = results[abs(results.inv_y) > 0].copy() x_basis_measurements = results[abs(results.inv_x) > 0].copy() if num_pulses and len(num_pulses) > 1: cols = tuple(f'pulse_{t}' for t in range(max_pulses)) x_basis_measurements[ 'num_pulses'] = x_basis_measurements.loc[:, cols].sum(axis=1) y_basis_measurements[ 'num_pulses'] = y_basis_measurements.loc[:, cols].sum(axis=1) x_basis_tabulation = _create_tabulation(x_basis_measurements) y_basis_tabulation = _create_tabulation(y_basis_measurements) # Return the results in a container object return T2DecayResult(x_basis_tabulation, y_basis_tabulation)
def known_two_q_operations_to_sycamore_operations( self, qubit_a: ops.Qid, qubit_b: ops.Qid, op: ops.GateOperation) -> ops.OP_TREE: """ Synthesize a known gate operation to a sycamore operation This function dispatches based on gate type Args: qubit_a: first qubit of GateOperation qubit_b: second qubit of GateOperation op: operation to decompose Returns: New operations iterable object """ gate = op.gate if isinstance(gate, ops.CNotPowGate): return [ ops.Y(qubit_b)**-0.5, cphase( cast(ops.CNotPowGate, gate).exponent * np.pi, qubit_a, qubit_b), ops.Y(qubit_b)**0.5, ] elif isinstance(gate, ops.CZPowGate): gate = cast(ops.CZPowGate, gate) if math.isclose(gate.exponent, 1.0): # check if CZ or CPHASE return decompose_cz_into_syc(qubit_a, qubit_b) else: # because CZPowGate == diag([1, 1, 1, e^{i pi phi}]) return cphase(gate.exponent * np.pi, qubit_a, qubit_b) elif isinstance(gate, ops.SwapPowGate) and math.isclose( cast(ops.SwapPowGate, gate).exponent, 1.0): return decompose_swap_into_syc(qubit_a, qubit_b) elif isinstance(gate, ops.ISwapPowGate) and math.isclose( cast(ops.ISwapPowGate, gate).exponent, 1.0): return decompose_iswap_into_syc(qubit_a, qubit_b) elif isinstance(gate, ops.ZZPowGate): return rzz( cast(ops.ZZPowGate, gate).exponent * np.pi / 2, *op.qubits) elif isinstance(gate, ops.MatrixGate) and len(op.qubits) == 2: new_ops = optimizers.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], op, allow_partial_czs=True) gate_ops = [] for new_op in new_ops: num_qubits = len(new_op.qubits) if num_qubits == 1: gate_ops.extend([ term.on(new_op.qubits[0]) for term in optimizers.single_qubit_matrix_to_gates( protocols.unitary(new_op)) ]) elif num_qubits == 2: gate_ops.extend( ops.flatten_to_ops( self.known_two_q_operations_to_sycamore_operations( new_op.qubits[0], new_op.qubits[1], cast(ops.GateOperation, new_op)))) return gate_ops else: raise ValueError("Unrecognized gate: {!r}".format(op))