def complete_acquaintance_strategy( qubit_order: Sequence['cirq.Qid'], acquaintance_size: int = 0, swap_gate: 'cirq.Gate' = ops.SWAP) -> 'cirq.Circuit': """Returns an acquaintance strategy with can handle the given number of qubits. Args: qubit_order: The qubits on which the strategy should be defined. acquaintance_size: The maximum number of qubits to be acted on by an operation. swap_gate: The gate used to swap logical indices. Returns: A circuit capable of implementing any set of k-local operations. Raises: ValueError: If `acquaintance_size` is negative. """ if acquaintance_size < 0: raise ValueError('acquaintance_size must be non-negative.') if acquaintance_size == 0: return circuits.Circuit() if acquaintance_size > len(qubit_order): return circuits.Circuit() if acquaintance_size == len(qubit_order): return circuits.Circuit(acquaint(*qubit_order)) strategy = circuits.Circuit((acquaint(q) for q in qubit_order)) for size_to_acquaint in range(2, acquaintance_size + 1): expose_acquaintance_gates(strategy) replace_acquaintance_with_swap_network(strategy, qubit_order, size_to_acquaint, swap_gate) return strategy
def _two_qubit_clifford_matrices(q_0: 'cirq.Qid', q_1: 'cirq.Qid', cliffords: Cliffords) -> np.ndarray: mats = [] # Total number of different gates in the two-qubit Clifford group. clifford_group_size = 11520 starters = [] for idx_0 in range(24): subset = [] for idx_1 in range(24): circuit = circuits.Circuit( _two_qubit_clifford_starters(q_0, q_1, idx_0, idx_1, cliffords)) subset.append(protocols.unitary(circuit)) starters.append(subset) mixers = [] # Add the identity for the case where there is no mixer. mixers.append(np.eye(4)) for idx_2 in range(1, 20): circuit = circuits.Circuit( _two_qubit_clifford_mixers(q_0, q_1, idx_2, cliffords)) mixers.append(protocols.unitary(circuit)) for i in range(clifford_group_size): idx_0, idx_1, idx_2 = _split_two_q_clifford_idx(i) mats.append(np.matmul(mixers[idx_2], starters[idx_0][idx_1])) return np.array(mats)
def test_depolarizer_different_gate(): q1 = ops.QubitId() q2 = ops.QubitId() cnot = Job(circuits.Circuit([ circuits.Moment([ops.CNOT(q1, q2)]), ])) allerrors = DepolarizerChannel( probability=1.0, depolarizing_gates=[xmon_gates.ExpZGate(), xmon_gates.ExpWGate()]) p0 = Symbol(DepolarizerChannel._parameter_name + '0') p1 = Symbol(DepolarizerChannel._parameter_name + '1') p2 = Symbol(DepolarizerChannel._parameter_name + '2') p3 = Symbol(DepolarizerChannel._parameter_name + '3') error_sweep = (Points(p0.name, [1.0]) + Points(p1.name, [1.0]) + Points(p2.name, [1.0]) + Points(p3.name, [1.0])) cnot_then_z = Job( circuits.Circuit([ circuits.Moment([ops.CNOT(q1, q2)]), circuits.Moment([ xmon_gates.ExpZGate(half_turns=p0).on(q1), xmon_gates.ExpZGate(half_turns=p1).on(q2) ]), circuits.Moment([ xmon_gates.ExpWGate(half_turns=p2).on(q1), xmon_gates.ExpWGate(half_turns=p3).on(q2) ]) ]), cnot.sweep * error_sweep) assert allerrors.transform_job(cnot) == cnot_then_z
def _strat_commutes_from_operation( v1: Any, v2: Any, *, atol: float, ) -> Union[bool, NotImplementedType, None]: if not isinstance(v1, ops.Operation) or not isinstance(v2, ops.Operation): return NotImplemented if set(v1.qubits).isdisjoint(v2.qubits): return True from cirq import circuits circuit12 = circuits.Circuit(v1, v2) circuit21 = circuits.Circuit(v2, v1) # Don't create gigantic matrices. if np.product(qid_shape_protocol.qid_shape(circuit12)) > 2**10: return NotImplemented # coverage: ignore m12 = unitary_protocol.unitary(circuit12, default=None) m21 = unitary_protocol.unitary(circuit21, default=None) if m12 is None: return NotImplemented return np.allclose(m12, m21, atol=atol)
def _cleanup_operations(operations: Sequence[ops.Operation]): circuit = circuits.Circuit(operations) circuit = merge_single_qubit_gates_to_phased_x_and_z(circuit) circuit = eject_phased_paulis(circuit) circuit = eject_z(circuit) circuit = circuits.Circuit(circuit.all_operations(), strategy=circuits.InsertStrategy.EARLIEST) return list(circuit.all_operations())
def _commutes_( self, other: Any, *, atol: Union[int, float] = 1e-8) -> Union[bool, NotImplementedType, None]: """Determine if this Operation commutes with the object""" if not isinstance(other, Operation): return NotImplemented if hasattr(other, 'qubits') and set(self.qubits).isdisjoint( other.qubits): return True from cirq import circuits circuit12 = circuits.Circuit(self, other) circuit21 = circuits.Circuit(other, self) # Don't create gigantic matrices. shape = protocols.qid_shape_protocol.qid_shape(circuit12) if np.product(shape) > 2**10: return NotImplemented # coverage: ignore m12 = protocols.unitary_protocol.unitary(circuit12, default=None) m21 = protocols.unitary_protocol.unitary(circuit21, default=None) if m12 is None or m21 is None: return NotImplemented return np.allclose(m12, m21, atol=atol)
def complete_acquaintance_strategy(qubit_order: Sequence[ops.Qid], acquaintance_size: int=0, ) -> circuits.Circuit: """ Returns an acquaintance strategy capable of executing a gate corresponding to any set of at most acquaintance_size qubits. Args: qubit_order: The qubits on which the strategy should be defined. acquaintance_size: The maximum number of qubits to be acted on by an operation. Returns: An circuit capable of implementing any set of k-local operation. """ if acquaintance_size < 0: raise ValueError('acquaintance_size must be non-negative.') elif acquaintance_size == 0: return circuits.Circuit(device=UnconstrainedAcquaintanceDevice) if acquaintance_size > len(qubit_order): return circuits.Circuit(device=UnconstrainedAcquaintanceDevice) if acquaintance_size == len(qubit_order): return circuits.Circuit.from_ops( acquaint(*qubit_order), device=UnconstrainedAcquaintanceDevice) strategy = circuits.Circuit.from_ops( (acquaint(q) for q in qubit_order), device=UnconstrainedAcquaintanceDevice) for size_to_acquaint in range(2, acquaintance_size + 1): expose_acquaintance_gates(strategy) replace_acquaintance_with_swap_network( strategy, qubit_order, size_to_acquaint) return strategy
def _split_into_unitary_then_general( circuit: 'cirq.Circuit', ) -> Tuple['cirq.Circuit', 'cirq.Circuit']: """Splits the circuit into a unitary prefix and non-unitary suffix. The splitting happens in a per-qubit fashion. A non-unitary operation on qubit A will cause later operations on A to be part of the non-unitary suffix, but later operations on other qubits will continue to be put into the unitary part (as long as those qubits have had no non-unitary operation up to that point). """ blocked_qubits: Set[cirq.Qid] = set() unitary_prefix = circuits.Circuit() general_suffix = circuits.Circuit() for moment in circuit: unitary_part = [] general_part = [] for op in moment: qs = set(op.qubits) if not protocols.has_unitary(op) or not qs.isdisjoint(blocked_qubits): blocked_qubits |= qs if qs.isdisjoint(blocked_qubits): unitary_part.append(op) else: general_part.append(op) if unitary_part: unitary_prefix.append(ops.Moment(unitary_part)) if general_part: general_suffix.append(ops.Moment(general_part)) return unitary_prefix, general_suffix
def _cleanup_operations(operations: List[ops.Operation]): circuit = circuits.Circuit(operations) optimizers.merge_single_qubit_gates.merge_single_qubit_gates_into_phased_x_z(circuit) optimizers.eject_phased_paulis.EjectPhasedPaulis().optimize_circuit(circuit) optimizers.eject_z.EjectZ().optimize_circuit(circuit) circuit = circuits.Circuit(circuit.all_operations(), strategy=circuits.InsertStrategy.EARLIEST) return list(circuit.all_operations())
def split_into_matching_protocol_then_general( circuit: 'cirq.Circuit', predicate: Callable[['cirq.Operation'], bool], ) -> Tuple['cirq.Circuit', 'cirq.Circuit']: """Splits the circuit into a matching prefix and non-matching suffix. The splitting happens in a per-qubit fashion. A non-matching operation on qubit A will cause later operations on A to be part of the non-matching suffix, but later operations on other qubits will continue to be put into the matching part (as long as those qubits have had no non-matching operation up to that point). """ blocked_qubits: Set[cirq.Qid] = set() matching_prefix = circuits.Circuit() general_suffix = circuits.Circuit() for moment in circuit: matching_part = [] general_part = [] for op in moment: qs = set(op.qubits) if not predicate(op) or not qs.isdisjoint(blocked_qubits): blocked_qubits |= qs if qs.isdisjoint(blocked_qubits): matching_part.append(op) else: general_part.append(op) if matching_part: matching_prefix.append(ops.Moment(matching_part)) if general_part: general_suffix.append(ops.Moment(general_part)) return matching_prefix, general_suffix
def swap_rzz(theta: float, q0: ops.Qid, q1: ops.Qid) -> ops.OP_TREE: """ An implementation of SWAP * EXP(1j theta ZZ) using three sycamore gates. This builds off of the zztheta method. A sycamore gate following the zz-gate is a SWAP EXP(1j (THETA - pi/24) ZZ). Args: theta: exp(1j * theta ) q0: First qubit id to operate on q1: Second qubit id to operate on Returns: The circuit that implements ZZ followed by a swap """ # Set interaction part. circuit = circuits.Circuit() angle_offset = np.pi / 24 - np.pi / 4 circuit.append(google.SYC(q0, q1)) circuit.append(rzz(theta - angle_offset, q0, q1)) # Get the intended circuit. intended_circuit = circuits.Circuit( ops.SWAP(q0, q1), ops.ZZPowGate(exponent=2 * theta / np.pi, global_shift=-0.5).on(q0, q1)) yield create_corrected_circuit(intended_circuit, circuit, q0, q1)
def test_leaves_singleton(): m = MergeRotations(0.000001) q = ops.QubitId() c = circuits.Circuit([circuits.Moment([ops.X(q)])]) m.optimization_at(c, 0, c.operation_at(q, 0)) assert c == circuits.Circuit([circuits.Moment([ops.X(q)])])
def test_removes_identity_sequence(): q = ops.QubitId() assert_optimizes(before=circuits.Circuit([ circuits.Moment([ops.Z(q)]), circuits.Moment([ops.H(q)]), circuits.Moment([ops.X(q)]), circuits.Moment([ops.H(q)]), ]), after=circuits.Circuit())
def test_leaves_big(): m = circuits.DropNegligible(0.001) q = ops.QubitId() c = circuits.Circuit([circuits.Moment([ops.Z(q)**0.1])]) assert m.optimization_at(c, 0, c.operation_at(q, 0)) is None d = circuits.Circuit(c.moments) m.optimize_circuit(d) assert d == c
def test_clears_paired_cnot(): q0 = ops.QubitId() q1 = ops.QubitId() assert_optimizes( before=circuits.Circuit([ circuits.Moment([ops.CNOT(q0, q1)]), circuits.Moment([ops.CNOT(q0, q1)]), ]), after=circuits.Circuit())
def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit': """Applies all maps to the contained circuit and returns the result. Args: deep: If true, this will also call mapped_circuit on any CircuitOperations this object contains. Returns: The contained circuit with all other member variables (repetitions, qubit mapping, parameterization, etc.) applied to it. This behaves like `cirq.decompose(self)`, but preserving moment structure. """ circuit = self.circuit.unfreeze() circuit = circuit.transform_qubits(lambda q: self.qubit_map.get(q, q)) if self.repetitions < 0: circuit = circuit**-1 has_measurements = protocols.is_measurement(circuit) if has_measurements: circuit = protocols.with_measurement_key_mapping( circuit, self.measurement_key_map) circuit = protocols.resolve_parameters(circuit, self.param_resolver, recursive=False) if deep: def map_deep(op: 'cirq.Operation') -> 'cirq.OP_TREE': return op.mapped_circuit( deep=True) if isinstance(op, CircuitOperation) else op if self.repetition_ids is None: return circuit.map_operations(map_deep) if not has_measurements: return circuit.map_operations(map_deep) * abs(self.repetitions) # Path must be constructed from the top down. rekeyed_circuit = circuits.Circuit( protocols.with_key_path(circuit, self.parent_path + (rep, )) for rep in self.repetition_ids) return rekeyed_circuit.map_operations(map_deep) if self.repetition_ids is None: return circuit if not has_measurements: return circuit * abs(self.repetitions) def rekey_op(op: 'cirq.Operation', rep: str): """Update measurement keys in `op` to include repetition ID `rep`.""" rekeyed_op = protocols.with_key_path(op, self.parent_path + (rep, )) if rekeyed_op is NotImplemented: return op return rekeyed_op return circuits.Circuit( circuit.map_operations(lambda op: rekey_op(op, rep)) for rep in self.repetition_ids)
def test_ignores_2qubit_target(): m = MergeRotations(0.000001) q = ops.QubitId() q2 = ops.QubitId() c = circuits.Circuit([ circuits.Moment([ops.CZ(q, q2)]), ]) m.optimization_at(c, 0, c.operation_at(q, 0)) assert c == circuits.Circuit([circuits.Moment([ops.CZ(q, q2)])])
def _to_circuit(program: 'cirq.CIRCUIT_LIKE') -> 'cirq.Circuit': result = None if isinstance(program, circuits.Circuit): # No change needed. result = program elif isinstance(program, ops.Gate): result = circuits.Circuit(program.on(*devices.LineQid.for_gate(program))) else: # It should be an OP_TREE. result = circuits.Circuit(program) return cast('cirq.Circuit', result)
def test_clears_small(): m = circuits.DropNegligible(0.001) q = ops.QubitId() c = circuits.Circuit([circuits.Moment([ops.Z(q)**0.000001])]) assert (m.optimization_at(c, 0, c.operation_at(q, 0)) == circuits.PointOptimizationSummary(clear_span=1, clear_qubits=[q], new_operations=[])) m.optimize_circuit(c) assert c == circuits.Circuit([circuits.Moment()])
def test_drop(): q1 = ops.QubitId() q2 = ops.QubitId() assert_optimizes(before=circuits.Circuit([ circuits.Moment(), circuits.Moment(), circuits.Moment([ops.CNOT(q1, q2)]), circuits.Moment(), ]), after=circuits.Circuit([ circuits.Moment([ops.CNOT(q1, q2)]), ]))
def circuit(self) -> 'cirq.Circuit': result = circuits.Circuit() for col in self._sub_cell_cols_sealed(): body = circuits.Circuit(cell.operations() for cell in col if cell is not None) if body: basis_change = circuits.Circuit(cell.basis_change() for cell in col if cell is not None) result += basis_change result += body result += basis_change**-1 return result
def estimate_single_qubit_readout_errors( sampler: 'cirq.Sampler', *, qubits: Iterable['cirq.Qid'], repetitions: int = 1000) -> SingleQubitReadoutCalibrationResult: """Estimate single-qubit readout error. For each qubit, prepare the |0⟩ state and measure. Calculate how often a 1 is measured. Also, prepare the |1⟩ state and calculate how often a 0 is measured. The state preparations and measurements are done in parallel, i.e., for the first experiment, we actually prepare every qubit in the |0⟩ state and measure them simultaneously. Args: sampler: The quantum engine or simulator to run the circuits. qubits: The qubits being tested. repetitions: The number of measurement repetitions to perform. Returns: A SingleQubitReadoutCalibrationResult storing the readout error probabilities as well as the number of repetitions used to estimate the probabilities. Also stores a timestamp indicating the time when data was finished being collected from the sampler. """ qubits = list(qubits) zeros_circuit = circuits.Circuit(ops.measure_each(*qubits, key_func=repr)) ones_circuit = circuits.Circuit(ops.X.on_each(*qubits), ops.measure_each(*qubits, key_func=repr)) zeros_result = sampler.run(zeros_circuit, repetitions=repetitions) ones_result = sampler.run(ones_circuit, repetitions=repetitions) timestamp = time.time() zero_state_errors = { q: np.mean(zeros_result.measurements[repr(q)]) for q in qubits } one_state_errors = { q: 1 - np.mean(ones_result.measurements[repr(q)]) for q in qubits } return SingleQubitReadoutCalibrationResult( zero_state_errors=zero_state_errors, one_state_errors=one_state_errors, repetitions=repetitions, timestamp=timestamp, )
def test_ignores_czs_separated_by_outer_cz(): q00 = ops.QubitId() q01 = ops.QubitId() q10 = ops.QubitId() assert_optimizes( before=circuits.Circuit([ circuits.Moment([ops.CZ(q00, q01)]), circuits.Moment([ops.CZ(q00, q10)]), circuits.Moment([ops.CZ(q00, q01)]), ]), after=circuits.Circuit([ circuits.Moment([ops.CZ(q00, q01)]), circuits.Moment([ops.CZ(q00, q10)]), circuits.Moment([ops.CZ(q00, q01)]), ]))
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_correct_mappings(): a, b, c = cirq.LineQubit.range(3) cirq.testing.assert_equivalent_computational_basis_map( maps={ 0b01: 0b01, 0b10: 0b10 }, circuit=circuits.Circuit(cirq.IdentityGate(num_qubits=2).on(a, b))) cirq.testing.assert_equivalent_computational_basis_map( maps={ 0b001: 0b100, 0b010: 0b010, 0b100: 0b001, }, circuit=circuits.Circuit(cirq.SWAP(a, c), cirq.I(b)))
def __init__(self, circuit: circuits.Circuit = circuits.Circuit(), sweep: study.Sweep = study.UnitSweep, repetitions: int = 1) -> None: self.circuit = circuit self.sweep = sweep self.repetitions = repetitions
def rzz(theta: float, q0: ops.Qid, q1: ops.Qid) -> ops.OP_TREE: """Generate exp(-1j * theta * zz) from Sycamore gates. Args: theta: rotation parameter q0: First qubit id to operate on q1: Second qubit id to operate on Returns: a Cirq program implementing the Ising gate rtype: cirq.OP_Tree """ phi = -np.pi / 24 c_phi = np.cos(2 * phi) target_unitary = scipy.linalg.expm(-1j * theta * UNITARY_ZZ) if abs(np.cos(theta)) > c_phi: c2 = abs(np.sin(theta)) / c_phi else: c2 = abs(np.cos(theta)) / c_phi # Prepare program that has same Schmidt coeffs as exp(1j theta ZZ) program = circuits.Circuit(google.SYC.on(q0, q1), ops.rx(2 * np.arccos(c2)).on(q1), google.SYC.on(q0, q1)) yield create_corrected_circuit(target_unitary, program, q0, q1)
def convert_circuit(self, circuit: circuits.Circuit) -> circuits.Circuit: new_circuit = circuits.Circuit() for moment in circuit: for op in moment.operations: new_circuit.append(self.convert_one(op)) return transformers.merge_single_qubit_gates_to_phased_x_and_z( new_circuit)
def generate_boixo_2018_supremacy_circuits_v2( qubits: Iterable[devices.GridQubit], cz_depth: int, seed: int ) -> circuits.Circuit: """Generates Google Random Circuits v2 as in github.com/sboixo/GRCS cz_v2. See also https://arxiv.org/abs/1807.10749 Args: qubits: qubit grid in which to generate the circuit. cz_depth: number of layers with CZ gates. seed: seed for the random instance. Returns: A circuit corresponding to instance inst_{n_rows}x{n_cols}_{cz_depth+1}_{seed} The mapping of qubits is cirq.GridQubit(j,k) -> q[j*n_cols+k] (as in the QASM mapping) """ non_diagonal_gates = [ops.pauli_gates.X ** (1 / 2), ops.pauli_gates.Y ** (1 / 2)] rand_gen = random.Random(seed).random circuit = circuits.Circuit() # Add an initial moment of Hadamards circuit.append(ops.common_gates.H(qubit) for qubit in qubits) layer_index = 0 if cz_depth: layer_index = _add_cz_layer(layer_index, circuit) # In the first moment, add T gates when possible for qubit in qubits: if not circuit.operation_at(qubit, 1): circuit.append(ops.common_gates.T(qubit), strategy=InsertStrategy.EARLIEST) for moment_index in range(2, cz_depth + 1): layer_index = _add_cz_layer(layer_index, circuit) # Add single qubit gates in the same moment for qubit in qubits: if not circuit.operation_at(qubit, moment_index): last_op = circuit.operation_at(qubit, moment_index - 1) if last_op: gate = cast(ops.GateOperation, last_op).gate # Add a random non diagonal gate after a CZ if gate == ops.CZ: circuit.append( _choice(rand_gen, non_diagonal_gates).on(qubit), strategy=InsertStrategy.EARLIEST, ) # Add a T gate after a non diagonal gate elif not gate == ops.T: circuit.append(ops.common_gates.T(qubit), strategy=InsertStrategy.EARLIEST) # Add a final moment of Hadamards circuit.append( [ops.common_gates.H(qubit) for qubit in qubits], strategy=InsertStrategy.NEW_THEN_INLINE ) return circuit
def _fix_single_qubit_gates_around_kak_interaction( *, desired: 'cirq.KakDecomposition', operations: List['cirq.Operation'], qubits: Sequence['cirq.Qid'], ) -> Iterator['cirq.Operation']: """Adds single qubit operations to complete a desired interaction. Args: desired: The kak decomposition of the desired operation. qubits: The pair of qubits that is being operated on. operations: A list of operations that composes into the desired kak interaction coefficients, but may not have the desired before/after single qubit operations or the desired global phase. Returns: A list of operations whose kak decomposition approximately equals the desired kak decomposition. """ actual = linalg.kak_decomposition(circuits.Circuit(operations)) def dag(a: np.ndarray) -> np.ndarray: return np.transpose(np.conjugate(a)) for k in range(2): g = ops.MatrixGate( dag(actual.single_qubit_operations_before[k]) @ desired.single_qubit_operations_before[k]) yield g(qubits[k]) yield from operations for k in range(2): g = ops.MatrixGate(desired.single_qubit_operations_after[k] @ dag( actual.single_qubit_operations_after[k])) yield g(qubits[k]) yield ops.GlobalPhaseOperation(desired.global_phase / actual.global_phase)