def test_measure_with_final_permutation(p): problem = nx.complete_graph(n=5) problem = random_plus_minus_1_weights(problem) qubits = cirq.LineQubit.range(5) c1 = cirq.Circuit(cirq.H.on_each(qubits), [[ ProblemUnitary(problem, gamma=np.random.random()).on(*qubits), DriverUnitary(5, beta=np.random.random()).on(*qubits) ] for _ in range(p)]) c2 = compile_problem_unitary_to_swap_network(c1) c3 = compile_swap_network_to_zzswap(c2) c4 = compile_driver_unitary_to_rx(c3) c5 = compile_to_syc(c4) validate_well_structured(c5, allow_terminal_permutations=True) c6, final_qubits = measure_with_final_permutation(c5, qubits) validate_well_structured(c6, allow_terminal_permutations=False) if p % 2 == 1: assert final_qubits == qubits[::-1] else: assert final_qubits == qubits permutation = [] for q in qubits: permutation.append(final_qubits.index(q)) c1_prime = (c1 + QuirkQubitPermutationGate('', '', permutation).on(*qubits) + cirq.measure(*qubits, key='z')) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c1_prime, c6, atol=1e-5)
def test_compile_to_syc(p): problem = nx.complete_graph(n=5) problem = random_plus_minus_1_weights(problem) qubits = cirq.LineQubit.range(5) c1 = cirq.Circuit( cirq.H.on_each(qubits), [ [ ProblemUnitary(problem, gamma=np.random.random()).on(*qubits), DriverUnitary(5, beta=np.random.random()).on(*qubits) ] for _ in range(p) ] ) c2 = compile_problem_unitary_to_swap_network(c1) c3 = compile_swap_network_to_zzswap(c2) c4 = compile_driver_unitary_to_rx(c3) c5 = compile_to_syc(c4) validate_well_structured(c5, allow_terminal_permutations=True) np.testing.assert_allclose(c1.unitary(), c2.unitary()) np.testing.assert_allclose(c1.unitary(), c3.unitary()) np.testing.assert_allclose(c1.unitary(), c4.unitary()) # Single qubit throws out global phase cirq.testing.assert_allclose_up_to_global_phase( c1.unitary(), c5.unitary(), atol=1e-8)
def get_routed_hardware_grid_circuit( problem_graph: nx.Graph, qubits: List[cirq.Qid], coordinates: List[Tuple[int, int]], gammas: Sequence[float], betas: Sequence[float]) -> cirq.Circuit: """Return a QAOA circuit "routed" according to sequential activation of the four links in the degree-4 hardware graph. See Also: :py:func:`get_compiled_hardware_grid_circuit` Args: problem_graph: A graph with contiguous 0-indexed integer nodes and edges with a 'weight' attribute. qubits: The qubits to use in construction of the circuit. coordinates: A mapping from problem node to position on a 2D grid to help the "routing". gammas: Gamma angles to use as parameters for problem unitaries betas: Beta angles to use as parameters for driver unitaries """ circuit = get_generic_qaoa_circuit( problem_graph=problem_graph, qubits=qubits, gammas=gammas, betas=betas) circuit = compile_problem_unitary_to_hardware_graph(circuit, coordinates) circuit = compile_driver_unitary_to_rx(circuit) return circuit
def get_routed_3_regular_maxcut_circuit( problem_graph: nx.Graph, device: cg.XmonDevice, gammas: Sequence[float], betas: Sequence[float], ) -> Tuple[List[cirq.Qid], cirq.Circuit, List[cirq.Qid]]: """Get a routed QAOA circuit for a 3-regular problem. See Also: :py:func:`get_compiled_3_regular_maxcut_circuit` Args: problem_graph: A graph with contiguous 0-indexed integer nodes and edges with a 'weight' attribute. qubits: The qubits to use in construction of the circuit. gammas: Gamma angles to use as parameters for problem unitaries betas: Beta angles to use as parameters for driver unitaries """ dummy_qubits = cirq.LineQubit.range(problem_graph.number_of_nodes()) circuit = get_generic_qaoa_circuit( problem_graph=problem_graph, qubits=dummy_qubits, gammas=gammas, betas=betas) circuit = compile_problem_unitary_to_arbitrary_zz(circuit) circuit = compile_driver_unitary_to_rx(circuit) circuit, initial_qubit_map, final_qubit_map = place_on_device(circuit, device) initial_qubits = [initial_qubit_map[q] for q in dummy_qubits] final_qubits = [final_qubit_map[q] for q in dummy_qubits] return initial_qubits, circuit, final_qubits
def test_compile_driver_unitary_to_rx(): n = 5 q = cirq.LineQubit.range(n) c1 = cirq.Circuit(DriverUnitary(num_qubits=n, beta=0.123).on(*q)) c2 = cirq.Circuit(cirq.rx(2 * 0.123).on_each(*q)) c3 = compile_driver_unitary_to_rx(c1) u1 = c1.unitary() u2 = c2.unitary() u3 = c3.unitary() np.testing.assert_allclose(u1, u2) np.testing.assert_allclose(u1, u3)
def test_place_on_device(): problem_graph = nx.random_regular_graph(d=3, n=10) nx.set_edge_attributes(problem_graph, values=1, name='weight') circuit_qubits = cirq.LineQubit.range(10) gammas = np.random.randn(2) betas = np.random.randn(2) circuit = get_generic_qaoa_circuit(problem_graph=problem_graph, qubits=circuit_qubits, gammas=gammas, betas=betas) # TODO: high-level function for getting low-level qaoa circuit circuit = compile_problem_unitary_to_arbitrary_zz(circuit) circuit = compile_driver_unitary_to_rx(circuit) device = cirq.google.Sycamore23 routed_circuit, initial_qubit_map, final_qubit_map = place_on_device( circuit, device) # Check that constraints are not violated for _, op, _ in routed_circuit.findall_operations_with_gate_type( cirq.TwoQubitGate): a, b = op.qubits a = cast(cirq.GridQubit, a) b = cast(cirq.GridQubit, b) assert a.is_adjacent(b) # Check that the circuits are equivalent final_to_initial_qubit_map = { final_qubit_map[cq]: initial_qubit_map[cq] for cq in circuit_qubits } initial_qubits = [initial_qubit_map[cq] for cq in circuit_qubits] final_permutation = [ initial_qubits.index(final_to_initial_qubit_map[q]) for q in initial_qubits ] rcircuit_with_perm = routed_circuit.copy() rcircuit_with_perm.append(permute_gate(initial_qubits, final_permutation)) expected = circuit.unitary( qubit_order=cirq.QubitOrder.explicit(circuit_qubits)) actual = rcircuit_with_perm.unitary( qubit_order=cirq.QubitOrder.explicit(initial_qubits)) cirq.testing.assert_allclose_up_to_global_phase(expected, actual, atol=1e-8)
def test_get_moment_classes(): n = 5 problem = nx.complete_graph(n=n) problem = random_plus_minus_1_weights(problem) qubits = cirq.LineQubit.range(n) p = 1 c1 = cirq.Circuit(cirq.H.on_each(qubits), [[ ProblemUnitary(problem, gamma=np.random.random()).on(*qubits), DriverUnitary(5, beta=np.random.random()).on(*qubits) ] for _ in range(p)]) c2 = compile_problem_unitary_to_swap_network(c1) c3 = compile_swap_network_to_zzswap(c2) c4 = compile_driver_unitary_to_rx(c3) c5 = compile_to_syc(c4) mom_classes = get_moment_classes(c5) should_be = [cirq.PhasedXPowGate, cirq.ZPowGate, cg.SycamoreGate ] * (n * p * 3) should_be += [ cirq.PhasedXPowGate, cirq.ZPowGate, QuirkQubitPermutationGate ] assert mom_classes == should_be
def get_routed_sk_model_circuit( problem_graph: nx.Graph, qubits: List[cirq.Qid], gammas: Sequence[float], betas: Sequence[float], ) -> cirq.Circuit: """Get a QAOA circuit for a fully-connected problem using the linear swap network. See Also: :py:func:`get_compiled_sk_model_circuit` Args: problem_graph: A graph with contiguous 0-indexed integer nodes and edges with a 'weight' attribute. qubits: The qubits to use in construction of the circuit. gammas: Gamma angles to use as parameters for problem unitaries betas: Beta angles to use as parameters for driver unitaries """ circuit = get_generic_qaoa_circuit(problem_graph, qubits, gammas, betas) circuit = compile_problem_unitary_to_swap_network(circuit) circuit = compile_swap_network_to_zzswap(circuit) circuit = compile_driver_unitary_to_rx(circuit) return circuit