def assert_optimizes( before: cirq.Circuit, expected: cirq.Circuit, pre_opts: Iterable[cirq.OptimizationPass] = (cg.ConvertToXmonGates( ignore_failures=True), ), post_opts: Iterable[cirq.OptimizationPass] = (cg.ConvertToXmonGates( ignore_failures=True), cirq.DropEmptyMoments())): opt = cg.EjectZ() if cirq.has_unitary(before): cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( before, expected, atol=1e-8) circuit = before.copy() for pre in pre_opts: pre.optimize_circuit(circuit) opt.optimize_circuit(circuit) for post in post_opts: post.optimize_circuit(circuit) post.optimize_circuit(expected) cirq.testing.assert_same_circuits(circuit, expected) # And it should be idempotent. opt.optimize_circuit(circuit) cirq.testing.assert_same_circuits(circuit, expected)
def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit, **kwargs): """Check that optimizing the circuit ``before`` produces the circuit ``expected``. The optimized circuit is cleaned up with follow up optimizations to make the comparison more robust to extra moments or extra gates nearly equal to identity that don't matter. Args: before: The input circuit to optimize. expected: The expected result of optimization to compare against. kwargs: Any extra arguments to pass to the ``MergeInteractionsToSqrtIswap`` constructor. """ actual = before.copy() opt = cirq.MergeInteractionsToSqrtIswap(**kwargs) opt.optimize_circuit(actual) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations: List[Callable[[cirq.Circuit], None]] = [ cirq.merge_single_qubit_gates_into_phased_x_z, cirq.EjectPhasedPaulis().optimize_circuit, cirq.EjectZ().optimize_circuit, cirq.DropNegligible().optimize_circuit, cirq.DropEmptyMoments().optimize_circuit, ] for post in followup_optimizations: post(actual) post(expected) assert actual == expected, f'ACTUAL {actual} : EXPECTED {expected}'
def test_post_clean_up(): class Marker(cirq.TwoQubitGate): pass a, b = cirq.LineQubit.range(2) c_orig = cirq.Circuit.from_ops( cirq.CZ(a, b), cirq.CZ(a, b), cirq.CZ(a, b), cirq.CZ(a, b), cirq.CZ(a, b), ) circuit = cirq.Circuit(c_orig) def clean_up(operations): yield Marker()(a, b) yield operations yield Marker()(a, b) optimizer = cirq.MergeInteractions(allow_partial_czs=False, post_clean_up=clean_up) optimizer.optimize_circuit(circuit) cirq.DropEmptyMoments().optimize_circuit(circuit) assert isinstance(circuit[0].operations[0].gate, Marker) assert isinstance(circuit[-1].operations[0].gate, Marker) u_before = c_orig.unitary() u_after = circuit[1:-1].unitary() cirq.testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-8)
def assert_optimizes( before: cirq.Circuit, expected: cirq.Circuit, pre_opts: Iterable[cirq.OptimizationPass] = (cg.ConvertToXmonGates( ignore_failures=True), ), post_opts: Iterable[cirq.OptimizationPass] = (cg.ConvertToXmonGates( ignore_failures=True), cirq.DropEmptyMoments())): opt = cg.EjectZ() circuit = before.copy() for pre in pre_opts: pre.optimize_circuit(circuit) opt.optimize_circuit(circuit) for post in post_opts: post.optimize_circuit(circuit) post.optimize_circuit(expected) if circuit != expected: # coverage: ignore print("BEFORE") print(before) print("AFTER") print(circuit) print("EXPECTED") print(expected) assert circuit == expected # And it should be idempotent. opt.optimize_circuit(circuit) assert circuit == expected
def assert_optimizes( before: cirq.Circuit, expected: cirq.Circuit, optimizer: Optional[Callable[[cirq.Circuit], None]] = None): if optimizer is None: optimizer = cirq.MergeSingleQubitGates().optimize_circuit optimizer(before) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations = [ cirq.DropNegligible(), cirq.DropEmptyMoments() ] for post in followup_optimizations: post(before) # type: ignore # error: "object" not callable post(expected) # type: ignore # error: "object" not callable try: assert before == expected except AssertionError: # coverage: ignore # coverage: ignore print("BEFORE") print(before) print("EXPECTED") print(expected) raise
def test_tensor_density_matrix_gridqubit(): qubits = cirq.GridQubit.rect(2, 2) circuit = cirq.testing.random_circuit(qubits=qubits, n_moments=10, op_density=0.8) cirq.DropEmptyMoments().optimize_circuit(circuit) noise_model = cirq.ConstantQubitNoiseModel(cirq.DepolarizingChannel(p=1e-3)) circuit = cirq.Circuit(noise_model.noisy_moments(circuit.moments, qubits)) rho1 = cirq.final_density_matrix(circuit, dtype=np.complex128) rho2 = ccq.tensor_density_matrix(circuit, qubits) np.testing.assert_allclose(rho1, rho2, atol=1e-8)
def assert_equal_mod_empty(expected, actual): drop_empty = cirq.DropEmptyMoments() drop_empty.optimize_circuit(actual) if expected != actual: # coverage: ignore print('EXPECTED') print(expected) print('ACTUAL') print(actual) assert expected == actual
def optimize(c): cirq.ConvertToCzAndSingleGates().optimize_circuit(circuit=c) cirq.MergeSingleQubitGates().optimize_circuit(circuit=c) cirq.EjectZ().optimize_circuit(circuit=c) cirq.EjectPhasedPaulis().optimize_circuit(circuit=c) cirq.MergeSingleQubitGates().optimize_circuit(circuit=c) cirq.DropNegligible().optimize_circuit(circuit=c) cirq.DropEmptyMoments().optimize_circuit(circuit=c) c2=cirq.Circuit() for g in c: for g2 in g: # print(g2) c2.append(g2,strategy=cirq.InsertStrategy.EARLIEST) return c2
def test_swap(): a, b = cirq.LineQubit.range(2) original = cirq.Circuit.from_ops([cirq.Rz(.123).on(a), cirq.SWAP(a, b)]) optimized = original.copy() cirq.EjectZ().optimize_circuit(optimized) cirq.DropEmptyMoments().optimize_circuit(optimized) assert optimized[0].operations == (cirq.SWAP(a, b),) # Note: EjectZ drops `global_phase` from Rz turning it into a Z assert optimized[1].operations == (cirq.Z(b)**(.123 / np.pi),) cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(original), cirq.unitary(optimized), atol=1e-8)
def test_drop_negligible(): q0, = _make_qubits(1) sym = cirq.Symbol('a') circuit = cirq.Circuit.from_ops( PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**0.25, PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**1e-10, PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**sym, ) expected = cirq.Circuit.from_ops( PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**0.25, PauliStringPhasor(cirq.PauliString({q0: cirq.Z}))**sym, ) cirq.DropNegligible().optimize_circuit(circuit) cirq.DropEmptyMoments().optimize_circuit(circuit) assert circuit == expected
def assert_optimizes( before: cirq.Circuit, expected: cirq.Circuit, optimizer: Optional[Callable[[cirq.Circuit], None]] = None, ): if optimizer is None: optimizer = cirq.MergeSingleQubitGates().optimize_circuit optimizer(before) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations = [cirq.DropNegligible(), cirq.DropEmptyMoments()] for post in followup_optimizations: post(before) # type: ignore # error: "object" not callable post(expected) # type: ignore # error: "object" not callable assert before == expected, 'BEFORE:\n{}\nEXPECTED:\n{}'.format(before, expected)
def compile_to_syc(circuit: cirq.Circuit, *, mutate=False) -> cirq.Circuit: """Compile a QAOA circuit to SYC gates. Args: circuit: The circuit mutate: By default, return a copy of the circuit. Otherwise, mutate in place. """ if mutate: c2 = circuit else: c2 = circuit.copy() _TwoQubitOperationsAsSYC().optimize_circuit(c2) _SingleQubitGates().optimize_circuit(c2) cirq.DropEmptyMoments().optimize_circuit(c2) return c2
def assert_optimizes(before, after, optimizer=None): if optimizer is None: optimizer = cirq.google.MergeRotations() optimizer.optimize_circuit(before) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations = [cirq.DropNegligible(), cirq.DropEmptyMoments()] for post in followup_optimizations: post.optimize_circuit(before) post.optimize_circuit(after) if before != after: # coverage: ignore print("before:", before) print("after:", after) assert before == after
def compile_single_qubit_gates(circuit: cirq.Circuit, *, mutate=False) -> cirq.Circuit: """Compile single qubit gates to constant-depth PhX and Z gates Args: circuit: The circuit mutate: By default, return a copy of the circuit. Otherwise, mutate in place. """ if mutate: c2 = circuit else: c2 = circuit.copy() _SingleQubitGates().optimize_circuit(c2) cirq.DropEmptyMoments().optimize_circuit(c2) return c2
def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit): actual = cirq.Circuit(before) opt = cirq.MergeInteractions() opt.optimize_circuit(actual) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations: List[Callable[[cirq.Circuit], None]] = [ cirq.merge_single_qubit_gates_into_phased_x_z, cirq.EjectPhasedPaulis().optimize_circuit, cirq.EjectZ().optimize_circuit, cirq.DropNegligible().optimize_circuit, cirq.DropEmptyMoments().optimize_circuit, ] for post in followup_optimizations: post(actual) post(expected) assert actual == expected, f'ACTUAL {actual} : EXPECTED {expected}'
def compile_out_virtual_z(circuit: cirq.Circuit, *, mutate=False) -> cirq.Circuit: """Eject Z gates from the circuit. This is a wrapper around cirq.EjectZ() Args: circuit: The circuit mutate: By default, return a copy of the circuit. Otherwise, mutate in place. """ if mutate: c2 = circuit else: c2 = circuit.copy() cirq.EjectZ().optimize_circuit(c2) cirq.DropEmptyMoments().optimize_circuit(c2) return c2
def test_rewrite(): q0 = cirq.LineQubit(0) q1 = cirq.LineQubit(1) circuit = cirq.Circuit.from_ops( cirq.X(q0), cirq.X(q1), cirq.Y(q0), cirq.CZ(q0, q1), cirq.Y(q1), ) cirq.MergeSingleQubitGates( rewriter=lambda ops: cirq.H(ops[0].qubits[0]) ).optimize_circuit(circuit) cirq.DropEmptyMoments().optimize_circuit(circuit) cirq.testing.assert_same_circuits(circuit, cirq.Circuit.from_ops( cirq.H(q0), cirq.H(q1), cirq.CZ(q0, q1), cirq.H(q1), ))
def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit, optimizer: cirq.OptimizationPass = None): if optimizer is None: optimizer = cirq.MergeSingleQubitGates() optimizer.optimize_circuit(before) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations = [cirq.DropNegligible(), cirq.DropEmptyMoments()] for post in followup_optimizations: post.optimize_circuit(before) post.optimize_circuit(expected) try: assert before == expected except AssertionError: # coverage: ignore # coverage: ignore print("BEFORE") print(before) print("EXPECTED") print(expected) raise
def compile_to_non_negligible(circuit: cirq.Circuit, *, tolerance=1e-5, mutate=False) -> cirq.Circuit: """Remove negligible gates from the circuit. This is a wrapper around cirq.DropNegligible(tolerance) Args: circuit: The circuit tolerance: Gates with trace distance below this value will be considered negligible. mutate: By default, return a copy of the circuit. Otherwise, mutate in place. """ if mutate: c2 = circuit else: c2 = circuit.copy() cirq.DropNegligible(tolerance=tolerance).optimize_circuit(c2) cirq.DropEmptyMoments().optimize_circuit(c2) return c2
def simplify_expectation_value_circuit(circuit_sand: cirq.Circuit): """For low weight operators on low-degree circuits, we can simplify the circuit representation of an expectation value. In particular, this should be used on `circuit_for_expectation_value` circuits. It will merge single- and two-qubit gates from the "forwards" and "backwards" parts of the circuit outside of the operator's lightcone. This might be too slow in practice and you can just use quimb to simplify things for you. """ n_op = sum(1 for _ in circuit_sand.all_operations()) while True: MergeNQubitGates(n_qubits=1).optimize_circuit(circuit_sand) cirq.DropNegligible(tolerance=1e-6).optimize_circuit(circuit_sand) MergeNQubitGates(n_qubits=2).optimize_circuit(circuit_sand) cirq.DropNegligible(tolerance=1e-6) cirq.DropEmptyMoments().optimize_circuit(circuit_sand) new_n_op = sum(1 for _ in circuit_sand.all_operations()) if new_n_op < n_op: n_op = new_n_op else: return
def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit): actual = cirq.Circuit(before) opt = cirq.MergeInteractions() opt.optimize_circuit(actual) # Ignore differences that would be caught by follow-up optimizations. followup_optimizations = [ cg.MergeRotations(), cg.EjectFullW(), cg.EjectZ(), cirq.DropNegligible(), cirq.DropEmptyMoments() ] for post in followup_optimizations: post.optimize_circuit(actual) post.optimize_circuit(expected) if actual != expected: # coverage: ignore print('ACTUAL') print(actual) print('EXPECTED') print(expected) assert actual == expected
def assert_equal_mod_empty(expected, actual): drop_empty = cirq.DropEmptyMoments() drop_empty.optimize_circuit(actual) assert expected == actual, f'EXPECTED {expected} : ACTUAL {actual}'
def assert_optimizes(before, after): with cirq.testing.assert_deprecated("Use cirq.drop_empty_moments", deadline='v1.0'): opt = cirq.DropEmptyMoments() opt.optimize_circuit(before) assert before == after
def zz_as_syc(theta: float, q0: cirq.Qid, q1: cirq.Qid) -> cirq.Circuit: """Return an Exp[i theta ZZ] circuit with two SYC gates.""" swz = cirq.Circuit(rzz(theta, q0, q1)) _SingleQubitGates().optimize_circuit(swz) cirq.DropEmptyMoments().optimize_circuit(swz) return swz
def assert_optimizes(before, after): opt = cirq.DropEmptyMoments() opt.optimize_circuit(before) assert before == after
def zzswap_as_syc(theta: float, q0: cirq.Qid, q1: cirq.Qid) -> cirq.Circuit: """Return a composite Exp[i theta ZZ] SWAP circuit with three SYC gates.""" swz = cirq.Circuit(swap_rzz(theta, q0, q1)) _SingleQubitGates().optimize_circuit(swz) cirq.DropEmptyMoments().optimize_circuit(swz) return swz