def test_tomography_plot_raises_for_incorrect_number_of_axes(): simulator = sim.Simulator() qubit = GridQubit(0, 0) circuit = circuits.Circuit(ops.X(qubit)**0.5) result = single_qubit_state_tomography(simulator, qubit, circuit, 1000) with pytest.raises(TypeError): # ax is not a List[plt.Axes] ax = plt.subplot() result.plot(ax) with pytest.raises(ValueError): _, axes = plt.subplots(1, 3) result.plot(axes)
def test_validation(): a = ops.QubitId() b = ops.QubitId() c = ops.QubitId() d = ops.QubitId() _ = Moment([]) _ = Moment([ops.X(a)]) _ = Moment([ops.CZ(a, b)]) _ = Moment([ops.CZ(b, d)]) _ = Moment([ops.CZ(a, b), ops.CZ(c, d)]) _ = Moment([ops.CZ(a, c), ops.CZ(b, d)]) _ = Moment([ops.CZ(a, c), ops.X(b)]) with pytest.raises(ValueError): _ = Moment([ops.X(a), ops.X(a)]) with pytest.raises(ValueError): _ = Moment([ops.CZ(a, c), ops.X(c)]) with pytest.raises(ValueError): _ = Moment([ops.CZ(a, c), ops.CZ(c, d)])
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 _easy_direction_partial_cz(q0: ops.QubitId, q1: ops.QubitId, t: float): """The actual hardware can only do CZs that phase counter-clockwise. This method replaces clockwise phase(t) to counter-clockwise. Args: q0: The first qubit being operated on. q1: The other qubit being operated on. t: The parameter to describe partial-CZ(CZ^t). Yields: Yields an equivalent circuit for CZ^t with counter-clock phased CZs. """ if t >= 0: yield ops.CZ(q0, q1)**t return yield ops.Z(q0)**t yield ops.X(q1) yield ops.CZ(q0, q1)**(-t) yield ops.X(q1)
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 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_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 test_eq(): q0 = ops.QubitId() eq = EqualsTester() eq.make_equality_pair( lambda: ScheduledOperation(Timestamp(), Duration(), ops.H(q0))) eq.make_equality_pair( lambda: ScheduledOperation(Timestamp(picos=5), Duration(), ops.H(q0))) eq.make_equality_pair( lambda: ScheduledOperation(Timestamp(), Duration(picos=5), ops.H(q0))) eq.make_equality_pair( lambda: ScheduledOperation(Timestamp(), Duration(), ops.X(q0)))
def _decompose_(self) -> ops.OP_TREE: if len(self.pauli_string) <= 0: return qubits = self.qubits any_qubit = qubits[0] to_z_ops = ops.freeze_op_tree(self.pauli_string.to_z_basis_ops()) xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit)) yield to_z_ops yield xor_decomp if isinstance(self.half_turns, sympy.Symbol): if self.pauli_string.negated: yield ops.X(any_qubit) yield ops.Z(any_qubit)**self.half_turns if self.pauli_string.negated: yield ops.X(any_qubit) else: half_turns = self.half_turns * (-1 if self.pauli_string.negated else 1) yield ops.Z(any_qubit)**half_turns yield protocols.inverse(xor_decomp) yield protocols.inverse(to_z_ops)
def default_decompose(self) -> ops.OP_TREE: if len(self.pauli_string) <= 0: return qubits = self.qubits any_qubit = qubits[0] to_z_ops = tuple(pauli_string_to_z_ops(self.pauli_string)) xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit)) yield to_z_ops yield xor_decomp if isinstance(self.half_turns, value.Symbol): if self.pauli_string.negated: yield ops.X(any_qubit) yield ops.RotZGate(half_turns=self.half_turns)(any_qubit) if self.pauli_string.negated: yield ops.X(any_qubit) else: half_turns = self.half_turns * (-1 if self.pauli_string.negated else 1) yield ops.Z(any_qubit)**half_turns yield ops.inverse(xor_decomp) yield ops.inverse(to_z_ops)
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 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 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 test_exclude(): q = ops.QubitId() zero = Timestamp(picos=0) ps = Duration(picos=1) op = ScheduledOperation(zero, ps, ops.H(q)) schedule = Schedule(device=UnconstrainedDevice, scheduled_operations=[op]) assert not schedule.exclude(ScheduledOperation(zero + ps, ps, ops.H(q))) assert not schedule.exclude(ScheduledOperation(zero, ps, ops.X(q))) assert schedule.query(time=zero, duration=ps * 10) == [op] assert schedule.exclude(ScheduledOperation(zero, ps, ops.H(q))) assert schedule.query(time=zero, duration=ps * 10) == [] assert not schedule.exclude(ScheduledOperation(zero, ps, ops.H(q)))
def _cpmg_circuit(qubit: 'cirq.Qid', 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.wait(qubit, nanos=delay_var), ops.X(qubit)) for n in range(max_pulses): pulse_n_on = sympy.Symbol(f'pulse_{n}') circuit.append(ops.wait(qubit, nanos=2 * delay_var * pulse_n_on)) circuit.append(ops.X(qubit)**pulse_n_on) circuit.append(ops.wait(qubit, nanos=delay_var)) return circuit
def _startdecompose(self, qubits): # qubits = [c1, c2, ..., cn, T] # Will "bootstrap" an ancilla CnXOneBorrow = CnXDirtyGate(num_controls=len(qubits[:-2]), num_ancilla=1) yield ops.H(qubits[-1]) yield CnXOneBorrow(*(qubits[:-2] + [qubits[-1]] + [qubits[-2]])) yield ops.Z(qubits[-1])**-0.25 yield ops.CNOT(qubits[-2], qubits[-1]) yield ops.Z(qubits[-1])**0.25 yield CnXOneBorrow(*(qubits[:-2] + [qubits[-1]] + [qubits[-2]])) yield ops.Z(qubits[-1])**-0.25 yield ops.CNOT(qubits[-2], qubits[-1]) yield ops.Z(qubits[-1])**0.25 yield ops.H(qubits[-1]) IncrementLinearWithBorrowedBitOp = IncrementLinearWithBorrowedBitGate( register_size=len(qubits) - 1) # Perform a +1 Gate on all of the top bits with bottom bit as borrowed yield IncrementLinearWithBorrowedBitOp(*qubits) # Perform -rt Z gates for i in range(1, len(qubits) - 1): yield ops.Z(qubits[i])**(-1 * 1 / (2**(len(qubits) - i))) # Perform a -1 Gate on the top bits for i in range(len(qubits) - 1): yield ops.X(qubits[i]) yield IncrementLinearWithBorrowedBitOp(*qubits) for i in range(len(qubits) - 1): yield ops.X(qubits[i]) # Perform rt Z gates for i in range(1, len(qubits) - 1): yield ops.Z(qubits[i])**(1 / (2**(len(qubits) - i))) yield ops.Z(qubits[0])**(1 / (2**(len(qubits) - 1)))
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 _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 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 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 test_stopped_at_2qubit(): m = MergeRotations(0.000001) q = ops.QubitId() q2 = ops.QubitId() c = circuits.Circuit([ circuits.Moment([ops.Z(q)]), circuits.Moment([ops.H(q)]), circuits.Moment([ops.X(q)]), circuits.Moment([ops.H(q)]), circuits.Moment([ops.CZ(q, q2)]), circuits.Moment([ops.H(q)]), ]) assert (m.optimization_at(c, 0, c.operation_at( q, 0)) == circuits.PointOptimizationSummary(clear_span=4, clear_qubits=[q], new_operations=[]))
def test_extension(): class DummyGate(ops.Gate): pass optimizer = MergeRotations(extensions=Extensions({ ops.KnownMatrixGate: { DummyGate: lambda _: ops.SingleQubitMatrixGate(np.array([[0, 1], [1, 0]])) } })) q = ops.QubitId() c = circuits.Circuit([ circuits.Moment([DummyGate().on(q)]), ]) assert_optimizes(before=c, after=circuits.Circuit([circuits.Moment([ops.X(q)])]), optimizer=optimizer)
def defer(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': if op in terminal_measurements: return op gate = op.gate if isinstance(gate, ops.MeasurementGate): if gate.confusion_map: raise NotImplementedError( "Deferring confused measurement is not implemented, but found " f"measurement with key={gate.key} and non-empty confusion map." ) key = value.MeasurementKey.parse_serialized(gate.key) targets = [_MeasurementQid(key, q) for q in op.qubits] measurement_qubits[key] = targets cxs = [ops.CX(q, target) for q, target in zip(op.qubits, targets)] xs = [ ops.X(targets[i]) for i, b in enumerate(gate.full_invert_mask()) if b ] return cxs + xs elif protocols.is_measurement(op): return [defer(op, None) for op in protocols.decompose_once(op)] elif op.classical_controls: controls = [] for c in op.classical_controls: if isinstance(c, value.KeyCondition): if c.key not in measurement_qubits: raise ValueError( f'Deferred measurement for key={c.key} not found.') qubits = measurement_qubits[c.key] if len(qubits) != 1: # TODO: Multi-qubit conditions require # https://github.com/quantumlib/Cirq/issues/4512 # Remember to update docstring above once this works. raise ValueError( 'Only single qubit conditions are allowed.') controls.extend(qubits) else: raise ValueError('Only KeyConditions are allowed.') return op.without_classical_controls().controlled_by( *controls, control_values=[ tuple(range(1, q.dimension)) for q in controls ]) return op
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 measure_confusion_matrix( sampler: 'cirq.Sampler', qubits: Union[Sequence['cirq.Qid'], Sequence[Sequence['cirq.Qid']]], repetitions: int = 1000, ) -> TensoredConfusionMatrices: """Prepares `TensoredConfusionMatrices` for the n qubits in the input. The confusion matrix (CM) for two qubits is the following matrix: ⎡ Pr(00|00) Pr(01|00) Pr(10|00) Pr(11|00) ⎤ ⎢ Pr(00|01) Pr(01|01) Pr(10|01) Pr(11|01) ⎥ ⎢ Pr(00|10) Pr(01|10) Pr(10|10) Pr(11|10) ⎥ ⎣ Pr(00|11) Pr(01|11) Pr(10|11) Pr(11|11) ⎦ where Pr(ij | pq) = Probability of observing “ij” given state “pq” was prepared. Args: sampler: Sampler to collect the data from. qubits: Qubits for which the confusion matrix should be measured. repetitions: Number of times to sample each circuit for a confusion matrix row. """ qubits = cast(Sequence[Sequence['cirq.Qid']], [qubits] if isinstance(qubits[0], ops.Qid) else qubits) confusion_matrices = [] for qs in qubits: flip_symbols = sympy.symbols(f'flip_0:{len(qs)}') flip_circuit = circuits.Circuit( [ops.X(q)**s for q, s in zip(qs, flip_symbols)], ops.measure(*qs), ) sweeps = study.Product( *[study.Points(f'flip_{i}', [0, 1]) for i in range(len(qs))]) results = sampler.run_sweep(flip_circuit, sweeps, repetitions=repetitions) confusion_matrices.append( np.asarray([vis.get_state_histogram(r) for r in results], dtype=float) / repetitions) return TensoredConfusionMatrices(confusion_matrices, qubits, repetitions=repetitions, timestamp=time.time())
def rabi_oscillations( sampler: 'cirq.Sampler', qubit: 'cirq.Qid', max_angle: float = 2 * np.pi, *, repetitions: int = 1000, num_points: int = 200, ) -> RabiResult: """Runs a Rabi oscillation experiment. Rotates a qubit around the x-axis of the Bloch sphere by a sequence of Rabi angles evenly spaced between 0 and max_angle. For each rotation, repeat the circuit a number of times and measure the average probability of the qubit being in the |1> state. Args: sampler: The quantum engine or simulator to run the circuits. qubit: The qubit under test. max_angle: The final Rabi angle in radians. repetitions: The number of repetitions of the circuit for each Rabi angle. num_points: The number of Rabi angles. Returns: A RabiResult object that stores and plots the result. """ theta = sympy.Symbol('theta') circuit = circuits.Circuit(ops.X(qubit)**theta) circuit.append(ops.measure(qubit, key='z')) sweep = study.Linspace(key='theta', start=0.0, stop=max_angle / np.pi, length=num_points) results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions) angles = np.linspace(0.0, max_angle, num_points) excited_state_probs = np.zeros(num_points) for i in range(num_points): excited_state_probs[i] = np.mean(results[i].measurements['z']) return RabiResult(angles, excited_state_probs)
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 _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': q = qubits[0] yield ops.Z(q)**-self._axis_phase_exponent yield ops.X(q)**self._x_exponent yield ops.Z(q)**(self._axis_phase_exponent + self._z_exponent)
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)