qoro-divi 0.3.1b0__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of qoro-divi might be problematic. Click here for more details.

Files changed (63) hide show
  1. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/PKG-INFO +3 -3
  2. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/_pbar.py +13 -14
  3. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/__init__.py +1 -1
  4. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_validator.py +1 -1
  5. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qlogger.py +6 -5
  6. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qoro_service.py +26 -13
  7. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/__init__.py +1 -1
  8. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_graph_partitioning.py +4 -7
  9. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_qaoa.py +15 -25
  10. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_qubo_partitioning.py +4 -5
  11. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_vqe.py +6 -5
  12. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/_vqe_sweep.py +3 -4
  13. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/batch.py +23 -15
  14. qoro_divi-0.3.3/divi/qprog/optimizers.py +201 -0
  15. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qprog/quantum_program.py +128 -193
  16. qoro_divi-0.3.3/divi/reporter.py +90 -0
  17. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/pyproject.toml +3 -3
  18. qoro_divi-0.3.1b0/divi/qprog/optimizers.py +0 -75
  19. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/LICENSE +0 -0
  20. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/LICENSES/.license-header +0 -0
  21. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/LICENSES/Apache-2.0.txt +0 -0
  22. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/README.md +0 -0
  23. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/__init__.py +0 -0
  24. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/circuits.py +0 -0
  25. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_lexer.py +0 -0
  26. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_parser.py +0 -0
  27. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_qasm_export.py +0 -0
  28. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/_qasm_import.py +0 -0
  29. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/cirq/exception.py +0 -0
  30. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/_cobyla.py +0 -0
  31. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/LICENCE.txt +0 -0
  32. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/__init__.py +0 -0
  33. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/__init__.py +0 -0
  34. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/cobyla.py +0 -0
  35. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/cobylb.py +0 -0
  36. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/geometry.py +0 -0
  37. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/initialize.py +0 -0
  38. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/trustregion.py +0 -0
  39. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/cobyla/update.py +0 -0
  40. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/__init__.py +0 -0
  41. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_bounds.py +0 -0
  42. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_linear_constraints.py +0 -0
  43. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_nonlinear_constraints.py +0 -0
  44. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/_project.py +0 -0
  45. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/checkbreak.py +0 -0
  46. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/consts.py +0 -0
  47. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/evaluate.py +0 -0
  48. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/history.py +0 -0
  49. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/infos.py +0 -0
  50. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/linalg.py +0 -0
  51. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/message.py +0 -0
  52. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/powalg.py +0 -0
  53. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/preproc.py +0 -0
  54. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/present.py +0 -0
  55. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/ratio.py +0 -0
  56. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/redrho.py +0 -0
  57. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/exp/scipy/pyprima/common/selectx.py +0 -0
  58. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/interfaces.py +0 -0
  59. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/parallel_simulator.py +0 -0
  60. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qasm.py +0 -0
  61. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qem.py +0 -0
  62. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/qpu_system.py +0 -0
  63. {qoro_divi-0.3.1b0 → qoro_divi-0.3.3}/divi/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qoro-divi
3
- Version: 0.3.1b0
3
+ Version: 0.3.3
4
4
  Summary: A Python library to automate generating, parallelizing, and executing quantum programs.
5
5
  Author: Ahmed Darwish
6
6
  Author-email: ahmed@qoroquantum.de
@@ -14,14 +14,14 @@ Requires-Dist: dwave-hybrid (>=0.6.14,<0.7.0)
14
14
  Requires-Dist: matplotlib (>=3.10.3,<4.0.0)
15
15
  Requires-Dist: mitiq (>=0.46,<0.47)
16
16
  Requires-Dist: networkx (>=3.5,<4.0)
17
- Requires-Dist: pennylane (>=0.40,<0.41)
17
+ Requires-Dist: pennylane (>=0.42.3,<0.43.0)
18
18
  Requires-Dist: ply (>=3.11,<4.0)
19
19
  Requires-Dist: pymetis (>=2025.1.1,<2026.0.0)
20
20
  Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
21
21
  Requires-Dist: qiskit (<2.0)
22
22
  Requires-Dist: qiskit-aer (>=0.17.1,<0.18.0)
23
23
  Requires-Dist: qiskit-ibm-runtime (>=0.37,<0.38)
24
- Requires-Dist: qiskit-optimization (>=0.6.1,<0.7.0)
24
+ Requires-Dist: qiskit-optimization[cplex] (>=0.7.0,<0.8.0)
25
25
  Requires-Dist: requests (>=2.32.4,<3.0.0)
26
26
  Requires-Dist: rich (>=14.0.0,<15.0.0)
27
27
  Requires-Dist: scikit-learn (>=1.7.0,<2.0.0)
@@ -28,12 +28,9 @@ class ConditionalSpinnerColumn(ProgressColumn):
28
28
 
29
29
 
30
30
  class PhaseStatusColumn(ProgressColumn):
31
- def __init__(self, max_retries: int, table_column=None):
31
+ def __init__(self, table_column=None):
32
32
  super().__init__(table_column)
33
33
 
34
- self._max_retries = max_retries
35
- self._last_message = ""
36
-
37
34
  def render(self, task):
38
35
  final_status = task.fields.get("final_status")
39
36
 
@@ -43,27 +40,29 @@ class PhaseStatusColumn(ProgressColumn):
43
40
  return Text("• Failed! ❌", style="bold red")
44
41
 
45
42
  message = task.fields.get("message")
46
- if message != "":
47
- self._last_message = message
48
43
 
49
44
  poll_attempt = task.fields.get("poll_attempt")
45
+ polling_str = ""
46
+ service_job_id = ""
50
47
  if poll_attempt > 0:
51
- return Text(
52
- f"[{self._last_message}] Polling {poll_attempt}/{self._max_retries}"
53
- )
48
+ max_retries = task.fields.get("max_retries")
49
+ service_job_id = task.fields.get("service_job_id").split("-")[0]
50
+ job_status = task.fields.get("job_status")
51
+ polling_str = f" [Job {service_job_id} is {job_status}. Polling attempt {poll_attempt} / {max_retries}]"
52
+
53
+ final_text = Text(f"[{message}]{polling_str}")
54
+ final_text.highlight_words([service_job_id], "blue")
54
55
 
55
- return Text(f"[{self._last_message}]")
56
+ return final_text
56
57
 
57
58
 
58
- def make_progress_bar(
59
- max_retries: int | None = None, is_jupyter: bool = False
60
- ) -> Progress:
59
+ def make_progress_bar(is_jupyter: bool = False) -> Progress:
61
60
  return Progress(
62
61
  TextColumn("[bold blue]{task.fields[job_name]}"),
63
62
  BarColumn(),
64
63
  MofNCompleteColumn(),
65
64
  ConditionalSpinnerColumn(),
66
- PhaseStatusColumn(max_retries=max_retries),
65
+ PhaseStatusColumn(),
67
66
  # For jupyter notebooks, refresh manually instead
68
67
  auto_refresh=not is_jupyter,
69
68
  # Give a dummy positive value if is_jupyter
@@ -5,4 +5,4 @@
5
5
  # TODO: delete whole module once Cirq properly supports parameters in openqasm 3.0
6
6
  from . import _qasm_export # Does nothing, just initiates the patch
7
7
  from ._qasm_import import cirq_circuit_from_qasm
8
- from ._validator import is_valid_qasm
8
+ from ._validator import is_valid_qasm, validate_qasm_raise
@@ -558,7 +558,7 @@ class Parser:
558
558
  self._expr_power(allow_id)
559
559
 
560
560
  def _expr_unary(self, allow_id: bool):
561
- if self.peek().type in ("PLUS", "MINUS"):
561
+ while self.peek().type in ("PLUS", "MINUS"):
562
562
  self.match(self.peek().type)
563
563
  self._expr_atom(allow_id)
564
564
 
@@ -44,22 +44,23 @@ class OverwriteStreamHandler(logging.StreamHandler):
44
44
 
45
45
  def emit(self, record):
46
46
  msg = self.format(record)
47
+ append = getattr(record, "append", False)
47
48
 
48
- if record.message.startswith(r"\c"):
49
- sep = r"\c"
50
- msg = f"{msg.split(sep)[0]}{self._last_record} [{record.message[2:-2]}]\r"
49
+ if append:
50
+ space = " " if self._last_record else ""
51
+ msg = f"{msg[:msg.index(record.message)]}{self._last_record}{space}[{record.message[:-2]}]\r"
51
52
 
52
53
  if msg.endswith("\r\n"):
53
54
  overwrite_and_newline = True
54
55
  clean_msg = msg[:-2]
55
56
 
56
- if not record.message.startswith("\c"):
57
+ if not append:
57
58
  self._last_record = record.message[:-2]
58
59
  elif msg.endswith("\r"):
59
60
  overwrite_and_newline = False
60
61
  clean_msg = msg[:-1]
61
62
 
62
- if not record.message.startswith(r"\c"):
63
+ if not append:
63
64
  self._last_record = record.message[:-1]
64
65
  else:
65
66
  # Normal message - no overwriting
@@ -15,7 +15,7 @@ import requests
15
15
  from dotenv import dotenv_values
16
16
  from requests.adapters import HTTPAdapter, Retry
17
17
 
18
- from divi.exp.cirq import is_valid_qasm
18
+ from divi.exp.cirq import validate_qasm_raise
19
19
  from divi.interfaces import CircuitRunner
20
20
  from divi.qpu_system import QPU, QPUSystem
21
21
 
@@ -241,8 +241,9 @@ class QoroService(CircuitRunner):
241
241
  raise ValueError("Only one circuit allowed for circuit-cutting jobs.")
242
242
 
243
243
  for key, circuit in circuits.items():
244
- if not is_valid_qasm(circuit):
245
- raise ValueError(f"Circuit {key} is not a valid QASM string.")
244
+ validate_qasm_raise(circuit)
245
+ # if not is_valid_qasm(circuit):
246
+ # raise ValueError(f"Circuit {key} is not a valid QASM string.")
246
247
 
247
248
  circuit_chunks = self._split_circuits(circuits)
248
249
 
@@ -342,7 +343,7 @@ class QoroService(CircuitRunner):
342
343
  loop_until_complete: bool = False,
343
344
  on_complete: Callable | None = None,
344
345
  verbose: bool = True,
345
- pbar_update_fn: Callable | None = None,
346
+ poll_callback: Callable[[int, str], None] | None = None,
346
347
  ):
347
348
  """
348
349
  Get the status of a job and optionally execute function *on_complete* on the results
@@ -354,13 +355,28 @@ class QoroService(CircuitRunner):
354
355
  on_complete (optional): A function to be called when the job is completed
355
356
  polling_interval (optional): The time to wait between retries
356
357
  verbose (optional): A flag to print the when retrying
357
- pbar_update_fn (optional): A function for updating progress bars while polling.
358
+ poll_callback (optional): A function for updating progress bars while polling.
359
+ Definition should be `poll_callback(retry_count: int, status: str) -> None`.
358
360
  Returns:
359
361
  status: The status of the job
360
362
  """
361
363
  if not isinstance(job_ids, list):
362
364
  job_ids = [job_ids]
363
365
 
366
+ # Decide once at the start
367
+ if poll_callback:
368
+ update_fn = poll_callback
369
+ elif verbose:
370
+ CYAN = "\033[36m"
371
+ RESET = "\033[0m"
372
+
373
+ update_fn = lambda retry_count, status: logger.info(
374
+ rf"Job {CYAN}{job_ids[0].split('-')[0]}{RESET} is {status}. Polling attempt {retry_count} / {self.max_retries}\r",
375
+ extra={"append": True},
376
+ )
377
+ else:
378
+ update_fn = lambda _, __: None
379
+
364
380
  if not loop_until_complete:
365
381
  statuses = [
366
382
  self._make_request(
@@ -386,7 +402,10 @@ class QoroService(CircuitRunner):
386
402
  timeout=200,
387
403
  )
388
404
 
389
- if response.json()["status"] == JobStatus.COMPLETED.value:
405
+ if response.json()["status"] in (
406
+ JobStatus.COMPLETED.value,
407
+ JobStatus.FAILED.value,
408
+ ):
390
409
  pending_job_ids.remove(job_id)
391
410
  responses.append(response)
392
411
 
@@ -396,13 +415,7 @@ class QoroService(CircuitRunner):
396
415
 
397
416
  time.sleep(self.polling_interval)
398
417
 
399
- if verbose:
400
- if pbar_update_fn:
401
- pbar_update_fn(retry_count)
402
- else:
403
- logger.info(
404
- rf"\cPolling {retry_count} / {self.max_retries} retries\r"
405
- )
418
+ update_fn(retry_count, response.json()["status"])
406
419
 
407
420
  if not pending_job_ids:
408
421
  if on_complete:
@@ -10,4 +10,4 @@ from ._vqe import VQE, VQEAnsatz
10
10
  from ._graph_partitioning import GraphPartitioningQAOA, PartitioningConfig
11
11
  from ._qubo_partitioning import QUBOPartitioningQAOA
12
12
  from ._vqe_sweep import VQEHyperparameterSweep, MoleculeTransformer
13
- from .optimizers import Optimizer
13
+ from .optimizers import ScipyOptimizer, ScipyMethod, MonteCarloOptimizer
@@ -21,16 +21,14 @@ from pymetis import part_graph
21
21
  from sklearn.cluster import SpectralClustering
22
22
 
23
23
  from divi.interfaces import CircuitRunner
24
- from divi.qprog import QAOA, ProgramBatch
24
+ from divi.qprog import QAOA, ProgramBatch, QuantumProgram
25
25
  from divi.qprog._qaoa import (
26
26
  _SUPPORTED_INITIAL_STATES_LITERAL,
27
27
  GraphProblem,
28
28
  GraphProblemTypes,
29
29
  draw_graph_solution_nodes,
30
30
  )
31
- from divi.qprog.quantum_program import QuantumProgram
32
-
33
- from .optimizers import Optimizer
31
+ from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
34
32
 
35
33
  AggregateFn = Callable[
36
34
  [list[int], str, nx.Graph | rx.PyGraph, dict[int, int]], list[int]
@@ -390,7 +388,6 @@ def dominance_aggregation(
390
388
 
391
389
 
392
390
  def _run_and_compute_solution(program: QuantumProgram):
393
-
394
391
  program.run()
395
392
 
396
393
  final_sol_circuit_count, final_sol_run_time = program.compute_final_solution()
@@ -408,7 +405,7 @@ class GraphPartitioningQAOA(ProgramBatch):
408
405
  partitioning_config: PartitioningConfig,
409
406
  initial_state: _SUPPORTED_INITIAL_STATES_LITERAL = "Recommended",
410
407
  aggregate_fn: AggregateFn = linear_aggregation,
411
- optimizer=Optimizer.MONTE_CARLO,
408
+ optimizer: Optimizer | None = None,
412
409
  max_iterations=10,
413
410
  **kwargs,
414
411
  ):
@@ -452,7 +449,7 @@ class GraphPartitioningQAOA(ProgramBatch):
452
449
  QAOA,
453
450
  initial_state=initial_state,
454
451
  graph_problem=graph_problem,
455
- optimizer=optimizer,
452
+ optimizer=optimizer if optimizer is not None else MonteCarloOptimizer(),
456
453
  max_iterations=self.max_iterations,
457
454
  backend=self.backend,
458
455
  n_layers=n_layers,
@@ -23,7 +23,7 @@ from qiskit_optimization.problems import VarType
23
23
 
24
24
  from divi.circuits import MetaCircuit
25
25
  from divi.qprog import QuantumProgram
26
- from divi.qprog.optimizers import Optimizer
26
+ from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
27
27
  from divi.utils import convert_qubo_matrix_to_pennylane_ising
28
28
 
29
29
  logger = logging.getLogger(__name__)
@@ -153,10 +153,11 @@ class QAOA(QuantumProgram):
153
153
  def __init__(
154
154
  self,
155
155
  problem: GraphProblemTypes | QUBOProblemTypes,
156
+ *,
156
157
  graph_problem: GraphProblem | None = None,
157
158
  n_layers: int = 1,
158
159
  initial_state: _SUPPORTED_INITIAL_STATES_LITERAL = "Recommended",
159
- optimizer: Optimizer = Optimizer.MONTE_CARLO,
160
+ optimizer: Optimizer | None = None,
160
161
  max_iterations: int = 10,
161
162
  **kwargs,
162
163
  ):
@@ -221,11 +222,11 @@ class QAOA(QuantumProgram):
221
222
 
222
223
  # Local Variables
223
224
  self.n_layers = n_layers
224
- self.optimizer = optimizer
225
225
  self.max_iterations = max_iterations
226
226
  self.current_iteration = 0
227
227
  self.n_params = 2
228
228
  self._is_compute_probabilites = False
229
+ self.optimizer = optimizer if optimizer is not None else MonteCarloOptimizer()
229
230
 
230
231
  # Shared Variables
231
232
  self.probs = kwargs.pop("probs", {})
@@ -245,10 +246,17 @@ class QAOA(QuantumProgram):
245
246
  )
246
247
  self.problem_metadata = problem_metadata[0] if problem_metadata else {}
247
248
 
248
- self.loss_constant = self.problem_metadata.get("constant", 0.0)
249
+ if "constant" in self.problem_metadata:
250
+ self.loss_constant = self.problem_metadata.get("constant")
251
+ try:
252
+ self.loss_constant = self.loss_constant.item()
253
+ except AttributeError:
254
+ pass
255
+ else:
256
+ self.loss_constant = 0.0
249
257
 
250
258
  kwargs.pop("is_constrained", None)
251
- super().__init__(**kwargs)
259
+ super().__init__(has_final_computation=True, **kwargs)
252
260
 
253
261
  self._meta_circuits = self._create_meta_circuits_dict()
254
262
 
@@ -387,16 +395,7 @@ class QAOA(QuantumProgram):
387
395
  - float: The total runtime of the optimization process.
388
396
  """
389
397
 
390
- if self._progress_queue:
391
- self._progress_queue.put(
392
- {
393
- "job_id": self.job_id,
394
- "message": "🏁 Computing Final Solution 🏁",
395
- "progress": 0,
396
- }
397
- )
398
- else:
399
- logger.info("🏁 Computing Final Solution 🏁")
398
+ self.reporter.info(message="🏁 Computing Final Solution 🏁")
400
399
 
401
400
  # Convert losses dict to list to apply ordinal operations
402
401
  final_losses_list = list(self.losses[-1].values())
@@ -440,16 +439,7 @@ class QAOA(QuantumProgram):
440
439
  m.start() for m in re.finditer("1", best_solution_bitstring)
441
440
  ]
442
441
 
443
- if self._progress_queue:
444
- self._progress_queue.put(
445
- {
446
- "job_id": self.job_id,
447
- "progress": 0,
448
- "final_status": "Success",
449
- }
450
- )
451
- else:
452
- logger.info(f"Computed Solution!")
442
+ self.reporter.info(message="Computed Final Solution!")
453
443
 
454
444
  return self._total_circuit_count, self._total_run_time
455
445
 
@@ -15,7 +15,7 @@ from dimod import BinaryQuadraticModel
15
15
  from divi.interfaces import CircuitRunner
16
16
  from divi.qprog._qaoa import QAOA, QUBOProblemTypes
17
17
  from divi.qprog.batch import ProgramBatch
18
- from divi.qprog.optimizers import Optimizer
18
+ from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
19
19
  from divi.qprog.quantum_program import QuantumProgram
20
20
 
21
21
 
@@ -50,7 +50,6 @@ def _sanitize_problem_input(qubo: T) -> tuple[T, BinaryQuadraticModel]:
50
50
 
51
51
 
52
52
  def _run_and_compute_solution(program: QuantumProgram):
53
-
54
53
  program.run()
55
54
 
56
55
  final_sol_circuit_count, final_sol_run_time = program.compute_final_solution()
@@ -66,8 +65,8 @@ class QUBOPartitioningQAOA(ProgramBatch):
66
65
  n_layers: int,
67
66
  backend: CircuitRunner,
68
67
  composer: hybrid.traits.SubsamplesComposer = hybrid.SplatComposer(),
69
- optimizer=Optimizer.MONTE_CARLO,
70
- max_iterations=10,
68
+ optimizer: Optimizer | None = None,
69
+ max_iterations: int = 10,
71
70
  **kwargs,
72
71
  ):
73
72
  """
@@ -101,7 +100,7 @@ class QUBOPartitioningQAOA(ProgramBatch):
101
100
 
102
101
  self._constructor = partial(
103
102
  QAOA,
104
- optimizer=optimizer,
103
+ optimizer=optimizer if optimizer is not None else MonteCarloOptimizer(),
105
104
  max_iterations=self.max_iterations,
106
105
  backend=self.backend,
107
106
  n_layers=n_layers,
@@ -10,7 +10,7 @@ import sympy as sp
10
10
 
11
11
  from divi.circuits import MetaCircuit
12
12
  from divi.qprog import QuantumProgram
13
- from divi.qprog.optimizers import Optimizer
13
+ from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
14
14
 
15
15
 
16
16
  class VQEAnsatz(Enum):
@@ -50,7 +50,7 @@ class VQE(QuantumProgram):
50
50
  n_electrons: int | None = None,
51
51
  n_layers: int = 1,
52
52
  ansatz=VQEAnsatz.HARTREE_FOCK,
53
- optimizer=Optimizer.MONTE_CARLO,
53
+ optimizer: Optimizer | None = None,
54
54
  max_iterations=10,
55
55
  **kwargs,
56
56
  ) -> None:
@@ -71,10 +71,11 @@ class VQE(QuantumProgram):
71
71
  self.n_layers = n_layers
72
72
  self.results = {}
73
73
  self.ansatz = ansatz
74
- self.optimizer = optimizer
75
74
  self.max_iterations = max_iterations
76
75
  self.current_iteration = 0
77
76
 
77
+ self.optimizer = optimizer if optimizer is not None else MonteCarloOptimizer()
78
+
78
79
  self._process_problem_input(
79
80
  hamiltonian=hamiltonian, molecule=molecule, n_electrons=n_electrons
80
81
  )
@@ -137,8 +138,8 @@ class VQE(QuantumProgram):
137
138
  )
138
139
  )
139
140
 
140
- self.loss_constant = sum(
141
- map(lambda x: hamiltonian[x].scalar, constant_terms_idx)
141
+ self.loss_constant = float(
142
+ sum(map(lambda x: hamiltonian[x].scalar, constant_terms_idx))
142
143
  )
143
144
 
144
145
  for idx in constant_terms_idx:
@@ -15,8 +15,7 @@ import numpy as np
15
15
  import pennylane as qml
16
16
 
17
17
  from divi.qprog import VQE, ProgramBatch, VQEAnsatz
18
-
19
- from .optimizers import Optimizer
18
+ from divi.qprog.optimizers import MonteCarloOptimizer, Optimizer
20
19
 
21
20
 
22
21
  def _ctor_attrs(obj):
@@ -395,7 +394,7 @@ class VQEHyperparameterSweep(ProgramBatch):
395
394
  self,
396
395
  ansatze: Sequence[VQEAnsatz],
397
396
  molecule_transformer: MoleculeTransformer,
398
- optimizer: Optimizer = Optimizer.MONTE_CARLO,
397
+ optimizer: Optimizer | None = None,
399
398
  max_iterations: int = 10,
400
399
  **kwargs,
401
400
  ):
@@ -424,7 +423,7 @@ class VQEHyperparameterSweep(ProgramBatch):
424
423
 
425
424
  self._constructor = partial(
426
425
  VQE,
427
- optimizer=optimizer,
426
+ optimizer=optimizer if optimizer is not None else MonteCarloOptimizer(),
428
427
  max_iterations=self.max_iterations,
429
428
  backend=self.backend,
430
429
  **kwargs,
@@ -10,6 +10,7 @@ from multiprocessing import Event, Manager
10
10
  from multiprocessing.synchronize import Event as EventClass
11
11
  from queue import Empty, Queue
12
12
  from threading import Lock, Thread
13
+ from typing import Any
13
14
  from warnings import warn
14
15
 
15
16
  from rich.console import Console
@@ -32,7 +33,7 @@ def queue_listener(
32
33
  ):
33
34
  while not done_event.is_set():
34
35
  try:
35
- msg = queue.get(timeout=0.1)
36
+ msg: dict[str, Any] = queue.get(timeout=0.1)
36
37
  except Empty:
37
38
  continue
38
39
  except Exception as e:
@@ -42,14 +43,25 @@ def queue_listener(
42
43
  with lock:
43
44
  task_id = pb_task_map[msg["job_id"]]
44
45
 
45
- progress_bar.update(
46
- task_id,
47
- advance=msg["progress"],
48
- poll_attempt=msg.get("poll_attempt", 0),
49
- message=msg.get("message", ""),
50
- final_status=msg.get("final_status", ""),
51
- refresh=is_jupyter,
52
- )
46
+ # Prepare update arguments, starting with progress.
47
+ update_args = {"advance": msg["progress"]}
48
+
49
+ if "poll_attempt" in msg:
50
+ update_args["poll_attempt"] = msg.get("poll_attempt", 0)
51
+ if "max_retries" in msg:
52
+ update_args["max_retries"] = msg.get("max_retries")
53
+ if "service_job_id" in msg:
54
+ update_args["service_job_id"] = msg.get("service_job_id")
55
+ if "job_status" in msg:
56
+ update_args["job_status"] = msg.get("job_status")
57
+ if msg.get("message"):
58
+ update_args["message"] = msg.get("message")
59
+ if "final_status" in msg:
60
+ update_args["final_status"] = msg.get("final_status", "")
61
+
62
+ update_args["refresh"] = is_jupyter
63
+
64
+ progress_bar.update(task_id, **update_args)
53
65
 
54
66
 
55
67
  def _default_task_function(program: QuantumProgram):
@@ -182,10 +194,7 @@ class ProgramBatch(ABC):
182
194
  raise RuntimeError("No programs to run.")
183
195
 
184
196
  self._progress_bar = (
185
- make_progress_bar(
186
- max_retries=None if self._is_local else self.backend.max_retries,
187
- is_jupyter=self._is_jupyter,
188
- )
197
+ make_progress_bar(is_jupyter=self._is_jupyter)
189
198
  if hasattr(self, "max_iterations")
190
199
  else None
191
200
  )
@@ -217,8 +226,7 @@ class ProgramBatch(ABC):
217
226
  if not blocking:
218
227
  # Arm safety net
219
228
  atexit.register(self._atexit_cleanup_hook)
220
-
221
- if blocking:
229
+ else:
222
230
  self.join()
223
231
 
224
232
  return self