classiq 0.75.0__py3-none-any.whl → 0.76.0__py3-none-any.whl

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.
Files changed (83) hide show
  1. classiq/_internals/api_wrapper.py +36 -0
  2. classiq/analyzer/show_interactive_hack.py +58 -2
  3. classiq/applications/chemistry/chemistry_model_constructor.py +8 -1
  4. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
  5. classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -4
  6. classiq/applications/qnn/gradients/quantum_gradient.py +3 -5
  7. classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -2
  8. classiq/applications/qnn/qlayer.py +14 -19
  9. classiq/applications/qnn/types.py +1 -4
  10. classiq/execution/__init__.py +3 -0
  11. classiq/execution/execution_session.py +3 -16
  12. classiq/execution/qnn.py +2 -2
  13. classiq/execution/user_budgets.py +38 -0
  14. classiq/executor.py +7 -19
  15. classiq/interface/_version.py +1 -1
  16. classiq/interface/debug_info/debug_info.py +16 -2
  17. classiq/interface/executor/user_budget.py +56 -0
  18. classiq/interface/generator/application_apis/finance_declarations.py +3 -0
  19. classiq/interface/generator/expressions/atomic_expression_functions.py +3 -0
  20. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +30 -124
  21. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +45 -21
  22. classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
  23. classiq/interface/generator/expressions/proxies/classical/utils.py +12 -11
  24. classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +9 -2
  25. classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +4 -1
  26. classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
  27. classiq/interface/generator/functions/classical_type.py +6 -1
  28. classiq/interface/generator/functions/type_name.py +7 -2
  29. classiq/interface/generator/functions/type_qualifier.py +15 -0
  30. classiq/interface/generator/model/preferences/preferences.py +7 -0
  31. classiq/interface/generator/quantum_program.py +5 -19
  32. classiq/interface/helpers/backward_compatibility.py +9 -0
  33. classiq/interface/helpers/datastructures.py +6 -0
  34. classiq/interface/model/port_declaration.py +1 -2
  35. classiq/interface/model/quantum_lambda_function.py +2 -1
  36. classiq/interface/server/routes.py +6 -0
  37. classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
  38. classiq/model_expansions/capturing/captured_vars.py +2 -0
  39. classiq/model_expansions/closure.py +5 -0
  40. classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
  41. classiq/model_expansions/evaluators/parameter_types.py +26 -13
  42. classiq/model_expansions/expression_evaluator.py +1 -1
  43. classiq/model_expansions/generative_functions.py +61 -34
  44. classiq/model_expansions/interpreters/base_interpreter.py +17 -6
  45. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +5 -0
  46. classiq/model_expansions/interpreters/generative_interpreter.py +13 -1
  47. classiq/model_expansions/quantum_operations/allocate.py +6 -1
  48. classiq/model_expansions/quantum_operations/assignment_result_processor.py +219 -20
  49. classiq/model_expansions/quantum_operations/bind.py +54 -30
  50. classiq/model_expansions/quantum_operations/block_evaluator.py +42 -0
  51. classiq/model_expansions/quantum_operations/call_emitter.py +14 -7
  52. classiq/model_expansions/quantum_operations/composite_emitter.py +1 -1
  53. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +23 -9
  54. classiq/model_expansions/quantum_operations/emitter.py +20 -3
  55. classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
  56. classiq/model_expansions/scope.py +10 -7
  57. classiq/model_expansions/sympy_conversion/arithmetics.py +18 -0
  58. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +2 -0
  59. classiq/model_expansions/sympy_conversion/sympy_to_python.py +10 -1
  60. classiq/model_expansions/transformers/model_renamer.py +45 -7
  61. classiq/model_expansions/utils/handles_collector.py +1 -1
  62. classiq/model_expansions/visitors/variable_references.py +45 -9
  63. classiq/qmod/builtins/functions/allocation.py +2 -2
  64. classiq/qmod/builtins/functions/arithmetic.py +14 -12
  65. classiq/qmod/builtins/functions/standard_gates.py +23 -23
  66. classiq/qmod/declaration_inferrer.py +19 -7
  67. classiq/qmod/generative.py +9 -1
  68. classiq/qmod/native/expression_to_qmod.py +4 -0
  69. classiq/qmod/native/pretty_printer.py +8 -3
  70. classiq/qmod/pretty_print/pretty_printer.py +1 -1
  71. classiq/qmod/python_classical_type.py +4 -5
  72. classiq/qmod/qmod_constant.py +15 -7
  73. classiq/qmod/qmod_variable.py +7 -1
  74. classiq/qmod/quantum_function.py +19 -6
  75. classiq/qmod/semantics/lambdas.py +6 -2
  76. classiq/qmod/semantics/validation/main_validation.py +17 -4
  77. classiq/qmod/symbolic.py +8 -19
  78. classiq/qmod/symbolic_expr.py +26 -0
  79. classiq/synthesis.py +17 -31
  80. classiq/visualization.py +35 -0
  81. {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/METADATA +1 -1
  82. {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/RECORD +83 -79
  83. {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/WHEEL +0 -0
@@ -24,8 +24,10 @@ from classiq.interface.execution.iqcc import (
24
24
  )
25
25
  from classiq.interface.execution.primitives import PrimitivesInput
26
26
  from classiq.interface.executor import execution_request
27
+ from classiq.interface.executor.user_budget import UserBudget
27
28
  from classiq.interface.generator import quantum_program as generator_result
28
29
  from classiq.interface.hardware import HardwareInformation, Provider
30
+ from classiq.interface.ide.visual_model import ProgramVisualModel
29
31
  from classiq.interface.jobs import JobDescription, JobID, JSONObject
30
32
  from classiq.interface.model.model import Model
31
33
  from classiq.interface.server import routes
@@ -122,6 +124,31 @@ class ApiWrapper:
122
124
  )
123
125
  return _parse_job_response(result, generator_result.QuantumProgram)
124
126
 
127
+ @classmethod
128
+ async def call_get_visual_model(
129
+ cls,
130
+ program_id: str,
131
+ http_client: Optional[httpx.AsyncClient] = None,
132
+ ) -> ProgramVisualModel:
133
+ raw_result = await cls._call_task(
134
+ http_method=HTTPMethod.GET,
135
+ url=f"{routes.ANALYZER_GET_VISUAL_MODEL_FULL_PATH}/{program_id}",
136
+ http_client=http_client,
137
+ )
138
+ return ProgramVisualModel.model_validate(raw_result)
139
+
140
+ @classmethod
141
+ async def call_visualization_task(
142
+ cls,
143
+ circuit: generator_result.QuantumProgram,
144
+ http_client: Optional[httpx.AsyncClient] = None,
145
+ ) -> ProgramVisualModel:
146
+ poller = JobPoller(base_url=routes.TASKS_VISUAL_MODEL_FULL_PATH)
147
+ result = await poller.run_pydantic(
148
+ circuit, timeout_sec=None, http_client=http_client
149
+ )
150
+ return _parse_job_response(result, ProgramVisualModel)
151
+
125
152
  @classmethod
126
153
  async def call_create_execution_session(
127
154
  cls,
@@ -488,3 +515,12 @@ class ApiWrapper:
488
515
  http_client=http_client,
489
516
  )
490
517
  return IQCCAuthItemsDetails.model_validate(response)
518
+
519
+ @classmethod
520
+ async def call_get_all_budgets(cls) -> list[UserBudget]:
521
+ data = await client().call_api(
522
+ http_method=HTTPMethod.GET,
523
+ url=routes.USER_BUDGETS_FULL_PATH,
524
+ )
525
+
526
+ return [UserBudget.model_validate(info) for info in data]
@@ -1,4 +1,6 @@
1
+ import os
1
2
  import webbrowser
3
+ from typing import Callable, Union
2
4
  from urllib.parse import urljoin
3
5
 
4
6
  from classiq.interface.exceptions import ClassiqAnalyzerVisualizationError
@@ -6,8 +8,54 @@ from classiq.interface.generator.model.preferences.preferences import QuantumFor
6
8
  from classiq.interface.generator.quantum_program import QuantumProgram
7
9
 
8
10
  from classiq._internals.api_wrapper import ApiWrapper
9
- from classiq._internals.async_utils import syncify_function
11
+ from classiq._internals.async_utils import is_notebook, syncify_function
10
12
  from classiq.analyzer.url_utils import circuit_page_uri, client_ide_base_url
13
+ from classiq.visualization import (
14
+ SerializedVisualModel,
15
+ visualize_async,
16
+ )
17
+
18
+ VisualizationRenderer = Callable[[SerializedVisualModel, str], None]
19
+
20
+
21
+ def is_classiq_studio() -> bool:
22
+ # Perhaps in the future we should add a dedicated unique environment var
23
+ # but so far should work just fine.
24
+ return bool(os.environ.get("OPENVSCODE"))
25
+
26
+
27
+ def get_visualization_renderer() -> Union[VisualizationRenderer, None]:
28
+ # Skip non-interactive environments
29
+ if not is_notebook():
30
+ return None
31
+ # Ideally, we should check if a notebook renderer is available to handle custom
32
+ # mime type, or at least if the Classiq vscode extension is installed.
33
+ # There's no such capabilities in IPython, so we make assumption from a fact that
34
+ # it's a Classiq Studio env.
35
+ # (Studio always has the extension, and the extension always supports mime type).
36
+ if not is_classiq_studio():
37
+ return None
38
+ try:
39
+ # Must be available since is_notebook passed
40
+ from IPython.display import display # type: ignore[import]
41
+ except ImportError:
42
+ # Just in case it failed anyway, fallback to IDE link open
43
+ return None
44
+
45
+ def renderer(visual_model: SerializedVisualModel, fallback: str) -> None:
46
+ display(
47
+ {
48
+ # Attempt to handle by notebook renderer from Classiq vscode extension
49
+ "application/vnd.classiq+qviz": visual_model,
50
+ # Fallback to IDE link display when no extension available.
51
+ # Shouldn't normally happen.
52
+ # Otherwise, is_classiq_studio detection is not correct.
53
+ "text/plain": fallback,
54
+ },
55
+ raw=True,
56
+ )
57
+
58
+ return renderer
11
59
 
12
60
 
13
61
  async def handle_remote_app(circuit: QuantumProgram, display_url: bool = True) -> None:
@@ -22,9 +70,17 @@ async def handle_remote_app(circuit: QuantumProgram, display_url: bool = True) -
22
70
  client_ide_base_url(),
23
71
  circuit_page_uri(circuit_id=circuit_dataid.id, circuit_version=circuit.version),
24
72
  )
73
+ link_label = f"Quantum program link: {app_url}"
74
+
75
+ renderer = get_visualization_renderer()
76
+ if renderer:
77
+ # Visualize in-place
78
+ visual_model = await visualize_async(circuit_dataid)
79
+ renderer(visual_model, link_label)
80
+ return
25
81
 
26
82
  if display_url:
27
- print(f"Quantum program link: {app_url}") # noqa: T201
83
+ print(link_label) # noqa: T201
28
84
 
29
85
  webbrowser.open_new_tab(app_url)
30
86
 
@@ -21,6 +21,7 @@ from classiq.interface.generator.functions.classical_type import (
21
21
  from classiq.interface.generator.functions.port_declaration import (
22
22
  PortDeclarationDirection,
23
23
  )
24
+ from classiq.interface.generator.functions.type_qualifier import TypeQualifier
24
25
  from classiq.interface.model.allocate import Allocate
25
26
  from classiq.interface.model.classical_parameter_declaration import (
26
27
  ClassicalParameterDeclaration,
@@ -464,7 +465,13 @@ def _get_chemistry_quantum_main(
464
465
  positional_arg_declarations=_get_chemistry_quantum_main_params(
465
466
  ansatz_parameters
466
467
  )
467
- + [PortDeclaration(name="qbv", direction=PortDeclarationDirection.Output)],
468
+ + [
469
+ PortDeclaration(
470
+ name="qbv",
471
+ direction=PortDeclarationDirection.Output,
472
+ type_qualifier=TypeQualifier.Quantum,
473
+ )
474
+ ],
468
475
  body=body,
469
476
  )
470
477
 
@@ -14,6 +14,7 @@ from classiq.interface.generator.functions.port_declaration import (
14
14
  PortDeclarationDirection,
15
15
  )
16
16
  from classiq.interface.generator.functions.type_name import Struct
17
+ from classiq.interface.generator.functions.type_qualifier import TypeQualifier
17
18
  from classiq.interface.model.allocate import Allocate
18
19
  from classiq.interface.model.classical_parameter_declaration import (
19
20
  ClassicalParameterDeclaration,
@@ -87,6 +88,7 @@ def construct_combi_opt_py_model(
87
88
  length=Expression(expr=f"{len_hamiltonian}"),
88
89
  ),
89
90
  direction=PortDeclarationDirection.Output,
91
+ type_qualifier=TypeQualifier.Quantum,
90
92
  ),
91
93
  ],
92
94
  body=[
@@ -12,7 +12,7 @@ from classiq.interface.executor.execution_preferences import ExecutionPreference
12
12
  from classiq.interface.executor.result import ExecutionDetails
13
13
  from classiq.interface.model.model import SerializedModel
14
14
 
15
- from classiq import Constraints, Preferences
15
+ from classiq import Constraints, Preferences, QuantumProgram
16
16
  from classiq.applications.combinatorial_helpers.combinatorial_problem_utils import (
17
17
  pyo_model_to_qmod_problem,
18
18
  )
@@ -27,7 +27,7 @@ from classiq.qmod.cparam import CReal
27
27
  from classiq.qmod.qfunc import qfunc
28
28
  from classiq.qmod.qmod_parameter import CArray
29
29
  from classiq.qmod.qmod_variable import Output, QVar
30
- from classiq.synthesis import SerializedQuantumProgram, synthesize
30
+ from classiq.synthesis import synthesize
31
31
 
32
32
 
33
33
  class CombinatorialProblem:
@@ -85,7 +85,7 @@ class CombinatorialProblem:
85
85
  ).get_model() # type:ignore[assignment]
86
86
  return self.model_ # type:ignore[return-value]
87
87
 
88
- def get_qprog(self) -> SerializedQuantumProgram:
88
+ def get_qprog(self) -> QuantumProgram:
89
89
  if self.model_ is None:
90
90
  self.get_model()
91
91
  self.qprog_ = synthesize(self.model_) # type:ignore[assignment,arg-type]
@@ -170,7 +170,7 @@ def execute_qaoa(
170
170
  num_layers: int,
171
171
  maxiter: int,
172
172
  execution_preferences: Optional[ExecutionPreferences] = None,
173
- ) -> tuple[SerializedModel, SerializedQuantumProgram, ExecutionDetails]:
173
+ ) -> tuple[SerializedModel, QuantumProgram, ExecutionDetails]:
174
174
  """
175
175
  Implements a simple QAOA algorithm, including the creation and synthesis of the QAOA
176
176
  ansatz and the classical optimization loop.
@@ -8,13 +8,12 @@ from classiq.interface.generator.quantum_program import QuantumProgram
8
8
 
9
9
  from classiq.applications.qnn.circuit_utils import extract_parameters, validate_circuit
10
10
  from classiq.applications.qnn.types import ExecuteFunction, PostProcessFunction
11
- from classiq.synthesis import SerializedQuantumProgram
12
11
 
13
12
 
14
13
  class QuantumGradient(abc.ABC):
15
14
  def __init__(
16
15
  self,
17
- quantum_program: SerializedQuantumProgram,
16
+ quantum_program: QuantumProgram,
18
17
  execute: ExecuteFunction,
19
18
  post_process: PostProcessFunction,
20
19
  *args: Any,
@@ -23,10 +22,9 @@ class QuantumGradient(abc.ABC):
23
22
  self._execute = execute
24
23
  self._post_process = post_process
25
24
 
26
- circuit = QuantumProgram.model_validate_json(quantum_program)
27
- validate_circuit(circuit)
25
+ validate_circuit(quantum_program)
28
26
  self._quantum_program = quantum_program
29
- self._parameters_names = extract_parameters(circuit)
27
+ self._parameters_names = extract_parameters(quantum_program)
30
28
 
31
29
  self.execute = functools.partial(execute, quantum_program)
32
30
 
@@ -5,6 +5,7 @@ from typing import Any
5
5
  import torch
6
6
  from torch import Tensor
7
7
 
8
+ from classiq import QuantumProgram
8
9
  from classiq.applications.qnn.circuit_utils import (
9
10
  batch_map_parameters,
10
11
  is_single_layer_circuit,
@@ -18,7 +19,6 @@ from classiq.applications.qnn.types import (
18
19
  Shape,
19
20
  TensorToArgumentsCallable,
20
21
  )
21
- from classiq.synthesis import SerializedQuantumProgram
22
22
 
23
23
  #
24
24
  # Types
@@ -66,7 +66,7 @@ def _differentiate_tensor(
66
66
  class SimpleQuantumGradient(QuantumGradient):
67
67
  def __init__(
68
68
  self,
69
- quantum_program: SerializedQuantumProgram,
69
+ quantum_program: QuantumProgram,
70
70
  execute: ExecuteFunction,
71
71
  post_process: PostProcessFunction,
72
72
  epsilon: float = EPSILON,
@@ -13,6 +13,7 @@ from torch.nn.parameter import Parameter
13
13
  from classiq.interface.exceptions import ClassiqQNNError, ClassiqTorchError
14
14
  from classiq.interface.executor.execution_result import ResultsCollection
15
15
 
16
+ from classiq import QuantumProgram
16
17
  from classiq.applications.qnn.circuit_utils import (
17
18
  extract_parameters,
18
19
  is_single_layer_circuit,
@@ -36,7 +37,6 @@ from classiq.applications.qnn.types import (
36
37
  )
37
38
  from classiq.execution import ExecutionSession
38
39
  from classiq.execution.qnn import _MAX_ARGUMENTS_SIZE, _execute_qnn_sample
39
- from classiq.synthesis import SerializedQuantumProgram
40
40
 
41
41
 
42
42
  class QLayerFunction(torch.autograd.Function):
@@ -45,7 +45,7 @@ class QLayerFunction(torch.autograd.Function):
45
45
  ctx: Any,
46
46
  inputs: Tensor,
47
47
  weights: Tensor,
48
- quantum_program: SerializedQuantumProgram,
48
+ quantum_program: QuantumProgram,
49
49
  execute: ExecuteFunction,
50
50
  post_process: PostProcessFunction,
51
51
  epsilon: Optional[float] = EPSILON,
@@ -63,8 +63,7 @@ class QLayerFunction(torch.autograd.Function):
63
63
  """
64
64
  if epsilon is None:
65
65
  epsilon = EPSILON
66
- circuit = Circuit.model_validate_json(quantum_program)
67
- validate_circuit(circuit)
66
+ validate_circuit(quantum_program)
68
67
 
69
68
  # save for backward
70
69
  ctx.save_for_backward(inputs, weights)
@@ -82,7 +81,7 @@ class QLayerFunction(torch.autograd.Function):
82
81
  ctx.num_out_features, ctx.num_weights = weights.shape
83
82
 
84
83
  # Todo: avoid computing `_get_extracted_parameters` on every `forward`
85
- extracted_parameters = extract_parameters(circuit)
84
+ extracted_parameters = extract_parameters(quantum_program)
86
85
 
87
86
  # Todo: avoid defining `convert_tensors_to_arguments` on every `forward`
88
87
  def convert_tensors_to_arguments(
@@ -141,11 +140,11 @@ class QLayerFunction(torch.autograd.Function):
141
140
  )
142
141
 
143
142
 
144
- CalcNumOutFeatures = Callable[[SerializedQuantumProgram], int]
143
+ CalcNumOutFeatures = Callable[[QuantumProgram], int]
145
144
 
146
145
 
147
146
  def calc_num_out_features_single_output(
148
- quantum_program: SerializedQuantumProgram,
147
+ quantum_program: QuantumProgram,
149
148
  ) -> int:
150
149
  return 1
151
150
 
@@ -156,7 +155,7 @@ class QLayer(nn.Module):
156
155
  @overload
157
156
  def __init__(
158
157
  self,
159
- quantum_program: SerializedQuantumProgram,
158
+ quantum_program: QuantumProgram,
160
159
  execute: ExecuteFunction,
161
160
  post_process: PostProcessFunction,
162
161
  # Optional parameters:
@@ -169,7 +168,7 @@ class QLayer(nn.Module):
169
168
  @overload
170
169
  def __init__(
171
170
  self,
172
- quantum_program: SerializedQuantumProgram,
171
+ quantum_program: QuantumProgram,
173
172
  post_process: PostProcessFunction,
174
173
  /,
175
174
  # Optional parameters:
@@ -181,12 +180,11 @@ class QLayer(nn.Module):
181
180
 
182
181
  def __init__(
183
182
  self,
184
- quantum_program: SerializedQuantumProgram,
183
+ quantum_program: QuantumProgram,
185
184
  *args: Any,
186
185
  **kwargs: Any,
187
186
  ) -> None:
188
- circuit = Circuit.model_validate_json(quantum_program)
189
- validate_circuit(circuit)
187
+ validate_circuit(quantum_program)
190
188
 
191
189
  super().__init__()
192
190
 
@@ -201,12 +199,11 @@ class QLayer(nn.Module):
201
199
  else:
202
200
  execute = arg_list.pop(0)
203
201
 
204
- self._initialize(quantum_program, circuit, execute, *arg_list, **kwargs)
202
+ self._initialize(quantum_program, execute, *arg_list, **kwargs)
205
203
  self._initialize_parameters()
206
204
 
207
205
  def _initialize(
208
206
  self,
209
- quantum_program: SerializedQuantumProgram,
210
207
  circuit: Circuit,
211
208
  execute: ExecuteFunction,
212
209
  post_process: PostProcessFunction,
@@ -219,11 +216,11 @@ class QLayer(nn.Module):
219
216
  self._head_start = head_start
220
217
  self._epsilon = epsilon
221
218
 
222
- self.quantum_program = quantum_program
219
+ self.quantum_program = circuit
223
220
 
224
221
  weights, _ = extract_parameters(circuit)
225
222
  self.in_features: int = len(weights)
226
- self.out_features: int = calc_num_out_features(quantum_program)
223
+ self.out_features: int = calc_num_out_features(circuit)
227
224
 
228
225
  def _initialize_parameters(self) -> None:
229
226
  shape: tuple[int, ...] = (
@@ -245,9 +242,7 @@ class QLayer(nn.Module):
245
242
 
246
243
  self.weight = Parameter(value)
247
244
 
248
- def _make_execute(
249
- self, quantum_program: SerializedQuantumProgram
250
- ) -> ExecuteFunction:
245
+ def _make_execute(self, quantum_program: QuantumProgram) -> ExecuteFunction:
251
246
  if os.environ.get("SDK_ENV") == "Studio":
252
247
  try:
253
248
  import classiq_studio_simulation
@@ -6,15 +6,12 @@ from torch import Tensor
6
6
  from classiq.interface.executor.execution_result import ResultsCollection, SavedResult
7
7
 
8
8
  from classiq import QuantumProgram
9
- from classiq.synthesis import SerializedQuantumProgram
10
9
 
11
10
  Arguments = dict[str, float]
12
11
  MultipleArguments = tuple[Arguments, ...]
13
12
 
14
13
  Circuit = QuantumProgram
15
- ExecuteFunction = Callable[
16
- [SerializedQuantumProgram, MultipleArguments], ResultsCollection
17
- ]
14
+ ExecuteFunction = Callable[[QuantumProgram, MultipleArguments], ResultsCollection]
18
15
  ExecuteFuncitonOnlyArguments = Callable[[MultipleArguments], ResultsCollection]
19
16
  PostProcessFunction = Callable[[SavedResult], Tensor]
20
17
  TensorToArgumentsCallable = Callable[[Tensor, Tensor], MultipleArguments]
@@ -11,6 +11,7 @@ from .execution_session import ExecutionSession
11
11
  from .iqcc import generate_iqcc_token, generate_iqcc_token_async
12
12
  from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
13
13
  from .qnn import execute_qnn
14
+ from .user_budgets import get_budget, get_budget_async
14
15
 
15
16
  __all__ = (
16
17
  _be_all
@@ -27,6 +28,8 @@ __all__ = (
27
28
  "execute_qnn",
28
29
  "generate_iqcc_token",
29
30
  "generate_iqcc_token_async",
31
+ "get_budget",
32
+ "get_budget_async",
30
33
  ]
31
34
  )
32
35
 
@@ -16,7 +16,6 @@ from classiq.interface.executor.result import (
16
16
  from classiq.interface.generator.arith import number_utils
17
17
  from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
18
18
  from classiq.interface.generator.quantum_program import (
19
- OMIT_DEBUG_INFO_FLAG,
20
19
  QuantumProgram,
21
20
  )
22
21
  from classiq.interface.model.quantum_type import QuantumBit, QuantumNumeric
@@ -33,10 +32,8 @@ from classiq.qmod.builtins.classical_execution_primitives import (
33
32
  CARRAY_SEPARATOR,
34
33
  ExecutionParams,
35
34
  )
36
- from classiq.synthesis import SerializedQuantumProgram
37
35
 
38
36
  Hamiltonian = Union[list[QmodPyStruct], list[PauliTerm]]
39
- Program = Union[SerializedQuantumProgram, QuantumProgram]
40
37
  ParsedExecutionParams = dict[str, Union[float, int]]
41
38
  ExecutionParameters = Optional[Union[ExecutionParams, list[ExecutionParams]]]
42
39
  ParsedExecutionParameters = Optional[
@@ -44,16 +41,6 @@ ParsedExecutionParameters = Optional[
44
41
  ]
45
42
 
46
43
 
47
- def _deserialize_program(program: Program) -> QuantumProgram:
48
- return (
49
- program
50
- if isinstance(program, QuantumProgram)
51
- else QuantumProgram.model_validate_json(
52
- program, context={OMIT_DEBUG_INFO_FLAG: True}
53
- )
54
- )
55
-
56
-
57
44
  def hamiltonian_to_pauli_terms(hamiltonian: Hamiltonian) -> list[PauliTerm]:
58
45
  if isinstance(hamiltonian[0], PauliTerm):
59
46
  return cast(list[PauliTerm], hamiltonian)
@@ -93,16 +80,16 @@ class ExecutionSession:
93
80
  The session must be closed in order to ensure resources are properly cleaned up. It's recommended to use `ExecutionSession` as a context manager for this purpose. Alternatively, you can directly use the `close` method.
94
81
 
95
82
  Attributes:
96
- quantum_program (Union[SerializedQuantumProgram, QuantumProgram]): The quantum program to execute.
83
+ quantum_program (QuantumProgram): The quantum program to execute.
97
84
  execution_preferences (Optional[ExecutionPreferences]): Execution preferences for the Quantum Program.
98
85
  """
99
86
 
100
87
  def __init__(
101
88
  self,
102
- quantum_program: Program,
89
+ quantum_program: QuantumProgram,
103
90
  execution_preferences: Optional[ExecutionPreferences] = None,
104
91
  ):
105
- self.program: QuantumProgram = _deserialize_program(quantum_program)
92
+ self.program: QuantumProgram = quantum_program
106
93
  self.update_execution_preferences(execution_preferences)
107
94
  # We never use classical_execution_code in ExecutionSession, and we don't want
108
95
  # the conversion route to fail because cmain is expected in some cases
classiq/execution/qnn.py CHANGED
@@ -13,11 +13,11 @@ from classiq.interface.executor.execution_result import (
13
13
  )
14
14
  from classiq.interface.executor.quantum_code import Arguments, MultipleArguments
15
15
 
16
+ from classiq import QuantumProgram
16
17
  from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
17
18
  pauli_operator_to_hamiltonian,
18
19
  )
19
20
  from classiq.execution.execution_session import ExecutionSession
20
- from classiq.synthesis import SerializedQuantumProgram
21
21
 
22
22
  _MAX_ARGUMENTS_SIZE = 1024
23
23
 
@@ -55,7 +55,7 @@ def _execute_qnn_sample(
55
55
 
56
56
 
57
57
  def execute_qnn(
58
- quantum_program: SerializedQuantumProgram,
58
+ quantum_program: QuantumProgram,
59
59
  arguments: MultipleArguments,
60
60
  observable: Optional[PauliOperator] = None,
61
61
  ) -> ResultsCollection:
@@ -0,0 +1,38 @@
1
+ from typing import Optional
2
+
3
+ from classiq.interface.backend.quantum_backend_providers import ProviderVendor
4
+ from classiq.interface.executor.user_budget import UserBudgets
5
+
6
+ from classiq._internals.api_wrapper import ApiWrapper
7
+ from classiq._internals.async_utils import syncify_function
8
+
9
+ PROVIDER_MAPPER = {
10
+ ProviderVendor.IONQ: "IONQ",
11
+ ProviderVendor.IBM_QUANTUM: "IBMQ",
12
+ ProviderVendor.AZURE_QUANTUM: "AZURE",
13
+ ProviderVendor.AMAZON_BRAKET: "AMAZON",
14
+ ProviderVendor.GOOGLE: "GOOGLE",
15
+ ProviderVendor.ALICE_AND_BOB: "ALICE_AND_BOB",
16
+ ProviderVendor.OQC: "OQC",
17
+ ProviderVendor.INTEL: "INTEL",
18
+ ProviderVendor.AQT: "AQT",
19
+ ProviderVendor.IQCC: "IQCC",
20
+ ProviderVendor.CLASSIQ: "CLASSIQ",
21
+ }
22
+
23
+
24
+ async def get_budget_async(
25
+ provider_vendor: Optional[ProviderVendor] = None,
26
+ ) -> UserBudgets:
27
+
28
+ budgets_list = await ApiWrapper().call_get_all_budgets()
29
+ if provider_vendor:
30
+ provider = PROVIDER_MAPPER.get(provider_vendor, None)
31
+ budgets_list = [
32
+ budget for budget in budgets_list if budget.provider == provider
33
+ ]
34
+
35
+ return UserBudgets(budgets=budgets_list)
36
+
37
+
38
+ get_budget = syncify_function(get_budget_async)
classiq/executor.py CHANGED
@@ -11,14 +11,12 @@ from classiq.interface.executor.quantum_code import QuantumCode
11
11
  from classiq.interface.executor.quantum_instruction_set import QuantumInstructionSet
12
12
  from classiq.interface.executor.result import ExecutionDetails
13
13
  from classiq.interface.generator.quantum_program import (
14
- OMIT_DEBUG_INFO_FLAG,
15
14
  QuantumProgram,
16
15
  )
17
16
 
18
17
  from classiq._internals import async_utils
19
18
  from classiq._internals.api_wrapper import ApiWrapper
20
19
  from classiq.execution.jobs import ExecutionJob
21
- from classiq.synthesis import SerializedQuantumProgram
22
20
 
23
21
  BatchExecutionResult: TypeAlias = Union[ExecutionDetails, BaseException]
24
22
  ProgramAndResult: TypeAlias = tuple[QuantumCode, BatchExecutionResult]
@@ -27,22 +25,13 @@ BackendPreferencesAndResult: TypeAlias = tuple[
27
25
  ]
28
26
 
29
27
 
30
- def _parse_serialized_qprog(
31
- quantum_program: SerializedQuantumProgram,
32
- ) -> QuantumProgram:
33
- return QuantumProgram.model_validate_json(
34
- quantum_program, context={OMIT_DEBUG_INFO_FLAG: True}
35
- )
36
-
37
-
38
- async def execute_async(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
39
- circuit = _parse_serialized_qprog(quantum_program)
40
- execution_input = await ApiWrapper.call_convert_quantum_program(circuit)
28
+ async def execute_async(quantum_program: QuantumProgram) -> ExecutionJob:
29
+ execution_input = await ApiWrapper.call_convert_quantum_program(quantum_program)
41
30
  result = await ApiWrapper.call_execute_execution_input(execution_input)
42
31
  return ExecutionJob(details=result)
43
32
 
44
33
 
45
- def execute(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
34
+ def execute(quantum_program: QuantumProgram) -> ExecutionJob:
46
35
  """
47
36
  Execute a quantum program. The preferences for execution are set on the quantum program using the method `set_execution_preferences`.
48
37
 
@@ -58,12 +47,11 @@ def execute(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
58
47
 
59
48
 
60
49
  def set_quantum_program_execution_preferences(
61
- quantum_program: SerializedQuantumProgram,
50
+ quantum_program: QuantumProgram,
62
51
  preferences: ExecutionPreferences,
63
- ) -> SerializedQuantumProgram:
64
- circuit = _parse_serialized_qprog(quantum_program)
65
- circuit.model.execution_preferences = preferences
66
- return SerializedQuantumProgram(circuit.model_dump_json())
52
+ ) -> QuantumProgram:
53
+ quantum_program.model.execution_preferences = preferences
54
+ return quantum_program
67
55
 
68
56
 
69
57
  __all__ = [
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.75.0'
6
+ SEMVER_VERSION = '0.76.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -1,5 +1,5 @@
1
- from collections.abc import Mapping
2
- from typing import Optional, Union
1
+ from collections.abc import Mapping, Sequence
2
+ from typing import Optional, Union, cast
3
3
  from uuid import UUID
4
4
 
5
5
  from pydantic import BaseModel, Field
@@ -10,6 +10,10 @@ from classiq.interface.generator.generated_circuit_data import (
10
10
  StatementType,
11
11
  )
12
12
  from classiq.interface.model.block import Block
13
+ from classiq.interface.model.handle_binding import ConcreteHandleBinding
14
+ from classiq.interface.model.port_declaration import PortDeclaration
15
+ from classiq.interface.model.quantum_function_call import ArgValue
16
+ from classiq.interface.model.quantum_function_declaration import PositionalArg
13
17
  from classiq.interface.model.statement_block import ConcreteQuantumStatement
14
18
 
15
19
  ParameterValue = Union[float, int, str, None]
@@ -98,3 +102,13 @@ def new_function_debug_info_by_node(
98
102
  name="",
99
103
  node=node._as_back_ref(),
100
104
  )
105
+
106
+
107
+ def calculate_port_to_passed_variable_mapping(
108
+ arg_decls: Sequence[PositionalArg], args: Sequence[Union[ArgValue, None]]
109
+ ) -> dict[str, str]:
110
+ return {
111
+ arg_decl.name: str(cast(ConcreteHandleBinding, arg))
112
+ for arg_decl, arg in zip(arg_decls, args)
113
+ if isinstance(arg_decl, PortDeclaration)
114
+ }