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.
- classiq/_internals/api_wrapper.py +36 -0
- classiq/analyzer/show_interactive_hack.py +58 -2
- classiq/applications/chemistry/chemistry_model_constructor.py +8 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -4
- classiq/applications/qnn/gradients/quantum_gradient.py +3 -5
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -2
- classiq/applications/qnn/qlayer.py +14 -19
- classiq/applications/qnn/types.py +1 -4
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +3 -16
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +38 -0
- classiq/executor.py +7 -19
- classiq/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +16 -2
- classiq/interface/executor/user_budget.py +56 -0
- classiq/interface/generator/application_apis/finance_declarations.py +3 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +3 -0
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +30 -124
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +45 -21
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +12 -11
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +9 -2
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +4 -1
- classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
- classiq/interface/generator/functions/classical_type.py +6 -1
- classiq/interface/generator/functions/type_name.py +7 -2
- classiq/interface/generator/functions/type_qualifier.py +15 -0
- classiq/interface/generator/model/preferences/preferences.py +7 -0
- classiq/interface/generator/quantum_program.py +5 -19
- classiq/interface/helpers/backward_compatibility.py +9 -0
- classiq/interface/helpers/datastructures.py +6 -0
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
- classiq/model_expansions/capturing/captured_vars.py +2 -0
- classiq/model_expansions/closure.py +5 -0
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +26 -13
- classiq/model_expansions/expression_evaluator.py +1 -1
- classiq/model_expansions/generative_functions.py +61 -34
- classiq/model_expansions/interpreters/base_interpreter.py +17 -6
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +5 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +13 -1
- classiq/model_expansions/quantum_operations/allocate.py +6 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +219 -20
- classiq/model_expansions/quantum_operations/bind.py +54 -30
- classiq/model_expansions/quantum_operations/block_evaluator.py +42 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +14 -7
- classiq/model_expansions/quantum_operations/composite_emitter.py +1 -1
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +23 -9
- classiq/model_expansions/quantum_operations/emitter.py +20 -3
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
- classiq/model_expansions/scope.py +10 -7
- classiq/model_expansions/sympy_conversion/arithmetics.py +18 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +2 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +10 -1
- classiq/model_expansions/transformers/model_renamer.py +45 -7
- classiq/model_expansions/utils/handles_collector.py +1 -1
- classiq/model_expansions/visitors/variable_references.py +45 -9
- classiq/qmod/builtins/functions/allocation.py +2 -2
- classiq/qmod/builtins/functions/arithmetic.py +14 -12
- classiq/qmod/builtins/functions/standard_gates.py +23 -23
- classiq/qmod/declaration_inferrer.py +19 -7
- classiq/qmod/generative.py +9 -1
- classiq/qmod/native/expression_to_qmod.py +4 -0
- classiq/qmod/native/pretty_printer.py +8 -3
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/python_classical_type.py +4 -5
- classiq/qmod/qmod_constant.py +15 -7
- classiq/qmod/qmod_variable.py +7 -1
- classiq/qmod/quantum_function.py +19 -6
- classiq/qmod/semantics/lambdas.py +6 -2
- classiq/qmod/semantics/validation/main_validation.py +17 -4
- classiq/qmod/symbolic.py +8 -19
- classiq/qmod/symbolic_expr.py +26 -0
- classiq/synthesis.py +17 -31
- classiq/visualization.py +35 -0
- {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/METADATA +1 -1
- {classiq-0.75.0.dist-info → classiq-0.76.0.dist-info}/RECORD +83 -79
- {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(
|
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
|
-
+ [
|
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
|
|
classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py
CHANGED
@@ -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
|
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) ->
|
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,
|
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:
|
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
|
-
|
27
|
-
validate_circuit(circuit)
|
25
|
+
validate_circuit(quantum_program)
|
28
26
|
self._quantum_program = quantum_program
|
29
|
-
self._parameters_names = extract_parameters(
|
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:
|
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:
|
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
|
-
|
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(
|
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[[
|
143
|
+
CalcNumOutFeatures = Callable[[QuantumProgram], int]
|
145
144
|
|
146
145
|
|
147
146
|
def calc_num_out_features_single_output(
|
148
|
-
quantum_program:
|
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:
|
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:
|
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:
|
183
|
+
quantum_program: QuantumProgram,
|
185
184
|
*args: Any,
|
186
185
|
**kwargs: Any,
|
187
186
|
) -> None:
|
188
|
-
|
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,
|
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 =
|
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(
|
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]
|
classiq/execution/__init__.py
CHANGED
@@ -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 (
|
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:
|
89
|
+
quantum_program: QuantumProgram,
|
103
90
|
execution_preferences: Optional[ExecutionPreferences] = None,
|
104
91
|
):
|
105
|
-
self.program: QuantumProgram =
|
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:
|
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
|
31
|
-
quantum_program
|
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:
|
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:
|
50
|
+
quantum_program: QuantumProgram,
|
62
51
|
preferences: ExecutionPreferences,
|
63
|
-
) ->
|
64
|
-
|
65
|
-
|
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__ = [
|
classiq/interface/_version.py
CHANGED
@@ -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
|
+
}
|