classiq 0.74.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 +23 -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 +18 -13
- 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 +46 -22
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +14 -13
- 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 +36 -1
- classiq/interface/generator/functions/type_name.py +32 -5
- classiq/interface/generator/functions/type_qualifier.py +15 -0
- classiq/interface/generator/generated_circuit_data.py +11 -25
- classiq/interface/generator/model/preferences/preferences.py +7 -0
- classiq/interface/generator/quantum_program.py +5 -19
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +10 -13
- classiq/interface/helpers/backward_compatibility.py +9 -0
- classiq/interface/helpers/datastructures.py +6 -0
- classiq/interface/helpers/versioned_model.py +12 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/handle_binding.py +12 -0
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/model/statement_block.py +9 -1
- classiq/interface/model/within_apply_operation.py +12 -0
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +82 -23
- classiq/model_expansions/capturing/captured_vars.py +2 -0
- classiq/model_expansions/closure.py +18 -0
- classiq/model_expansions/evaluators/argument_types.py +6 -5
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +26 -13
- classiq/model_expansions/evaluators/type_type_match.py +2 -2
- classiq/model_expansions/expression_evaluator.py +1 -1
- classiq/model_expansions/generative_functions.py +66 -33
- classiq/model_expansions/interpreters/base_interpreter.py +27 -19
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +26 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +25 -1
- classiq/model_expansions/quantum_operations/allocate.py +27 -11
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +220 -19
- 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 -12
- 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 +21 -8
- classiq/model_expansions/quantum_operations/expression_evaluator.py +1 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -0
- 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 +48 -8
- classiq/model_expansions/utils/handles_collector.py +1 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +197 -0
- 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 +30 -2
- 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 +34 -2
- classiq/qmod/write_qmod.py +5 -1
- classiq/synthesis.py +17 -31
- classiq/visualization.py +35 -0
- {classiq-0.74.0.dist-info → classiq-0.76.0.dist-info}/METADATA +1 -1
- {classiq-0.74.0.dist-info → classiq-0.76.0.dist-info}/RECORD +96 -91
- {classiq-0.74.0.dist-info → classiq-0.76.0.dist-info}/WHEEL +1 -1
@@ -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,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import functools
|
2
2
|
import inspect
|
3
|
+
import os
|
3
4
|
import typing
|
4
5
|
from typing import Any, Callable, Optional, Union, overload
|
5
6
|
|
@@ -12,6 +13,7 @@ from torch.nn.parameter import Parameter
|
|
12
13
|
from classiq.interface.exceptions import ClassiqQNNError, ClassiqTorchError
|
13
14
|
from classiq.interface.executor.execution_result import ResultsCollection
|
14
15
|
|
16
|
+
from classiq import QuantumProgram
|
15
17
|
from classiq.applications.qnn.circuit_utils import (
|
16
18
|
extract_parameters,
|
17
19
|
is_single_layer_circuit,
|
@@ -35,7 +37,6 @@ from classiq.applications.qnn.types import (
|
|
35
37
|
)
|
36
38
|
from classiq.execution import ExecutionSession
|
37
39
|
from classiq.execution.qnn import _MAX_ARGUMENTS_SIZE, _execute_qnn_sample
|
38
|
-
from classiq.synthesis import SerializedQuantumProgram
|
39
40
|
|
40
41
|
|
41
42
|
class QLayerFunction(torch.autograd.Function):
|
@@ -44,7 +45,7 @@ class QLayerFunction(torch.autograd.Function):
|
|
44
45
|
ctx: Any,
|
45
46
|
inputs: Tensor,
|
46
47
|
weights: Tensor,
|
47
|
-
quantum_program:
|
48
|
+
quantum_program: QuantumProgram,
|
48
49
|
execute: ExecuteFunction,
|
49
50
|
post_process: PostProcessFunction,
|
50
51
|
epsilon: Optional[float] = EPSILON,
|
@@ -62,8 +63,7 @@ class QLayerFunction(torch.autograd.Function):
|
|
62
63
|
"""
|
63
64
|
if epsilon is None:
|
64
65
|
epsilon = EPSILON
|
65
|
-
|
66
|
-
validate_circuit(circuit)
|
66
|
+
validate_circuit(quantum_program)
|
67
67
|
|
68
68
|
# save for backward
|
69
69
|
ctx.save_for_backward(inputs, weights)
|
@@ -81,7 +81,7 @@ class QLayerFunction(torch.autograd.Function):
|
|
81
81
|
ctx.num_out_features, ctx.num_weights = weights.shape
|
82
82
|
|
83
83
|
# Todo: avoid computing `_get_extracted_parameters` on every `forward`
|
84
|
-
extracted_parameters = extract_parameters(
|
84
|
+
extracted_parameters = extract_parameters(quantum_program)
|
85
85
|
|
86
86
|
# Todo: avoid defining `convert_tensors_to_arguments` on every `forward`
|
87
87
|
def convert_tensors_to_arguments(
|
@@ -140,11 +140,11 @@ class QLayerFunction(torch.autograd.Function):
|
|
140
140
|
)
|
141
141
|
|
142
142
|
|
143
|
-
CalcNumOutFeatures = Callable[[
|
143
|
+
CalcNumOutFeatures = Callable[[QuantumProgram], int]
|
144
144
|
|
145
145
|
|
146
146
|
def calc_num_out_features_single_output(
|
147
|
-
quantum_program:
|
147
|
+
quantum_program: QuantumProgram,
|
148
148
|
) -> int:
|
149
149
|
return 1
|
150
150
|
|
@@ -155,7 +155,7 @@ class QLayer(nn.Module):
|
|
155
155
|
@overload
|
156
156
|
def __init__(
|
157
157
|
self,
|
158
|
-
quantum_program:
|
158
|
+
quantum_program: QuantumProgram,
|
159
159
|
execute: ExecuteFunction,
|
160
160
|
post_process: PostProcessFunction,
|
161
161
|
# Optional parameters:
|
@@ -168,7 +168,7 @@ class QLayer(nn.Module):
|
|
168
168
|
@overload
|
169
169
|
def __init__(
|
170
170
|
self,
|
171
|
-
quantum_program:
|
171
|
+
quantum_program: QuantumProgram,
|
172
172
|
post_process: PostProcessFunction,
|
173
173
|
/,
|
174
174
|
# Optional parameters:
|
@@ -180,12 +180,11 @@ class QLayer(nn.Module):
|
|
180
180
|
|
181
181
|
def __init__(
|
182
182
|
self,
|
183
|
-
quantum_program:
|
183
|
+
quantum_program: QuantumProgram,
|
184
184
|
*args: Any,
|
185
185
|
**kwargs: Any,
|
186
186
|
) -> None:
|
187
|
-
|
188
|
-
validate_circuit(circuit)
|
187
|
+
validate_circuit(quantum_program)
|
189
188
|
|
190
189
|
super().__init__()
|
191
190
|
|
@@ -200,12 +199,11 @@ class QLayer(nn.Module):
|
|
200
199
|
else:
|
201
200
|
execute = arg_list.pop(0)
|
202
201
|
|
203
|
-
self._initialize(quantum_program,
|
202
|
+
self._initialize(quantum_program, execute, *arg_list, **kwargs)
|
204
203
|
self._initialize_parameters()
|
205
204
|
|
206
205
|
def _initialize(
|
207
206
|
self,
|
208
|
-
quantum_program: SerializedQuantumProgram,
|
209
207
|
circuit: Circuit,
|
210
208
|
execute: ExecuteFunction,
|
211
209
|
post_process: PostProcessFunction,
|
@@ -218,11 +216,11 @@ class QLayer(nn.Module):
|
|
218
216
|
self._head_start = head_start
|
219
217
|
self._epsilon = epsilon
|
220
218
|
|
221
|
-
self.quantum_program =
|
219
|
+
self.quantum_program = circuit
|
222
220
|
|
223
221
|
weights, _ = extract_parameters(circuit)
|
224
222
|
self.in_features: int = len(weights)
|
225
|
-
self.out_features: int = calc_num_out_features(
|
223
|
+
self.out_features: int = calc_num_out_features(circuit)
|
226
224
|
|
227
225
|
def _initialize_parameters(self) -> None:
|
228
226
|
shape: tuple[int, ...] = (
|
@@ -244,9 +242,15 @@ class QLayer(nn.Module):
|
|
244
242
|
|
245
243
|
self.weight = Parameter(value)
|
246
244
|
|
247
|
-
def _make_execute(
|
248
|
-
|
249
|
-
|
245
|
+
def _make_execute(self, quantum_program: QuantumProgram) -> ExecuteFunction:
|
246
|
+
if os.environ.get("SDK_ENV") == "Studio":
|
247
|
+
try:
|
248
|
+
import classiq_studio_simulation
|
249
|
+
|
250
|
+
return classiq_studio_simulation.make_execute_qnn(quantum_program)
|
251
|
+
except ImportError:
|
252
|
+
pass
|
253
|
+
|
250
254
|
session = ExecutionSession(quantum_program)
|
251
255
|
self._session = session
|
252
256
|
|
@@ -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