def test_decompose_tagged_operation(): op = cirq.TaggedOperation( cirq.CircuitOperation( circuit=cirq.FrozenCircuit( [ cirq.Moment( cirq.SWAP(cirq.LineQubit(0), cirq.LineQubit(1)), ), ] ), ), 'tag', ) assert cirq.decompose_once(op) == cirq.decompose_once(op.untagged)
def test_inhomogeneous_measurement_count_padding(): q = cirq.LineQubit(0) key = cirq.MeasurementKey('m') sim = cirq.Simulator() c = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit(cirq.X(q) ** 0.2, cirq.measure(q, key=key)), use_repetition_ids=False, repeat_until=cirq.KeyCondition(key), ) ) results = sim.run(c, repetitions=10) for i in range(10): assert np.sum(results.records['m'][i, :, :]) == 1
def test_mapped_circuit_keeps_keys_under_parent_path(): q = cirq.LineQubit(0) op1 = cirq.CircuitOperation( cirq.FrozenCircuit( cirq.measure(q, key='A'), cirq.measure_single_paulistring(cirq.X(q), key='B'), cirq.MixedUnitaryChannel.from_mixture(cirq.bit_flip(0.5), key='C').on(q), cirq.KrausChannel.from_channel(cirq.phase_damp(0.5), key='D').on(q), )) op2 = op1.with_key_path(('X', )) assert cirq.measurement_key_names( op2.mapped_circuit()) == {'X:A', 'X:B', 'X:C', 'X:D'}
def test_apply_tag_to_inverted_op_set(): q = cirq.LineQubit.range(2) op = cirq.CNOT(*q) tag = "tag_to_flip" c_orig = cirq.Circuit(op, op.with_tags(tag), cirq.CircuitOperation(cirq.FrozenCircuit(op))) # Toggle with deep = True. c_toggled = cirq.Circuit( op.with_tags(tag), op, cirq.CircuitOperation(cirq.FrozenCircuit(op.with_tags(tag)))) cirq.testing.assert_same_circuits( cirq.toggle_tags(c_orig, [tag], deep=True), c_toggled) cirq.testing.assert_same_circuits( cirq.toggle_tags(c_toggled, [tag], deep=True), c_orig) # Toggle with deep = False c_toggled = cirq.Circuit( op.with_tags(tag), op, cirq.CircuitOperation(cirq.FrozenCircuit(op)).with_tags(tag)) cirq.testing.assert_same_circuits( cirq.toggle_tags(c_orig, [tag], deep=False), c_toggled) cirq.testing.assert_same_circuits( cirq.toggle_tags(c_toggled, [tag], deep=False), c_orig)
def test_nonterminal_in_subcircuit(): a, b = cirq.LineQubit.range(2) fc = cirq.FrozenCircuit(cirq.H(a), cirq.measure(b, key='m1'), cirq.X(b)) op = cirq.CircuitOperation(fc) c = cirq.Circuit(cirq.X(a), op) assert isinstance(op, cirq.CircuitOperation) assert not c.are_all_measurements_terminal() assert not c.are_any_measurements_terminal() op = op.with_tags('test') c = cirq.Circuit(cirq.X(a), op) assert not isinstance(op, cirq.CircuitOperation) assert not c.are_all_measurements_terminal() assert not c.are_any_measurements_terminal()
def test_post_selection(sim): q = cirq.LineQubit(0) key = cirq.MeasurementKey('m') c = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit(cirq.X(q) ** 0.2, cirq.measure(q, key=key)), use_repetition_ids=False, repeat_until=cirq.KeyCondition(key), ) ) result = sim.run(c) assert result.records['m'][0][-1] == (1,) for i in range(len(result.records['m'][0]) - 1): assert result.records['m'][0][i] == (0,)
def test_serialize_circuit_op_errors(): serializer = cg.CircuitSerializer('my_gate_set') constants = [default_circuit_proto()] raw_constants = {default_circuit(): 0} op = cirq.CircuitOperation(default_circuit()) with pytest.raises(ValueError, match='CircuitOp serialization requires a constants list'): serializer._serialize_circuit_op(op) with pytest.raises(ValueError, match='CircuitOp serialization requires a constants list'): serializer._serialize_circuit_op(op, constants=constants) with pytest.raises(ValueError, match='CircuitOp serialization requires a constants list'): serializer._serialize_circuit_op(op, raw_constants=raw_constants)
def test_decompose_loops(): a, b = cirq.LineQubit.range(2) circuit = cirq.FrozenCircuit(cirq.H(a), cirq.CX(a, b)) base_op = cirq.CircuitOperation(circuit) op = base_op.with_qubits(b, a).repeat(3) expected_circuit = cirq.Circuit(cirq.H(b), cirq.CX(b, a), cirq.H(b), cirq.CX(b, a), cirq.H(b), cirq.CX(b, a)) assert cirq.Circuit(cirq.decompose_once(op)) == expected_circuit op = base_op.repeat(-2) expected_circuit = cirq.Circuit(cirq.CX(a, b), cirq.H(a), cirq.CX(a, b), cirq.H(a)) assert cirq.Circuit(cirq.decompose_once(op)) == expected_circuit
def test_repeat_zero_times(add_measurements, use_repetition_ids, initial_reps): q = cirq.LineQubit(0) subcircuit = cirq.Circuit(cirq.X(q)) if add_measurements: subcircuit.append(cirq.measure(q)) op = cirq.CircuitOperation(subcircuit.freeze(), repetitions=initial_reps, use_repetition_ids=use_repetition_ids) result = cirq.Simulator().simulate(cirq.Circuit(op)) assert np.allclose(result.state_vector(), [0, 1] if initial_reps % 2 else [1, 0]) result = cirq.Simulator().simulate(cirq.Circuit(op**0)) assert np.allclose(result.state_vector(), [1, 0])
def test_scope_extern_wrapping_with_non_repeating_subcircuits(): def wrap(*ops): return cirq.CircuitOperation(cirq.FrozenCircuit(*ops)) def wrap_frozen(*ops): return cirq.FrozenCircuit(wrap(*ops)) q = cirq.LineQubit(0) inner = wrap_frozen( wrap(cirq.measure(q, key='a')), wrap(cirq.X(q).with_classical_controls('b')), ) middle = wrap_frozen( wrap(cirq.measure(q, key=cirq.MeasurementKey('b'))), wrap(cirq.CircuitOperation(inner, repetitions=2)), ) outer_subcircuit = cirq.CircuitOperation(middle, repetitions=2) circuit = outer_subcircuit.mapped_circuit(deep=True) internal_control_keys = [ str(condition) for op in circuit.all_operations() for condition in cirq.control_keys(op) ] assert internal_control_keys == ['0:b', '0:b', '1:b', '1:b'] assert not cirq.control_keys(outer_subcircuit) assert not cirq.control_keys(circuit) cirq.testing.assert_has_diagram( circuit, """ 0: ─────M───M('0:0:a')───X───M('0:1:a')───X───M───M('1:0:a')───X───M('1:1:a')───X─── ║ ║ ║ ║ ║ ║ 0:b: ═══@════════════════^════════════════^═══╬════════════════╬════════════════╬═══ ║ ║ ║ 1:b: ═════════════════════════════════════════@════════════════^════════════════^═══ """, use_unicode_characters=True, ) assert circuit == cirq.Circuit(cirq.decompose(outer_subcircuit))
def test_scope_flatten_inner(): q = cirq.LineQubit(0) inner = cirq.Circuit(cirq.measure(q, key='a'), cirq.X(q).with_classical_controls('a')) middle = cirq.Circuit( cirq.CircuitOperation(inner.freeze(), repetitions=2, use_repetition_ids=False)) outer_subcircuit = cirq.CircuitOperation(middle.freeze(), repetitions=2) circuit = outer_subcircuit.mapped_circuit(deep=True) internal_control_keys = [ str(condition) for op in circuit.all_operations() for condition in cirq.control_keys(op) ] assert internal_control_keys == ['0:a', '0:a', '1:a', '1:a'] assert not cirq.control_keys(outer_subcircuit) assert not cirq.control_keys(circuit) cirq.testing.assert_has_diagram( cirq.Circuit(outer_subcircuit), """ [ [ 0: ───M───X─── ] ] 0: ───[ 0: ───[ ║ ║ ]──────────────────────── ]──────────── [ [ a: ═══@═══^═══ ](loops=2, no_rep_ids) ](loops=2) """, use_unicode_characters=True, ) cirq.testing.assert_has_diagram( circuit, """ 0: ─────M───X───M───X───M───X───M───X─── ║ ║ ║ ║ ║ ║ ║ ║ 0:a: ═══@═══^═══@═══^═══╬═══╬═══╬═══╬═══ ║ ║ ║ ║ 1:a: ═══════════════════@═══^═══@═══^═══ """, use_unicode_characters=True, )
def test_dephase(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.CX(q1, q0), cirq.measure(q0, key='a'), cirq.CX(q0, q1), cirq.measure(q1, key='b'), ))) dephased = cirq.dephase_measurements(circuit) cirq.testing.assert_same_circuits( dephased, cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.CX(q1, q0), cirq.KrausChannel.from_channel(cirq.phase_damp(1), key='a')(q0), cirq.CX(q0, q1), cirq.KrausChannel.from_channel(cirq.phase_damp(1), key='b')(q1), ))), )
def test_circuit_operation_conversion(): q0, q1 = cirq.LineQubit.range(2) subcircuit = cirq.FrozenCircuit(cirq.X(q0), cirq.SWAP(q0, q1)) circuit = cirq.Circuit(cirq.CircuitOperation(subcircuit)) converted_circuit = circuit.copy() cgoc.ConvertToSycamoreGates().optimize_circuit(converted_circuit) # Verify that the CircuitOperation was preserved. ops = list(converted_circuit.all_operations()) assert isinstance(ops[0], cirq.CircuitOperation) # Verify that the contents of the CircuitOperation were optimized. reconverted_subcircuit = ops[0].circuit.unfreeze().copy() cgoc.ConvertToSycamoreGates().optimize_circuit(reconverted_subcircuit) assert ops[0].circuit == reconverted_subcircuit cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, converted_circuit, atol=1e-8)
def get_ops(use_circuit_op, use_global_phase): q = cirq.LineQubit.range(3) yield [ CustomX(q[0]).with_tags('custom tags'), CustomX(q[1])**2, CustomX(q[2])**3 ] yield [CustomX(q[0])**0.5, cirq.testing.TwoQubitGate()(*q[:2])] if use_circuit_op: circuit_op = cirq.CircuitOperation( cirq.FrozenCircuit(get_ops(False, False)), repetitions=10).with_tags('circuit op tags') recursive_circuit_op = cirq.CircuitOperation( cirq.FrozenCircuit([circuit_op, CustomX(q[2])**0.5]), repetitions=10, qubit_map={ q[0]: q[1], q[1]: q[2], q[2]: q[0] }, ) yield [circuit_op, recursive_circuit_op] if use_global_phase: yield cirq.global_phase_operation(1j)
def test_layered_circuit_operations_with_controls_in_between(): q = cirq.LineQubit(0) outer_subcircuit = cirq.CircuitOperation( cirq.Circuit( cirq.CircuitOperation(cirq.FrozenCircuit( cirq.X(q), cirq.Y(q))).with_classical_controls('m')).freeze()) circuit = outer_subcircuit.mapped_circuit(deep=True) cirq.testing.assert_has_diagram( cirq.Circuit(outer_subcircuit), """ [ 0: ───[ 0: ───X───Y─── ].with_classical_controls(m)─── ] 0: ───[ ║ ]─── [ m: ═══╩═══════════════════════════════════════════════ ] ║ m: ═══╩════════════════════════════════════════════════════════════ """, use_unicode_characters=True, ) cirq.testing.assert_has_diagram( circuit, """ 0: ───[ 0: ───X───Y─── ].with_classical_controls(m)─── ║ m: ═══╩═══════════════════════════════════════════════ """, use_unicode_characters=True, ) cirq.testing.assert_has_diagram( cirq.Circuit(cirq.decompose(outer_subcircuit)), """ 0: ───X───Y─── ║ ║ m: ═══^═══^═══ """, use_unicode_characters=True, )
def test_with_measurement_keys(): a, b = cirq.LineQubit.range(2) circuit = cirq.FrozenCircuit(cirq.X(a), cirq.measure(b, key='mb'), cirq.measure(a, key='ma')) op_base = cirq.CircuitOperation(circuit) op_with_keys = op_base.with_measurement_key_mapping({'ma': 'pa', 'x': 'z'}) assert op_with_keys.base_operation() == op_base assert op_with_keys.measurement_key_map == {'ma': 'pa'} assert cirq.measurement_key_names(op_with_keys) == {'pa', 'mb'} assert cirq.with_measurement_key_mapping(op_base, {'ma': 'pa'}) == op_with_keys # Two measurement keys cannot be mapped onto the same target string. with pytest.raises(ValueError): _ = op_base.with_measurement_key_mapping({'ma': 'mb'})
def test_repeat_until_sympy(sim): q1, q2 = cirq.LineQubit.range(2) circuitop = cirq.CircuitOperation( cirq.FrozenCircuit(cirq.X(q2), cirq.measure(q2, key='b')), use_repetition_ids=False, repeat_until=cirq.SympyCondition(sympy.Eq(sympy.Symbol('a'), sympy.Symbol('b'))), ) c = cirq.Circuit(cirq.measure(q1, key='a'), circuitop) # Validate commutation assert len(c) == 2 assert cirq.control_keys(circuitop) == {cirq.MeasurementKey('a')} measurements = sim.run(c).records['b'][0] assert len(measurements) == 2 assert measurements[0] == (1,) assert measurements[1] == (0,)
def test_tag_propagation(): # Tags are not propagated from the CircuitOperation to its components. # TODO: support tag propagation for better serialization. a, b, c = cirq.LineQubit.range(3) circuit = cirq.FrozenCircuit(cirq.X(a), cirq.H(b), cirq.H(c), cirq.CZ(a, c)) op = cirq.CircuitOperation(circuit) test_tag = 'test_tag' op = op.with_tags(test_tag) assert test_tag in op.tags # TODO: Tags must propagate during decomposition. sub_ops = cirq.decompose(op) for op in sub_ops: assert test_tag not in op.tags
def test_drop_terminal_nonterminal_error(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit(cirq.measure(q0, q1, key='a~b', invert_mask=[0, 1]), cirq.CX(q0, q1)) ) ) with pytest.raises(ValueError, match='Circuit contains a non-terminal measurement'): _ = cirq.drop_terminal_measurements(circuit) with pytest.raises(ValueError, match='Context has `deep=False`'): _ = cirq.drop_terminal_measurements(circuit, context=cirq.TransformerContext(deep=False)) with pytest.raises(ValueError, match='Context has `deep=False`'): _ = cirq.drop_terminal_measurements(circuit, context=None)
def test_ideal_sqrt_iswap_simulates_correctly_invalid_circuit_fails(): engine_simulator = PhasedFSimEngineSimulator.create_with_ideal_sqrt_iswap() a, b = cirq.LineQubit.range(2) with pytest.raises(IncompatibleMomentError): circuit = cirq.Circuit([cirq.CZ.on(a, b)]) engine_simulator.simulate(circuit) with pytest.raises(IncompatibleMomentError): circuit = cirq.Circuit(cirq.global_phase_operation(coefficient=1.0)) engine_simulator.simulate(circuit) with pytest.raises(IncompatibleMomentError): circuit = cirq.Circuit(cirq.CircuitOperation(cirq.FrozenCircuit(cirq.X(a)))) engine_simulator.simulate(circuit)
def test_repetitions_and_ids_length_mismatch(): a, b, c = cirq.LineQubit.range(3) circuit = cirq.FrozenCircuit( cirq.X(a), cirq.Y(b), cirq.H(c), cirq.CX(a, b)**sympy.Symbol('exp'), cirq.measure(a, b, c, key='m'), ) with pytest.raises( ValueError, match='Expected repetition_ids to be a list of length 2'): _ = cirq.CircuitOperation(circuit, repetitions=2, repetition_ids=['a', 'b', 'c'])
def test_repeat_until(sim): q = cirq.LineQubit(0) key = cirq.MeasurementKey('m') c = cirq.Circuit( cirq.X(q), cirq.CircuitOperation( cirq.FrozenCircuit(cirq.X(q), cirq.measure(q, key=key)), use_repetition_ids=False, repeat_until=cirq.KeyCondition(key), ), ) measurements = sim.run(c).records['m'][0] assert len(measurements) == 2 assert measurements[0] == (0, ) assert measurements[1] == (1, )
def test_repeat_until_diagram(): q = cirq.LineQubit(0) key = cirq.MeasurementKey('m') c = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit(cirq.X(q)**0.2, cirq.measure(q, key=key)), use_repetition_ids=False, repeat_until=cirq.KeyCondition(key), )) cirq.testing.assert_has_diagram( c, """ 0: ───[ 0: ───X^0.2───M('m')─── ](no_rep_ids, until=m)─── """, use_unicode_characters=True, )
def test_key_set_in_subcircuit_outer_scope(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.X(q0), cirq.measure(q0, key='a'), ) # TODO (daxfohl): This will not need an InsertStrategy after scope PR. circuit.append( cirq.CircuitOperation( cirq.FrozenCircuit(cirq.X(q1).with_classical_controls('a'))), strategy=cirq.InsertStrategy.NEW, ) circuit.append(cirq.measure(q1, key='b')) result = cirq.Simulator().run(circuit) assert result.measurements['a'] == 1 assert result.measurements['b'] == 1
def test_decompose_preserving_structure_forwards_args(decompose_mode): a, b = cirq.LineQubit.range(2) fc1 = cirq.FrozenCircuit(cirq.SWAP(a, b), cirq.FSimGate(0.1, 0.2).on(a, b)) cop1_1 = cirq.CircuitOperation(fc1).with_tags('test_tag') cop1_2 = cirq.CircuitOperation(fc1).with_qubit_mapping({a: b, b: a}) fc2 = cirq.FrozenCircuit(cirq.X(a), cop1_1, cop1_2) cop2 = cirq.CircuitOperation(fc2) circuit = cirq.Circuit(cop2, cirq.measure(a, b, key='m')) def keep_func(op: 'cirq.Operation'): # Only decompose SWAP and X. return not isinstance(op.gate, (cirq.SwapPowGate, cirq.XPowGate)) def x_to_hzh(op: 'cirq.Operation'): if isinstance(op.gate, cirq.XPowGate) and op.gate.exponent == 1: return [ cirq.H(*op.qubits), cirq.Z(*op.qubits), cirq.H(*op.qubits), ] actual = cirq.Circuit( cirq.decompose( circuit, keep=keep_func, intercepting_decomposer=x_to_hzh if decompose_mode == 'intercept' else None, fallback_decomposer=x_to_hzh if decompose_mode == 'fallback' else None, preserve_structure=True, ), ) # This should keep the CircuitOperations but decompose their SWAPs. fc1_decomp = cirq.FrozenCircuit( cirq.decompose( fc1, keep=keep_func, fallback_decomposer=x_to_hzh, )) expected = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.H(a), cirq.Z(a), cirq.H(a), cirq.CircuitOperation(fc1_decomp).with_tags('test_tag'), cirq.CircuitOperation(fc1_decomp).with_qubit_mapping({ a: b, b: a }), )), cirq.measure(a, b, key='m'), ) assert actual == expected
def test_subcircuit_key_unset(sim): q0, q1 = cirq.LineQubit.range(2) inner = cirq.Circuit( cirq.measure(q0, key='c'), cirq.X(q1).with_classical_controls('c'), cirq.measure(q1, key='b'), ) circuit = cirq.Circuit( cirq.CircuitOperation(inner.freeze(), repetitions=2, measurement_key_map={'c': 'a'})) result = sim.run(circuit) assert result.measurements['0:a'] == 0 assert result.measurements['0:b'] == 0 assert result.measurements['1:a'] == 0 assert result.measurements['1:b'] == 0
def test_circuit_op_to_proto_errors(): serializer = cg.CircuitOpSerializer() to_serialize = cirq.CircuitOperation(default_circuit()) constants = [ v2.program_pb2.Constant(string_value=DEFAULT_TOKEN), v2.program_pb2.Constant(circuit_value=default_circuit_proto()), ] raw_constants = { DEFAULT_TOKEN: 0, default_circuit(): 1, } with pytest.raises( ValueError, match='CircuitOp serialization requires a constants list'): serializer.to_proto(to_serialize) with pytest.raises( ValueError, match='CircuitOp serialization requires a constants list'): serializer.to_proto(to_serialize, constants=constants) with pytest.raises( ValueError, match='CircuitOp serialization requires a constants list'): serializer.to_proto(to_serialize, raw_constants=raw_constants) with pytest.raises(ValueError, match='Serializer expected CircuitOperation'): serializer.to_proto(v2.program_pb2.Operation(), constants=constants, raw_constants=raw_constants) bad_raw_constants = {cirq.FrozenCircuit(): 0} with pytest.raises( ValueError, match='Encountered a circuit not in the constants table'): serializer.to_proto(to_serialize, constants=constants, raw_constants=bad_raw_constants) with pytest.raises(ValueError, match='Cannot serialize repetitions of type'): serializer.to_proto(to_serialize**sympy.Symbol('a'), constants=constants, raw_constants=raw_constants)
def test_circuit_op_to_proto_complex(): serializer = cg.CircuitOpSerializer() to_serialize = cirq.CircuitOperation( circuit=default_circuit(), qubit_map={cirq.GridQubit(1, 1): cirq.GridQubit(1, 2)}, measurement_key_map={'m': 'results'}, param_resolver={'k': 1.0j}, repetitions=10, repetition_ids=None, ) constants = [ v2.program_pb2.Constant(string_value=DEFAULT_TOKEN), v2.program_pb2.Constant(circuit_value=default_circuit_proto()), ] raw_constants = {DEFAULT_TOKEN: 0, default_circuit(): 1} with pytest.raises(ValueError, match='complex value'): serializer.to_proto(to_serialize, constants=constants, raw_constants=raw_constants)
def test_serialize_deserialize_circuit_op(): constants = [default_circuit_proto()] raw_constants = {default_circuit(): 0} deserialized_constants = [default_circuit()] proto = v2.program_pb2.CircuitOperation() proto.circuit_constant_index = 0 proto.repetition_specification.repetition_count = 1 op = cirq.CircuitOperation(default_circuit()) assert proto == MY_GATE_SET.serialize_op(op, constants=constants, raw_constants=raw_constants) assert (MY_GATE_SET.deserialize_op( proto, constants=constants, deserialized_constants=deserialized_constants) == op)
def test_decompose_loops_with_measurements(): a, b = cirq.LineQubit.range(2) circuit = cirq.FrozenCircuit(cirq.H(a), cirq.CX(a, b), cirq.measure(a, b, key='m')) base_op = cirq.CircuitOperation(circuit) op = base_op.with_qubits(b, a).repeat(3) expected_circuit = cirq.Circuit( cirq.H(b), cirq.CX(b, a), cirq.measure(b, a, key=cirq.MeasurementKey.parse_serialized('0:m')), cirq.H(b), cirq.CX(b, a), cirq.measure(b, a, key=cirq.MeasurementKey.parse_serialized('1:m')), cirq.H(b), cirq.CX(b, a), cirq.measure(b, a, key=cirq.MeasurementKey.parse_serialized('2:m')), ) assert cirq.Circuit(cirq.decompose_once(op)) == expected_circuit