classiq 0.75.0__py3-none-any.whl → 0.77.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 (101) 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 +15 -7
  4. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +11 -1
  5. classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -7
  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_qarray_proxy.py +6 -15
  25. classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +22 -6
  26. classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +9 -4
  27. classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
  28. classiq/interface/generator/functions/classical_type.py +6 -1
  29. classiq/interface/generator/functions/type_name.py +7 -2
  30. classiq/interface/generator/functions/type_qualifier.py +15 -0
  31. classiq/interface/generator/model/preferences/preferences.py +7 -0
  32. classiq/interface/generator/quantum_program.py +5 -19
  33. classiq/interface/helpers/backward_compatibility.py +9 -0
  34. classiq/interface/helpers/datastructures.py +6 -0
  35. classiq/interface/model/handle_binding.py +8 -0
  36. classiq/interface/model/model.py +3 -6
  37. classiq/interface/model/port_declaration.py +1 -2
  38. classiq/interface/model/quantum_function_call.py +31 -1
  39. classiq/interface/model/quantum_lambda_function.py +2 -1
  40. classiq/interface/model/quantum_statement.py +14 -1
  41. classiq/interface/server/routes.py +6 -0
  42. classiq/interface/source_reference.py +7 -2
  43. classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
  44. classiq/model_expansions/capturing/captured_vars.py +18 -6
  45. classiq/model_expansions/closure.py +5 -0
  46. classiq/model_expansions/evaluators/arg_type_match.py +2 -2
  47. classiq/model_expansions/evaluators/argument_types.py +3 -3
  48. classiq/model_expansions/evaluators/classical_expression.py +9 -9
  49. classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
  50. classiq/model_expansions/evaluators/parameter_types.py +45 -24
  51. classiq/model_expansions/expression_evaluator.py +21 -12
  52. classiq/model_expansions/function_builder.py +45 -0
  53. classiq/model_expansions/generative_functions.py +62 -35
  54. classiq/model_expansions/interpreters/base_interpreter.py +32 -7
  55. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +9 -3
  56. classiq/model_expansions/interpreters/generative_interpreter.py +17 -5
  57. classiq/model_expansions/quantum_operations/allocate.py +8 -3
  58. classiq/model_expansions/quantum_operations/assignment_result_processor.py +221 -20
  59. classiq/model_expansions/quantum_operations/bind.py +54 -30
  60. classiq/model_expansions/quantum_operations/block_evaluator.py +42 -0
  61. classiq/model_expansions/quantum_operations/call_emitter.py +35 -18
  62. classiq/model_expansions/quantum_operations/composite_emitter.py +1 -1
  63. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +23 -9
  64. classiq/model_expansions/quantum_operations/emitter.py +21 -9
  65. classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
  66. classiq/model_expansions/scope.py +63 -10
  67. classiq/model_expansions/sympy_conversion/arithmetics.py +18 -0
  68. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +2 -0
  69. classiq/model_expansions/sympy_conversion/sympy_to_python.py +10 -1
  70. classiq/model_expansions/transformers/model_renamer.py +45 -7
  71. classiq/model_expansions/utils/handles_collector.py +1 -1
  72. classiq/model_expansions/visitors/symbolic_param_inference.py +3 -3
  73. classiq/model_expansions/visitors/variable_references.py +45 -9
  74. classiq/open_library/functions/lookup_table.py +1 -1
  75. classiq/open_library/functions/state_preparation.py +1 -1
  76. classiq/qmod/builtins/functions/allocation.py +2 -2
  77. classiq/qmod/builtins/functions/arithmetic.py +14 -12
  78. classiq/qmod/builtins/functions/standard_gates.py +23 -23
  79. classiq/qmod/create_model_function.py +21 -3
  80. classiq/qmod/declaration_inferrer.py +19 -7
  81. classiq/qmod/generative.py +9 -1
  82. classiq/qmod/global_declarative_switch.py +19 -0
  83. classiq/qmod/native/expression_to_qmod.py +4 -0
  84. classiq/qmod/native/pretty_printer.py +12 -3
  85. classiq/qmod/pretty_print/pretty_printer.py +5 -1
  86. classiq/qmod/python_classical_type.py +4 -5
  87. classiq/qmod/qfunc.py +31 -23
  88. classiq/qmod/qmod_constant.py +15 -7
  89. classiq/qmod/qmod_variable.py +7 -1
  90. classiq/qmod/quantum_expandable.py +29 -1
  91. classiq/qmod/quantum_function.py +45 -25
  92. classiq/qmod/semantics/lambdas.py +6 -2
  93. classiq/qmod/semantics/validation/main_validation.py +17 -4
  94. classiq/qmod/symbolic.py +8 -19
  95. classiq/qmod/symbolic_expr.py +26 -0
  96. classiq/qmod/write_qmod.py +36 -10
  97. classiq/synthesis.py +24 -37
  98. classiq/visualization.py +35 -0
  99. {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/METADATA +1 -1
  100. {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/RECORD +101 -96
  101. {classiq-0.75.0.dist-info → classiq-0.77.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,
@@ -52,6 +53,7 @@ from classiq.qmod.builtins.structs import (
52
53
  MoleculeProblem as QmodMoleculeProblem,
53
54
  Position as QmodPosition,
54
55
  )
56
+ from classiq.qmod.global_declarative_switch import set_global_declarative_switch
55
57
  from classiq.qmod.utilities import qmod_val_to_expr_str
56
58
 
57
59
  # isort: split
@@ -59,6 +61,11 @@ from classiq.qmod.utilities import qmod_val_to_expr_str
59
61
  # This import causes a circular import if done earlier. We use isort: split to avoid it
60
62
  from classiq.open_library.functions.hea import full_hea
61
63
 
64
+ with set_global_declarative_switch():
65
+ _FULL_HEA = cast(
66
+ NativeFunctionDefinition, full_hea.create_model().function_dict["full_hea"]
67
+ )
68
+
62
69
  _LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
63
70
  "+": "PLUS",
64
71
  "-": "MINUS",
@@ -464,7 +471,13 @@ def _get_chemistry_quantum_main(
464
471
  positional_arg_declarations=_get_chemistry_quantum_main_params(
465
472
  ansatz_parameters
466
473
  )
467
- + [PortDeclaration(name="qbv", direction=PortDeclarationDirection.Output)],
474
+ + [
475
+ PortDeclaration(
476
+ name="qbv",
477
+ direction=PortDeclarationDirection.Output,
478
+ type_qualifier=TypeQualifier.Quantum,
479
+ )
480
+ ],
468
481
  body=body,
469
482
  )
470
483
 
@@ -499,12 +512,7 @@ def construct_chemistry_model(
499
512
  )
500
513
  ]
501
514
  if isinstance(ansatz_parameters, HEAParameters):
502
- chemistry_functions.append(
503
- cast(
504
- NativeFunctionDefinition,
505
- full_hea.create_model().function_dict["full_hea"],
506
- )
507
- )
515
+ chemistry_functions.append(_FULL_HEA)
508
516
  model = Model(
509
517
  functions=chemistry_functions,
510
518
  classical_execution_code=_get_chemistry_classical_code(
@@ -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,
@@ -35,6 +36,14 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import
35
36
  )
36
37
  from classiq.applications.combinatorial_optimization import OptimizerConfig, QAOAConfig
37
38
  from classiq.open_library.functions.qaoa_penalty import qaoa_penalty
39
+ from classiq.qmod.global_declarative_switch import set_global_declarative_switch
40
+
41
+ with set_global_declarative_switch():
42
+ _LIBRARY_FUNCTIONS = [
43
+ f.model_dump()
44
+ for f in qaoa_penalty.create_model().functions
45
+ if f.name != "main"
46
+ ]
38
47
 
39
48
 
40
49
  def construct_combi_opt_py_model(
@@ -87,6 +96,7 @@ def construct_combi_opt_py_model(
87
96
  length=Expression(expr=f"{len_hamiltonian}"),
88
97
  ),
89
98
  direction=PortDeclarationDirection.Output,
99
+ type_qualifier=TypeQualifier.Quantum,
90
100
  ),
91
101
  ],
92
102
  body=[
@@ -105,7 +115,7 @@ def construct_combi_opt_py_model(
105
115
  ),
106
116
  ],
107
117
  ),
108
- *[f for f in qaoa_penalty.create_model().functions if f.name != "main"],
118
+ *_LIBRARY_FUNCTIONS,
109
119
  ],
110
120
  classical_execution_code=f"""
111
121
  vqe_result = vqe(
@@ -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
  )
@@ -24,10 +24,11 @@ from classiq.open_library.functions.utility_functions import (
24
24
  from classiq.qmod.builtins.functions import RX
25
25
  from classiq.qmod.builtins.operations import allocate, phase, repeat
26
26
  from classiq.qmod.cparam import CReal
27
+ from classiq.qmod.create_model_function import create_model
27
28
  from classiq.qmod.qfunc import qfunc
28
29
  from classiq.qmod.qmod_parameter import CArray
29
30
  from classiq.qmod.qmod_variable import Output, QVar
30
- from classiq.synthesis import SerializedQuantumProgram, synthesize
31
+ from classiq.synthesis import synthesize
31
32
 
32
33
 
33
34
  class CombinatorialProblem:
@@ -80,12 +81,12 @@ class CombinatorialProblem:
80
81
  ],
81
82
  )
82
83
 
83
- self.model_ = main.create_model(
84
- constraints=constraints, preferences=preferences
85
- ).get_model() # type:ignore[assignment]
84
+ self.model_ = create_model(
85
+ main, constraints=constraints, preferences=preferences
86
+ ) # type:ignore[assignment]
86
87
  return self.model_ # type:ignore[return-value]
87
88
 
88
- def get_qprog(self) -> SerializedQuantumProgram:
89
+ def get_qprog(self) -> QuantumProgram:
89
90
  if self.model_ is None:
90
91
  self.get_model()
91
92
  self.qprog_ = synthesize(self.model_) # type:ignore[assignment,arg-type]
@@ -170,7 +171,7 @@ def execute_qaoa(
170
171
  num_layers: int,
171
172
  maxiter: int,
172
173
  execution_preferences: Optional[ExecutionPreferences] = None,
173
- ) -> tuple[SerializedModel, SerializedQuantumProgram, ExecutionDetails]:
174
+ ) -> tuple[SerializedModel, QuantumProgram, ExecutionDetails]:
174
175
  """
175
176
  Implements a simple QAOA algorithm, including the creation and synthesis of the QAOA
176
177
  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.77.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))