def test_qid_shape(): assert cirq.qid_shape(cirq.WaitGate(0, qid_shape=(2, 3))) == (2, 3) assert cirq.qid_shape(cirq.WaitGate(0, num_qubits=3)) == (2, 2, 2) with pytest.raises(ValueError, match='empty set of qubits'): cirq.WaitGate(0, num_qubits=0) with pytest.raises(ValueError, match='num_qubits'): cirq.WaitGate(0, qid_shape=(2, 2), num_qubits=1)
def test_cpmg_circuit(): """Tests sub-component to make sure CPMG circuit is generated correctly.""" q = cirq.GridQubit(1, 1) t = sympy.Symbol('t') circuit = t2._cpmg_circuit(q, t, 2) expected = cirq.Circuit( cirq.Y(q)**0.5, cirq.WaitGate(cirq.Duration(nanos=t))(q), cirq.X(q), cirq.WaitGate(cirq.Duration(nanos=2 * t * sympy.Symbol('pulse_0')))(q), cirq.X(q)**sympy.Symbol('pulse_0'), cirq.WaitGate(cirq.Duration(nanos=2 * t * sympy.Symbol('pulse_1')))(q), cirq.X(q)**sympy.Symbol('pulse_1'), cirq.WaitGate(cirq.Duration(nanos=t))(q)) assert circuit == expected
def test_init(): g = cirq.WaitGate(datetime.timedelta(0, 0, 5)) assert g.duration == cirq.Duration(micros=5) g = cirq.WaitGate(cirq.Duration(nanos=4)) assert g.duration == cirq.Duration(nanos=4) g = cirq.WaitGate(0) assert g.duration == cirq.Duration(0) with pytest.raises(ValueError, match='duration < 0'): _ = cirq.WaitGate(cirq.Duration(nanos=-4)) with pytest.raises(TypeError, match='Not a `cirq.DURATION_LIKE`'): _ = cirq.WaitGate(2)
def test_setters_deprecated(): duration = cirq.Duration(millis=1) gate = cirq.WaitGate(duration) assert gate.duration == duration with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): new_duration = cirq.Duration(millis=2) gate.duration = new_duration assert gate.duration == new_duration
def test_make_floquet_request_for_operations() -> None: q00 = cirq.GridQubit(0, 0) q01 = cirq.GridQubit(0, 1) q10 = cirq.GridQubit(1, 0) q11 = cirq.GridQubit(1, 1) q20 = cirq.GridQubit(2, 0) q21 = cirq.GridQubit(2, 1) options = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION # Prepare characterizations for a single circuit. circuit_1 = cirq.Circuit([ [cirq.X(q00), cirq.Y(q11)], [SQRT_ISWAP_GATE.on(q00, q01), SQRT_ISWAP_GATE.on(q10, q11)], [cirq.WaitGate(duration=cirq.Duration(micros=5.0)).on(q01)], ]) requests_1 = workflow.prepare_floquet_characterization_for_operations( circuit_1, options=options) assert requests_1 == [ cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((q10, q11), ), gate=SQRT_ISWAP_GATE, options=options), cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((q00, q01), ), gate=SQRT_ISWAP_GATE, options=options), ] # Prepare characterizations for a list of circuits. circuit_2 = cirq.Circuit([ [SQRT_ISWAP_GATE.on(q00, q01), SQRT_ISWAP_GATE.on(q10, q11)], [SQRT_ISWAP_GATE.on(q00, q10), SQRT_ISWAP_GATE.on(q01, q11)], [SQRT_ISWAP_GATE.on(q10, q20), SQRT_ISWAP_GATE.on(q11, q21)], ]) requests_2 = workflow.prepare_floquet_characterization_for_operations( [circuit_1, circuit_2], options=options) # The order of moments originates from HALF_GRID_STAGGERED_PATTERN. assert requests_2 == [ cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((q00, q10), (q11, q21)), gate=SQRT_ISWAP_GATE, options=options), cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((q01, q11), (q10, q20)), gate=SQRT_ISWAP_GATE, options=options), cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((q10, q11), ), gate=SQRT_ISWAP_GATE, options=options), cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((q00, q01), ), gate=SQRT_ISWAP_GATE, options=options), ]
def test_final_density_matrix_is_not_last_object(): sim = cirq.DensityMatrixSimulator() q = cirq.LineQubit(0) initial_state = np.array([[1, 0], [0, 0]], dtype=np.complex64) circuit = cirq.Circuit(cirq.WaitGate(0)(q)) result = sim.simulate(circuit, initial_state=initial_state) assert result.final_density_matrix is not initial_state assert not np.shares_memory(result.final_density_matrix, initial_state) np.testing.assert_equal(result.final_density_matrix, initial_state)
def test_final_state_vector_is_not_last_object(): sim = cirq.Simulator() q = cirq.LineQubit(0) initial_state = np.array([1, 0], dtype=np.complex64) circuit = cirq.Circuit(cirq.WaitGate(0)(q)) result = sim.simulate(circuit, initial_state=initial_state) assert result.state_vector() is not initial_state assert not np.shares_memory(result.state_vector(), initial_state) np.testing.assert_equal(result.state_vector(), initial_state)
def test_gate_durations(): assert get_duration_ns(cirq.X) == 25.0 assert get_duration_ns(cirq.FSimGate(3 * np.pi / 2, np.pi / 6)) == 12.0 assert get_duration_ns(cirq.FSimGate(3 * np.pi / 4, np.pi / 6)) == 32.0 assert get_duration_ns(cirq.ISWAP) == 32.0 assert get_duration_ns(cirq.ZPowGate(exponent=5)) == 0.0 assert get_duration_ns(cirq.MeasurementGate(1, 'a')) == 4000.0 wait_gate = cirq.WaitGate(cirq.Duration(nanos=4)) assert get_duration_ns(wait_gate) == 4.0 assert get_duration_ns(cirq.CZ) == 25.0
def test_protocols(): t = sympy.Symbol('t') p = cirq.WaitGate(cirq.Duration(millis=5 * t)) c = cirq.WaitGate(cirq.Duration(millis=2)) q = cirq.LineQubit(0) cirq.testing.assert_implements_consistent_protocols(cirq.wait(q, nanos=0)) cirq.testing.assert_implements_consistent_protocols(c.on(q)) cirq.testing.assert_implements_consistent_protocols(p.on(q)) assert cirq.has_unitary(p) assert cirq.has_unitary(c) assert cirq.is_parameterized(p) assert not cirq.is_parameterized(c) assert cirq.resolve_parameters(p, {'t': 2}) == cirq.WaitGate(cirq.Duration(millis=10)) assert cirq.resolve_parameters(c, {'t': 2}) == c assert cirq.resolve_parameters_once(c, {'t': 2}) == c assert cirq.trace_distance_bound(p) == 0 assert cirq.trace_distance_bound(c) == 0 assert cirq.inverse(c) == c assert cirq.inverse(p) == p assert cirq.decompose(c.on(q)) == [] assert cirq.decompose(p.on(q)) == []
def test_sycamore_devices(device, qubit_size, layout_str): q0 = cirq.GridQubit(5, 3) q1 = cirq.GridQubit(5, 4) valid_sycamore_gates_and_ops = [ cirq_google.SYC, cirq.SQRT_ISWAP, cirq.SQRT_ISWAP_INV, cirq.X, cirq.Y, cirq.Z, cirq.Z(q0).with_tags(cirq_google.PhysicalZTag()), coupler_pulse.CouplerPulse(hold_time=cirq.Duration(nanos=10), coupling_mhz=25.0), cirq.measure(q0), cirq.WaitGate(cirq.Duration(millis=5)), # TODO(#5050) Uncomment after GlobalPhaseGate support is added. # cirq.GlobalPhaseGate(-1.0), ] syc = cirq.FSimGate(theta=np.pi / 2, phi=np.pi / 6)(q0, q1) sqrt_iswap = cirq.FSimGate(theta=np.pi / 4, phi=0)(q0, q1) assert str(device) == layout_str assert len(device.metadata.qubit_pairs) == qubit_size assert all(gate_or_op in device.metadata.gateset for gate_or_op in valid_sycamore_gates_and_ops) assert len(device.metadata.gate_durations) == len( device.metadata.gateset.gates) assert any( isinstance(cgs, cirq_google.SycamoreTargetGateset) for cgs in device.metadata.compilation_target_gatesets) assert any( isinstance(cgs, cirq.SqrtIswapTargetGateset) for cgs in device.metadata.compilation_target_gatesets) device.validate_operation(syc) device.validate_operation(sqrt_iswap) assert next( (duration for gate_family, duration in device.metadata.gate_durations.items() if syc in gate_family), None, ) == cirq.Duration(nanos=12) assert next( (duration for gate_family, duration in device.metadata.gate_durations.items() if sqrt_iswap in gate_family), None, ) == cirq.Duration(nanos=32)
def test_prepare_characterization_for_operations(options_cls): options, cls = options_cls q00 = cirq.GridQubit(0, 0) q01 = cirq.GridQubit(0, 1) q10 = cirq.GridQubit(1, 0) q11 = cirq.GridQubit(1, 1) q20 = cirq.GridQubit(2, 0) q21 = cirq.GridQubit(2, 1) # Prepare characterizations for a single circuit. circuit_1 = cirq.Circuit([ [cirq.X(q00), cirq.Y(q11)], [SQRT_ISWAP_GATE.on(q00, q01), SQRT_ISWAP_GATE.on(q10, q11)], [cirq.WaitGate(duration=cirq.Duration(micros=5.0)).on(q01)], ]) requests_1 = workflow.prepare_characterization_for_operations( circuit_1, options=options) assert requests_1 == [ cls(pairs=((q10, q11), ), gate=SQRT_ISWAP_GATE, options=options), cls(pairs=((q00, q01), ), gate=SQRT_ISWAP_GATE, options=options), ] # Prepare characterizations for a list of circuits. circuit_2 = cirq.Circuit([ [SQRT_ISWAP_GATE.on(q00, q01), SQRT_ISWAP_GATE.on(q10, q11)], [SQRT_ISWAP_GATE.on(q00, q10), SQRT_ISWAP_GATE.on(q01, q11)], [SQRT_ISWAP_GATE.on(q10, q20), SQRT_ISWAP_GATE.on(q11, q21)], ]) requests_2 = workflow.prepare_characterization_for_operations( [circuit_1, circuit_2], options=options) # The order of moments originates from HALF_GRID_STAGGERED_PATTERN. assert requests_2 == [ cls(pairs=((q00, q10), (q11, q21)), gate=SQRT_ISWAP_GATE, options=options), cls(pairs=((q01, q11), (q10, q20)), gate=SQRT_ISWAP_GATE, options=options), cls(pairs=((q10, q11), ), gate=SQRT_ISWAP_GATE, options=options), cls(pairs=((q00, q01), ), gate=SQRT_ISWAP_GATE, options=options), ]
def test_proto_with_waitgate(): wait_gateset = cg.serializable_gate_set.SerializableGateSet( gate_set_name='wait_gateset', serializers=[cgc.WAIT_GATE_SERIALIZER], deserializers=[cgc.WAIT_GATE_DESERIALIZER], ) wait_proto = cg.devices.known_devices.create_device_proto_from_diagram( "aa\naa", [wait_gateset], ) wait_device = cg.SerializableDevice.from_proto(proto=wait_proto, gate_sets=[wait_gateset]) q0 = cirq.GridQubit(1, 1) wait_op = cirq.WaitGate(duration=cirq.Duration(nanos=25))(q0) wait_device.validate_operation(wait_op) assert str(wait_proto) == """\
def test_prepare_characterization_for_moments(options_cls): options, cls = options_cls a, b, c, d = cirq.LineQubit.range(4) circuit = cirq.Circuit([ [cirq.X(a), cirq.Y(c)], [SQRT_ISWAP_GATE.on(a, b), SQRT_ISWAP_GATE.on(c, d)], [SQRT_ISWAP_GATE.on(b, c)], [cirq.WaitGate(duration=cirq.Duration(micros=5.0)).on(b)], ]) circuit_with_calibration, requests = workflow.prepare_characterization_for_moments( circuit, options=options) assert requests == [ cls(pairs=((a, b), (c, d)), gate=SQRT_ISWAP_GATE, options=options), cls(pairs=((b, c), ), gate=SQRT_ISWAP_GATE, options=options), ] assert circuit_with_calibration.circuit == circuit assert circuit_with_calibration.moment_to_calibration == [None, 0, 1, None]
def test_wait_gate(): gate_set = cg.SerializableGateSet('test', [cgc.WAIT_GATE_SERIALIZER], [cgc.WAIT_GATE_DESERIALIZER]) proto_dict = { 'gate': { 'id': 'wait' }, 'args': { 'nanos': { 'arg_value': { 'float_value': 20.0 } } }, 'qubits': [{ 'id': '1_2' }] } q = cirq.GridQubit(1, 2) op = cirq.WaitGate(cirq.Duration(nanos=20)).on(q) assert gate_set.serialize_op_dict(op) == proto_dict assert gate_set.deserialize_op_dict(proto_dict) == op
def test_serialize_deserialize_wait_gate(): op = cirq.WaitGate(duration=cirq.Duration(nanos=50.0))(cirq.GridQubit( 1, 2)) proto = op_proto({ 'gate': { 'id': 'wait' }, 'qubits': [{ 'id': '1_2' }], 'args': { 'nanos': { 'arg_value': { 'float_value': 50.0 } }, }, }) assert cg.SYC_GATESET.serialize_op(op) == proto assert cg.SYC_GATESET.deserialize_op(proto) == op assert cg.SQRT_ISWAP_GATESET.serialize_op(op) == proto assert cg.SQRT_ISWAP_GATESET.deserialize_op(proto) == op
def _all_operations(q0, q1, q2, q3, q4, include_measurements=True): return ( cirq.Z(q0), cirq.Z(q0)**.625, cirq.Y(q0), cirq.Y(q0)**.375, cirq.X(q0), cirq.X(q0)**.875, cirq.H(q1), cirq.CZ(q0, q1), cirq.CZ(q0, q1)**0.25, # Requires 2-qubit decomposition cirq.CNOT(q0, q1), cirq.CNOT(q0, q1)**0.5, # Requires 2-qubit decomposition cirq.SWAP(q0, q1), cirq.SWAP(q0, q1)**0.75, # Requires 2-qubit decomposition cirq.CCZ(q0, q1, q2), cirq.CCX(q0, q1, q2), cirq.CCZ(q0, q1, q2)**0.5, cirq.CCX(q0, q1, q2)**0.5, cirq.CSWAP(q0, q1, q2), cirq.XX(q0, q1), cirq.XX(q0, q1)**0.75, cirq.YY(q0, q1), cirq.YY(q0, q1)**0.75, cirq.ZZ(q0, q1), cirq.ZZ(q0, q1)**0.75, cirq.IdentityGate(1).on(q0), cirq.IdentityGate(3).on(q0, q1, q2), cirq.ISWAP(q2, q0), # Requires 2-qubit decomposition cirq.PhasedXPowGate(phase_exponent=0.111, exponent=0.25).on(q1), cirq.PhasedXPowGate(phase_exponent=0.333, exponent=0.5).on(q1), cirq.PhasedXPowGate(phase_exponent=0.777, exponent=-0.5).on(q1), cirq.WaitGate(0).on(q0), cirq.measure(q0, key='xX'), cirq.measure(q2, key='x_a'), cirq.measure(q3, key='X'), cirq.measure(q2, key='x_a'), cirq.measure(q1, q2, q3, key='multi', invert_mask=(False, True)))
def test_make_floquet_request_for_moments() -> None: a, b, c, d = cirq.LineQubit.range(4) circuit = cirq.Circuit([ [cirq.X(a), cirq.Y(c)], [SQRT_ISWAP_GATE.on(a, b), SQRT_ISWAP_GATE.on(c, d)], [SQRT_ISWAP_GATE.on(b, c)], [cirq.WaitGate(duration=cirq.Duration(micros=5.0)).on(b)], ]) options = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION circuit_with_calibration, requests = workflow.prepare_floquet_characterization_for_moments( circuit, options=options) assert requests == [ cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((a, b), (c, d)), gate=SQRT_ISWAP_GATE, options=options), cirq_google.calibration.FloquetPhasedFSimCalibrationRequest( pairs=((b, c), ), gate=SQRT_ISWAP_GATE, options=options), ] assert circuit_with_calibration.circuit == circuit assert circuit_with_calibration.moment_to_calibration == [None, 0, 1, None]
cirq.X(Q0), 'SwapPowGate': [cirq.SwapPowGate(), cirq.SWAP**0.5], 'SYC': cirq.google.SYC, 'SycamoreGate': cirq.google.SycamoreGate(), 'T': cirq.T, 'TOFFOLI': cirq.TOFFOLI, 'TwoQubitMatrixGate': cirq.TwoQubitMatrixGate(np.eye(4)), 'UNCONSTRAINED_DEVICE': cirq.UNCONSTRAINED_DEVICE, 'WaitGate': cirq.WaitGate(cirq.Duration(nanos=10)), '_QubitAsQid': [ cirq.NamedQubit('a').with_dimension(5), cirq.GridQubit(1, 2).with_dimension(1) ], 'XPowGate': cirq.X**0.123, 'XX': cirq.XX, 'XXPowGate': [cirq.XXPowGate(), cirq.XX**0.123], 'YPowGate': cirq.Y**0.456, 'YY': cirq.YY, 'YYPowGate': [cirq.YYPowGate(), cirq.YY**0.456], 'ZPowGate':
def _deserialize_gate_op( self, operation_proto: v2.program_pb2.Operation, *, arg_function_language: str = '', constants: Optional[List[v2.program_pb2.Constant]] = None, deserialized_constants: Optional[List[Any]] = None, ) -> cirq.Operation: """Deserialize an Operation from a cirq_google.api.v2.Operation. Args: operation_proto: A dictionary representing a cirq.google.api.v2.Operation proto. arg_function_language: The `arg_function_language` field from `Program.Language`. constants: The list of Constant protos referenced by constant table indices in `proto`. deserialized_constants: The deserialized contents of `constants`. cirq_google.api.v2.Operation proto. Returns: The deserialized Operation. """ if deserialized_constants is not None: qubits = [ deserialized_constants[q] for q in operation_proto.qubit_constant_index ] else: qubits = [] for q in operation_proto.qubits: # Preserve previous functionality in case # constants table was not used qubits.append(v2.qubit_from_proto_id(q.id)) which_gate_type = operation_proto.WhichOneof('gate_value') if which_gate_type == 'xpowgate': op = cirq.XPowGate(exponent=arg_func_langs.float_arg_from_proto( operation_proto.xpowgate.exponent, arg_function_language=arg_function_language, required_arg_name=None, ))(*qubits) elif which_gate_type == 'ypowgate': op = cirq.YPowGate(exponent=arg_func_langs.float_arg_from_proto( operation_proto.ypowgate.exponent, arg_function_language=arg_function_language, required_arg_name=None, ))(*qubits) elif which_gate_type == 'zpowgate': op = cirq.ZPowGate(exponent=arg_func_langs.float_arg_from_proto( operation_proto.zpowgate.exponent, arg_function_language=arg_function_language, required_arg_name=None, ))(*qubits) if operation_proto.zpowgate.is_physical_z: op = op.with_tags(PhysicalZTag()) elif which_gate_type == 'phasedxpowgate': exponent = arg_func_langs.float_arg_from_proto( operation_proto.phasedxpowgate.exponent, arg_function_language=arg_function_language, required_arg_name=None, ) phase_exponent = arg_func_langs.float_arg_from_proto( operation_proto.phasedxpowgate.phase_exponent, arg_function_language=arg_function_language, required_arg_name=None, ) op = cirq.PhasedXPowGate(exponent=exponent, phase_exponent=phase_exponent)(*qubits) elif which_gate_type == 'phasedxzgate': x_exponent = arg_func_langs.float_arg_from_proto( operation_proto.phasedxzgate.x_exponent, arg_function_language=arg_function_language, required_arg_name=None, ) z_exponent = arg_func_langs.float_arg_from_proto( operation_proto.phasedxzgate.z_exponent, arg_function_language=arg_function_language, required_arg_name=None, ) axis_phase_exponent = arg_func_langs.float_arg_from_proto( operation_proto.phasedxzgate.axis_phase_exponent, arg_function_language=arg_function_language, required_arg_name=None, ) op = cirq.PhasedXZGate( x_exponent=x_exponent, z_exponent=z_exponent, axis_phase_exponent=axis_phase_exponent, )(*qubits) elif which_gate_type == 'czpowgate': op = cirq.CZPowGate(exponent=arg_func_langs.float_arg_from_proto( operation_proto.czpowgate.exponent, arg_function_language=arg_function_language, required_arg_name=None, ))(*qubits) elif which_gate_type == 'iswappowgate': op = cirq.ISwapPowGate( exponent=arg_func_langs.float_arg_from_proto( operation_proto.iswappowgate.exponent, arg_function_language=arg_function_language, required_arg_name=None, ))(*qubits) elif which_gate_type == 'fsimgate': theta = arg_func_langs.float_arg_from_proto( operation_proto.fsimgate.theta, arg_function_language=arg_function_language, required_arg_name=None, ) phi = arg_func_langs.float_arg_from_proto( operation_proto.fsimgate.phi, arg_function_language=arg_function_language, required_arg_name=None, ) if isinstance(theta, (float, sympy.Basic)) and isinstance( phi, (float, sympy.Basic)): op = cirq.FSimGate(theta=theta, phi=phi)(*qubits) else: raise ValueError( 'theta and phi must be specified for FSimGate') elif which_gate_type == 'measurementgate': key = arg_func_langs.arg_from_proto( operation_proto.measurementgate.key, arg_function_language=arg_function_language, required_arg_name=None, ) invert_mask = arg_func_langs.arg_from_proto( operation_proto.measurementgate.invert_mask, arg_function_language=arg_function_language, required_arg_name=None, ) if isinstance(invert_mask, list) and isinstance(key, str): op = cirq.MeasurementGate( num_qubits=len(qubits), key=key, invert_mask=tuple(invert_mask))(*qubits) else: raise ValueError( f'Incorrect types for measurement gate {invert_mask} {key}' ) elif which_gate_type == 'waitgate': total_nanos = arg_func_langs.float_arg_from_proto( operation_proto.waitgate.duration_nanos, arg_function_language=arg_function_language, required_arg_name=None, ) op = cirq.WaitGate(duration=cirq.Duration(nanos=total_nanos))( *qubits) else: raise ValueError( f'Unsupported serialized gate with type "{which_gate_type}".' f'\n\noperation_proto:\n{operation_proto}') which = operation_proto.WhichOneof('token') if which == 'token_constant_index': if not constants: raise ValueError('Proto has references to constants table ' 'but none was passed in, value =' f'{operation_proto}') op = op.with_tags( CalibrationTag(constants[ operation_proto.token_constant_index].string_value)) elif which == 'token_value': op = op.with_tags(CalibrationTag(operation_proto.token_value)) return op
def build_otoc_circuits( qubits: Sequence[cirq.GridQubit], ancilla: cirq.GridQubit, cycle: int, interaction_sequence: Sequence[Set[Tuple[cirq.GridQubit, cirq.GridQubit]]], forward_ops: Union[_GATE_CORRECTIONS, List[_GATE_CORRECTIONS]], reverse_ops: Union[_GATE_CORRECTIONS, List[_GATE_CORRECTIONS]], butterfly_qubits: Union[cirq.GridQubit, Sequence[cirq.GridQubit]], cycles_per_echo: Optional[int] = None, random_seed: Optional[int] = None, sq_gates: Optional[np.ndarray] = None, cz_correction: Optional[Dict[Tuple[cirq.GridQubit, cirq.GridQubit], cirq.Circuit]] = None, use_physical_cz: bool = False, light_cone_filter: bool = False, cliffords: bool = False, z_only: bool = False, padding: Optional[float] = None, layer_by_layer_cal: bool = False, idle_echo_frequency: int = 1, ) -> OTOCCircuits: r"""Build experimental circuits for measuring OTOCs. A random circuit, $U$, composed of alternating layers of random single-qubit gates and fixed two-qubit gates is first created, similar to those used in an XEB experiment. The inverse of the random circuit, $U^\dagger$, is also created and added after $U$. A perturbation, in the form of Pauli operators I, X, Y, or Z on one or more 'butterfly' qubits, is added between $U$ and $U^\dagger$. An ancilla qubit interacts with one qubit in the system through a CZ gate at the beginning and the end of the quantum circuit, and single-qubit readout on the ancilla is performed at the end of the quantum circuit. Args: qubits: The qubits involved in the random circuits $U$ and $U^\dagger$. ancilla: The ancilla qubit to measure OTOC with. cycle: The number of interleaved single- and two-qubit gate layers in $U$ (same in $U^\dagger$). interaction_sequence: Qubit pairs that interact in each cycle. If the number of cycles is larger than len(interaction_sequence), the interacting qubit pairs will repeat themselves every len(interaction_sequence) cycles. forward_ops: The two-qubit gates assigned to each qubit pair in $U$. Each two-qubit gate is represented as a cirq.Circuit. It could be a circuit made of a single gate such as cirq.CZ, or a collection of gates such as cirq.CZ with multiple cirq.Z gates (which may be obtained from e.g. parallel-xeb calibrations). If specified as a list (must have a length equal to cycle), each cycle will use gates contained in the corresponding element of the list. reverse_ops: The two-qubit gates assigned to each qubit pair in $U^\dagger$, having the same format as forward_ops. butterfly_qubits: The qubits to which a perturbation between $U$ and $U^\dagger$ is to be applied. cycles_per_echo: How often a spin-echo pulse (a Y gate) is to be applied to the ancilla during its idling time. For example, if specified to be 2, a Y gate is applied every two cycles. random_seed: The seed for the random single-qubit gates. If unspecified, no seed will be used. sq_gates: Indices for the random single-qubit gates. Dimension should be len(qubits) $\times$ cycle. The values should be integers from 0 to 7 if z_only is False, and floats between -1 and 1 if z_only is True. cz_correction: Correction to the composite CZ gate, obtained from parallel-XEB. If unspecified, the ideal decomposition for CZ into sqrt-iSWAP and single-qubit gates will be used. use_physical_cz: If True, a direct CZ gate will be used (instead of composite gate from sqrt-iSWAP and single-qubit gates). light_cone_filter: If True, gates outside the light-cones of the butterfly qubit(s) will be removed and replaced with spin-echo gates. Gates outside the light-cone of the measurement qubit (i.e. qubits[0]) will be completely removed. cliffords: If True (and sq_gates is unspecified), Clifford gates drawn randomly from +/-X/2 and +/-Y/2 will be used for the single-qubit gates. z_only: If True, only Z gates (with a random exponent between -1 and 1) will be used for the random single-qubit gates. padding: If specified, a delay with the given value (in nano-seconds) will be added between $U$ and $U^\dagger$. layer_by_layer_cal: If True, the two-qubit gates in forward_ops and reverse_ops are different in each layer (i.e. forward_ops and reverse_ops are specified as List[ _GATE_CORRECTIONS]). idle_echo_frequency: How often spin-echo pulses (random +/-X or +/-Y gates) are applied to qubits outside the light-cones of the butterfly qubit(s). Has no effect if light_cone_filter is False. Returns: An OTOCCircuits containing the following fields: butterfly_I: 4 OTOC circuits with I as the butterfly operator (i.e. normalization circuits). butterfly_X: 4 OTOC circuits with X as the butterfly operator. butterfly_Y: 4 OTOC circuits with Y as the butterfly operator. butterfly_Z: 4 OTOC circuits with Z as the butterfly operator. For each case, the OTOC measurement result is $(p_0 - p_1 - p_2 + p_3) / 2$, where $p_i$ is the excited state probability of the $i^\text{th}$ circuit for the corresponding butterfly operator. """ if cliffords and z_only: raise ValueError("cliffords and z_only cannot both be True") num_ops = len(interaction_sequence) num_qubits = len(qubits) multi_b = True if np.ndim(butterfly_qubits) == 1 else False # Specify the random single-qubit gates (rand_num) in term of random # np.ndarray. The inverse of the single-qubit gates (rand_nums_rev) is # also specified. random_state = cirq.value.parse_random_state(random_seed) if sq_gates is not None: rand_nums = sq_gates[:, 0:cycle] else: if cliffords: rand_nums = random_state.choice(4, (num_qubits, cycle)) * 2 elif z_only: rand_nums = random_state.uniform(-1, 1, (num_qubits, cycle)) else: rand_nums = random_state.choice(8, (num_qubits, cycle)) rand_nums_rev = _reverse_sq_indices(rand_nums, z_only=z_only) # Specify the quantum circuits $U$ and $U^\dagger$ if no lightcone filter # is applied. if not light_cone_filter: moments_for = _compile_moments(interaction_sequence, forward_ops, layer_by_layer_cal=layer_by_layer_cal) moments_back_0 = _compile_moments( interaction_sequence, reverse_ops, layer_by_layer_cal=layer_by_layer_cal) end_layer = (cycle - 1) % num_ops moments_back = list(moments_back_0[end_layer::-1]) moments_back.extend(list(moments_back_0[-1:end_layer:-1])) circuits_forward, _ = build_xeb_circuits( qubits, [cycle], moments_for, sq_rand_nums=rand_nums, z_only=z_only, ancilla=ancilla, cycles_per_echo=cycles_per_echo, ) circuits_backward, _ = build_xeb_circuits( qubits, [cycle], moments_back, sq_rand_nums=rand_nums_rev, z_only=False, ancilla=ancilla, cycles_per_echo=cycles_per_echo, reverse=True, ) # Specify the quantum circuits $U$ and $U^\dagger$ if lightcone filter # is applied. else: light_cone_u = _extract_light_cone( butterfly_qubits, cycle, interaction_sequence, reverse=False, from_right=True, multiple_butterflies=multi_b, ) light_cone_u_dagger = _extract_light_cone( butterfly_qubits, cycle, interaction_sequence, reverse=True, from_right=False, multiple_butterflies=multi_b, ) light_cone_meas = _extract_light_cone( qubits[0], cycle, interaction_sequence, reverse=True, from_right=True, multiple_butterflies=False, ) full_cone = [*light_cone_u, *light_cone_u_dagger] idle_echo_indices = np.zeros((num_qubits, cycle * 2), dtype=int) for idx, qubit in enumerate(qubits): idle_cycles = [] for i, cone in enumerate(full_cone): if qubit not in cone: idle_cycles.append(i) echo_locs = list( range(idle_echo_frequency - 1, len(idle_cycles), idle_echo_frequency)) if len(echo_locs) % 2 == 1: echo_locs.remove(echo_locs[-1]) rand_echoes = random_state.choice(4, int(len(echo_locs) / 2)) + 1 for k, echo_idx in enumerate(rand_echoes): idle_echo_indices[idx, idle_cycles[echo_locs[2 * k]]] = echo_idx idle_echo_indices[ idx, idle_cycles[echo_locs[2 * k + 1]]] = (echo_idx + 1) % 4 + 1 echo_indices_for = idle_echo_indices[:, 0:cycle] echo_indices_back = idle_echo_indices[:, cycle:(2 * cycle)] seq_for, seq_back = _compile_interactions(qubits[0], butterfly_qubits, cycle, interaction_sequence) moments_for = _compile_moments(seq_for, forward_ops, layer_by_layer_cal=layer_by_layer_cal) moments_back = _compile_moments(seq_back, reverse_ops, layer_by_layer_cal=layer_by_layer_cal) circuits_forward, _ = build_xeb_circuits( qubits, [cycle], moments_for, sq_rand_nums=rand_nums, z_only=z_only, ancilla=ancilla, cycles_per_echo=cycles_per_echo, light_cones=[light_cone_u], echo_indices=echo_indices_for, ) circuits_backward, _ = build_xeb_circuits( qubits, [cycle], moments_back, sq_rand_nums=rand_nums_rev, z_only=z_only, ancilla=ancilla, cycles_per_echo=cycles_per_echo, reverse=True, light_cones=[light_cone_u_dagger, light_cone_meas], echo_indices=echo_indices_back, ) butterfly_ops = [None, cirq.X, cirq.Y, cirq.Z] prep_phases = [0.0, 1.0] meas_phases = [0.0, 1.0] otoc_circuit_list = [] # Combine $U$ and $U^\dagger$ with other gates related to SPAM to # complete the OTOC circuits. for b_ops, p_prep, p_meas in itertools.product(butterfly_ops, prep_phases, meas_phases): # Initialize the ancilla with +/-X/2 gate, all other qubits with a Y/2 # gate, and then a CZ gate between the ancilla and the first # (measurement) qubit. init_ops = [ cirq.PhasedXPowGate(phase_exponent=p_prep, exponent=0.5)(ancilla), cirq.Y(qubits[0])**0.5, ] circuit_full = cirq.Circuit(init_ops) # CZ is either a single pulse or a composite gate made from # sqrt-iSWAP and single-qubit gates. if use_physical_cz: circuit_full.append(cirq.CZ(ancilla, qubits[0])) additional_layer = [] else: cz_seq = cz_to_sqrt_iswap(ancilla, qubits[0], corrections=cz_correction) circuit_full.append(cz_seq[:-1]) additional_layer = cz_seq[-1:] # If z_only is True, the system is initialized in a half-filling # state, i.e. a basis state of the form |01010101...>. Otherwise the # system is initialized into a superposition state |+++++...>. if z_only: for q in qubits[1:]: if (q.row + q.col) % 2 == 0: additional_layer.append(cirq.Y(q)) else: additional_layer.append([cirq.Y(q)**0.5 for q in qubits[1:]]) circuit_full.append(additional_layer) circuit_full.append(circuits_forward[0]) # Adds a waiting period (in ns) between $U$ and $U^\dagger$, # if specified. if padding is not None: moment_pad = cirq.Moment([ cirq.WaitGate(duration=cirq.Duration(nanos=padding))(q) for q in qubits ]) circuit_full.append(moment_pad) # Add the butterfly operator. if b_ops is not None: if multi_b is True: b_mom = cirq.Moment([b_ops(q_b) for q_b in butterfly_qubits]) circuit_full.append(b_mom) else: circuit_full.append(b_ops(butterfly_qubits), strategy=cirq.InsertStrategy.NEW) circuit_full.append(circuits_backward[0]) # Add the CZ gate between ancilla and measurement qubit before # projective measurement. if use_physical_cz: circuit_full.append(cirq.CZ(ancilla, qubits[0])) else: circuit_full.append( cz_to_sqrt_iswap(ancilla, qubits[0], corrections=cz_correction)) # Pulse the ancilla to the z-axis (along either +z or -z) before # measurement. circuit_full.append( cirq.PhasedXPowGate(phase_exponent=p_meas, exponent=0.5)(ancilla)) circuit_full.append(cirq.measure(ancilla, key="z"), strategy=cirq.InsertStrategy.NEW) otoc_circuit_list.append(circuit_full) return OTOCCircuits( butterfly_I=otoc_circuit_list[0:4], butterfly_X=otoc_circuit_list[4:8], butterfly_Y=otoc_circuit_list[8:12], butterfly_Z=otoc_circuit_list[12:16], )
def test_resolve_parameters(num_qubits: int) -> None: gate = cirq.WaitGate(duration=cirq.Duration(nanos=sympy.Symbol('t_ns')), num_qubits=num_qubits) resolved = cirq.resolve_parameters(gate, {'t_ns': 10}) assert resolved.duration == cirq.Duration(nanos=10) assert cirq.num_qubits(resolved) == num_qubits
def test_str(): assert str(cirq.WaitGate(cirq.Duration(nanos=5))) == 'WaitGate(5 ns)'
( cirq.FSimGate(theta=2, phi=1)(Q0, Q1), op_proto({ 'fsimgate': { 'theta': { 'float_value': 2.0 }, 'phi': { 'float_value': 1.0 } }, 'qubit_constant_index': [0, 1], }), ), ( cirq.WaitGate(duration=cirq.Duration(nanos=15))(Q0), op_proto({ 'waitgate': { 'duration_nanos': { 'float_value': 15 } }, 'qubit_constant_index': [0], }), ), ( cirq.MeasurementGate(num_qubits=2, key='iron', invert_mask=(True, False))(Q0, Q1), op_proto({ 'measurementgate': {
def test_eq(): eq = cirq.testing.EqualsTester() eq.add_equality_group(cirq.WaitGate(0), cirq.WaitGate(cirq.Duration())) eq.make_equality_group(lambda: cirq.WaitGate(cirq.Duration(nanos=4)))