diff --git a/examples/examples_test.py b/examples/examples_test.py index 641c383ee51..d5918e3f021 100644 --- a/examples/examples_test.py +++ b/examples/examples_test.py @@ -1,6 +1,7 @@ # pylint: disable=wrong-or-nonexistent-copyright-notice import itertools +import networkx import numpy as np import pytest import matplotlib.pyplot as plt @@ -93,7 +94,28 @@ def test_example_heatmaps(): def test_example_runs_qaoa(): - examples.qaoa.main(repetitions=10, maxiter=5) + examples.qaoa.main(repetitions=10, maxiter=5, use_boolean_hamiltonian_gate=False) + examples.qaoa.main(repetitions=10, maxiter=5, use_boolean_hamiltonian_gate=True) + + +def test_example_qaoa_same_unitary(): + n = 6 + p = 2 + + qubits = cirq.LineQubit.range(n) + + graph = networkx.random_regular_graph(3, n) + + betas = np.random.uniform(-np.pi, np.pi, size=p) + gammas = np.random.uniform(-np.pi, np.pi, size=p) + circuits = [ + examples.qaoa.qaoa_max_cut_circuit( + qubits, betas, gammas, graph, use_boolean_hamiltonian_gate + ) + for use_boolean_hamiltonian_gate in [True, False] + ] + + assert cirq.allclose_up_to_global_phase(cirq.unitary(circuits[0]), cirq.unitary(circuits[1])) def test_example_runs_quantum_teleportation(): diff --git a/examples/qaoa.py b/examples/qaoa.py index 8bf5b1ee38d..47a4df06aa3 100644 --- a/examples/qaoa.py +++ b/examples/qaoa.py @@ -58,7 +58,7 @@ import cirq -def main(repetitions=1000, maxiter=50): +def main(repetitions=10, maxiter=50, use_boolean_hamiltonian_gate=False): # Set problem parameters n = 6 p = 2 @@ -72,7 +72,7 @@ def main(repetitions=1000, maxiter=50): # Print an example circuit betas = np.random.uniform(-np.pi, np.pi, size=p) gammas = np.random.uniform(-np.pi, np.pi, size=p) - circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph) + circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph, use_boolean_hamiltonian_gate) print('Example QAOA circuit:') print(circuit.to_text_diagram(transpose=True)) @@ -89,7 +89,7 @@ def f(x): # Create circuit betas = x[:p] gammas = x[p:] - circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph) + circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph, use_boolean_hamiltonian_gate) # Sample bitstrings from circuit result = simulator.run(circuit, repetitions=repetitions) bitstrings = result.measurements['m'] @@ -128,18 +128,29 @@ def rzz(rads): return cirq.ZZPowGate(exponent=2 * rads / np.pi, global_shift=-0.5) -def qaoa_max_cut_unitary(qubits, betas, gammas, graph): # Nodes should be integers - for beta, gamma in zip(betas, gammas): - yield (rzz(-0.5 * gamma).on(qubits[i], qubits[j]) for i, j in graph.edges) - yield cirq.rx(2 * beta).on_each(*qubits) - - -def qaoa_max_cut_circuit(qubits, betas, gammas, graph): # Nodes should be integers +def qaoa_max_cut_unitary( + qubits, betas, gammas, graph, use_boolean_hamiltonian_gate +): # Nodes should be integers + if use_boolean_hamiltonian_gate: + booleans = [f"x{i} ^ x{j}" for i, j in sorted(graph.edges)] + param_names = [f"x{i}" for i in range(len(qubits))] + for beta, gamma in zip(betas, gammas): + yield cirq.BooleanHamiltonianGate(param_names, booleans, 2.0 * gamma).on(*qubits) + yield cirq.rx(2 * beta).on_each(*qubits) + else: + for beta, gamma in zip(betas, gammas): + yield (rzz(-0.5 * gamma).on(qubits[i], qubits[j]) for i, j in graph.edges) + yield cirq.rx(2 * beta).on_each(*qubits) + + +def qaoa_max_cut_circuit( + qubits, betas, gammas, graph, use_boolean_hamiltonian_gate +): # Nodes should be integers return cirq.Circuit( # Prepare uniform superposition cirq.H.on_each(*qubits), # Apply QAOA unitary - qaoa_max_cut_unitary(qubits, betas, gammas, graph), + qaoa_max_cut_unitary(qubits, betas, gammas, graph, use_boolean_hamiltonian_gate), # Measure cirq.measure(*qubits, key='m'), )