Skip to content

Commit 86771b2

Browse files
authoredApr 20, 2023
Merge pull request entropicalabs#225 from entropicalabs/bugfix_dump_methods
Bugfix dump methods
2 parents 97a80ff + 58a5d08 commit 86771b2

16 files changed

+482
-360
lines changed
 

‎.github/workflows/test_main_linux.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
run: |
4747
IBMQ_TOKEN=$IBMQ_TOKEN
4848
source env/bin/activate
49-
python -c'from qiskit import IBMQ; import os; IBMQ.save_account(os.environ.get("IBMQ_TOKEN"))'
49+
python -c'from qiskit_ibm_provider import IBMProvider; import os; IBMProvider.save_account(os.environ.get("IBMQ_TOKEN"))'
5050
- name: Setup AWS
5151
env:
5252
ACCESS_KEY: ${{ secrets.ACCESS_KEY }}

‎src/openqaoa-core/algorithms/baseworkflow.py

+27-27
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ def __init__(self, device=DeviceLocal("vectorized")):
107107
"target": None,
108108
"cloud": None,
109109
"client": None,
110-
"qubit_number": None, # it is set automatically in the compilation from the problem object
111110
"execution_time_start": None,
112111
"execution_time_end": None,
113112
}
@@ -131,13 +130,13 @@ def __setattr__(self, __name, __value):
131130

132131
def set_header(
133132
self,
134-
project_id: str,
135-
description: str,
136-
run_by: str,
137-
provider: str,
138-
target: str,
139-
cloud: str,
140-
client: str,
133+
project_id: str = None,
134+
description: str = None,
135+
run_by: str = None,
136+
provider: str = None,
137+
target: str = None,
138+
cloud: str = None,
139+
client: str = None,
141140
experiment_id: str = None,
142141
):
143142
"""
@@ -147,16 +146,17 @@ def set_header(
147146
----------
148147
TODO : document the parameters
149148
"""
149+
if project_id is not None:
150+
if not is_valid_uuid(project_id):
151+
raise ValueError(
152+
"The project_id is not a valid uuid, example of a valid uuid: 8353185c-b175-4eda-9628-b4e58cb0e41b"
153+
)
150154

151-
if not is_valid_uuid(project_id):
152-
raise ValueError(
153-
"The project_id is not a valid uuid, example of a valid uuid: 8353185c-b175-4eda-9628-b4e58cb0e41b"
154-
)
155-
156-
if experiment_id != None:
155+
if experiment_id is not None:
157156
if not is_valid_uuid(experiment_id):
158157
raise ValueError(
159-
"The experiment_id is not a valid uuid, example of a valid uuid: 8353185c-b175-4eda-9628-b4e58cb0e41b"
158+
"The experiment_id is not a valid uuid, \
159+
example of a valid uuid: 8353185c-b175-4eda-9628-b4e58cb0e41b"
160160
)
161161
else:
162162
self.header["experiment_id"] = experiment_id
@@ -335,13 +335,13 @@ def compile(self, problem: QUBO):
335335
self.header["atomic_id"] = generate_uuid()
336336

337337
# header is updated with the qubit number of the problem
338-
self.header["qubit_number"] = self.problem.n
338+
self.set_exp_tags({"qubit_number": self.problem.n})
339339

340340
def optimize():
341341
raise NotImplementedError
342342

343343
def _serializable_dict(
344-
self, complex_to_string: bool = False, intermediate_mesurements: bool = True
344+
self, complex_to_string: bool = False, intermediate_measurements: bool = True
345345
):
346346
"""
347347
Returns a dictionary with all values and attributes of the object that we want to
@@ -355,7 +355,7 @@ def _serializable_dict(
355355
complex_to_string: bool
356356
If True, converts all complex numbers to strings. This is useful for
357357
JSON serialization, for the `dump(s)` methods.
358-
intermediate_mesurements: bool
358+
intermediate_measurements: bool
359359
If True, intermediate measurements are included in the dump.
360360
If False, intermediate measurements are not included in the dump.
361361
Default is True.
@@ -381,8 +381,8 @@ def _serializable_dict(
381381
)
382382

383383
data["result"] = (
384-
self.result.asdict(False, complex_to_string, intermediate_mesurements)
385-
if not self.result in [None, {}]
384+
self.result.asdict(False, complex_to_string, intermediate_measurements)
385+
if self.result not in [None, {}]
386386
else None
387387
)
388388

@@ -437,7 +437,7 @@ def asdict(self, exclude_keys: List[str] = [], options: dict = {}):
437437
complex_to_string : bool
438438
If True, converts complex numbers to strings. If False,
439439
complex numbers are not converted to strings.
440-
intermediate_mesurements : bool
440+
intermediate_measurements : bool
441441
If True, includes the intermediate measurements in the results.
442442
If False, only the final measurements are included.
443443
@@ -469,7 +469,7 @@ def dumps(self, indent: int = 2, exclude_keys: List[str] = [], options: dict = {
469469
options : dict
470470
A dictionary of options to pass to the method that creates
471471
the dictionary to dump.
472-
intermediate_mesurements : bool
472+
intermediate_measurements : bool
473473
If True, includes the intermediate measurements in the results.
474474
If False, only the final measurements are included.
475475
@@ -530,7 +530,7 @@ def dump(
530530
raises an error if the file already exists.
531531
options : dict
532532
A dictionary of options to pass to the method that creates the dictionary to dump.
533-
intermediate_mesurements : bool
533+
intermediate_measurements : bool
534534
If True, includes the intermediate measurements in the results.
535535
If False, only the final measurements are included.
536536
"""
@@ -544,11 +544,11 @@ def dump(
544544
)
545545

546546
# get the full name
547-
if prepend_id == False and file_name == "":
547+
if prepend_id is False and file_name == "":
548548
raise ValueError(
549549
"dump method missing argument: 'file_name'. Otherwise 'prepend_id' must be specified as True."
550550
)
551-
elif prepend_id == False:
551+
elif prepend_id is False:
552552
file = file_path + file_name
553553
elif file_name == "":
554554
file = (
@@ -577,12 +577,12 @@ def dump(
577577
file = file + ".gz" if ".gz" != file[-3:] else file
578578

579579
# checking if the file already exists, and raising an error if it does and overwrite is False
580-
if overwrite == False and exists(file):
580+
if overwrite is False and exists(file):
581581
raise FileExistsError(
582582
f"The file {file} already exists. Please change the name of the file or set overwrite=True."
583583
)
584584

585-
## saving the file
585+
# saving the file
586586
if compresslevel == 0: # if compresslevel is 0, save as json file
587587
with open(file, "w") as f:
588588
if exclude_keys == []:

‎src/openqaoa-core/algorithms/qaoa/qaoa_result.py

+63-34
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818

1919
def most_probable_bitstring(cost_hamiltonian, measurement_outcomes):
20-
20+
"""
21+
Computing the most probable bitstring
22+
"""
2123
mea_out = list(measurement_outcomes.values())
2224
index_likliest_states = np.argwhere(mea_out == np.max(mea_out))
2325
# degeneracy = len(index_likliest_states)
@@ -54,7 +56,9 @@ def __init__(
5456
cost_hamiltonian: Type[Hamiltonian],
5557
type_backend: Type[QAOABaseBackend],
5658
):
57-
59+
"""
60+
init method
61+
"""
5862
self.__type_backend = type_backend
5963
self.method = method
6064
self.cost_hamiltonian = cost_hamiltonian
@@ -116,7 +120,7 @@ def asdict(
116120
self,
117121
keep_cost_hamiltonian: bool = True,
118122
complex_to_string: bool = False,
119-
intermediate_mesurements: bool = True,
123+
intermediate_measurements: bool = True,
120124
exclude_keys: List[str] = [],
121125
):
122126
"""
@@ -132,7 +136,7 @@ def asdict(
132136
complex_to_string: `bool`
133137
If True, the complex numbers are converted to strings. If False, they are kept as complex numbers.
134138
This is useful for the JSON serialization.
135-
intermediate_mesurements: bool, optional
139+
intermediate_measurements: bool, optional
136140
If True, intermediate measurements are included in the dump.
137141
If False, intermediate measurements are not included in the dump.
138142
Default is True.
@@ -152,7 +156,7 @@ def asdict(
152156
return_dict["evals"] = self.evals
153157
return_dict["most_probable_states"] = self.most_probable_states
154158

155-
complx_to_str = (
159+
complex_to_str = (
156160
lambda x: str(x)
157161
if isinstance(x, np.complex128) or isinstance(x, complex)
158162
else x
@@ -161,43 +165,67 @@ def asdict(
161165
# if the backend is a statevector backend, the measurement outcomes will be the statevector,
162166
# meaning that it is a list of complex numbers, which is not serializable.
163167
# If that is the case, and complex_to_string is true the complex numbers are converted to strings.
164-
if complex_to_string and issubclass(
165-
self.__type_backend, QAOABaseBackendStatevector
166-
):
168+
if complex_to_string:
167169
return_dict["intermediate"] = {}
168170
for key, value in self.intermediate.items():
169-
if (
170-
intermediate_mesurements == False and "measurement" in key
171-
): # if intermediate_mesurements is false, the intermediate measurements are not included in the dump
172-
return_dict["intermediate"][key] = []
173-
elif "measurement" in key and (
174-
isinstance(value, list) or isinstance(value, np.ndarray)
171+
# Measurements and Cost may require casting
172+
if "measurement" in key:
173+
if len(value) > 0:
174+
if intermediate_measurements is False:
175+
# if intermediate_measurements is false, the intermediate measurements are not included
176+
return_dict["intermediate"][key] = []
177+
elif isinstance(
178+
value[0], np.ndarray
179+
): # Statevector -> convert complex to str
180+
return_dict["intermediate"][key] = [
181+
[complex_to_str(item) for item in list_]
182+
for list_ in value
183+
if (
184+
isinstance(list_, list)
185+
or isinstance(list_, np.ndarray)
186+
)
187+
]
188+
else: # All other case -> cast numpy into
189+
return_dict["intermediate"][key] = [
190+
{k_: int(v_) for k_, v_ in v.items()} for v in value
191+
]
192+
else:
193+
pass
194+
elif "cost" == key and (
195+
isinstance(value[0], np.float64) or isinstance(value[0], np.float32)
175196
):
176-
return_dict["intermediate"][key] = [
177-
[complx_to_str(item) for item in list_]
178-
for list_ in value
179-
if (isinstance(list_, list) or isinstance(list_, np.ndarray))
180-
]
197+
return_dict["intermediate"][key] = [float(item) for item in value]
181198
else:
182199
return_dict["intermediate"][key] = value
183200

184201
return_dict["optimized"] = {}
185202
for key, value in self.optimized.items():
203+
# If wavefunction do complex to str
186204
if "measurement" in key and (
187205
isinstance(value, list) or isinstance(value, np.ndarray)
188206
):
189207
return_dict["optimized"][key] = [
190-
complx_to_str(item) for item in value
208+
complex_to_str(item) for item in value
191209
]
210+
# if dictionary, convert measurement values to integers
211+
elif "measurement" in key and (isinstance(value, dict)):
212+
return_dict["optimized"][key] = {
213+
k: int(v) for k, v in value.items()
214+
}
192215
else:
193216
return_dict["optimized"][key] = value
217+
218+
if "cost" in key and (
219+
isinstance(value, np.float64) or isinstance(value, np.float32)
220+
):
221+
return_dict["optimized"][key] = float(value)
194222
else:
195223
return_dict["intermediate"] = self.intermediate
196224
return_dict["optimized"] = self.optimized
197225

198226
# if we are using a shot adaptive optimizer, we need to add the number of shots to the result,
199227
# so if attribute n_shots is not empty, it is added to the dictionary
200-
if getattr(self, "n_shots", None) != None:
228+
if getattr(self, "n_shots", None) is not None:
201229
return_dict["n_shots"] = self.n_shots
202230

203231
return (
@@ -233,7 +261,7 @@ def from_dict(
233261
setattr(result, key, value)
234262

235263
# if there is an input cost hamiltonian, it is added to the result
236-
if cost_hamiltonian != None:
264+
if cost_hamiltonian is not None:
237265
result.cost_hamiltonian = cost_hamiltonian
238266

239267
# if the measurement_outcomes are strings, they are converted to complex numbers
@@ -281,7 +309,7 @@ def get_counts(measurement_outcomes):
281309
the actual measurement counts.
282310
"""
283311

284-
if type(measurement_outcomes) == type(np.array([])):
312+
if isinstance(measurement_outcomes, type(np.array([]))):
285313
measurement_outcomes = qaoa_probabilities(measurement_outcomes)
286314

287315
return measurement_outcomes
@@ -335,7 +363,6 @@ def plot_probabilities(
335363
color="tab:blue",
336364
ax=None,
337365
):
338-
339366
"""
340367
Helper function to plot the probabilities corresponding to each basis states
341368
(with prob != 0) obtained from the optimized result
@@ -359,7 +386,7 @@ def plot_probabilities(
359386
outcome = self.optimized["measurement_outcomes"]
360387

361388
# converting to counts dictionary if outcome is statevector
362-
if type(outcome) == type(np.array([])):
389+
if isinstance(outcome, type(np.array([]))):
363390
outcome = self.get_counts(outcome)
364391
# setting norm to 1 since it might differ slightly for statevectors due to numerical preicision
365392
norm = np.float64(1)
@@ -407,7 +434,7 @@ def plot_probabilities(
407434
]
408435
labels.append("rest")
409436

410-
# represent the bar with the addition of all the remaining probabilites
437+
# represent the bar with the addition of all the remaining probabilities
411438
rest = sum(probs[n_states_to_keep:])
412439

413440
if ax is None:
@@ -470,7 +497,7 @@ def plot_n_shots(
470497
if ax is None:
471498
ax = plt.subplots(figsize=figsize)[1]
472499

473-
## creating a list of parameters to plot
500+
# creating a list of parameters to plot
474501
# if param_to_plot is not given, plot all the parameters
475502
if param_to_plot is None:
476503
param_to_plot = list(range(len(self.n_shots[0])))
@@ -504,22 +531,23 @@ def plot_n_shots(
504531
color = [color]
505532

506533
# if param_top_plot is a list and label or color are not lists, raise error
507-
if (type(label) != list) or (type(color) != list and color != None):
534+
if (type(label) != list) or (type(color) != list and color is not None):
508535
raise TypeError("`label` and `color` must be list of str")
509536
# if label is a list, check that all the elements are strings
510-
for l in label:
511-
assert type(l) == str, "`label` must be a list of strings"
537+
for lab in label:
538+
assert type(lab) == str, "`label` must be a list of strings"
512539
# if color is a list, check that all the elements are strings
513-
if color != None:
540+
if color is not None:
514541
for c in color:
515542
assert type(c) == str, "`color` must be a list of strings"
516543

517544
# if label and color are lists, check if they have the same length as param_to_plot
518545
if len(label) != len(param_to_plot) or (
519-
color != None and len(color) != len(param_to_plot)
546+
color is not None and len(color) != len(param_to_plot)
520547
):
521548
raise ValueError(
522-
f"`param_to_plot`, `label` and `color` must have the same length, `param_to_plot` is a list of {len(param_to_plot)} elements"
549+
f"`param_to_plot`, `label` and `color` must have the same length, \
550+
`param_to_plot` is a list of {len(param_to_plot)} elements"
523551
)
524552

525553
# linestyle must be a string or a list of strings, if it is a string, convert it to a list of strings
@@ -529,7 +557,8 @@ def plot_n_shots(
529557
linestyle = [linestyle for _ in range(len(param_to_plot))]
530558
elif len(linestyle) != len(param_to_plot):
531559
raise ValueError(
532-
f"`linestyle` must have the same length as param_to_plot (length of `param_to_plot` is {len(param_to_plot)}), or be a string"
560+
f"`linestyle` must have the same length as param_to_plot \
561+
(length of `param_to_plot` is {len(param_to_plot)}), or be a string"
533562
)
534563
else:
535564
for ls in linestyle:

‎src/openqaoa-core/algorithms/qaoa/qaoa_workflow.py

+24-12
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
from .qaoa_result import QAOAResult
66
from ..workflow_properties import CircuitProperties
77
from ..baseworkflow import Workflow, check_compiled
8-
from ...backends.basebackend import QAOABaseBackendStatevector
98
from ...backends import QAOABackendAnalyticalSimulator
10-
from ...backends.cost_function import cost_function
11-
from ...backends.devices_core import DeviceLocal, DeviceBase
9+
from ...backends.devices_core import DeviceLocal
1210
from ...backends.qaoa_backend import get_qaoa_backend
1311
from ...problems import QUBO
1412
from ...qaoa_components import (
@@ -262,11 +260,24 @@ def compile(
262260
optimizer_dict=self.classical_optimizer.asdict(),
263261
)
264262

263+
# Set the header properties
264+
self.header["target"] = self.device.device_name
265+
self.header["cloud"] = self.device.device_location
266+
267+
metadata = {
268+
"p": self.circuit_properties.p,
269+
"param_type": self.circuit_properties.param_type,
270+
"init_type": self.circuit_properties.init_type,
271+
"optimizer_method": self.classical_optimizer.method,
272+
}
273+
274+
self.set_exp_tags(tags=metadata)
275+
265276
self.compiled = True
266277

267278
if verbose:
268279
print("\t \033[1m ### Summary ###\033[0m")
269-
print(f"OpenQAOA has been compiled with the following properties")
280+
print("OpenQAOA has been compiled with the following properties")
270281
print(
271282
f"Solving QAOA with \033[1m {self.device.device_name} \033[0m on"
272283
f"\033[1m{self.device.device_location}\033[0m"
@@ -296,7 +307,7 @@ def optimize(self, verbose=False):
296307
A method running the classical optimisation loop
297308
"""
298309

299-
if self.compiled == False:
310+
if self.compiled is False:
300311
raise ValueError("Please compile the QAOA before optimizing it!")
301312

302313
# timestamp for the start of the optimization
@@ -310,7 +321,7 @@ def optimize(self, verbose=False):
310321
self.header["execution_time_end"] = generate_timestamp()
311322

312323
if verbose:
313-
print(f"optimization completed.")
324+
print("Optimization completed.")
314325
return
315326

316327
def evaluate_circuit(
@@ -338,10 +349,11 @@ def evaluate_circuit(
338349
"""
339350

340351
# before evaluating the circuit we check that the QAOA object has been compiled
341-
if self.compiled == False:
352+
if self.compiled is False:
342353
raise ValueError("Please compile the QAOA before optimizing it!")
343354

344-
## Check the type of the input parameters and save them as a QAOAVariationalBaseParams object at the variable `params_obj`
355+
# Check the type of the input parameters and save them as a
356+
# QAOAVariationalBaseParams object at the variable `params_obj`
345357

346358
# if the parameters are passed as a dictionary we copy and update the variational parameters of the QAOA object
347359
if isinstance(params, dict):
@@ -382,7 +394,7 @@ def evaluate_circuit(
382394
f"The input params must be a list or a dictionary. Instead, received {type(params)}"
383395
)
384396

385-
## Evaluate the QAOA circuit and return the results
397+
# Evaluate the QAOA circuit and return the results
386398
output_dict = {
387399
"cost": None,
388400
"uncertainty": None,
@@ -409,7 +421,7 @@ def evaluate_circuit(
409421
return output_dict
410422

411423
def _serializable_dict(
412-
self, complex_to_string: bool = False, intermediate_mesurements: bool = True
424+
self, complex_to_string: bool = False, intermediate_measurements: bool = True
413425
):
414426
"""
415427
Returns all values and attributes of the object that we want to return in
@@ -426,7 +438,7 @@ def _serializable_dict(
426438
serializable_dict: dict
427439
A dictionary containing all the values and attributes of the object
428440
that we want to return in `asdict` and `dump(s)` methods.
429-
intermediate_mesurements: bool
441+
intermediate_measurements: bool
430442
If True, intermediate measurements are included in the dump.
431443
If False, intermediate measurements are not included in the dump.
432444
Default is True.
@@ -435,7 +447,7 @@ def _serializable_dict(
435447
# we call the _serializable_dict method of the parent class,
436448
# specifying the keys to delete from the results dictionary
437449
serializable_dict = super()._serializable_dict(
438-
complex_to_string, intermediate_mesurements
450+
complex_to_string, intermediate_measurements
439451
)
440452

441453
# we add the keys of the QAOA object that we want to return

‎src/openqaoa-core/algorithms/rqaoa/rqaoa_result.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def asdict(
1818
self,
1919
keep_cost_hamiltonian: bool = True,
2020
complex_to_string: bool = False,
21-
intermediate_mesurements: bool = True,
21+
intermediate_measurements: bool = True,
2222
exclude_keys: List[str] = [],
2323
):
2424
"""
@@ -32,7 +32,7 @@ def asdict(
3232
complex_to_string : bool, optional
3333
If True, the complex numbers are converted to strings, by default False.
3434
This is useful for JSON serialization.
35-
intermediate_mesurements: bool, optional
35+
intermediate_measurements: bool, optional
3636
If True, intermediate measurements are included in the dump. If False,
3737
intermediate measurements are not included in the dump.
3838
Default is True.
@@ -55,7 +55,7 @@ def asdict(
5555
"qaoa_results": step["qaoa_results"].asdict(
5656
keep_cost_hamiltonian,
5757
complex_to_string,
58-
intermediate_mesurements,
58+
intermediate_measurements,
5959
),
6060
"exp_vals_z": step["exp_vals_z"].tolist(),
6161
"corr_matrix": step["corr_matrix"].tolist(),

‎src/openqaoa-core/algorithms/rqaoa/rqaoa_utils.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def max_terms(exp_vals_z: np.ndarray, corr_matrix: np.ndarray, n_elim: int):
6565

6666
# Flag if we have have not been able to extract any relation for the terms
6767
if max_terms_and_stats == {}:
68-
print(f"All expectation values are 0: Breaking degeneracy by fixing a qubit\n")
68+
print("All expectation values are 0: Breaking degeneracy by fixing a qubit\n")
6969
max_terms_and_stats = {(0,): -1.0}
7070

7171
return max_terms_and_stats
@@ -132,7 +132,7 @@ def ada_max_terms(exp_vals_z: np.ndarray, corr_matrix: np.ndarray, n_max: int):
132132

133133
# Flag if we have have not been able to extract any relation for the terms
134134
if max_terms_and_stats == {}:
135-
print(f"All expectation values are 0: Breaking degeneracy by fixing a qubit\n")
135+
print("All expectation values are 0: Breaking degeneracy by fixing a qubit\n")
136136
max_terms_and_stats = {(0,): -1.0}
137137

138138
# Correlation average magnitude
@@ -395,7 +395,7 @@ def redefine_problem(problem: QUBO, spin_map: dict):
395395
# get a set of all the spins to be eliminated
396396
eliminated_spins = set()
397397
for spin in spin_map.keys():
398-
if spin != spin_map[spin][1] or spin_map[spin][1] == None:
398+
if spin != spin_map[spin][1] or spin_map[spin][1] is None:
399399
eliminated_spins.add(spin)
400400

401401
# Scan all terms and weights
@@ -605,7 +605,8 @@ def final_solution(
605605

606606
def solution_for_vanishing_instances(hamiltonian: Hamiltonian, spin_map: dict):
607607
"""
608-
Constructs the final solution of the smallest non vanishing problem by fixing the vanishing spins arbitrarily to 1 while obeying the correlations identified by the last run of QAOA before the problem vanished.
608+
Constructs the final solution of the smallest non vanishing problem by fixing the vanishing spins arbitrarily to 1
609+
while obeying the correlations identified by the last run of QAOA before the problem vanished.
609610
Computing the classical energy of the generated string.
610611
611612
Parameters
@@ -621,12 +622,14 @@ def solution_for_vanishing_instances(hamiltonian: Hamiltonian, spin_map: dict):
621622
cl_energy: `float`
622623
The energy of the solution wrt the cost Hamiltonian.
623624
cl_ground_state: `list`
624-
The (single) classical solution to the problem reconstructed accordingly to the last spin map. Represented as a binary string and then cast to a list to match the output of the `ground_state_hamiltonian` function which is used usually.
625+
The (single) classical solution to the problem reconstructed accordingly to the last spin map.
626+
Represented as a binary string and then cast to a list to match the output of the
627+
`ground_state_hamiltonian` function which is used usually.
625628
"""
626629
cl_ground_state = ""
627630

628631
for spin in spin_map.keys():
629-
if spin_map[spin][1] == None:
632+
if spin_map[spin][1] is None:
630633
cl_ground_state += "1"
631634
else:
632635
# fix according to correlation factor

‎src/openqaoa-core/algorithms/rqaoa/rqaoa_workflow.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ def optimize(
494494
# dump the object if dump is true
495495
if dump:
496496
self.dump(
497-
**{**dump_options, **{"options": {"intermediate_mesurements": False}}}
497+
**{**dump_options, **{"options": {"intermediate_measurements": False}}}
498498
)
499499

500500
if verbose:
@@ -548,7 +548,7 @@ def __n_step(self, n_qubits, n_cutoff, counter):
548548
return (n_qubits - n_cutoff) if (n_qubits - n_cutoff) < n else n
549549

550550
def _serializable_dict(
551-
self, complex_to_string: bool = False, intermediate_mesurements: bool = True
551+
self, complex_to_string: bool = False, intermediate_measurements: bool = True
552552
):
553553
"""
554554
Returns all values and attributes of the object that we want to
@@ -565,15 +565,15 @@ def _serializable_dict(
565565
serializable_dict: dict
566566
Dictionary containing all the values and attributes of the object
567567
that we want to return in `asdict` and `dump(s)` methods.
568-
intermediate_mesurements: bool
568+
intermediate_measurements: bool
569569
If True, intermediate measurements are included in the dump. If False,
570570
intermediate measurements are not included in the dump.
571571
Default is True.
572572
"""
573573
# we call the _serializable_dict method of the parent class,
574574
# specifying the keys to delete from the results dictionary
575575
serializable_dict = super()._serializable_dict(
576-
complex_to_string, intermediate_mesurements
576+
complex_to_string, intermediate_measurements
577577
)
578578

579579
# we add the keys of the RQAOA object that we want to return

‎src/openqaoa-core/algorithms/rqaoa/rqaoa_workflow_properties.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ def __init__(
5353
n_max: `int`
5454
Maximum number of eliminations allowed at each step when using the adaptive method. Defaults to 1.
5555
steps: `Union[list,int]`
56-
Elimination schedule for the RQAOA algorithm. If an integer is passed, it sets the number of spins eliminated
57-
at each step. If a list is passed, the algorithm will follow the list to select how many spins to eliminate
58-
at each step. Note that the list needs enough elements to specify eliminations from the initial number of qubits
59-
up to the cutoff value. If the list contains more, the algorithm will follow instructions until the cutoff value
56+
Elimination schedule for the RQAOA algorithm. If an integer is passed, it sets the number of spins
57+
eliminated at each step. If a list is passed, the algorithm will follow the list to select
58+
how many spins to eliminate at each step. Note that the list needs enough elements to specify
59+
eliminations from the initial number of qubits up to the cutoff value. If the list contains more,
60+
the algorithm will follow instructions until the cutoff value
6061
is reached. Defaults to 1.
6162
n_cutoff: `int`
6263
Cutoff value at which the RQAOA algorithm obtains the solution classically. Defaults to 5.
@@ -74,7 +75,7 @@ def __init__(
7475
self.counter = counter
7576

7677
# check if the rqaoa type is correct
77-
if not self.rqaoa_type in ALLOWED_RQAOA_TYPES:
78+
if self.rqaoa_type not in ALLOWED_RQAOA_TYPES:
7879
self.compiled = False
7980
raise Exception(
8081
f'rqaoa_type {self.rqaoa_type} is not supported. Please select "adaptive" or "custom".'
@@ -84,16 +85,17 @@ def __init__(
8485
if self.rqaoa_type == "adaptive":
8586
if self.steps != 1:
8687
raise ValueError(
87-
f"When using the adaptive method, the `steps` parameter is not required. \
88+
"When using the adaptive method, the `steps` parameter is not required. \
8889
The parameter that specifies the maximum number of eliminations per step is `n_max`."
8990
)
9091
if self.counter != 0:
9192
raise ValueError(
92-
f"When using the adaptive method, the `counter` parameter is not required."
93+
"When using the adaptive method, the `counter` parameter is not required."
9394
)
9495
else:
9596
if self.n_max != 1:
9697
raise ValueError(
97-
f"When using the custom method, the `n_max` parameter is not required. \
98-
The parameter that specifies the number of eliminations is `steps`, which can be a string or a list."
98+
"When using the custom method, the `n_max` parameter is not required. \
99+
The parameter that specifies the number of eliminations is `steps`,\
100+
which can be a string or a list."
99101
)

‎tests/jobs_test_input/input_data/openqaoa_params.json

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"header": {
3-
"atomic_id": "210a6aaa-932d-45a6-b260-f3fdd085c547",
4-
"experiment_id": "74779bb1-867c-4131-89d2-ac9238422cd9",
3+
"atomic_id": "386997de-0e90-4e1c-8236-cd722801615f",
4+
"experiment_id": "ce2f83d7-4000-4507-9e98-96e3f9afd55e",
55
"project_id": null,
66
"algorithm": "rqaoa",
77
"description": null,
@@ -10,10 +10,10 @@
1010
"target": null,
1111
"cloud": null,
1212
"client": null,
13-
"qubit_number": 10,
1413
"execution_time_start": null,
1514
"execution_time_end": null,
1615
"metadata": {
16+
"qubit_number": 10,
1717
"problem_type": "minimum_vertex_cover",
1818
"n_shots": 100,
1919
"optimizer_method": "cobyla",
@@ -22,11 +22,13 @@
2222
"p": 1,
2323
"rqaoa_type": "custom",
2424
"rqaoa_n_max": 1,
25-
"rqaoa_n_cutoff": 3
25+
"rqaoa_n_cutoff": 6
2626
}
2727
},
2828
"data": {
29-
"exp_tags": {},
29+
"exp_tags": {
30+
"qubit_number": 10
31+
},
3032
"input_problem": {
3133
"terms": [
3234
[
@@ -212,8 +214,8 @@
212214
},
213215
"input_parameters": {
214216
"device": {
215-
"device_location": "local",
216-
"device_name": "vectorized"
217+
"device_location": "aws",
218+
"device_name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1"
217219
},
218220
"backend_properties": {
219221
"init_hadamard": true,
@@ -268,15 +270,12 @@
268270
"rqaoa_type": "custom",
269271
"n_max": 1,
270272
"steps": [
271-
2,
272-
2,
273-
2,
274-
2,
275-
2,
276-
2,
277-
2
273+
1,
274+
1,
275+
1,
276+
1
278277
],
279-
"n_cutoff": 3,
278+
"n_cutoff": 6,
280279
"original_hamiltonian": null,
281280
"counter": 0
282281
}

‎tests/test_backends.py

+22-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import unittest
22
import json
3-
import os
43
import pytest
54
import subprocess
65

@@ -38,12 +37,13 @@ class TestingBackendLocal(unittest.TestCase):
3837

3938
def test_get_counts_and_expectation_n_shots(self):
4039
"""
41-
Check that the .get_counts admit n_shots as an argument, and works properly for the backend of all local devices.
42-
Also check that .expectation and .expecation_w_uncertainty methods admit n_shots as an argument for the QAOABaseBackendShotBased backends.
40+
Check that the .get_counts admit n_shots as an argument, and works properly for
41+
the backend of all local devices.
42+
Also check that .expectation and .expecation_w_uncertainty methods admit n_shots
43+
as an argument for the QAOABaseBackendShotBased backends.
4344
"""
4445

4546
for device_name in DEVICE_NAME_TO_OBJECT_MAPPER.keys():
46-
4747
# Analytical device doesn't have any of those so we are skipping it in the tests.
4848
if device_name in ["analytical_simulator"]:
4949
continue
@@ -62,15 +62,17 @@ def test_get_counts_and_expectation_n_shots(self):
6262
).values()
6363
)
6464
== 58
65-
), "`n_shots` is not being respected for the local simulator `{}` when calling backend.get_counts(n_shots=58).".format(
65+
), "`n_shots` is not being respected for the local simulator `{}` when \
66+
calling backend.get_counts(n_shots=58).".format(
6667
device_name
6768
)
6869
if isinstance(backend, QAOABaseBackendShotBased):
6970
try:
7071
backend.expectation(params=variational_params_std, n_shots=58)
7172
except Exception:
7273
raise Exception(
73-
"backend.expectation does not admit `n_shots` as an argument for the local simulator `{}`.".format(
74+
"backend.expectation does not admit `n_shots` as an argument \
75+
for the local simulator `{}`.".format(
7476
device_name
7577
)
7678
)
@@ -80,7 +82,8 @@ def test_get_counts_and_expectation_n_shots(self):
8082
)
8183
except Exception:
8284
raise Exception(
83-
"backend.expectation_w_uncertainty does not admit `n_shots` as an argument for the local simulator `{}`.".format(
85+
"backend.expectation_w_uncertainty does not admit `n_shots` \
86+
as an argument for the local simulator `{}`.".format(
8487
device_name
8588
)
8689
)
@@ -96,7 +99,6 @@ class TestingBackendQPUs(unittest.TestCase):
9699

97100
@pytest.mark.qpu
98101
def setUp(self):
99-
100102
self.HUB = "ibm-q"
101103
self.GROUP = "open"
102104
self.PROJECT = "main"
@@ -123,9 +125,11 @@ def setUp(self):
123125
@pytest.mark.qpu
124126
def test_get_counts_and_expectation_n_shots(self):
125127
"""
126-
TODO: test needs to be updated as DEVICE_ACCESS_OBJECT_MAPPER is now dynamically filled based on whether a module exists.
127-
128-
Check that the .get_counts, .expectation and .expecation_w_uncertainty methods admit n_shots as an argument for the backends of all QPUs.
128+
TODO: test needs to be updated as DEVICE_ACCESS_OBJECT_MAPPER is now dynamically filled
129+
based on whether a module exists.
130+
131+
Check that the .get_counts, .expectation and .expecation_w_uncertainty methods
132+
admit n_shots as an argument for the backends of all QPUs.
129133
"""
130134

131135
list_device_attributes = [
@@ -134,7 +138,7 @@ def test_get_counts_and_expectation_n_shots(self):
134138
"device_name": "rigetti.sim.qvm",
135139
"resource_id": self.RESOURCE_ID,
136140
"az_location": self.AZ_LOCATION,
137-
},
141+
},
138142
{
139143
"QPU": "AWS",
140144
"device_name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1",
@@ -157,12 +161,12 @@ def test_get_counts_and_expectation_n_shots(self):
157161

158162
assert len(list_device_attributes) == len(
159163
DEVICE_ACCESS_OBJECT_MAPPER
160-
), "The number of QPUs in the list of tests is not the same as the number of QPUs in the DEVICE_ACCESS_OBJECT_MAPPER. The list should be updated."
164+
), "The number of QPUs in the list of tests is not the same as the number of QPUs in \
165+
the DEVICE_ACCESS_OBJECT_MAPPER. The list should be updated."
161166
print(DEVICE_ACCESS_OBJECT_MAPPER.items(), list_device_attributes)
162167
for (device, backend), device_attributes in zip(
163168
DEVICE_ACCESS_OBJECT_MAPPER.items(), list_device_attributes
164169
):
165-
166170
qaoa_descriptor, variational_params_std = get_params()
167171

168172
QPU_name = device_attributes.pop("QPU")
@@ -185,15 +189,17 @@ def test_get_counts_and_expectation_n_shots(self):
185189
init_hadamard=True,
186190
)
187191

188-
# Check that the .get_counts, .expectation and .expectation_w_variance methods admit n_shots as an argument
192+
# Check that the .get_counts, .expectation and .expectation_w_variance methods
193+
# admit n_shots as an argument
189194
assert (
190195
sum(
191196
backend.get_counts(
192197
params=variational_params_std, n_shots=58
193198
).values()
194199
)
195200
== 58
196-
), "`n_shots` is not being respected when calling .get_counts(n_shots=58).".format(
201+
), "`n_shots` is not being respected \
202+
when calling .get_counts(n_shots=58) for QPU `{}`.".format(
197203
QPU_name
198204
)
199205
backend.expectation(params=variational_params_std, n_shots=58)
@@ -202,7 +208,6 @@ def test_get_counts_and_expectation_n_shots(self):
202208
)
203209

204210
except Exception as e:
205-
206211
raise e from type(e)(f"Error raised for `{QPU_name}`: " + str(e))
207212

208213
print("Test passed for {} backend.".format(QPU_name))

‎tests/test_benchmark.py

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import unittest
22
import numpy as np
33
import matplotlib.pyplot as plt
4+
import pytest
5+
import sys
46

57
from openqaoa import QAOA, create_device, QAOABenchmark
68
from openqaoa.problems import QUBO
@@ -89,6 +91,10 @@ def test_type_qaoa_reference(self):
8991
benchmark.reference.backend, type(qaoa_vectorized.backend)
9092
), "The qaoa reference should have a vectorized backend."
9193

94+
@pytest.mark.skipif(
95+
sys.platform == "darwin" or sys.platform.startswith("win"),
96+
reason="Test does not run on Mac and Windows currently",
97+
)
9298
def __compare_values_benchmark(
9399
self,
94100
qaoa,
@@ -196,6 +202,10 @@ def __compare_values_benchmark(
196202
n_points_axis, ranges, run_reference
197203
)
198204

205+
@pytest.mark.skipif(
206+
sys.platform == "darwin" or sys.platform.startswith("win"),
207+
reason="Test does not run on Mac and Windows currently",
208+
)
199209
def test_values_1D(self):
200210
"Test the values of the benchmark for 1D ranges."
201211

@@ -234,6 +244,10 @@ def test_values_1D(self):
234244
],
235245
)
236246

247+
@pytest.mark.skipif(
248+
sys.platform == "darwin" or sys.platform.startswith("win"),
249+
reason="Test does not run on Mac and Windows currently",
250+
)
237251
def test_values_2D(self):
238252
"Test the values of the benchmark for 2D ranges."
239253

@@ -259,6 +273,10 @@ def test_values_2D(self):
259273
run_reference=True,
260274
)
261275

276+
@pytest.mark.skipif(
277+
sys.platform == "darwin" or sys.platform.startswith("win"),
278+
reason="Test does not run on Mac and Windows currently",
279+
)
262280
def test_values_3D(self):
263281
"Test the values of the benchmark for 3D ranges."
264282

@@ -284,6 +302,10 @@ def test_values_3D(self):
284302
run_reference=True,
285303
)
286304

305+
@pytest.mark.skipif(
306+
sys.platform == "darwin" or sys.platform.startswith("win"),
307+
reason="Test does not run on Mac and Windows currently",
308+
)
287309
def test_difference(self):
288310
"Test the property difference and difference_mean."
289311

@@ -353,6 +375,10 @@ def test_difference(self):
353375
error
354376
), "An error should be raised if the difference is called before running the benchmark."
355377

378+
@pytest.mark.skipif(
379+
sys.platform == "darwin" or sys.platform.startswith("win"),
380+
reason="Test does not run on Mac and Windows currently",
381+
)
356382
def test_input_checks(self):
357383
"Test the input assertions of the run method."
358384

@@ -437,6 +463,10 @@ def test_input_checks(self):
437463
benchmark.run, n_points_axis=4, ranges=[(1, 2), (1, 3)], verbose="d"
438464
), "An error should be raised when verbose is not a boolean."
439465

466+
@pytest.mark.skipif(
467+
sys.platform == "darwin" or sys.platform.startswith("win"),
468+
reason="Test does not run on Mac and Windows currently",
469+
)
440470
def test_plot(self):
441471
"Test the plot method."
442472

@@ -477,6 +507,10 @@ def test_plot(self):
477507
benchmark.run(n_points_axis=4, ranges=[(0, np.pi), (-5, 9), (0, 1), (1,)])
478508
benchmark.plot()
479509

510+
@pytest.mark.skipif(
511+
sys.platform == "darwin" or sys.platform.startswith("win"),
512+
reason="Test does not run on Mac and Windows currently",
513+
)
480514
def test_plot_inputs(self):
481515
"Test the plot method with different inputs."
482516

@@ -529,6 +563,10 @@ def test_plot_inputs(self):
529563
plt.show()
530564
plt.close(fig)
531565

566+
@pytest.mark.skipif(
567+
sys.platform == "darwin" or sys.platform.startswith("win"),
568+
reason="Test does not run on Mac and Windows currently",
569+
)
532570
def test_plot_input_checks(self):
533571
"Test the plot method assertion inputs."
534572

@@ -616,8 +654,11 @@ def test_plot_input_checks(self):
616654
benchmark.plot, main=False, reference=False, difference=True
617655
), "An error should be raised when no values are available"
618656

657+
@pytest.mark.skipif(
658+
sys.platform == "darwin" or sys.platform.startswith("win"),
659+
reason="Test does not run on Mac and Windows currently",
660+
)
619661
def test_run_w_plots(self):
620-
621662
qaoa = QAOA()
622663
qaoa.compile(QUBO.random_instance(5))
623664
benchmark = QAOABenchmark(qaoa)

‎tests/test_circuit_routing.py

+11-20
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# unit testing for circuit routing functionality in OQ
22
import unittest
33
import numpy as np
4-
from typing import List, Callable, Optional
4+
from typing import List, Optional
55
import pytest
66

7-
from openqaoa import QAOA
7+
from openqaoa import QAOA, create_device, QUBO
88
from openqaoa.qaoa_components import (
99
create_qaoa_variational_params,
1010
QAOADescriptor,
1111
PauliOp,
1212
Hamiltonian,
1313
)
1414
from openqaoa.utilities import X_mixer_hamiltonian
15-
from openqaoa.backends import QAOAvectorizedBackendSimulator, create_device
16-
from openqaoa.problems import NumberPartition, QUBO, Knapsack, MaximumCut, ShortestPath
15+
from openqaoa.problems import NumberPartition, Knapsack, MaximumCut, ShortestPath
1716
from openqaoa_pyquil.backends import DevicePyquil, QAOAPyQuilQPUBackend
1817
from openqaoa.backends.devices_core import DeviceBase
1918
from openqaoa.qaoa_components.ansatz_constructor.gatemap import SWAPGateMap
@@ -35,7 +34,6 @@ def test_no_swap(self):
3534
"""
3635

3736
def routing_function_test1(device, problem_to_solve):
38-
3937
# tuples ordered from 0,n, both SWAP and ising gates
4038
gate_list_indices = [[0, 1]]
4139

@@ -117,7 +115,6 @@ def routing_function_test1(device, problem_to_solve):
117115
device_pyquil.quantum_computer.qam.random_seed = seed
118116

119117
for i in range(len(p_lst)):
120-
121118
p = p_lst[i]
122119
args = args_lst[i]
123120
cost_hamil = cost_hamil_lst[i]
@@ -166,14 +163,13 @@ def routing_function_test1(device, problem_to_solve):
166163

167164
def test_cancelled_swap(self):
168165
"""
169-
Tests that QAOADescriptor with a trivial `routing_function` input (with two swaps that cancel each other) returns identical
170-
results as QAOADescriptor with no `routing_function` input, by comparing output of seeded QVM run.
171-
Different values of p, arguments, and cost hamiltonian coefficients are tested.
172-
166+
Tests that QAOADescriptor with a trivial `routing_function` input (with two swaps that cancel each other)
167+
returns identical results as QAOADescriptor with no `routing_function` input,
168+
by comparing output of seeded QVM run. Different values of p, arguments,
169+
and cost hamiltonian coefficients are tested.
173170
"""
174171

175172
def routing_function_test1(device, problem_to_solve):
176-
177173
# tuples ordered from 0,n, both SWAP and ising gates
178174
gate_list_indices = [[0, 1], [0, 1], [0, 1]]
179175

@@ -255,7 +251,6 @@ def routing_function_test1(device, problem_to_solve):
255251
device_pyquil.quantum_computer.qam.random_seed = seed
256252

257253
for i in range(len(p_lst)):
258-
259254
p = p_lst[i]
260255
args = args_lst[i]
261256
cost_hamil = cost_hamil_lst[i]
@@ -314,7 +309,6 @@ def test_simplest_swap(self):
314309
"""
315310

316311
def routing_function_test1(device, problem_to_solve):
317-
318312
# tuples ordered from 0,n, both SWAP and ising gates
319313
gate_list_indices = [[0, 1], [0, 1]]
320314

@@ -396,7 +390,6 @@ def routing_function_test1(device, problem_to_solve):
396390
device_pyquil.quantum_computer.qam.random_seed = seed
397391

398392
for i in range(len(p_lst)):
399-
400393
p = p_lst[i]
401394
args = args_lst[i]
402395
cost_hamil = cost_hamil_lst[i]
@@ -454,7 +447,6 @@ def test_different_topologies(self):
454447
"""
455448

456449
def routing_function_test1(device, problem_to_solve):
457-
458450
# tuples ordered from 0,n, both SWAP and ising gates
459451
gate_list_indices = [[0, 1], [1, 0], [0, 1]]
460452

@@ -500,7 +492,6 @@ def routing_function_test1(device, problem_to_solve):
500492
seed = 1
501493

502494
for i in range(len(p_lst)):
503-
504495
p = p_lst[i]
505496
args = args_lst[i]
506497
cost_hamil = cost_hamil_lst[i]
@@ -603,9 +594,10 @@ def values_return(self):
603594

604595

605596
class TestingQubitRouting(unittest.TestCase):
606-
@pytest.mark.qpu
607597
def setUp(self):
608-
598+
"""
599+
Test edge cases
600+
"""
609601
# case qubits device > qubits problem (IBM NAIROBI)
610602
self.IBM_NAIROBI_KNAPSACK = ExpectedRouting(
611603
qubo=Knapsack.random_instance(n_items=3, seed=20).qubo,
@@ -882,7 +874,7 @@ def setUp(self):
882874
)
883875

884876
# case qubits device == qubits problem (RIGETTI)
885-
self.RIGETTI_MACUT = ExpectedRouting(
877+
self.RIGETTI_MAXCUT = ExpectedRouting(
886878
qubo=MaximumCut.random_instance(
887879
n_nodes=9, edge_probability=0.9, seed=20
888880
).qubo,
@@ -1132,7 +1124,6 @@ def __compare_results(self, expected: ExpectedRouting, p: int):
11321124

11331125
@pytest.mark.qpu
11341126
def test_qubit_routing(self):
1135-
11361127
for i, case in enumerate(self.list_of_cases):
11371128
print("Test case {} out of {}:".format(i + 1, len(self.list_of_cases)))
11381129
self.__compare_results(case, p=i % 4 + 1)

‎tests/test_notebooks.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
from nbconvert.preprocessors import ExecutePreprocessor
77
import pytest
88

9-
import sys, os
9+
import sys
10+
import os
1011

1112
myPath = os.path.dirname(os.path.abspath(__file__))
1213
sys.path.insert(0, myPath + "/../")
1314

1415

1516
def notebook_test_function(name):
16-
1717
with open(name, encoding="utf-8") as f:
1818
nb = nbformat.read(f, as_version=4)
1919

@@ -88,8 +88,7 @@ def test_X_dumping_data():
8888
notebook_test_function("./examples/X_dumping_data.ipynb")
8989

9090

91-
### Community Tutorials
92-
91+
# Community Tutorials
9392
# @pytest.mark.notebook
9493
def test_tutorial_quantum_approximate_optimization_algorithm():
9594
notebook_test_function(

‎tests/test_qpu_braket.py

+10-14
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ def test_circuit_angle_assignment_qpu_backend(self):
8787

8888
self.assertEqual(main_circuit, qpu_circuit)
8989

90-
9190
@pytest.mark.braket_api
9291
def test_circuit_angle_assignment_qpu_backend_w_hadamard(self):
9392
"""
@@ -150,7 +149,6 @@ def test_circuit_angle_assignment_qpu_backend_w_hadamard(self):
150149

151150
self.assertEqual(main_circuit, qpu_circuit)
152151

153-
154152
@pytest.mark.braket_api
155153
def test_prepend_circuit(self):
156154
"""
@@ -210,7 +208,6 @@ def test_prepend_circuit(self):
210208

211209
self.assertEqual(main_circuit, qpu_circuit)
212210

213-
214211
@pytest.mark.braket_api
215212
def test_append_circuit(self):
216213
"""
@@ -271,10 +268,8 @@ def test_append_circuit(self):
271268

272269
self.assertEqual(main_circuit, qpu_circuit)
273270

274-
275271
@pytest.mark.braket_api
276272
def test_prepend_exception(self):
277-
278273
"""
279274
Test that the error catching for a prepend ciruit larger than the problem
280275
circuit is invalid
@@ -301,12 +296,15 @@ def test_prepend_exception(self):
301296
)
302297
mixer_hamil = X_mixer_hamiltonian(n_qubits=nqubits)
303298
qaoa_descriptor = QAOADescriptor(cost_hamil, mixer_hamil, p=p)
304-
variate_params = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
299+
300+
# Try to create the variate params
301+
_ = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
305302

306303
aws_device = DeviceAWS("arn:aws:braket:::device/quantum-simulator/amazon/sv1")
307304

308305
try:
309-
aws_backend = QAOAAWSQPUBackend(
306+
# Try to create the AWS backend
307+
_ = QAOAAWSQPUBackend(
310308
qaoa_descriptor, aws_device, shots, prepend_circuit, None, True, 1.0
311309
)
312310
except Exception as e:
@@ -316,7 +314,6 @@ def test_prepend_exception(self):
316314

317315
@pytest.mark.braket_api
318316
def test_exceptions_in_init(self):
319-
320317
"""
321318
Testing the Exceptions in the init function of the QAOAAWSQPUBackend
322319
"""
@@ -335,7 +332,9 @@ def test_exceptions_in_init(self):
335332
)
336333
mixer_hamil = X_mixer_hamiltonian(n_qubits=nqubits)
337334
qaoa_descriptor = QAOADescriptor(cost_hamil, mixer_hamil, p=p)
338-
variate_params = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
335+
336+
# Try instantiating the variate params
337+
_ = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
339338

340339
# If the user's aws credentials is not correct.
341340
mock_device = Mock()
@@ -383,10 +382,8 @@ def test_exceptions_in_init(self):
383382

384383
QAOAAWSQPUBackend(qaoa_descriptor, aws_device, shots, None, None, True, 1.0)
385384

386-
387-
@pytest.mark.braket_api
385+
@pytest.mark.braket_api
388386
def test_remote_qubit_overflow(self):
389-
390387
"""
391388
If the user creates a circuit that is larger than the maximum circuit size
392389
that is supported by the QPU. An Exception should be raised with the
@@ -417,9 +414,8 @@ def test_remote_qubit_overflow(self):
417414
"There are lesser qubits on the device than the number of qubits required for the circuit.",
418415
)
419416

420-
@pytest.mark.qpu
417+
@pytest.mark.sim
421418
def test_remote_integration_qpu_run(self):
422-
423419
"""
424420
Run a toy example in manual mode to make sure everything works as
425421
expected for a remote backend

‎tests/test_qpu_qiskit.py

+91-68
Original file line numberDiff line numberDiff line change
@@ -26,145 +26,169 @@
2626
)
2727
from openqaoa.utilities import X_mixer_hamiltonian
2828
from openqaoa.problems import NumberPartition
29-
from openqaoa import QAOA
29+
from openqaoa import QAOA, create_device
3030

3131

3232
class TestingQAOAQiskitQPUBackendAzure(unittest.TestCase):
33-
34-
"""This Object tests the QAOA Qiskit QPU Backend object with the Azure
33+
34+
"""This Object tests the QAOA Qiskit QPU Backend object with the Azure
3535
Device object. This checks that the use of qiskit to send circuits to Azure
3636
is working as intended.
37-
37+
3838
The Azure CLI has to be configured beforehand to run these tests.
3939
"""
40-
40+
4141
@pytest.mark.api
4242
def setUp(self):
43-
43+
"""
44+
Setting up the credentials
45+
"""
4446
bashCommand = "az resource list"
4547
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
4648
output, error = process.communicate()
47-
49+
4850
if error is not None:
4951
print(error)
50-
raise Exception('You must have the Azure CLI installed and must be logged in to use the Azure Quantum Backends')
52+
raise Exception(
53+
"You must have the Azure CLI installed and must be logged in to use the Azure Quantum Backends"
54+
)
5155
else:
5256
output_json = json.loads(output)
53-
output_json_s = [each_json for each_json in output_json if each_json['name'] == 'TestingOpenQAOA'][0]
54-
self.RESOURCE_ID = output_json_s['id']
55-
self.AZ_LOCATION = output_json_s['location']
56-
57+
output_json_s = [
58+
each_json
59+
for each_json in output_json
60+
if each_json["name"] == "TestingOpenQAOA"
61+
][0]
62+
self.RESOURCE_ID = output_json_s["id"]
63+
self.AZ_LOCATION = output_json_s["location"]
64+
5765
@pytest.mark.sim
5866
def check_shots_tally(self):
59-
60-
"""There is a known bug in the qiskit backend for azure where if the shots
61-
argument might be ignored. This test checks that the output from the azure
67+
"""
68+
There is a known bug in the qiskit backend for azure where if the shots
69+
argument might be ignored. This test checks that the output from the azure
6270
computation matches the input requirements.
6371
"""
64-
72+
6573
shots = 1024
6674
problem_qubo = NumberPartition([1, 2, 3]).qubo
67-
azure_device = create_device(location='azure', name='rigetti.sim.qvm',
68-
resource_id=self.RESOURCE_ID,
69-
az_location=self.AZ_LOCATION)
70-
75+
azure_device = create_device(
76+
location="azure",
77+
name="rigetti.sim.qvm",
78+
resource_id=self.RESOURCE_ID,
79+
az_location=self.AZ_LOCATION,
80+
)
81+
7182
q = QAOA()
7283
q.set_device(azure_device)
7384
q.set_backend_properties(n_shots=shots)
74-
q.set_classical_optimizer(maxiter = 1)
85+
q.set_classical_optimizer(maxiter=1)
7586
q.compile(problem_qubo)
7687
q.optimize()
77-
78-
comp_shots = sum(q.result.optimized['optimized measurement outcomes'].values())
79-
88+
89+
q.dump(file_name="check_shots_tally", prepend_id=False, overwrite=True)
90+
91+
comp_shots = sum(q.result.optimized["optimized measurement outcomes"].values())
92+
8093
self.assertEqual(shots, comp_shots)
81-
94+
8295
@pytest.mark.api
8396
def test_expectations_in_init(self):
84-
8597
"""
8698
Testing the Exceptions in the init function of the QiskitQPUShotBasedBackend
8799
"""
88-
100+
89101
nqubits = 3
90102
p = 1
91103
weights = [1, 1, 1]
92-
gammas = [1/8*np.pi]
93-
betas = [1/8*np.pi]
104+
gammas = [1 / 8 * np.pi]
105+
betas = [1 / 8 * np.pi]
94106
shots = 10000
95107

96-
cost_hamil = Hamiltonian([PauliOp('ZZ', (0, 1)), PauliOp('ZZ', (1, 2)),
97-
PauliOp('ZZ', (0, 2))], weights, 1)
108+
cost_hamil = Hamiltonian(
109+
[PauliOp("ZZ", (0, 1)), PauliOp("ZZ", (1, 2)), PauliOp("ZZ", (0, 2))],
110+
weights,
111+
1,
112+
)
98113
mixer_hamil = X_mixer_hamiltonian(n_qubits=nqubits)
99114
qaoa_descriptor = QAOADescriptor(cost_hamil, mixer_hamil, p=p)
100-
variate_params = QAOAVariationalStandardParams(qaoa_descriptor,
101-
betas, gammas)
102-
115+
116+
# Try to compute the variate params
117+
_ = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
118+
103119
# We mock the potential Exception that could occur in the Device class
104-
azure_device = DeviceAzure('', '', '')
120+
azure_device = DeviceAzure("", "", "")
105121
azure_device._check_provider_connection = Mock(return_value=False)
106-
122+
107123
try:
108-
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device,
109-
shots, None, None, True)
124+
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device, shots, None, None, True)
110125
except Exception as e:
111-
self.assertEqual(str(e), 'Error connecting to AZURE.')
112-
126+
self.assertEqual(str(e), "Error connecting to AZURE.")
127+
113128
with self.assertRaises(Exception):
114129
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device, shots, None, None, True)
115-
116130

117-
azure_device = DeviceAzure(device_name='', resource_id=self.RESOURCE_ID,
118-
az_location=self.AZ_LOCATION)
119-
131+
azure_device = DeviceAzure(
132+
device_name="", resource_id=self.RESOURCE_ID, az_location=self.AZ_LOCATION
133+
)
134+
120135
try:
121-
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device,
122-
shots, None, None, True)
136+
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device, shots, None, None, True)
123137
except Exception as e:
124-
self.assertEqual(str(e), 'Connection to AZURE was made. Error connecting to the specified backend.')
125-
138+
self.assertEqual(
139+
str(e),
140+
"Connection to AZURE was made. Error connecting to the specified backend.",
141+
)
142+
126143
with self.assertRaises(Exception):
127144
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device, shots, None, None, True)
128-
145+
129146
@pytest.mark.api
130147
def test_remote_qubit_overflow(self):
131-
132148
"""
133149
If the user creates a circuit that is larger than the maximum circuit size
134-
that is supported by the QPU. An Exception should be raised with the
150+
that is supported by the QPU. An Exception should be raised with the
135151
appropriate error message alerting the user to the error.
136152
"""
137-
153+
138154
shots = 100
139-
155+
140156
set_of_numbers = np.random.randint(1, 10, 6).tolist()
141157
qubo = NumberPartition(set_of_numbers).qubo
142158

143159
mixer_hamil = X_mixer_hamiltonian(n_qubits=6)
144160
qaoa_descriptor = QAOADescriptor(qubo.hamiltonian, mixer_hamil, p=1)
145-
variate_params = create_qaoa_variational_params(qaoa_descriptor, 'standard', 'rand')
146161

147-
azure_device = DeviceAzure('rigetti.sim.qvm', self.RESOURCE_ID, self.AZ_LOCATION)
148-
162+
# Check the creation of the varitional parms
163+
_ = create_qaoa_variational_params(qaoa_descriptor, "standard", "rand")
164+
165+
azure_device = DeviceAzure(
166+
"rigetti.sim.qvm", self.RESOURCE_ID, self.AZ_LOCATION
167+
)
168+
149169
try:
150-
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device,
151-
shots, None, None, True)
170+
QAOAQiskitQPUBackend(qaoa_descriptor, azure_device, shots, None, None, True)
152171
except Exception as e:
153-
self.assertEqual(str(e), 'There are lesser qubits on the device than the number of qubits required for the circuit.')
172+
self.assertEqual(
173+
str(e),
174+
"There are lesser qubits on the device than the number of qubits required for the circuit.",
175+
)
154176

155177

156178
class TestingQAOAQiskitQPUBackend(unittest.TestCase):
157179

158180
"""This Object tests the QAOA Qiskit QPU Backend objects, which is tasked with the
159181
creation and execution of a QAOA circuit for the selected QPU provider and
160182
backend.
161-
183+
162184
IBMQ Account has to be saved locally to run these tests.
163185
"""
164186

165187
@pytest.mark.api
166188
def setUp(self):
167-
189+
"""
190+
Define the credentials
191+
"""
168192
self.HUB = "ibm-q"
169193
self.GROUP = "open"
170194
self.PROJECT = "main"
@@ -419,7 +443,6 @@ def test_append_circuit(self):
419443

420444
@pytest.mark.api
421445
def test_expectations_in_init(self):
422-
423446
"""
424447
Testing the Exceptions in the init function of the QiskitQPUShotBasedBackend
425448
"""
@@ -438,7 +461,9 @@ def test_expectations_in_init(self):
438461
)
439462
mixer_hamil = X_mixer_hamiltonian(n_qubits=nqubits)
440463
qaoa_descriptor = QAOADescriptor(cost_hamil, mixer_hamil, p=p)
441-
variate_params = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
464+
465+
# Check the creation of the varitional parms
466+
_ = QAOAVariationalStandardParams(qaoa_descriptor, betas, gammas)
442467

443468
# We mock the potential Exception that could occur in the Device class
444469
qiskit_device = DeviceQiskit("", "", "", "")
@@ -503,7 +528,6 @@ def test_remote_integration_sim_run(self):
503528
shots = 10000
504529

505530
for i in range(4):
506-
507531
cost_hamil = Hamiltonian(
508532
[PauliOp("ZZ", (0, 1)), PauliOp("ZZ", (1, 2)), PauliOp("ZZ", (0, 2))],
509533
weights,
@@ -538,7 +562,6 @@ def test_remote_integration_sim_run(self):
538562

539563
@pytest.mark.api
540564
def test_remote_qubit_overflow(self):
541-
542565
"""
543566
If the user creates a circuit that is larger than the maximum circuit size
544567
that is supported by the QPU. An Exception should be raised with the
@@ -552,9 +575,9 @@ def test_remote_qubit_overflow(self):
552575

553576
mixer_hamil = X_mixer_hamiltonian(n_qubits=6)
554577
qaoa_descriptor = QAOADescriptor(qubo.hamiltonian, mixer_hamil, p=1)
555-
variate_params = create_qaoa_variational_params(
556-
qaoa_descriptor, "standard", "rand"
557-
)
578+
579+
# Check the creation of the varitional parms
580+
_ = create_qaoa_variational_params(qaoa_descriptor, "standard", "rand")
558581

559582
qiskit_device = DeviceQiskit("ibmq_manila", self.HUB, self.GROUP, self.PROJECT)
560583

‎tests/test_workflows.py

+147-125
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.