From 2497cebcfc757152c573fcdb3bbb3d360685b6ec Mon Sep 17 00:00:00 2001 From: Ganesan Date: Thu, 2 Nov 2023 14:28:22 -0400 Subject: [PATCH 01/13] fix default behavior of overlap objective --- qokit/qaoa_objective.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qokit/qaoa_objective.py b/qokit/qaoa_objective.py index 33bea38a8..6245e65b8 100644 --- a/qokit/qaoa_objective.py +++ b/qokit/qaoa_objective.py @@ -190,6 +190,9 @@ def fq(*args): if precomputed_optimal_bitstrings is not None and objective != "expectation": bitstring_loc = np.array([reduce(lambda a, b: 2 * a + b, x) for x in precomputed_optimal_bitstrings]) + if precomputed_objectives is not None and precomputed_optimal_bitstrings is None: + bitstring_loc = np.argmax(precomputed_objectives) + # -- Final function def f(*args): gamma, beta = qokit.parameter_utils.convert_to_gamma_beta(*args, parameterization=parameterization) @@ -207,6 +210,7 @@ def f(*args): return f + def get_qaoa_labs_overlap(N: int, p: int, **kwargs): """To be deprecated. Use get_qaoa_labs_objective going forward. Please consult the docstring for get_qaoa_labs_objective for kwargs From f629a693c4585ea41508e5a7dd0aec9fe207c60f Mon Sep 17 00:00:00 2001 From: Ganesan Date: Thu, 2 Nov 2023 14:32:20 -0400 Subject: [PATCH 02/13] fix default behavior of overlap objective --- qokit/qaoa_objective.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qokit/qaoa_objective.py b/qokit/qaoa_objective.py index 6245e65b8..9ed52995f 100644 --- a/qokit/qaoa_objective.py +++ b/qokit/qaoa_objective.py @@ -210,7 +210,6 @@ def f(*args): return f - def get_qaoa_labs_overlap(N: int, p: int, **kwargs): """To be deprecated. Use get_qaoa_labs_objective going forward. Please consult the docstring for get_qaoa_labs_objective for kwargs From db77a7533d9603281c0628341a738df8f669cbd3 Mon Sep 17 00:00:00 2001 From: Ganesan Date: Tue, 14 Nov 2023 11:07:17 -0500 Subject: [PATCH 03/13] Modified Max-Cut logic to send negative cost for maximization, removed relative import and renamed the precomputed energy to precomputed costs --- qokit/__init__.py | 4 ++-- qokit/qaoa_circuit_portfolio.py | 4 ++-- qokit/qaoa_objective.py | 27 ++++++++++++--------------- qokit/qaoa_objective_labs.py | 20 ++++++++++---------- qokit/qaoa_objective_maxcut.py | 8 +++++--- qokit/qaoa_objective_portfolio.py | 2 +- tests/conftest.py | 2 ++ tests/test_maxcut.py | 4 ++-- 8 files changed, 36 insertions(+), 35 deletions(-) create mode 100644 tests/conftest.py diff --git a/qokit/__init__.py b/qokit/__init__.py index 2d81e9700..d34a1959e 100644 --- a/qokit/__init__.py +++ b/qokit/__init__.py @@ -3,5 +3,5 @@ # // Copyright : JP Morgan Chase & Co ############################################################################### -from .qaoa_objective import get_qaoa_objective -from .qaoa_objective_labs import get_qaoa_labs_objective +from qaoa_objective import get_qaoa_objective +from qaoa_objective_labs import get_qaoa_labs_objective diff --git a/qokit/qaoa_circuit_portfolio.py b/qokit/qaoa_circuit_portfolio.py index 80eaec48c..89cf794bd 100644 --- a/qokit/qaoa_circuit_portfolio.py +++ b/qokit/qaoa_circuit_portfolio.py @@ -4,10 +4,10 @@ ############################################################################### import qiskit import numpy as np -from .portfolio_optimization import yield_all_indices_cosntrained, get_configuration_cost +from portfolio_optimization import yield_all_indices_cosntrained, get_configuration_cost from qiskit import QuantumCircuit, execute, Aer, QuantumRegister from qiskit.circuit import ParameterVector -from .utils import reverse_array_index_bit_order, state_to_ampl_counts +from utils import reverse_array_index_bit_order, state_to_ampl_counts def generate_dicke_state_fast(N, K): diff --git a/qokit/qaoa_objective.py b/qokit/qaoa_objective.py index 9ed52995f..ce9e1eb27 100644 --- a/qokit/qaoa_objective.py +++ b/qokit/qaoa_objective.py @@ -9,14 +9,14 @@ from functools import reduce import numba.cuda -from .fur import choose_simulator, choose_simulator_xyring, QAOAFastSimulatorBase +from fur import choose_simulator, choose_simulator_xyring, QAOAFastSimulatorBase import typing -from .parameter_utils import from_fourier_basis +from parameter_utils import from_fourier_basis import qokit.parameter_utils from qokit.parameter_utils import QAOAParameterization -from .qaoa_circuit_portfolio import measure_circuit -from .utils import reverse_array_index_bit_order +from qaoa_circuit_portfolio import measure_circuit +from utils import reverse_array_index_bit_order def precompute_terms(terms, N): @@ -117,7 +117,7 @@ def get_qaoa_objective( N: int, p: int | None = None, precomputed_diagonal_hamiltonian=None, - precomputed_objectives=None, + precomputed_costs=None, terms=None, precomputed_optimal_bitstrings=None, parameterization: str | QAOAParameterization = "theta", @@ -166,7 +166,7 @@ def get_qaoa_objective( # -- Qiskit edge case if simulator == "qiskit": - g = _get_qiskit_objective(parameterized_circuit, precomputed_objectives, precomputed_optimal_bitstrings, objective, terms, parameterization, mixer) + g = _get_qiskit_objective(parameterized_circuit, precomputed_costs, precomputed_optimal_bitstrings, objective, terms, parameterization, mixer) def fq(*args): gamma, beta = qokit.parameter_utils.convert_to_gamma_beta(*args, parameterization=parameterization) @@ -183,28 +183,25 @@ def fq(*args): raise ValueError(f"Unknown mixer type passed to get_qaoa_objective: {mixer}, allowed ['x', 'xy']") sim = simulator_cls(N, terms=terms, costs=precomputed_diagonal_hamiltonian) - if precomputed_objectives is None: - precomputed_objectives = sim.get_cost_diagonal() + if precomputed_costs is None: + precomputed_costs = sim.get_cost_diagonal() bitstring_loc = None if precomputed_optimal_bitstrings is not None and objective != "expectation": bitstring_loc = np.array([reduce(lambda a, b: 2 * a + b, x) for x in precomputed_optimal_bitstrings]) - if precomputed_objectives is not None and precomputed_optimal_bitstrings is None: - bitstring_loc = np.argmax(precomputed_objectives) - # -- Final function def f(*args): gamma, beta = qokit.parameter_utils.convert_to_gamma_beta(*args, parameterization=parameterization) result = sim.simulate_qaoa(gamma, beta, initial_state, n_trotters=n_trotters) if objective == "expectation": - return sim.get_expectation(result, costs=precomputed_objectives, preserve_state=False) + return sim.get_expectation(result, costs=precomputed_costs, preserve_state=False) elif objective == "overlap": - overlap = sim.get_overlap(result, costs=precomputed_objectives, indices=bitstring_loc, preserve_state=False) + overlap = sim.get_overlap(result, costs=precomputed_costs, indices=bitstring_loc, preserve_state=False) return 1 - overlap elif objective == "expectation and overlap": - overlap = sim.get_overlap(result, costs=precomputed_objectives, indices=bitstring_loc, preserve_state=True) - expectation = sim.get_expectation(result, costs=precomputed_objectives) + overlap = sim.get_overlap(result, costs=precomputed_costs, indices=bitstring_loc, preserve_state=True) + expectation = sim.get_expectation(result, costs=precomputed_costs) return expectation, 1 - overlap return f diff --git a/qokit/qaoa_objective_labs.py b/qokit/qaoa_objective_labs.py index 6fb4859fc..66f8bcc8a 100644 --- a/qokit/qaoa_objective_labs.py +++ b/qokit/qaoa_objective_labs.py @@ -8,16 +8,16 @@ import numpy as np from pathlib import Path -from .labs import ( +from labs import ( get_energy_term_indices, negative_merit_factor_from_bitstring, true_optimal_energy, energy_vals_from_bitstring, ) -from .utils import precompute_energies -from .qaoa_circuit_labs import get_parameterized_qaoa_circuit -from .qaoa_objective import get_qaoa_objective +from utils import precompute_energies +from qaoa_circuit_labs import get_parameterized_qaoa_circuit +from qaoa_objective import get_qaoa_objective qaoa_objective_labs_folder = Path(__file__).parent @@ -142,7 +142,7 @@ def get_random_guess_merit_factor(N: int) -> float: def get_qaoa_labs_objective( N: int, p: int, - precomputed_merit_factors: np.ndarray | None = None, + precomputed_negative_merit_factors: np.ndarray | None = None, parameterization: str = "theta", objective: str = "expectation", precomputed_optimal_bitstrings: np.ndarray | None = None, @@ -156,7 +156,7 @@ def get_qaoa_labs_objective( Number of qubits p : int Number of QAOA layers (number of parameters will be 2*p) - precomputed_merit_factors : np.array + precomputed_negative_merit_factors : np.array precomputed merit factors to compute the QAOA expectation parameterization : str If parameterization == 'theta', then f takes one parameter (gamma and beta concatenated) @@ -186,19 +186,19 @@ def get_qaoa_labs_objective( terms_ix, offset = get_energy_term_indices(N) - if precomputed_merit_factors is None: - precomputed_merit_factors = get_precomputed_labs_merit_factors(N) + if precomputed_negative_merit_factors is None: + precomputed_negative_merit_factors = get_precomputed_labs_merit_factors(N) if objective in ["overlap", "expectation and overlap"] and precomputed_optimal_bitstrings is None: precomputed_optimal_bitstrings = get_precomputed_optimal_bitstrings(N) - precomputed_diagonal_hamiltonian = -(N**2) / (2 * precomputed_merit_factors) - offset + precomputed_diagonal_hamiltonian = -(N**2) / (2 * precomputed_negative_merit_factors) - offset return get_qaoa_objective( N=N, p=p, precomputed_diagonal_hamiltonian=precomputed_diagonal_hamiltonian, - precomputed_objectives=precomputed_merit_factors, + precomputed_costs=precomputed_negative_merit_factors, precomputed_optimal_bitstrings=precomputed_optimal_bitstrings, parameterization=parameterization, objective=objective, diff --git a/qokit/qaoa_objective_maxcut.py b/qokit/qaoa_objective_maxcut.py index cd81308bc..e1a6b7e72 100644 --- a/qokit/qaoa_objective_maxcut.py +++ b/qokit/qaoa_objective_maxcut.py @@ -35,7 +35,8 @@ def get_qaoa_maxcut_objective( G : nx.Graph graph on which MaxCut will be solved precomputed_cuts : np.array - precomputed cuts to compute the QAOA expectation + precomputed cuts to compute the QAOA expectation, for maximization problem + send the precomputed cuts/energies as negative parameterization : str If parameterization == 'theta', then f takes one parameter (gamma and beta concatenated) If parameterization == 'gamma beta', then f takes two parameters (gamma and beta) @@ -68,12 +69,13 @@ def get_qaoa_maxcut_objective( parameterized_circuit = get_parameterized_qaoa_circuit(G, p) else: parameterized_circuit = None - + # Reverse the sign for computing maximizing problem + precomputed_costs = precomputed_cuts * -1 if precomputed_cuts is not None else None return get_qaoa_objective( N=N, p=p, precomputed_diagonal_hamiltonian=precomputed_cuts, - precomputed_objectives=precomputed_cuts, + precomputed_costs=precomputed_costs, terms=terms, precomputed_optimal_bitstrings=precomputed_optimal_bitstrings, parameterized_circuit=parameterized_circuit, diff --git a/qokit/qaoa_objective_portfolio.py b/qokit/qaoa_objective_portfolio.py index e6c18b6ae..e7baacb85 100644 --- a/qokit/qaoa_objective_portfolio.py +++ b/qokit/qaoa_objective_portfolio.py @@ -78,7 +78,7 @@ def get_qaoa_portfolio_objective( N=N, p=p, precomputed_diagonal_hamiltonian=po_problem["scale"] * precomputed_energies, - precomputed_objectives=precomputed_energies, + precomputed_costs=precomputed_energies, precomputed_optimal_bitstrings=precomputed_optimal_bitstrings, parameterized_circuit=parameterized_circuit, parameterization=parameterization, diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..41960256d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,2 @@ +import sys +sys.path.append("./qokit") \ No newline at end of file diff --git a/tests/test_maxcut.py b/tests/test_maxcut.py index 395416bcb..3356313da 100644 --- a/tests/test_maxcut.py +++ b/tests/test_maxcut.py @@ -55,7 +55,7 @@ def test_maxcut_qaoa_obj_fixed_angles(): gamma, beta, AR = get_fixed_gamma_beta(d, p, return_AR=True) for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) - assert f(gamma, beta) / optimal_cut > AR + assert abs(f(gamma, beta) / optimal_cut) > AR def test_maxcut_weighted_qaoa_obj(): @@ -70,7 +70,7 @@ def test_maxcut_weighted_qaoa_obj(): for _, row in df.iterrows(): for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(row["G"].number_of_nodes(), row["p"], G=row["G"], parameterization="gamma beta", simulator=simulator) - assert np.isclose(f(row["gamma"], row["beta"]), row["Expected cut of QAOA"]) + assert np.isclose(abs(f(row["gamma"], row["beta"])), row["Expected cut of QAOA"]) # Qiskit non-parameterized circuit must be tested separately precomputed_cuts = precompute_energies(maxcut_obj, row["G"].number_of_nodes(), w=get_adjacency_matrix(row["G"])) From 7014003a7a019aec664fd18c9b9eade545c2b05f Mon Sep 17 00:00:00 2001 From: Ganesan Date: Tue, 14 Nov 2023 11:39:45 -0500 Subject: [PATCH 04/13] Modified Max-Cut logic to send negative cost for maximization, removed relative import and renamed the precomputed energy to precomputed costs --- tests/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 41960256d..45524f1f7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,2 +1,3 @@ import sys -sys.path.append("./qokit") \ No newline at end of file + +sys.path.append("./qokit") From fe3bd8b766c24ca94d726c74afad8140420721de Mon Sep 17 00:00:00 2001 From: Ganesan Date: Fri, 17 Nov 2023 11:59:21 -0500 Subject: [PATCH 05/13] reverted old relative imports --- qokit/__init__.py | 4 ++-- qokit/qaoa_circuit_portfolio.py | 4 ++-- qokit/qaoa_objective.py | 8 ++++---- qokit/qaoa_objective_labs.py | 8 ++++---- tests/conftest.py | 3 --- 5 files changed, 12 insertions(+), 15 deletions(-) delete mode 100644 tests/conftest.py diff --git a/qokit/__init__.py b/qokit/__init__.py index d34a1959e..2d81e9700 100644 --- a/qokit/__init__.py +++ b/qokit/__init__.py @@ -3,5 +3,5 @@ # // Copyright : JP Morgan Chase & Co ############################################################################### -from qaoa_objective import get_qaoa_objective -from qaoa_objective_labs import get_qaoa_labs_objective +from .qaoa_objective import get_qaoa_objective +from .qaoa_objective_labs import get_qaoa_labs_objective diff --git a/qokit/qaoa_circuit_portfolio.py b/qokit/qaoa_circuit_portfolio.py index 89cf794bd..80eaec48c 100644 --- a/qokit/qaoa_circuit_portfolio.py +++ b/qokit/qaoa_circuit_portfolio.py @@ -4,10 +4,10 @@ ############################################################################### import qiskit import numpy as np -from portfolio_optimization import yield_all_indices_cosntrained, get_configuration_cost +from .portfolio_optimization import yield_all_indices_cosntrained, get_configuration_cost from qiskit import QuantumCircuit, execute, Aer, QuantumRegister from qiskit.circuit import ParameterVector -from utils import reverse_array_index_bit_order, state_to_ampl_counts +from .utils import reverse_array_index_bit_order, state_to_ampl_counts def generate_dicke_state_fast(N, K): diff --git a/qokit/qaoa_objective.py b/qokit/qaoa_objective.py index ce9e1eb27..e2e41c2ee 100644 --- a/qokit/qaoa_objective.py +++ b/qokit/qaoa_objective.py @@ -9,14 +9,14 @@ from functools import reduce import numba.cuda -from fur import choose_simulator, choose_simulator_xyring, QAOAFastSimulatorBase +from .fur import choose_simulator, choose_simulator_xyring, QAOAFastSimulatorBase import typing -from parameter_utils import from_fourier_basis +from .parameter_utils import from_fourier_basis import qokit.parameter_utils from qokit.parameter_utils import QAOAParameterization -from qaoa_circuit_portfolio import measure_circuit -from utils import reverse_array_index_bit_order +from .qaoa_circuit_portfolio import measure_circuit +from .utils import reverse_array_index_bit_order def precompute_terms(terms, N): diff --git a/qokit/qaoa_objective_labs.py b/qokit/qaoa_objective_labs.py index 66f8bcc8a..6d8e72db5 100644 --- a/qokit/qaoa_objective_labs.py +++ b/qokit/qaoa_objective_labs.py @@ -8,16 +8,16 @@ import numpy as np from pathlib import Path -from labs import ( +from .labs import ( get_energy_term_indices, negative_merit_factor_from_bitstring, true_optimal_energy, energy_vals_from_bitstring, ) -from utils import precompute_energies -from qaoa_circuit_labs import get_parameterized_qaoa_circuit -from qaoa_objective import get_qaoa_objective +from .utils import precompute_energies +from .qaoa_circuit_labs import get_parameterized_qaoa_circuit +from .qaoa_objective import get_qaoa_objective qaoa_objective_labs_folder = Path(__file__).parent diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 45524f1f7..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys - -sys.path.append("./qokit") From f779c0e2c3158cbd489c54248f404d27d2f7f30a Mon Sep 17 00:00:00 2001 From: Ganesan Date: Wed, 22 Nov 2023 13:47:11 -0500 Subject: [PATCH 06/13] resolved energy calculation in consistent with terms, precomputed and various simulators --- qokit/maxcut.py | 6 ++--- qokit/parameter_utils.py | 19 +++++++++++++-- qokit/qaoa_circuit_maxcut.py | 2 +- tests/test_maxcut.py | 18 +++++++++------ tests/test_qaoa_objective_maxcut.py | 36 +++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 tests/test_qaoa_objective_maxcut.py diff --git a/qokit/maxcut.py b/qokit/maxcut.py index d1c6e7ff4..562db79c7 100644 --- a/qokit/maxcut.py +++ b/qokit/maxcut.py @@ -35,14 +35,14 @@ def get_maxcut_terms(G: nx.Graph) -> TermsType: terms to be used in the simulation """ if nx.is_weighted(G): - terms = [(-float(G[u][v]["weight"]) / 2, (int(u), int(v))) for u, v, *_ in G.edges()] + terms = [(float(G[u][v]["weight"]) / 2, (int(u), int(v))) for u, v, *_ in G.edges()] total_w = sum([float(G[u][v]["weight"]) for u, v, *_ in G.edges()]) else: - terms = [(-1 / 2, (int(e[0]), int(e[1]))) for e in G.edges()] + terms = [(1 / 2, (int(e[0]), int(e[1]))) for e in G.edges()] total_w = int(G.number_of_edges()) N = G.number_of_nodes() - terms.append((+total_w / 2, tuple())) + terms.append((-total_w / 2, tuple())) return terms diff --git a/qokit/parameter_utils.py b/qokit/parameter_utils.py index e0923907f..a3895e8bf 100644 --- a/qokit/parameter_utils.py +++ b/qokit/parameter_utils.py @@ -11,6 +11,8 @@ from importlib_resources import files from enum import Enum from typing import Callable +from functools import lru_cache, cached_property,cache +from datetime import datetime def from_fourier_basis(u, v): @@ -210,6 +212,20 @@ def get_sk_gamma_beta(p, parameterization: QAOAParameterization | str = "gamma b elif parameterization == QAOAParameterization.GAMMA_BETA: return 4 * gamma, beta +@cache +def _get_gamma_beta_from_file(): + """ + Caches the dataframe after the first call to load JSon, subsequent calls will get from cache and save I/O + + Parameters + ---------- + None + + Returns + ------- + df: Pandas Dataframe + """ + return pd.read_json(str(files("qokit.assets.maxcut_datasets").joinpath("fixed_angles_for_regular_graphs.json")), orient="index") def get_fixed_gamma_beta(d, p, return_AR=False): """ @@ -231,8 +247,7 @@ def get_fixed_gamma_beta(d, p, return_AR=False): AR : float Only returned is flag return_AR is raised """ - df = pd.read_json(str(files("qokit.assets.maxcut_datasets").joinpath("fixed_angles_for_regular_graphs.json")), orient="index") - + df = _get_gamma_beta_from_file() row = df[(df["d"] == d) & (df["p"] == p)] if len(row) != 1: raise ValueError(f"Failed to retrieve fixed angles for d={d}, p={p}") diff --git a/qokit/qaoa_circuit_maxcut.py b/qokit/qaoa_circuit_maxcut.py index 140c4e022..0fc11cc4a 100644 --- a/qokit/qaoa_circuit_maxcut.py +++ b/qokit/qaoa_circuit_maxcut.py @@ -11,7 +11,7 @@ def append_zz_term(qc, q1, q2, gamma): - qc.rzz(-gamma / 2, q1, q2) + qc.rzz(gamma / 2, q1, q2) def append_maxcut_cost_operator_circuit(qc, G, gamma): diff --git a/tests/test_maxcut.py b/tests/test_maxcut.py index 3356313da..6f9fb3407 100644 --- a/tests/test_maxcut.py +++ b/tests/test_maxcut.py @@ -53,7 +53,8 @@ def test_maxcut_qaoa_obj_fixed_angles(): for p in range(1, max_p + 1): gamma, beta, AR = get_fixed_gamma_beta(d, p, return_AR=True) - for simulator in ["auto", "qiskit"]: + gamma = -1 * np.asarray(gamma) + for simulator in ["auto","qiskit"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) assert abs(f(gamma, beta) / optimal_cut) > AR @@ -68,14 +69,14 @@ def test_maxcut_weighted_qaoa_obj(): ) for _, row in df.iterrows(): - for simulator in ["auto", "qiskit"]: + for simulator in ["auto","qiskit"]: f = get_qaoa_maxcut_objective(row["G"].number_of_nodes(), row["p"], G=row["G"], parameterization="gamma beta", simulator=simulator) - assert np.isclose(abs(f(row["gamma"], row["beta"])), row["Expected cut of QAOA"]) + assert np.isclose(abs(f(-1 * np.asarray(row["gamma"]), row["beta"])), row["Expected cut of QAOA"]) # Qiskit non-parameterized circuit must be tested separately precomputed_cuts = precompute_energies(maxcut_obj, row["G"].number_of_nodes(), w=get_adjacency_matrix(row["G"])) - qc = get_qaoa_circuit(row["G"], row["beta"], row["gamma"]) - qc_param = get_parameterized_qaoa_circuit(row["G"], row["p"]).bind_parameters(np.hstack([row["beta"], row["gamma"]])) + qc = get_qaoa_circuit(row["G"], row["beta"], -1 * np.asarray(row["gamma"])) + qc_param = get_parameterized_qaoa_circuit(row["G"], row["p"]).bind_parameters(np.hstack([row["beta"], -1 * np.asarray(row["gamma"])])) sv = np.asarray(qiskit_backend.run(qc).result().get_statevector()) sv_param = np.asarray(qiskit_backend.run(qc_param).result().get_statevector()) @@ -92,6 +93,7 @@ def test_maxcut_precompute(simclass): for u, v, w in G.edges(data=True): w["weight"] = np.random.rand() precomputed_cuts = precompute_energies(maxcut_obj, N, w=get_adjacency_matrix(G)) + precomputed_cuts = precomputed_cuts * -1 terms = get_maxcut_terms(G) sim = simclass(N, terms=terms) cuts = sim.get_cost_diagonal() @@ -105,14 +107,16 @@ def test_sk_ini_maxcut(): obj = partial(maxcut_obj, w=get_adjacency_matrix(G)) optimal_cut, x = brute_force(obj, N, function_takes="bits") precomputed_energies = precompute_energies(obj, N) + precomputed_energies = precomputed_energies * -1 last_ar = 0 for p in range(1, max_p + 1): gamma, beta = get_sk_gamma_beta(p) + gamma = -1 * np.asarray(gamma) for simulator in ["auto"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) cur_ar = f(gamma / np.sqrt(d), beta) / optimal_cut if p == 1: - assert cur_ar > np.mean(precomputed_energies) / optimal_cut + assert cur_ar < np.mean(precomputed_energies) / optimal_cut else: - assert cur_ar > last_ar + assert cur_ar < last_ar last_ar = cur_ar diff --git a/tests/test_qaoa_objective_maxcut.py b/tests/test_qaoa_objective_maxcut.py new file mode 100644 index 000000000..9bf2b98d0 --- /dev/null +++ b/tests/test_qaoa_objective_maxcut.py @@ -0,0 +1,36 @@ +############################################################################### +# // SPDX-License-Identifier: Apache-2.0 +# // Copyright : JP Morgan Chase & Co +############################################################################### +import math +import networkx as nx +import numpy as np +from qokit.qaoa_objective_maxcut import get_qaoa_maxcut_objective +from qokit.utils import precompute_energies +from qokit.parameter_utils import get_fixed_gamma_beta +from qokit.maxcut import maxcut_obj, get_adjacency_matrix + + +def test_validate_energy_for_terms_and_precomputedcuts_are_same(): + G = nx.random_regular_graph(3,16) + #without precomputed cuts + f_terms = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization='gamma beta') + # with precomputed cuts + precomputed_cuts = precompute_energies(maxcut_obj, G.number_of_nodes(), w=get_adjacency_matrix(G)) + f_precomputedcuts = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, precomputed_cuts=precomputed_cuts, parameterization='gamma beta') + p = 1 + gamma, beta = get_fixed_gamma_beta(3,p) + energy_terms = f_terms(-1 * np.asarray(gamma), beta) + energy_precomputedcuts = f_precomputedcuts(gamma,beta) + assert (energy_terms == energy_precomputedcuts) + + +def test_validate_energy_for_terms_with_simulators_are_same(): + G = nx.random_regular_graph(3,16) + f = f = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization='gamma beta', simulator="auto") + g = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization='gamma beta', simulator="qiskit") + p = 1 + gamma, beta = get_fixed_gamma_beta(3,p) + auto = f(-1 * np.asarray(gamma), beta) + qiskit = g(-1 * np.asarray(gamma), beta) + assert math.isclose(auto,qiskit, rel_tol=0.00000000001) From 24a3daae7bf8f918caabb6af69ef07a511dd1e04 Mon Sep 17 00:00:00 2001 From: Ganesan Date: Wed, 22 Nov 2023 13:49:46 -0500 Subject: [PATCH 07/13] resolved energy calculation in consistent with terms, precomputed and various simulators --- qokit/parameter_utils.py | 6 ++++-- tests/test_maxcut.py | 4 ++-- tests/test_qaoa_objective_maxcut.py | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/qokit/parameter_utils.py b/qokit/parameter_utils.py index a3895e8bf..6903b15be 100644 --- a/qokit/parameter_utils.py +++ b/qokit/parameter_utils.py @@ -11,7 +11,7 @@ from importlib_resources import files from enum import Enum from typing import Callable -from functools import lru_cache, cached_property,cache +from functools import lru_cache, cached_property, cache from datetime import datetime @@ -212,6 +212,7 @@ def get_sk_gamma_beta(p, parameterization: QAOAParameterization | str = "gamma b elif parameterization == QAOAParameterization.GAMMA_BETA: return 4 * gamma, beta + @cache def _get_gamma_beta_from_file(): """ @@ -224,9 +225,10 @@ def _get_gamma_beta_from_file(): Returns ------- df: Pandas Dataframe - """ + """ return pd.read_json(str(files("qokit.assets.maxcut_datasets").joinpath("fixed_angles_for_regular_graphs.json")), orient="index") + def get_fixed_gamma_beta(d, p, return_AR=False): """ Returns the parameters for QAOA for MaxCut on regular graphs from arXiv:2107.00677 diff --git a/tests/test_maxcut.py b/tests/test_maxcut.py index 6f9fb3407..5a3fbd5ee 100644 --- a/tests/test_maxcut.py +++ b/tests/test_maxcut.py @@ -54,7 +54,7 @@ def test_maxcut_qaoa_obj_fixed_angles(): for p in range(1, max_p + 1): gamma, beta, AR = get_fixed_gamma_beta(d, p, return_AR=True) gamma = -1 * np.asarray(gamma) - for simulator in ["auto","qiskit"]: + for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) assert abs(f(gamma, beta) / optimal_cut) > AR @@ -69,7 +69,7 @@ def test_maxcut_weighted_qaoa_obj(): ) for _, row in df.iterrows(): - for simulator in ["auto","qiskit"]: + for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(row["G"].number_of_nodes(), row["p"], G=row["G"], parameterization="gamma beta", simulator=simulator) assert np.isclose(abs(f(-1 * np.asarray(row["gamma"]), row["beta"])), row["Expected cut of QAOA"]) diff --git a/tests/test_qaoa_objective_maxcut.py b/tests/test_qaoa_objective_maxcut.py index 9bf2b98d0..2f4331198 100644 --- a/tests/test_qaoa_objective_maxcut.py +++ b/tests/test_qaoa_objective_maxcut.py @@ -12,25 +12,25 @@ def test_validate_energy_for_terms_and_precomputedcuts_are_same(): - G = nx.random_regular_graph(3,16) - #without precomputed cuts - f_terms = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization='gamma beta') + G = nx.random_regular_graph(3, 16) + # without precomputed cuts + f_terms = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization="gamma beta") # with precomputed cuts precomputed_cuts = precompute_energies(maxcut_obj, G.number_of_nodes(), w=get_adjacency_matrix(G)) - f_precomputedcuts = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, precomputed_cuts=precomputed_cuts, parameterization='gamma beta') + f_precomputedcuts = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, precomputed_cuts=precomputed_cuts, parameterization="gamma beta") p = 1 - gamma, beta = get_fixed_gamma_beta(3,p) + gamma, beta = get_fixed_gamma_beta(3, p) energy_terms = f_terms(-1 * np.asarray(gamma), beta) - energy_precomputedcuts = f_precomputedcuts(gamma,beta) - assert (energy_terms == energy_precomputedcuts) + energy_precomputedcuts = f_precomputedcuts(gamma, beta) + assert energy_terms == energy_precomputedcuts def test_validate_energy_for_terms_with_simulators_are_same(): - G = nx.random_regular_graph(3,16) - f = f = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization='gamma beta', simulator="auto") - g = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization='gamma beta', simulator="qiskit") + G = nx.random_regular_graph(3, 16) + f = f = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization="gamma beta", simulator="auto") + g = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization="gamma beta", simulator="qiskit") p = 1 - gamma, beta = get_fixed_gamma_beta(3,p) + gamma, beta = get_fixed_gamma_beta(3, p) auto = f(-1 * np.asarray(gamma), beta) qiskit = g(-1 * np.asarray(gamma), beta) - assert math.isclose(auto,qiskit, rel_tol=0.00000000001) + assert math.isclose(auto, qiskit, rel_tol=0.00000000001) From 7fdd6955e25770de6b3fef352508942048a37a8a Mon Sep 17 00:00:00 2001 From: Ruslan Shaydulin Date: Fri, 1 Dec 2023 13:13:55 -0500 Subject: [PATCH 08/13] Update qaoa_objective_maxcut.py --- qokit/qaoa_objective_maxcut.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qokit/qaoa_objective_maxcut.py b/qokit/qaoa_objective_maxcut.py index e1a6b7e72..6a1c16298 100644 --- a/qokit/qaoa_objective_maxcut.py +++ b/qokit/qaoa_objective_maxcut.py @@ -69,7 +69,7 @@ def get_qaoa_maxcut_objective( parameterized_circuit = get_parameterized_qaoa_circuit(G, p) else: parameterized_circuit = None - # Reverse the sign for computing maximizing problem + # Reverse the sign as get_qaoa_objective assumes that the problem is minimization precomputed_costs = precomputed_cuts * -1 if precomputed_cuts is not None else None return get_qaoa_objective( N=N, From d4b186b5a968ab15e1e01fb74147d1de61003607 Mon Sep 17 00:00:00 2001 From: Ruslan Shaydulin Date: Fri, 1 Dec 2023 13:20:34 -0500 Subject: [PATCH 09/13] Update test_qaoa_objective_maxcut.py --- tests/test_qaoa_objective_maxcut.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_qaoa_objective_maxcut.py b/tests/test_qaoa_objective_maxcut.py index 2f4331198..76f72f61e 100644 --- a/tests/test_qaoa_objective_maxcut.py +++ b/tests/test_qaoa_objective_maxcut.py @@ -2,7 +2,6 @@ # // SPDX-License-Identifier: Apache-2.0 # // Copyright : JP Morgan Chase & Co ############################################################################### -import math import networkx as nx import numpy as np from qokit.qaoa_objective_maxcut import get_qaoa_maxcut_objective @@ -33,4 +32,4 @@ def test_validate_energy_for_terms_with_simulators_are_same(): gamma, beta = get_fixed_gamma_beta(3, p) auto = f(-1 * np.asarray(gamma), beta) qiskit = g(-1 * np.asarray(gamma), beta) - assert math.isclose(auto, qiskit, rel_tol=0.00000000001) + assert np.isclose(auto, qiskit, rel_tol=0.00000000001) From 27fd7fd0afcdd72068353e053f16baf99d8ec710 Mon Sep 17 00:00:00 2001 From: Ruslan Shaydulin Date: Fri, 1 Dec 2023 13:28:28 -0500 Subject: [PATCH 10/13] Update test_qaoa_objective_maxcut.py --- tests/test_qaoa_objective_maxcut.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_qaoa_objective_maxcut.py b/tests/test_qaoa_objective_maxcut.py index 76f72f61e..a16e3e809 100644 --- a/tests/test_qaoa_objective_maxcut.py +++ b/tests/test_qaoa_objective_maxcut.py @@ -32,4 +32,4 @@ def test_validate_energy_for_terms_with_simulators_are_same(): gamma, beta = get_fixed_gamma_beta(3, p) auto = f(-1 * np.asarray(gamma), beta) qiskit = g(-1 * np.asarray(gamma), beta) - assert np.isclose(auto, qiskit, rel_tol=0.00000000001) + assert np.isclose(auto, qiskit) From 163f7802d34464f68737ea0f82559774208a29a1 Mon Sep 17 00:00:00 2001 From: Ganesan Date: Wed, 13 Dec 2023 09:59:08 -0500 Subject: [PATCH 11/13] flipped gamma sign in get_fixed_gamma_beta and fixed the test cases --- qokit/parameter_utils.py | 5 +++-- tests/test_maxcut.py | 11 +++++------ tests/test_qaoa_objective_maxcut.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/qokit/parameter_utils.py b/qokit/parameter_utils.py index 6903b15be..113fcc365 100644 --- a/qokit/parameter_utils.py +++ b/qokit/parameter_utils.py @@ -210,6 +210,7 @@ def get_sk_gamma_beta(p, parameterization: QAOAParameterization | str = "gamma b if parameterization == QAOAParameterization.THETA: return np.concatenate((4 * gamma, beta), axis=0) elif parameterization == QAOAParameterization.GAMMA_BETA: + # return -1 * (4 * gamma), beta return 4 * gamma, beta @@ -255,9 +256,9 @@ def get_fixed_gamma_beta(d, p, return_AR=False): raise ValueError(f"Failed to retrieve fixed angles for d={d}, p={p}") row = row.squeeze() if return_AR: - return row["gamma"], row["beta"], row["AR"] + return -1 * np.asarray(row["gamma"]), row["beta"], row["AR"] else: - return row["gamma"], row["beta"] + return -1 * np.asarray(row["gamma"]), row["beta"] def get_best_known_parameters_for_LABS_wrt_overlap(N: int) -> pd.DataFrame: diff --git a/tests/test_maxcut.py b/tests/test_maxcut.py index 5a3fbd5ee..1823f4658 100644 --- a/tests/test_maxcut.py +++ b/tests/test_maxcut.py @@ -50,10 +50,8 @@ def test_maxcut_qaoa_obj_fixed_angles(): obj = partial(maxcut_obj, w=get_adjacency_matrix(G)) optimal_cut, x = brute_force(obj, N, function_takes="bits") - for p in range(1, max_p + 1): gamma, beta, AR = get_fixed_gamma_beta(d, p, return_AR=True) - gamma = -1 * np.asarray(gamma) for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) assert abs(f(gamma, beta) / optimal_cut) > AR @@ -67,17 +65,18 @@ def test_maxcut_weighted_qaoa_obj(): lambda row: nx.node_link_graph(row["G_json"]), axis=1, ) + # changing the sign of gamma got from file + df["gamma"] = df["gamma"].apply(lambda x: [-y for y in x]) for _, row in df.iterrows(): for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(row["G"].number_of_nodes(), row["p"], G=row["G"], parameterization="gamma beta", simulator=simulator) - assert np.isclose(abs(f(-1 * np.asarray(row["gamma"]), row["beta"])), row["Expected cut of QAOA"]) + assert np.isclose(abs(f(row["gamma"], row["beta"])), row["Expected cut of QAOA"]) # Qiskit non-parameterized circuit must be tested separately precomputed_cuts = precompute_energies(maxcut_obj, row["G"].number_of_nodes(), w=get_adjacency_matrix(row["G"])) - qc = get_qaoa_circuit(row["G"], row["beta"], -1 * np.asarray(row["gamma"])) - qc_param = get_parameterized_qaoa_circuit(row["G"], row["p"]).bind_parameters(np.hstack([row["beta"], -1 * np.asarray(row["gamma"])])) - + qc = get_qaoa_circuit(row["G"], row["beta"], row["gamma"]) + qc_param = get_parameterized_qaoa_circuit(row["G"], row["p"]).bind_parameters(np.hstack([row["beta"], row["gamma"]])) sv = np.asarray(qiskit_backend.run(qc).result().get_statevector()) sv_param = np.asarray(qiskit_backend.run(qc_param).result().get_statevector()) diff --git a/tests/test_qaoa_objective_maxcut.py b/tests/test_qaoa_objective_maxcut.py index a16e3e809..df52b82cb 100644 --- a/tests/test_qaoa_objective_maxcut.py +++ b/tests/test_qaoa_objective_maxcut.py @@ -30,6 +30,6 @@ def test_validate_energy_for_terms_with_simulators_are_same(): g = get_qaoa_maxcut_objective(G.number_of_nodes(), 1, G=G, parameterization="gamma beta", simulator="qiskit") p = 1 gamma, beta = get_fixed_gamma_beta(3, p) - auto = f(-1 * np.asarray(gamma), beta) - qiskit = g(-1 * np.asarray(gamma), beta) + auto = f(gamma, beta) + qiskit = g(gamma, beta) assert np.isclose(auto, qiskit) From d6371a0fe5e9761ce25f19be74595b714d0a3930 Mon Sep 17 00:00:00 2001 From: Ganesan Date: Wed, 13 Dec 2023 10:22:30 -0500 Subject: [PATCH 12/13] flipped gamma sign in get_fixed_gamma_beta and fixed the test cases --- qokit/parameter_utils.py | 5 ++--- qokit/portfolio_optimization.py | 2 +- tests/test_maxcut.py | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/qokit/parameter_utils.py b/qokit/parameter_utils.py index 113fcc365..3763671da 100644 --- a/qokit/parameter_utils.py +++ b/qokit/parameter_utils.py @@ -208,10 +208,9 @@ def get_sk_gamma_beta(p, parameterization: QAOAParameterization | str = "gamma b raise ValueError(f"p={p} not supported, try lower p") parameterization = QAOAParameterization(parameterization) if parameterization == QAOAParameterization.THETA: - return np.concatenate((4 * gamma, beta), axis=0) + return np.concatenate((-1 * (4 * gamma), beta), axis=0) elif parameterization == QAOAParameterization.GAMMA_BETA: - # return -1 * (4 * gamma), beta - return 4 * gamma, beta + return -1 * (4 * gamma), beta @cache diff --git a/qokit/portfolio_optimization.py b/qokit/portfolio_optimization.py index eb67c9db4..53b840f0d 100644 --- a/qokit/portfolio_optimization.py +++ b/qokit/portfolio_optimization.py @@ -275,7 +275,7 @@ def get_sk_ini(p: int): """ scaled the sk look-up table for the application of portfolio optimziation """ - gamma_scale, beta_scale = -0.5, 1 + gamma_scale, beta_scale = 0.5, 1 gamma, beta = get_sk_gamma_beta(p, parameterization="gamma beta") scaled_gamma, scaled_beta = gamma_scale * gamma, beta_scale * beta X0 = np.concatenate((scaled_gamma, scaled_beta), axis=0) diff --git a/tests/test_maxcut.py b/tests/test_maxcut.py index 1823f4658..b839478bb 100644 --- a/tests/test_maxcut.py +++ b/tests/test_maxcut.py @@ -110,7 +110,6 @@ def test_sk_ini_maxcut(): last_ar = 0 for p in range(1, max_p + 1): gamma, beta = get_sk_gamma_beta(p) - gamma = -1 * np.asarray(gamma) for simulator in ["auto"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) cur_ar = f(gamma / np.sqrt(d), beta) / optimal_cut From 50b6006448e1b9064bf93a6a639f02670280b5eb Mon Sep 17 00:00:00 2001 From: Ruslan Shaydulin Date: Wed, 13 Dec 2023 16:32:32 -0500 Subject: [PATCH 13/13] Replace abs with sign flip in test_maxcut.py to reduce ambiguity in tests --- tests/test_maxcut.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_maxcut.py b/tests/test_maxcut.py index b839478bb..87bfd9413 100644 --- a/tests/test_maxcut.py +++ b/tests/test_maxcut.py @@ -54,7 +54,7 @@ def test_maxcut_qaoa_obj_fixed_angles(): gamma, beta, AR = get_fixed_gamma_beta(d, p, return_AR=True) for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(N, p, G=G, parameterization="gamma beta", simulator=simulator) - assert abs(f(gamma, beta) / optimal_cut) > AR + assert -f(gamma, beta) / optimal_cut > AR def test_maxcut_weighted_qaoa_obj(): @@ -71,7 +71,7 @@ def test_maxcut_weighted_qaoa_obj(): for _, row in df.iterrows(): for simulator in ["auto", "qiskit"]: f = get_qaoa_maxcut_objective(row["G"].number_of_nodes(), row["p"], G=row["G"], parameterization="gamma beta", simulator=simulator) - assert np.isclose(abs(f(row["gamma"], row["beta"])), row["Expected cut of QAOA"]) + assert np.isclose(-f(row["gamma"], row["beta"]), row["Expected cut of QAOA"]) # Qiskit non-parameterized circuit must be tested separately precomputed_cuts = precompute_energies(maxcut_obj, row["G"].number_of_nodes(), w=get_adjacency_matrix(row["G"]))