From 2e9b17bf0d213432cff3d0e90efc120dcc480ff5 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:28:07 -0400 Subject: [PATCH 01/28] added proper doc string to ising_trans() --- grove/ising/ising_qaoa.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 3f6ba28..da2aa5a 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -38,7 +38,13 @@ def print_fun(x): def ising_trans(x): - # Transformation to Ising notation + """ + Transformation to Ising notation. + + :param x: (int) Value of a single binary bit from {0, 1}. + :return: Transformed bit value from {-1, 1}. + :rtype: Integer. + """ if x == 1: return -1 else: @@ -119,8 +125,7 @@ def ising(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samp vqe_options=vqe_option) betas, gammas = qaoa_inst.get_angles() - most_freq_string, sampling_results = qaoa_inst.get_string( - betas, gammas) + most_freq_string, sampling_results = qaoa_inst.get_string(betas, gammas) most_freq_string_ising = [ising_trans(it) for it in most_freq_string] energy_ising = energy_value(h, J, most_freq_string_ising) param_prog = qaoa_inst.get_parameterized_program() From 3651e565f52800834e3bc142e3e62570551ba349 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:41:23 -0400 Subject: [PATCH 02/28] changed ``h`` argument from list to dict Ising instances can have many variables but almost no bias terms so a dictionary is naturally a better choice in order to account for sparse bias vectors --- grove/ising/ising_qaoa.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index da2aa5a..7d53a36 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -55,10 +55,10 @@ def ising(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samp initial_beta=None, initial_gamma=None, minimizer_kwargs=None, vqe_option=None): """ - Ising set up method + Ising set up method for QAOA. Supports 2-local as well as k-local interaction terms. - :param h: External magnectic term of the Ising problem. List. - :param J: Interaction term of the Ising problem. Dictionary. + :param h: (dict) External magnectic term of the Ising problem. + :param J: (dict) Interaction terms of the Ising problem (may be k-local). :param num_steps: (Optional.Default=2 * len(h)) Trotterization order for the QAOA algorithm. :param verbose: (Optional.Default=True) Verbosity of the code. @@ -95,7 +95,7 @@ def ising(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samp for i, j in J.keys(): cost_operators.append(PauliSum([PauliTerm("Z", i, J[(i, j)]) * PauliTerm("Z", j)])) - for i in range(n_nodes): + for i in h.keys(): cost_operators.append(PauliSum([PauliTerm("Z", i, h[i])])) for i in range(n_nodes): From 25253f8108a440223874454edb8ff0459665d4df Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:44:18 -0400 Subject: [PATCH 03/28] extracting qubit indices from ``h`` and ``J`` Ising instances can make use of arbitrary qubits especially when we have to map to a QPU hardware graph. Makes much more sense to extract the qubit indices and compute n_nodes like this. --- grove/ising/ising_qaoa.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 7d53a36..89fd073 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -88,7 +88,9 @@ def ising(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samp if num_steps == 0: num_steps = 2 * len(h) - n_nodes = len(h) + qubit_indices = set([ index for tuple_ in list(J.keys()) for index in tuple_] + + list(h.keys())) + n_nodes = len(qubit_indices) cost_operators = [] driver_operators = [] @@ -98,7 +100,7 @@ def ising(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samp for i in h.keys(): cost_operators.append(PauliSum([PauliTerm("Z", i, h[i])])) - for i in range(n_nodes): + for i in qubit_indices: driver_operators.append(PauliSum([PauliTerm("X", i, -1.0)])) if connection is None: From 38a18543bb0788fd8d0aa624380d727e2d12cdc0 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:46:06 -0400 Subject: [PATCH 04/28] renamed ising() to ising_qaoa() to make clear that it is a QAOA wrapper --- grove/ising/ising_qaoa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 89fd073..f52be82 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -51,7 +51,7 @@ def ising_trans(x): return 1 -def ising(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samples=None, +def ising_qaoa(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samples=None, initial_beta=None, initial_gamma=None, minimizer_kwargs=None, vqe_option=None): """ From 3dec036809d6723a63301dd1adb42cf5c64fa975 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:49:54 -0400 Subject: [PATCH 05/28] cleaned up doc string for better read the docs later on --- grove/ising/ising_qaoa.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index f52be82..8fee7b9 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -67,21 +67,19 @@ def ising_qaoa(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, :param connection: (Optional) connection to the QVM. Default is None. :param samples: (Optional. Default=None) VQE option. Number of samples (circuit preparation and measurement) to use in operator - averaging. + averaging. Required when using QPU backend. :param initial_beta: (Optional. Default=None) Initial guess for beta parameters. :param initial_gamma: (Optional. Default=None) Initial guess for gamma parameters. :param minimizer_kwargs: (Optional. Default=None). Minimizer optional arguments. If None set to - {'method': 'Nelder-Mead', - 'options': {'ftol': 1.0e-2, 'xtol': 1.0e-2, - 'disp': False} - :param vqe_option: (Optional. Default=None). VQE optional - arguments. If None set to + {'method': 'Nelder-Mead', 'options': {'ftol': 1.0e-2, + 'xtol': 1.0e-2, disp': False} + :param vqe_option: (Optional. Default=None). VQE optional arguments. If None set to vqe_option = {'disp': print_fun, 'return_all': True, 'samples': samples} - :return: Most frequent Ising string, Energy of the Ising string, Circuit used to obtain result. + :return: Most frequent Ising string, energy of the Ising string, circuit used to obtain result. :rtype: List, Integer or float, 'pyquil.quil.Program'. """ From e978b70dbbd8444b75f3b8235dec9d36bd54371c Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:50:15 -0400 Subject: [PATCH 06/28] supporting k-local interaction terms in J --- grove/ising/ising_qaoa.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 8fee7b9..7eb8c8c 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -92,8 +92,16 @@ def ising_qaoa(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, cost_operators = [] driver_operators = [] - for i, j in J.keys(): - cost_operators.append(PauliSum([PauliTerm("Z", i, J[(i, j)]) * PauliTerm("Z", j)])) + for key in J.keys(): + # first PauliTerm is multiplied with coefficient obtained from J + pauli_product = PauliTerm("Z", key[0], J[key]) + + for i in range(1,len(key)): + # multiply with additional Z PauliTerms depending + # on the locality of the interaction terms + pauli_product *= PauliTerm("Z", key[i]) + + cost_operators.append(PauliSum([pauli_product])) for i in h.keys(): cost_operators.append(PauliSum([PauliTerm("Z", i, h[i])])) From bfc6ea78953868903e6db8c95b8af8ae2fa142fb Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:52:27 -0400 Subject: [PATCH 07/28] energy_value() now supports k-local interaction terms --- grove/ising/ising_qaoa.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 7eb8c8c..848d673 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -15,20 +15,25 @@ def energy_value(h, J, sol): """ Obtain energy of an Ising solution for a given Ising problem (h,J). - :param h: External magnectic term of the Ising problem. List. - :param J: Interaction term of the Ising problem. Dictionary. - :param sol: Ising solution. List. + :param h: (dict) External magnetic term of the Ising problem. + :param J: (dict) Interaction terms of the Ising problem (may be k-local). + :param sol: (list) Ising solution. :return: Energy of the Ising string. :rtype: Integer or float. """ ener_ising = 0 for elm in J.keys(): - if elm[0] == elm[1]: - raise TypeError("""Interaction term must connect two different variables""") + paired_indices = [(a, b) for a, b in zip(elm, elm)] + if len(paired_indices) != len(set(paired_indices)): + raise TypeError(f"Interaction term must connect different variables. The term {elm} contains a duplicate.") else: - ener_ising += J[elm] * int(sol[elm[0]]) * int(sol[elm[1]]) - for i in range(len(h)): + multipliers = int(sol[elm[0]]) * int(sol[elm[1]]) + # if locality > 2 then add more multipliers + for i in range(2, len(elm)): + multipliers *= sol[elm[i]] + ener_ising += J[elm] * multipliers + for i in h.keys(): ener_ising += h[i] * int(sol[i]) return ener_ising From 229c7a601511a3f07db484ab13a0ef9291f38cc1 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:58:19 -0400 Subject: [PATCH 08/28] fixed existing tests for ising_qaoa() --- grove/tests/ising/test_ising.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index b76d8d5..cff8a62 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -1,4 +1,4 @@ -from grove.ising.ising_qaoa import ising +from grove.ising.ising_qaoa import ising_qaoa from grove.ising.ising_qaoa import energy_value import numpy as np from mock import patch @@ -6,7 +6,7 @@ def test_energy_value(): J = {(0, 1): 2.3} - h = [-2.4, 5.2] + h = {0: -2.4, 1: 5.2} sol = [1, -1] ener_ising = energy_value(h, J, sol) @@ -20,9 +20,9 @@ def test_ising_mock(): cxn.expectation.return_value = [-0.4893891813015294, 0.8876822987380573, -0.4893891813015292, -0.9333372094534063, -0.9859245403423198, 0.9333372094534065] J = {(0, 1): -2, (2, 3): 3} - h = [1, 1, -1, 1] + h = {0: 1, 1: 1, 2: -1, 3: 1} p = 1 - most_freq_string_ising, energy_ising, circuit = ising(h, J, num_steps=p, vqe_option=None, connection=cxn) + most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) assert most_freq_string_ising == [-1, -1, 1, -1] assert energy_ising == -9 From b5494a8dcf2e895bc1c99ecb23f2423bd2c1f2ed Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:00:45 -0400 Subject: [PATCH 09/28] more detailed tests for ising_qaoa() --- grove/tests/ising/test_ising.py | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index cff8a62..6a82fb2 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -26,3 +26,57 @@ def test_ising_mock(): assert most_freq_string_ising == [-1, -1, 1, -1] assert energy_ising == -9 + + with patch("pyquil.api.QVMConnection") as cxn: + # Mock the response + cxn.run_and_measure.return_value = [[1, 0, 1, 0]] + cxn.expectation.return_value = [0, 0, 0, 0] # dummy + + # checkerboard with couplings + J = {(0, 1): 1, (0, 2): 1, (1, 3): 1, (2, 3): 1} + h = {} + p = 1 + most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) + + assert most_freq_string_ising == [-1, 1, -1, 1] + assert energy_ising == 0 + + with patch("pyquil.api.QVMConnection") as cxn: + # Mock the response + cxn.run_and_measure.return_value = [[1, 0, 1, 0]] + cxn.expectation.return_value = [0, 0, 0, 0] # dummy + + # checkerboard with biases + J = {} + h = {0: 1, 1: -1, 2: 1, 3: -1} + p = 1 + most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) + + assert most_freq_string_ising == [-1, 1, -1, 1] + assert energy_ising == -4 + + with patch("pyquil.api.QVMConnection") as cxn: + # Mock the response + cxn.run_and_measure.return_value = [[1, 0, 1, 0, 1]] + cxn.expectation.return_value = [0, 0, 0, 0, 0] # dummy + + J = {(0, 4): -1} + h = {0: 1, 1: -1, 2: 1, 3: -1} + p = 1 + most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) + + assert most_freq_string_ising == [-1, 1, -1, 1, -1] + assert energy_ising == -5 + + with patch("pyquil.api.QVMConnection") as cxn: + # Mock the response + cxn.run_and_measure.return_value = [[0, 1, 1, 0]] + cxn.expectation.return_value = [0, 0, 0, 0, 0, 0, 0] # dummy + + J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5 , (0, 2, 3): 0.5, (1, 3): 3.1} + h = {0: -2.4, 1: 5.2 , 3: -0.3} + p = 1 + most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) + + assert most_freq_string_ising == [1, -1, -1, 1] + assert energy_ising == -7.8 From 7a6f81977a272589ee41502f38d62496a51d1da4 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:02:32 -0400 Subject: [PATCH 10/28] new tests added for ising_trans() and energy_value() --- grove/tests/ising/test_ising.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index 6a82fb2..083fae5 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -1,5 +1,4 @@ -from grove.ising.ising_qaoa import ising_qaoa -from grove.ising.ising_qaoa import energy_value +from grove.ising.ising_qaoa import * import numpy as np from mock import patch @@ -12,6 +11,17 @@ def test_energy_value(): assert(np.isclose(ener_ising, -9.9)) + J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5 , (0, 2, 3): 0.5, (1, 3): 3.1} + h = {0: -2.4, 1: 5.2 , 3: -0.3} + sol = [1, -1, -1, 1] + ener_ising = energy_value(h, J, sol) + + assert(np.isclose(ener_ising, -7.8)) + +def test_ising_trans(): + sol = [0, 1, 1, 0] + ising_sol = [ising_trans(bit) for bit in sol] + assert ising_sol == [1, -1, -1, 1] def test_ising_mock(): with patch("pyquil.api.QVMConnection") as cxn: From 33227ee16f2ad4aeac906dcc4cb81de0f4354a79 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:08:00 -0400 Subject: [PATCH 11/28] ``driver_operators`` added to arguments allows for user-defined mixer/driver hamiltonian in order to enforce hard constraints tests & docs also updated --- grove/ising/ising_qaoa.py | 18 +++++++++++++----- grove/tests/ising/test_ising.py | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 848d673..a61e10f 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -56,9 +56,10 @@ def ising_trans(x): return 1 -def ising_qaoa(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, samples=None, - initial_beta=None, initial_gamma=None, minimizer_kwargs=None, - vqe_option=None): +def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, + rand_seed=None, connection=None, samples=None, + initial_beta=None, initial_gamma=None, minimizer_kwargs=None, + vqe_option=None): """ Ising set up method for QAOA. Supports 2-local as well as k-local interaction terms. @@ -66,6 +67,10 @@ def ising_qaoa(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, :param J: (dict) Interaction terms of the Ising problem (may be k-local). :param num_steps: (Optional.Default=2 * len(h)) Trotterization order for the QAOA algorithm. + :param driver_operators: (Optional. Default: X on all qubits.) The mixer/driver + Hamiltonian used in QAOA. Can be used to enforce hard constraints + and ensure that solution stays in feasible subspace. + Must be PauliSum objects. :param verbose: (Optional.Default=True) Verbosity of the code. :param rand_seed: (Optional. Default=None) random seed when beta and gamma angles are not provided. @@ -111,8 +116,11 @@ def ising_qaoa(h, J, num_steps=0, verbose=True, rand_seed=None, connection=None, for i in h.keys(): cost_operators.append(PauliSum([PauliTerm("Z", i, h[i])])) - for i in qubit_indices: - driver_operators.append(PauliSum([PauliTerm("X", i, -1.0)])) + if driver_operators is None: + driver_operators = [] + # default to X mixer + for i in qubit_indices: + driver_operators.append(PauliSum([PauliTerm("X", i, -1.0)])) if connection is None: connection = CXN diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index 083fae5..e75ccbc 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -90,3 +90,23 @@ def test_ising_mock(): assert most_freq_string_ising == [1, -1, -1, 1] assert energy_ising == -7.8 + + with patch("pyquil.api.QVMConnection") as cxn: + # Mock the response + cxn.run_and_measure.return_value = [[0, 1, 1, 0]] + cxn.expectation.return_value = [0, 0, 0, 0, 0, 0, 0] # dummy + + swap_mixer = [] + for i in range(4): + for j in range(4): + if j != i: + swap_mixer.append(PauliSum([PauliTerm("X", i, 0.5) * PauliTerm("X", j, 1.0)])) + swap_mixer.append(PauliSum([PauliTerm("Y", i, 0.5) * PauliTerm("Y", j, 1.0)])) + + J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5 , (0, 2, 3): 0.5, (1, 3): 3.1} + h = {0: -2.4, 1: 5.2 , 3: -0.3} + p = 1 + most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, driver_operators=swap_mixer, num_steps=p, vqe_option=None, connection=cxn) + + assert most_freq_string_ising == [1, -1, -1, 1] + assert energy_ising == -7.8 From c10dd1ed0f23ee4018c145302f377c5c00c03ffa Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:15:23 -0400 Subject: [PATCH 12/28] read the docs for Ising QAOA added extensive documentation for the Ising QAOA wrapper added images added ising_qaoa to index.rst --- docs/index.rst | 1 + docs/ising_qaoa.rst | 268 ++++++++++++++++++ docs/ising_qaoa/2d_checkerboard.png | Bin 0 -> 19577 bytes docs/ising_qaoa/2d_checkerboard_solutions.png | Bin 0 -> 16964 bytes docs/ising_qaoa/generalplan.png | Bin 0 -> 29756 bytes docs/ising_qaoa/simple_coupling.png | Bin 0 -> 7717 bytes docs/ising_qaoa/triangle.png | Bin 0 -> 12883 bytes docs/ising_qaoa/triangle_desired.png | Bin 0 -> 5774 bytes grove/ising/ising_qaoa.py | 3 +- 9 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 docs/ising_qaoa.rst create mode 100644 docs/ising_qaoa/2d_checkerboard.png create mode 100644 docs/ising_qaoa/2d_checkerboard_solutions.png create mode 100644 docs/ising_qaoa/generalplan.png create mode 100644 docs/ising_qaoa/simple_coupling.png create mode 100644 docs/ising_qaoa/triangle.png create mode 100644 docs/ising_qaoa/triangle_desired.png diff --git a/docs/index.rst b/docs/index.rst index 3aa5e38..c85fe46 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,6 +23,7 @@ of which has its own self-contained documentation. installation vqe qaoa + ising_qaoa qft phaseestimation tomography diff --git a/docs/ising_qaoa.rst b/docs/ising_qaoa.rst new file mode 100644 index 0000000..ccb451d --- /dev/null +++ b/docs/ising_qaoa.rst @@ -0,0 +1,268 @@ +Ising Wrapper for QAOA +====================== + +Overview +-------- + +Ising QAOA is a wrapper for the +`quantum approximate optimization algorithm `_ +that makes it easy to work within the framework of Ising-type Hamiltonians +with binary variables \\( \\sigma_{k} \\in \\{+1, -1\\} \\). + +This wrapper is particulary useful for people that have been working with quantum annealers +in the past. However, in comparison to current quantum annealers the Ising QAOA wrapper +supports not only 2-local but also k-local interaction terms and the driver (mixer) +Hamiltonian is not dictated by the hardware but can be defined by the user. + +For each Ising instance the user specifies the bias terms \\( h_{i} \\), the +interaction tensor \\( J_{i,j,..,k} \\) and the approximation order of the algorithm. +``ising_qaoa.py`` contains routines for approximating the ground state of +the specified Ising-type Hamiltonian through the use of QAOA which itself +finds the optimal rotation angles via Grove's +`variational-quantum-eigensolver method `_. + +.. _quickstart-example: + +Quickstart Example +------------------- + +To test your installation and get going we can run Ising QAOA for +a very simple Ising Hamiltonian: the 2D checkerboard. +(for a detailed explanation see :ref:`2d-checkerboard`) +In your python script import the packages and connect to your QVM: + +.. code-block:: python + + import pyquil.api as api + from grove.ising.ising_qaoa import ising as ising_qaoa + qvm_connection = api.QVMConnection() + +Next we define the appropriate bias and interaction terms of the Ising Hamiltonian +for the checkerboard problem: + +.. code-block:: python + + J = {(0, 1): 1, (0, 2): 1, (1, 3): 1, (2, 3): 1} + h = {0: -1, 1: 1, 2: 1, 3: -1} + +There are plenty of optional configuration parameters for the algorithm but the two +most important are the number of steps to use for the trotterization (roughly corresponds to +the accuracy of the optimization) and the driver Hamiltonian (which determines how the +state space is searched). We instantiate the algorithm and run the optimization routine on our QVM: + +.. code-block:: python + + steps = 2 + solution_string, ising_energy, _ = ising_qaoa(h=h, J=J, num_steps=steps) + print(f'The algorithm returned {solution_string} with an energy of {ising_energy}') + +When running this routine you should observe the expectation value converging towards -8.0 +and the solution with the highest probability should be \\( [1, -1, -1, 1] \\) with an energy of \\( -8.0 \\). + +We can verify this by running the Ising QAOA multiple times and collecting statistics. +To do this, replace the last line of the last code block with: + +.. code-block:: python + + runs = 10 + stats = dict() + for _ in range(runs): + solution_string, ising_energy, _ = ising_qaoa(h=h, J=J, num_steps=steps) + if tuple(solution_string) in stats.keys(): + stats[tuple(solution_string)] += 1 + else: + stats[tuple(solution_string)] = 1 + print(f'Solution statistics: {stats}') + +You should see that the algorithm returns the aforementioned solution with ~99% probability (unless the classical minimizer got stuck in a local minima). + + +Algorithm and Details +--------------------- + +Introduction +~~~~~~~~~~~~ + +The Ising model is a very famous mathematical model by physicist Ernst Ising that was originally developed +to model ferromagnetism in statistical mechanics. The Ising model can be written as a +quadratic function of a set of spins \\( \\sigma_{i} = \\pm\, 1 \\): + +$$\\mathbf{H}(\\sigma_{i},...,\\sigma_{N}) = - \\sum_{i`_]: + +$$\\mathbf{H}(\\sigma_{i},...,\\sigma_{N}) = - \\sum_{i`_] +we know that finding the ground state of a two-dimensional Ising model without magnetic field lies +in the complexity class \\( P \\). However, as soon as you turn on that external magnetic field +you find yourself in the complexity class \\( NP \\) when trying to find the ground state and that's why +we are in desperate need for quantum computers to help us explore the energy landscape more efficiently! But +keep in mind that there is no proof that quantum computers can solve these types of problems in polynomial time... + +One of the reasons for the Ising model's popularity is the fact that many NP problems, such as number and graph partitioning or 3SAT, can be mapped to +it as discussed in e.g. [`3 `_]. + +This Ising QAOA wrapper automatically generates the cost Hamiltonian for the QAOA based on the provided +biases \\( h_{i} \\) and interaction terms \\( J_{i,j} \\). It operates with binary variables from the +set \\( \\{-1, +1\\} \\) and calculates the energy of the solution string. +Using either the QVM or the QPU, it can be used as a stand alone optimizer or a plugin +optimization routine in a larger environment. The usage pipeline is as follows: +1) formulate your problem in terms of an Ising model, +2) instantiate Ising QAOA with \\( h \\) and \\( J \\), +3) retrieve ground state solution by sampling. + +.. figure:: ising_qaoa/generalplan.png + :align: center + :figwidth: 100% + +The following sections give three concrete examples of how to use the +Ising QAOA wrapper to approximate ground states of various Hamiltonians. + +.. _2d-checkerboard: + +2-local Checkerboard Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before we try to create a checkerboard pattern, let's quickly think about the interaction or coupling term. +Consider two spins \\( \\sigma_{i} \\) and \\( \\sigma_{j} \\) and their 2-local interaction term \\( J_{i,j} \\): + +.. image:: ising_qaoa/simple_coupling.png + :align: center + :scale: 75% + +Suppose there are no biases on spins \\( i \\) and \\( j \\) and the coupling is \\( J_{i,j} = -1 \\). +Which values of \\( \\sigma_{i} \\) and \\( \\sigma_{j} \\) minimize the energy? Both spins should have the same +value, either +1 or -1, in order to get an overall energy of -1. Hence, a negative coupling term *correlates* spins! + +If the coupling is \\( J_{i,j} = +1 \\) the energy is minimized when the two spins have opposite values. +Thus, a positive coupling *anti-correlates* spins! + +Now consider the following two-dimensional graph with spins \\( \\sigma_{0}, \\sigma_{1}, \\sigma_{2}, \\sigma_{3}\\): + +.. image:: ising_qaoa/2d_checkerboard.png + :align: center + :scale: 75% + +Let's define that we colour vertex \\( i \\) black if \\( \\sigma_{i} = -1 \\) and white if \\( \\sigma_{i} = +1 \\). +The goal is to create a checkerboard pattern with the four vertices in the graph. There is various ways of defining +\\( h \\) and \\( J \\) to achieve this result. There are two possible solutions to this problem: + +.. image:: ising_qaoa/2d_checkerboard_solutions.png + :align: center + :scale: 75% + +The example used in the :ref:`quickstart-example` is one way of doing it. However, it involved bias terms which +strongly biased for solution nr. 2. This time we want don't care which solution we get as long as it is a valid +solution. Hence, we don't use any bias terms and only anticorrelate each pair of neighbouring spins: + +.. code-block:: python + + import pyquil.api as api + from grove.ising.ising_qaoa import ising as ising_qaoa + qvm_connection = api.QVMConnection() + + J = {(0, 1): 1, (0, 2): 1, (1, 3): 1, (2, 3): 1} + h = {} + + +Given this Ising problem, we run the QAOA algorithm with two \\( \\beta \\) and two \\( \\gamma \\) parameters (``steps=2``). +We run it ten times in order to collect some statistics: + +.. code-block:: python + + steps = 2 + runs = 10 + stats = dict() + for _ in range(runs): + solution_string, ising_energy, _ = ising_qaoa(h=h, J=J, num_steps=steps) + if tuple(solution_string) in stats.keys(): + stats[tuple(solution_string)] += 1 + else: + stats[tuple(solution_string)] = 1 + print(f'Solution statistics: {stats}') + +You should get the two possible solution strings \\( [-1, 1, 1, -1] \\) and \\( [1, -1, -1, 1] \\) +with roughly equal probabilities and an energy value of \\( -4.0 \\) each. + +3-local Triangle Example +~~~~~~~~~~~~~~~~~~~~~~~~ + +To illustrate the use of Ising QAOA with k-local interaction terms we will now consider a triangular graph. +This time we are dealing with 3 spins \\( \\sigma_{0}, \\sigma_{1}, \\sigma_{2}\\): + +.. image:: ising_qaoa/triangle.png + :align: center + :scale: 75% + +where the orange plane represents the 3-local interactions \\( J_{0,1,2} \\). The goal is to colour the graph +such that it looks like this: + +.. image:: ising_qaoa/triangle_desired.png + :align: center + :scale: 75% +Let's again define that we colour vertex \\( i \\) black if \\( \\sigma_{i} = -1 \\) and white if \\( \\sigma_{i} = +1 \\). +To get the desired colouring we define a strongly negative 3-local interaction term \\( J_{0,1,2} \\). This ensures that +either all vertices are coloured white or two vertices are coloured black. In order to incentivize the latter, +we set the following biases on \\( \\sigma_{0} \\) and \\( \\sigma_{1}\\): + +.. code-block:: python + + import pyquil.api as api + from grove.ising.ising_qaoa import ising as ising_qaoa + + qvm_connection = api.QVMConnection() + + J = {(0,1,2): -3} + h = {0: 1, 1: -1} + +We can now run the algorithm ten times with step size 2 to collect statistics (this might take a couple of minutes): + +.. code-block:: python + + steps = 2 + runs = 10 + stats = dict() + for _ in range(runs): + solution_string, ising_energy, _ = ising_qaoa(h=h, J=J, num_steps=steps) + if tuple(solution_string) in stats.keys(): + stats[tuple(solution_string)] += 1 + else: + stats[tuple(solution_string)] = 1 + print(f'Solution statistics: {stats}') + +The majority of the results should be the correct solution string \\( [-1, 1, -1 ] \\) (with energy -5.0). + +Source Code Docs +---------------- + +Here you can find documentation for the different functions of Ising QAOA. + +grove.ising.ising_qaoa.ising_qaoa +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: grove.ising.ising_qaoa.ising_qaoa + +grove.ising.ising_qaoa.ising_trans +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: grove.ising.ising_qaoa.ising_trans + +grove.ising.ising_qaoa.energy_value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: grove.ising.ising_qaoa.energy_value diff --git a/docs/ising_qaoa/2d_checkerboard.png b/docs/ising_qaoa/2d_checkerboard.png new file mode 100644 index 0000000000000000000000000000000000000000..04eb90e8631e5fc22c0d44d1a885a9e89fe31f05 GIT binary patch literal 19577 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 Awg3PC literal 0 HcmV?d00001 diff --git a/docs/ising_qaoa/2d_checkerboard_solutions.png b/docs/ising_qaoa/2d_checkerboard_solutions.png new file mode 100644 index 0000000000000000000000000000000000000000..83bde03fcf1365b862740037d619a70510093e5e GIT binary patch literal 16964 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 literal 0 HcmV?d00001 diff --git a/docs/ising_qaoa/generalplan.png b/docs/ising_qaoa/generalplan.png new file mode 100644 index 0000000000000000000000000000000000000000..7b6a17c1613bb8a6a4f34e36214a9736d4190b29 GIT binary patch literal 29756 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 literal 0 HcmV?d00001 diff --git a/docs/ising_qaoa/simple_coupling.png b/docs/ising_qaoa/simple_coupling.png new file mode 100644 index 0000000000000000000000000000000000000000..412875cb853581ba4da25e97dd0f6db864c2cf20 GIT binary patch literal 7717 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 iqGPH|+p9l&#Ep)of}kLy`VJ;-9Q;2XLvru{ literal 0 HcmV?d00001 diff --git a/docs/ising_qaoa/triangle_desired.png b/docs/ising_qaoa/triangle_desired.png new file mode 100644 index 0000000000000000000000000000000000000000..0933881d2b29712d802c8a2b861d51906b96674b GIT binary patch literal 5774 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 literal 0 HcmV?d00001 diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index a61e10f..889e947 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -1,4 +1,3 @@ - """ Finding the minimum energy for an Ising problem by QAOA. """ @@ -89,7 +88,7 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, :param vqe_option: (Optional. Default=None). VQE optional arguments. If None set to vqe_option = {'disp': print_fun, 'return_all': True, 'samples': samples} - :return: Most frequent Ising string, energy of the Ising string, circuit used to obtain result. + :return: Most frequent Ising string, Energy of the Ising string, Circuit used to obtain result. :rtype: List, Integer or float, 'pyquil.quil.Program'. """ From a73d510ca8c60053c111f52fa5adcc42c8f43078 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:20:37 -0400 Subject: [PATCH 13/28] changed IsingQAOA notebook to new syntax --- examples/IsingSolver.ipynb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/IsingSolver.ipynb b/examples/IsingSolver.ipynb index 4a43a7a..4d17f8f 100644 --- a/examples/IsingSolver.ipynb +++ b/examples/IsingSolver.ipynb @@ -20,7 +20,7 @@ "metadata": {}, "outputs": [], "source": [ - "from grove.ising.ising_qaoa import ising\n", + "from grove.ising.ising_qaoa import ising_qaoa\n", "from mock import patch" ] }, @@ -68,9 +68,9 @@ "outputs": [], "source": [ "J = {(0, 1): -2, (2, 3): 3}\n", - "h = [1, 1, -1, 1]\n", + "h = {0: 1, 1: 1, 2: -1, 3: 1}\n", "\n", - "solution, min_energy, circuit = ising(h, J, connection=cxn)" + "solution, min_energy, circuit = ising_qaoa(h, J, connection=cxn)" ] }, { @@ -86,7 +86,7 @@ "metadata": {}, "outputs": [], "source": [ - "solution_2, min_energy_2, circuit_2 = ising(h, J, num_steps=9, verbose=False, connection=cxn)" + "solution_2, min_energy_2, circuit_2 = ising_qaoa(h, J, num_steps=9, verbose=False, connection=cxn)" ] }, { From d077b073c6644e611f951ad8c4e37c3de461e218 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:49:54 -0400 Subject: [PATCH 14/28] cleaned up doc string for better read the docs later on --- grove/ising/ising_qaoa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 889e947..44558d2 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -88,7 +88,7 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, :param vqe_option: (Optional. Default=None). VQE optional arguments. If None set to vqe_option = {'disp': print_fun, 'return_all': True, 'samples': samples} - :return: Most frequent Ising string, Energy of the Ising string, Circuit used to obtain result. + :return: Most frequent Ising string, energy of the Ising string, circuit used to obtain result. :rtype: List, Integer or float, 'pyquil.quil.Program'. """ From d5ca6e7f7915303f7539e69c138229872eae8b34 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 15:58:19 -0400 Subject: [PATCH 15/28] fixed existing tests for ising_qaoa() --- grove/tests/ising/test_ising.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index e75ccbc..17c10e7 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -1,4 +1,5 @@ -from grove.ising.ising_qaoa import * +from grove.ising.ising_qaoa import ising_qaoa +from grove.ising.ising_qaoa import energy_value import numpy as np from mock import patch From d8dbfe302b99e783ce606a4eb6910fb7ed9e2c4b Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:02:32 -0400 Subject: [PATCH 16/28] new tests added for ising_trans() and energy_value() --- grove/tests/ising/test_ising.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index 17c10e7..e75ccbc 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -1,5 +1,4 @@ -from grove.ising.ising_qaoa import ising_qaoa -from grove.ising.ising_qaoa import energy_value +from grove.ising.ising_qaoa import * import numpy as np from mock import patch From 3fcf6aba815b5936a5d241b37e2e8a752593d173 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Wed, 28 Mar 2018 16:15:23 -0400 Subject: [PATCH 17/28] read the docs for Ising QAOA added extensive documentation for the Ising QAOA wrapper added images added ising_qaoa to index.rst --- grove/ising/ising_qaoa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 44558d2..889e947 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -88,7 +88,7 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, :param vqe_option: (Optional. Default=None). VQE optional arguments. If None set to vqe_option = {'disp': print_fun, 'return_all': True, 'samples': samples} - :return: Most frequent Ising string, energy of the Ising string, circuit used to obtain result. + :return: Most frequent Ising string, Energy of the Ising string, Circuit used to obtain result. :rtype: List, Integer or float, 'pyquil.quil.Program'. """ From f4472732a0798b50e9e7bd9df255190f95c80b0f Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Wed, 28 Mar 2018 14:25:38 -0400 Subject: [PATCH 18/28] ising_qaoa: Make Python2 compatible --- grove/ising/ising_qaoa.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 889e947..fa54005 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -25,7 +25,8 @@ def energy_value(h, J, sol): for elm in J.keys(): paired_indices = [(a, b) for a, b in zip(elm, elm)] if len(paired_indices) != len(set(paired_indices)): - raise TypeError(f"Interaction term must connect different variables. The term {elm} contains a duplicate.") + raise TypeError("Interaction term must connect different variables. " + "The term {} contains a duplicate.".format(elm)) else: multipliers = int(sol[elm[0]]) * int(sol[elm[1]]) # if locality > 2 then add more multipliers From 17a3a3a42b6e9308363b89b28039f6a4e9773a52 Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Thu, 29 Mar 2018 18:09:00 -0400 Subject: [PATCH 19/28] tests: Do not use start imports --- grove/tests/ising/test_ising.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index e75ccbc..b03b44f 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -1,7 +1,9 @@ -from grove.ising.ising_qaoa import * import numpy as np from mock import patch +from pyquil.paulis import PauliSum, PauliTerm +from grove.ising.ising_qaoa import energy_value, ising_trans, ising_qaoa + def test_energy_value(): J = {(0, 1): 2.3} From 8e424a5e996aa8a4744735ea333882eb1f1ff4f0 Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Thu, 29 Mar 2018 18:18:29 -0400 Subject: [PATCH 20/28] docs: Fix incorrect import --- docs/ising_qaoa.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ising_qaoa.rst b/docs/ising_qaoa.rst index ccb451d..2ed332b 100644 --- a/docs/ising_qaoa.rst +++ b/docs/ising_qaoa.rst @@ -34,7 +34,7 @@ In your python script import the packages and connect to your QVM: .. code-block:: python import pyquil.api as api - from grove.ising.ising_qaoa import ising as ising_qaoa + from grove.ising.ising_qaoa import ising_qaoa qvm_connection = api.QVMConnection() Next we define the appropriate bias and interaction terms of the Ising Hamiltonian @@ -173,7 +173,7 @@ solution. Hence, we don't use any bias terms and only anticorrelate each pair of .. code-block:: python import pyquil.api as api - from grove.ising.ising_qaoa import ising as ising_qaoa + from grove.ising.ising_qaoa import ising_qaoa qvm_connection = api.QVMConnection() J = {(0, 1): 1, (0, 2): 1, (1, 3): 1, (2, 3): 1} @@ -223,7 +223,7 @@ we set the following biases on \\( \\sigma_{0} \\) and \\( \\sigma_{1}\\): .. code-block:: python import pyquil.api as api - from grove.ising.ising_qaoa import ising as ising_qaoa + from grove.ising.ising_qaoa import ising_qaoa qvm_connection = api.QVMConnection() From af3cd11a4220dd1a8e6ab52f50a6356d08eab0fb Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Thu, 29 Mar 2018 18:19:36 -0400 Subject: [PATCH 21/28] style: Minor PEP8 fixes --- docs/ising_qaoa.rst | 2 +- grove/pyqaoa/qaoa.py | 2 +- grove/tests/ising/test_ising.py | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/ising_qaoa.rst b/docs/ising_qaoa.rst index 2ed332b..92aeb84 100644 --- a/docs/ising_qaoa.rst +++ b/docs/ising_qaoa.rst @@ -227,7 +227,7 @@ we set the following biases on \\( \\sigma_{0} \\) and \\( \\sigma_{1}\\): qvm_connection = api.QVMConnection() - J = {(0,1,2): -3} + J = {(0, 1, 2): -3} h = {0: 1, 1: -1} We can now run the algorithm ten times with step size 2 to collect statistics (this might take a couple of minutes): diff --git a/grove/pyqaoa/qaoa.py b/grove/pyqaoa/qaoa.py index 8103aab..612f48d 100644 --- a/grove/pyqaoa/qaoa.py +++ b/grove/pyqaoa/qaoa.py @@ -139,7 +139,7 @@ def get_parameterized_program(self): cost_para_programs = [] driver_para_programs = [] - for idx in range(self.steps): + for _ in range(self.steps): cost_list = [] driver_list = [] for cost_pauli_sum in self.cost_ham: diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index b03b44f..a9f36c8 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -13,8 +13,8 @@ def test_energy_value(): assert(np.isclose(ener_ising, -9.9)) - J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5 , (0, 2, 3): 0.5, (1, 3): 3.1} - h = {0: -2.4, 1: 5.2 , 3: -0.3} + J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5, (0, 2, 3): 0.5, (1, 3): 3.1} + h = {0: -2.4, 1: 5.2, 3: -0.3} sol = [1, -1, -1, 1] ener_ising = energy_value(h, J, sol) @@ -42,7 +42,7 @@ def test_ising_mock(): with patch("pyquil.api.QVMConnection") as cxn: # Mock the response cxn.run_and_measure.return_value = [[1, 0, 1, 0]] - cxn.expectation.return_value = [0, 0, 0, 0] # dummy + cxn.expectation.return_value = [0, 0, 0, 0] # dummy # checkerboard with couplings J = {(0, 1): 1, (0, 2): 1, (1, 3): 1, (2, 3): 1} @@ -56,7 +56,7 @@ def test_ising_mock(): with patch("pyquil.api.QVMConnection") as cxn: # Mock the response cxn.run_and_measure.return_value = [[1, 0, 1, 0]] - cxn.expectation.return_value = [0, 0, 0, 0] # dummy + cxn.expectation.return_value = [0, 0, 0, 0] # dummy # checkerboard with biases J = {} @@ -70,7 +70,7 @@ def test_ising_mock(): with patch("pyquil.api.QVMConnection") as cxn: # Mock the response cxn.run_and_measure.return_value = [[1, 0, 1, 0, 1]] - cxn.expectation.return_value = [0, 0, 0, 0, 0] # dummy + cxn.expectation.return_value = [0, 0, 0, 0, 0] # dummy J = {(0, 4): -1} h = {0: 1, 1: -1, 2: 1, 3: -1} @@ -83,10 +83,10 @@ def test_ising_mock(): with patch("pyquil.api.QVMConnection") as cxn: # Mock the response cxn.run_and_measure.return_value = [[0, 1, 1, 0]] - cxn.expectation.return_value = [0, 0, 0, 0, 0, 0, 0] # dummy + cxn.expectation.return_value = [0, 0, 0, 0, 0, 0, 0] # dummy - J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5 , (0, 2, 3): 0.5, (1, 3): 3.1} - h = {0: -2.4, 1: 5.2 , 3: -0.3} + J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5, (0, 2, 3): 0.5, (1, 3): 3.1} + h = {0: -2.4, 1: 5.2, 3: -0.3} p = 1 most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) @@ -96,7 +96,7 @@ def test_ising_mock(): with patch("pyquil.api.QVMConnection") as cxn: # Mock the response cxn.run_and_measure.return_value = [[0, 1, 1, 0]] - cxn.expectation.return_value = [0, 0, 0, 0, 0, 0, 0] # dummy + cxn.expectation.return_value = [0, 0, 0, 0, 0, 0, 0] # dummy swap_mixer = [] for i in range(4): @@ -105,8 +105,8 @@ def test_ising_mock(): swap_mixer.append(PauliSum([PauliTerm("X", i, 0.5) * PauliTerm("X", j, 1.0)])) swap_mixer.append(PauliSum([PauliTerm("Y", i, 0.5) * PauliTerm("Y", j, 1.0)])) - J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5 , (0, 2, 3): 0.5, (1, 3): 3.1} - h = {0: -2.4, 1: 5.2 , 3: -0.3} + J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5, (0, 2, 3): 0.5, (1, 3): 3.1} + h = {0: -2.4, 1: 5.2, 3: -0.3} p = 1 most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, driver_operators=swap_mixer, num_steps=p, vqe_option=None, connection=cxn) From 848cfc91f28104a90f631787b073a5186c6f935f Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Mon, 9 Apr 2018 16:23:59 -0400 Subject: [PATCH 22/28] ising_qaoa: Fix energy value computation --- grove/ising/ising_qaoa.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index fa54005..7a69e9b 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -21,6 +21,9 @@ def energy_value(h, J, sol): :rtype: Integer or float. """ + # Solution string is reversed when obtained from qvm/qpu + sol = list(reversed(sol)) + ener_ising = 0 for elm in J.keys(): paired_indices = [(a, b) for a, b in zip(elm, elm)] From c923a5ff02f13932a8e70ce4c5a2e2fc46d319e2 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Mon, 9 Apr 2018 21:17:54 -0400 Subject: [PATCH 23/28] fixed tests to accommodate new energy computation --- grove/tests/ising/test_ising.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grove/tests/ising/test_ising.py b/grove/tests/ising/test_ising.py index a9f36c8..de1c585 100644 --- a/grove/tests/ising/test_ising.py +++ b/grove/tests/ising/test_ising.py @@ -11,7 +11,7 @@ def test_energy_value(): sol = [1, -1] ener_ising = energy_value(h, J, sol) - assert(np.isclose(ener_ising, -9.9)) + assert(np.isclose(ener_ising, 5.3)) J = {(0, 1, 2): 1.2, (0, 1, 2, 3): 2.5, (0, 2, 3): 0.5, (1, 3): 3.1} h = {0: -2.4, 1: 5.2, 3: -0.3} @@ -37,7 +37,7 @@ def test_ising_mock(): most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) assert most_freq_string_ising == [-1, -1, 1, -1] - assert energy_ising == -9 + assert energy_ising == 5 with patch("pyquil.api.QVMConnection") as cxn: # Mock the response @@ -65,7 +65,7 @@ def test_ising_mock(): most_freq_string_ising, energy_ising, circuit = ising_qaoa(h, J, num_steps=p, vqe_option=None, connection=cxn) assert most_freq_string_ising == [-1, 1, -1, 1] - assert energy_ising == -4 + assert energy_ising == 4 with patch("pyquil.api.QVMConnection") as cxn: # Mock the response From 46d6a05cc1db6cb96d4a47efe17de1d52d5a2d40 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Sun, 22 Jul 2018 18:58:35 -0400 Subject: [PATCH 24/28] sphinx bug fixes implemented --- docs/ising_qaoa.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/ising_qaoa.rst b/docs/ising_qaoa.rst index 92aeb84..a8af8c0 100644 --- a/docs/ising_qaoa.rst +++ b/docs/ising_qaoa.rst @@ -215,6 +215,7 @@ such that it looks like this: .. image:: ising_qaoa/triangle_desired.png :align: center :scale: 75% + Let's again define that we colour vertex \\( i \\) black if \\( \\sigma_{i} = -1 \\) and white if \\( \\sigma_{i} = +1 \\). To get the desired colouring we define a strongly negative 3-local interaction term \\( J_{0,1,2} \\). This ensures that either all vertices are coloured white or two vertices are coloured black. In order to incentivize the latter, @@ -253,7 +254,7 @@ Source Code Docs Here you can find documentation for the different functions of Ising QAOA. grove.ising.ising_qaoa.ising_qaoa -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autofunction:: grove.ising.ising_qaoa.ising_qaoa From 97c073b22eb57ea84b928f3f46ebe4c12be43d30 Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Sun, 22 Jul 2018 19:11:04 -0400 Subject: [PATCH 25/28] implemented some requested changes - fixed doc strings - fixed spacing according to PEP8 --- grove/ising/ising_qaoa.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 7a69e9b..1ab8cb2 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -14,9 +14,9 @@ def energy_value(h, J, sol): """ Obtain energy of an Ising solution for a given Ising problem (h,J). - :param h: (dict) External magnetic term of the Ising problem. - :param J: (dict) Interaction terms of the Ising problem (may be k-local). - :param sol: (list) Ising solution. + :param dict h: External magnetic term of the Ising problem. + :param dict J: Interaction terms of the Ising problem (may be k-local). + :param list sol: Ising solution as returned from QVM/QPU. :return: Energy of the Ising string. :rtype: Integer or float. @@ -49,7 +49,7 @@ def ising_trans(x): """ Transformation to Ising notation. - :param x: (int) Value of a single binary bit from {0, 1}. + :param int x: Value of a single binary bit from {0, 1}. :return: Transformed bit value from {-1, 1}. :rtype: Integer. """ @@ -66,8 +66,8 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, """ Ising set up method for QAOA. Supports 2-local as well as k-local interaction terms. - :param h: (dict) External magnectic term of the Ising problem. - :param J: (dict) Interaction terms of the Ising problem (may be k-local). + :param dict h: External magnectic term of the Ising problem. + :param dict J: Interaction terms of the Ising problem (may be k-local). :param num_steps: (Optional.Default=2 * len(h)) Trotterization order for the QAOA algorithm. :param driver_operators: (Optional. Default: X on all qubits.) The mixer/driver @@ -80,7 +80,7 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, :param connection: (Optional) connection to the QVM. Default is None. :param samples: (Optional. Default=None) VQE option. Number of samples (circuit preparation and measurement) to use in operator - averaging. Required when using QPU backend. + averaging. :param initial_beta: (Optional. Default=None) Initial guess for beta parameters. :param initial_gamma: (Optional. Default=None) Initial guess for gamma @@ -99,7 +99,7 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, if num_steps == 0: num_steps = 2 * len(h) - qubit_indices = set([ index for tuple_ in list(J.keys()) for index in tuple_] + qubit_indices = set([index for tuple_ in list(J.keys()) for index in tuple_] + list(h.keys())) n_nodes = len(qubit_indices) From fc381d4840a6325c2577ea5c48901b47769fe63a Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Mon, 23 Jul 2018 10:20:34 -0400 Subject: [PATCH 26/28] fixed driver_operators bug - declaring driver_operators as empty list led to no driver Hamiltonian being used --- grove/ising/ising_qaoa.py | 1 - 1 file changed, 1 deletion(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index 1ab8cb2..f4cde33 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -104,7 +104,6 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, n_nodes = len(qubit_indices) cost_operators = [] - driver_operators = [] for key in J.keys(): # first PauliTerm is multiplied with coefficient obtained from J pauli_product = PauliTerm("Z", key[0], J[key]) From 11b012ae3d6d61138ec84404c600b485970c6c5b Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Mon, 23 Jul 2018 10:30:14 -0400 Subject: [PATCH 27/28] simplified test for duplicate elements in J.keys() --- grove/ising/ising_qaoa.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index f4cde33..df3b3d5 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -26,8 +26,7 @@ def energy_value(h, J, sol): ener_ising = 0 for elm in J.keys(): - paired_indices = [(a, b) for a, b in zip(elm, elm)] - if len(paired_indices) != len(set(paired_indices)): + if len(elm) != len(set(elm)): raise TypeError("Interaction term must connect different variables. " "The term {} contains a duplicate.".format(elm)) else: From a652814dec86e4eab65a9d76feec3202575e51da Mon Sep 17 00:00:00 2001 From: Mark Fingerhuth Date: Mon, 23 Jul 2018 11:02:51 -0400 Subject: [PATCH 28/28] initializing multipliers + removed -1.0 from driver_ops --- grove/ising/ising_qaoa.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/grove/ising/ising_qaoa.py b/grove/ising/ising_qaoa.py index df3b3d5..d2b8b91 100644 --- a/grove/ising/ising_qaoa.py +++ b/grove/ising/ising_qaoa.py @@ -30,10 +30,9 @@ def energy_value(h, J, sol): raise TypeError("Interaction term must connect different variables. " "The term {} contains a duplicate.".format(elm)) else: - multipliers = int(sol[elm[0]]) * int(sol[elm[1]]) - # if locality > 2 then add more multipliers - for i in range(2, len(elm)): - multipliers *= sol[elm[i]] + multipliers = 1 + for idx in elm: + multipliers *= sol[idx] ener_ising += J[elm] * multipliers for i in h.keys(): ener_ising += h[i] * int(sol[i]) @@ -69,10 +68,10 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, :param dict J: Interaction terms of the Ising problem (may be k-local). :param num_steps: (Optional.Default=2 * len(h)) Trotterization order for the QAOA algorithm. - :param driver_operators: (Optional. Default: X on all qubits.) The mixer/driver + :param list driver_operators: (Optional. Default: X on all qubits.) The mixer/driver Hamiltonian used in QAOA. Can be used to enforce hard constraints and ensure that solution stays in feasible subspace. - Must be PauliSum objects. + Must be list of PauliSum objects. :param verbose: (Optional.Default=True) Verbosity of the code. :param rand_seed: (Optional. Default=None) random seed when beta and gamma angles are not provided. @@ -121,7 +120,7 @@ def ising_qaoa(h, J, num_steps=0, driver_operators=None, verbose=True, driver_operators = [] # default to X mixer for i in qubit_indices: - driver_operators.append(PauliSum([PauliTerm("X", i, -1.0)])) + driver_operators.append(PauliSum([PauliTerm("X", i, 1.0)])) if connection is None: connection = CXN