classiq 0.64.0__py3-none-any.whl → 0.65.1__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 +30 -0
- classiq/applications/chemistry/chemistry_model_constructor.py +8 -9
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +2 -5
- classiq/applications/finance/finance_model_constructor.py +7 -12
- classiq/applications/grover/grover_model_constructor.py +4 -6
- classiq/applications/qsvm/qsvm_model_constructor.py +6 -4
- classiq/execution/execution_session.py +14 -13
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +1 -9
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/model/allocate.py +16 -0
- classiq/interface/model/quantum_type.py +26 -0
- classiq/interface/model/statement_block.py +2 -0
- classiq/interface/server/routes.py +1 -0
- classiq/model_expansions/evaluators/quantum_type_utils.py +10 -0
- classiq/model_expansions/function_builder.py +35 -11
- classiq/model_expansions/generative_functions.py +6 -4
- classiq/model_expansions/interpreters/base_interpreter.py +37 -138
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +144 -3
- classiq/model_expansions/quantum_operations/call_emitter.py +43 -91
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
- classiq/model_expansions/quantum_operations/emitter.py +5 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +9 -0
- classiq/model_expansions/quantum_operations/shallow_emitter.py +20 -1
- classiq/model_expansions/scope.py +15 -15
- classiq/model_expansions/scope_initialization.py +3 -5
- classiq/open_library/functions/discrete_sine_cosine_transform.py +8 -2
- classiq/open_library/functions/grover.py +1 -1
- classiq/open_library/functions/modular_exponentiation.py +8 -2
- classiq/open_library/functions/state_preparation.py +23 -13
- classiq/open_library/functions/swap_test.py +1 -2
- classiq/open_library/functions/variational.py +1 -2
- classiq/qmod/builtins/__init__.py +1 -1
- classiq/qmod/builtins/operations.py +51 -0
- classiq/qmod/native/pretty_printer.py +9 -1
- classiq/qmod/pretty_print/pretty_printer.py +12 -1
- classiq/qmod/qmod_variable.py +38 -38
- classiq/qmod/quantum_function.py +4 -4
- classiq/qmod/semantics/annotation/__init__.py +0 -0
- classiq/qmod/semantics/annotation/call_annotation.py +92 -0
- classiq/qmod/semantics/lambdas.py +25 -0
- classiq/qmod/semantics/static_semantics_visitor.py +8 -46
- classiq/qmod/utilities.py +16 -0
- {classiq-0.64.0.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
- {classiq-0.64.0.dist-info → classiq-0.65.1.dist-info}/RECORD +50 -45
- classiq/qmod/semantics/annotation.py +0 -36
- /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
- {classiq-0.64.0.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
@@ -22,6 +22,7 @@ from classiq.interface.execution.jobs import (
|
|
22
22
|
ExecutionJobDetailsV1,
|
23
23
|
ExecutionJobsQueryResultsV1,
|
24
24
|
)
|
25
|
+
from classiq.interface.execution.primitives import PrimitivesInput
|
25
26
|
from classiq.interface.executor import execution_request
|
26
27
|
from classiq.interface.generator import quantum_program as generator_result
|
27
28
|
from classiq.interface.hardware import HardwareInformation, Provider
|
@@ -120,6 +121,35 @@ class ApiWrapper:
|
|
120
121
|
)
|
121
122
|
return _parse_job_response(result, generator_result.QuantumProgram)
|
122
123
|
|
124
|
+
@classmethod
|
125
|
+
async def call_create_execution_session(
|
126
|
+
cls,
|
127
|
+
circuit: generator_result.QuantumProgram,
|
128
|
+
http_client: Optional[httpx.AsyncClient] = None,
|
129
|
+
) -> str:
|
130
|
+
raw_result = await cls._call_task_pydantic(
|
131
|
+
http_method=HTTPMethod.POST,
|
132
|
+
url=routes.EXECUTION_SESSIONS_PREFIX,
|
133
|
+
model=circuit,
|
134
|
+
http_client=http_client,
|
135
|
+
)
|
136
|
+
return raw_result["id"]
|
137
|
+
|
138
|
+
@classmethod
|
139
|
+
async def call_create_session_job(
|
140
|
+
cls,
|
141
|
+
session_id: str,
|
142
|
+
primitives_input: PrimitivesInput,
|
143
|
+
http_client: Optional[httpx.AsyncClient] = None,
|
144
|
+
) -> execution_request.ExecutionJobDetails:
|
145
|
+
data = await cls._call_task_pydantic(
|
146
|
+
http_method=HTTPMethod.POST,
|
147
|
+
url=routes.EXECUTION_SESSIONS_PREFIX + f"/{session_id}",
|
148
|
+
model=primitives_input,
|
149
|
+
http_client=http_client,
|
150
|
+
)
|
151
|
+
return execution_request.ExecutionJobDetails.model_validate(data)
|
152
|
+
|
123
153
|
@classmethod
|
124
154
|
async def call_convert_quantum_program(
|
125
155
|
cls,
|
@@ -7,6 +7,8 @@ from classiq.interface.chemistry.fermionic_operator import (
|
|
7
7
|
FermionicOperator,
|
8
8
|
SummedFermionicOperator,
|
9
9
|
)
|
10
|
+
from classiq.interface.model.allocate import Allocate
|
11
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
10
12
|
from classiq.qmod.builtins.structs import (
|
11
13
|
MoleculeProblem as QmodMoleculeProblem,
|
12
14
|
Molecule as QmodMolecule,
|
@@ -441,16 +443,13 @@ def _get_chemistry_quantum_main(
|
|
441
443
|
use_hartree_fock: bool,
|
442
444
|
ansatz_parameters: AnsatzParameters,
|
443
445
|
) -> NativeFunctionDefinition:
|
444
|
-
body = []
|
446
|
+
body: list[QuantumStatement] = []
|
445
447
|
body.append(
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
),
|
452
|
-
HandleBinding(name="qbv"),
|
453
|
-
],
|
448
|
+
Allocate(
|
449
|
+
size=Expression(
|
450
|
+
expr=f"get_field(get_field({_get_problem_to_hamiltonian_name(chemistry_problem)}({_convert_library_problem_to_qmod_problem(chemistry_problem)})[0], 'pauli'), 'len')"
|
451
|
+
),
|
452
|
+
target=HandleBinding(name="qbv"),
|
454
453
|
),
|
455
454
|
)
|
456
455
|
if use_hartree_fock:
|
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.model.allocate import Allocate
|
17
18
|
from classiq.interface.model.classical_parameter_declaration import (
|
18
19
|
ClassicalParameterDeclaration,
|
19
20
|
)
|
@@ -89,12 +90,9 @@ def construct_combi_opt_py_model(
|
|
89
90
|
),
|
90
91
|
],
|
91
92
|
body=[
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
Expression(expr="get_field(target, 'len')"),
|
96
|
-
HandleBinding(name="target"),
|
97
|
-
],
|
93
|
+
Allocate(
|
94
|
+
size=Expression(expr="get_field(target, 'len')"),
|
95
|
+
target=HandleBinding(name="target"),
|
98
96
|
),
|
99
97
|
QuantumFunctionCall(
|
100
98
|
function="qaoa_penalty",
|
@@ -21,11 +21,8 @@ from classiq.open_library.functions.utility_functions import (
|
|
21
21
|
apply_to_all,
|
22
22
|
hadamard_transform,
|
23
23
|
)
|
24
|
-
from classiq.qmod.builtins.functions import
|
25
|
-
|
26
|
-
allocate,
|
27
|
-
)
|
28
|
-
from classiq.qmod.builtins.operations import phase, repeat
|
24
|
+
from classiq.qmod.builtins.functions import RX
|
25
|
+
from classiq.qmod.builtins.operations import allocate, phase, repeat
|
29
26
|
from classiq.qmod.cparam import CReal
|
30
27
|
from classiq.qmod.create_model_function import create_model
|
31
28
|
from classiq.qmod.qfunc import qfunc
|
@@ -9,6 +9,7 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
9
9
|
from classiq.interface.generator.functions.port_declaration import (
|
10
10
|
PortDeclarationDirection,
|
11
11
|
)
|
12
|
+
from classiq.interface.model.allocate import Allocate
|
12
13
|
from classiq.interface.model.handle_binding import HandleBinding
|
13
14
|
from classiq.interface.model.model import Model, SerializedModel
|
14
15
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
@@ -78,19 +79,13 @@ def construct_finance_model(
|
|
78
79
|
],
|
79
80
|
body=[
|
80
81
|
VariableDeclarationStatement(name="unitary_port"),
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
Expression(expr=f"{num_unitary_qubits}"),
|
85
|
-
HandleBinding(name="unitary_port"),
|
86
|
-
],
|
82
|
+
Allocate(
|
83
|
+
size=Expression(expr=f"{num_unitary_qubits}"),
|
84
|
+
target=HandleBinding(name="unitary_port"),
|
87
85
|
),
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
Expression(expr=f"{phase_port_size}"),
|
92
|
-
HandleBinding(name="phase_port"),
|
93
|
-
],
|
86
|
+
Allocate(
|
87
|
+
size=Expression(expr=f"{phase_port_size}"),
|
88
|
+
target=HandleBinding(name="phase_port"),
|
94
89
|
),
|
95
90
|
QuantumFunctionCall(
|
96
91
|
function="qmci",
|
@@ -2,6 +2,7 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
2
2
|
from classiq.interface.generator.functions.port_declaration import (
|
3
3
|
PortDeclarationDirection,
|
4
4
|
)
|
5
|
+
from classiq.interface.model.allocate import Allocate
|
5
6
|
from classiq.interface.model.bind_operation import BindOperation
|
6
7
|
from classiq.interface.model.handle_binding import HandleBinding, SlicedHandleBinding
|
7
8
|
from classiq.interface.model.model import Model, SerializedModel
|
@@ -121,12 +122,9 @@ def construct_grover_model(
|
|
121
122
|
),
|
122
123
|
body=[
|
123
124
|
VariableDeclarationStatement(name="packed_vars"),
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
Expression(expr=f"{num_qubits}"),
|
128
|
-
HandleBinding(name="packed_vars"),
|
129
|
-
],
|
125
|
+
Allocate(
|
126
|
+
size=Expression(expr=f"{num_qubits}"),
|
127
|
+
target=HandleBinding(name="packed_vars"),
|
130
128
|
),
|
131
129
|
QuantumFunctionCall(
|
132
130
|
function="grover_search",
|
@@ -6,11 +6,13 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
6
6
|
from classiq.interface.generator.functions.port_declaration import (
|
7
7
|
PortDeclarationDirection,
|
8
8
|
)
|
9
|
+
from classiq.interface.model.allocate import Allocate
|
9
10
|
from classiq.interface.model.handle_binding import HandleBinding
|
10
11
|
from classiq.interface.model.model import Model, SerializedModel
|
11
12
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
12
13
|
from classiq.interface.model.port_declaration import PortDeclaration
|
13
14
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
15
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
14
16
|
|
15
17
|
from classiq.qmod.builtins.enums import Pauli, QSVMFeatureMapEntanglement
|
16
18
|
from classiq.qmod.utilities import qmod_val_to_expr_str
|
@@ -61,7 +63,7 @@ def _pauli_feature_map_function_params(
|
|
61
63
|
|
62
64
|
def get_qsvm_qmain_body(
|
63
65
|
feature_map_function_name: str, **kwargs: Any
|
64
|
-
) -> list[
|
66
|
+
) -> list[QuantumStatement]:
|
65
67
|
if feature_map_function_name == "bloch_sphere_feature_map":
|
66
68
|
params, size_expr = _bloch_sphere_feature_map_function_params(**kwargs)
|
67
69
|
elif feature_map_function_name == "pauli_feature_map":
|
@@ -70,9 +72,9 @@ def get_qsvm_qmain_body(
|
|
70
72
|
raise ClassiqValueError(INVALID_FEATURE_MAP_FUNC_NAME_MSG)
|
71
73
|
|
72
74
|
return [
|
73
|
-
|
74
|
-
|
75
|
-
|
75
|
+
Allocate(
|
76
|
+
size=Expression(expr=size_expr),
|
77
|
+
target=HandleBinding(name="qbv"),
|
76
78
|
),
|
77
79
|
QuantumFunctionCall(
|
78
80
|
function=feature_map_function_name,
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import json
|
2
2
|
import random
|
3
|
-
from functools import cached_property
|
4
3
|
from types import TracebackType
|
5
4
|
from typing import Callable, Optional, Union, cast
|
6
5
|
|
@@ -110,6 +109,8 @@ class ExecutionSession:
|
|
110
109
|
|
111
110
|
self._async_client = client().async_client()
|
112
111
|
|
112
|
+
self._session_id: str | None = None
|
113
|
+
|
113
114
|
def __enter__(self) -> "ExecutionSession":
|
114
115
|
return self
|
115
116
|
|
@@ -127,22 +128,22 @@ class ExecutionSession:
|
|
127
128
|
"""
|
128
129
|
async_utils.run(self._async_client.aclose())
|
129
130
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
131
|
+
def get_session_id(self) -> str:
|
132
|
+
if self._session_id is None:
|
133
|
+
self._session_id = async_utils.run(
|
134
|
+
ApiWrapper.call_create_execution_session(
|
135
|
+
self.program, self._async_client
|
136
|
+
)
|
137
|
+
)
|
138
|
+
return self._session_id
|
135
139
|
|
136
140
|
def _execute(self, primitives_input: PrimitivesInput) -> ExecutionJob:
|
137
141
|
primitives_input.random_seed = self._random_seed
|
138
142
|
self._random_seed = self._rng.randint(0, 2**32 - 1)
|
139
|
-
execution_input = self._execution_input.copy()
|
140
|
-
# The use of `model_dump_json` is necessary for complex numbers serialization
|
141
|
-
execution_input["primitives_input"] = json.loads(
|
142
|
-
primitives_input.model_dump_json()
|
143
|
-
)
|
144
143
|
result = async_utils.run(
|
145
|
-
ApiWrapper.
|
144
|
+
ApiWrapper.call_create_session_job(
|
145
|
+
self.get_session_id(), primitives_input, self._async_client
|
146
|
+
)
|
146
147
|
)
|
147
148
|
return ExecutionJob(details=result)
|
148
149
|
|
@@ -360,7 +361,7 @@ class ExecutionSession:
|
|
360
361
|
output_name: The name of the register to filter
|
361
362
|
condition: Filter out values of the statevector for which this callable is False
|
362
363
|
"""
|
363
|
-
if
|
364
|
+
if self._session_id is not None:
|
364
365
|
raise ClassiqError(
|
365
366
|
"set_measured_state_filter must be called before use of the first primitive (sample, estimate...)"
|
366
367
|
)
|
classiq/interface/_version.py
CHANGED
@@ -22,7 +22,7 @@ from classiq.interface.backend.quantum_backend_providers import (
|
|
22
22
|
ProviderTypeVendor,
|
23
23
|
ProviderVendor,
|
24
24
|
)
|
25
|
-
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
25
|
+
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
26
26
|
from classiq.interface.hardware import Provider
|
27
27
|
|
28
28
|
|
@@ -225,14 +225,6 @@ class AwsBackendPreferences(BackendPreferences):
|
|
225
225
|
description="Run through Classiq's credentials while using user's allocated budget.",
|
226
226
|
)
|
227
227
|
|
228
|
-
@pydantic.field_validator("s3_bucket_name", mode="before")
|
229
|
-
@classmethod
|
230
|
-
def _validate_s3_bucket_name(cls, s3_bucket_name: str) -> str:
|
231
|
-
s3_bucket_name = s3_bucket_name.strip()
|
232
|
-
if not s3_bucket_name.startswith("amazon-braket-"):
|
233
|
-
raise ClassiqValueError('S3 bucket name should start with "amazon-braket-"')
|
234
|
-
return s3_bucket_name
|
235
|
-
|
236
228
|
|
237
229
|
class IBMBackendProvider(BaseModel):
|
238
230
|
"""
|
@@ -3,7 +3,10 @@ from typing import TYPE_CHECKING, Any, Union
|
|
3
3
|
|
4
4
|
from sympy import Integer
|
5
5
|
|
6
|
-
from classiq.interface.exceptions import
|
6
|
+
from classiq.interface.exceptions import (
|
7
|
+
ClassiqInternalExpansionError,
|
8
|
+
ClassiqValueError,
|
9
|
+
)
|
7
10
|
from classiq.interface.generator.expressions.expression import Expression
|
8
11
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
9
12
|
from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
|
@@ -18,12 +21,7 @@ if TYPE_CHECKING:
|
|
18
21
|
|
19
22
|
|
20
23
|
ILLEGAL_SLICING_STEP_MSG = "Slicing with a step of a quantum variable is not supported"
|
21
|
-
SLICE_OUT_OF_BOUNDS_MSG = "Slice indices out of bounds"
|
22
|
-
SUBSCRIPT_OUT_OF_BOUNDS_MSG = "Subscript index out of bounds"
|
23
24
|
ILLEGAL_SLICE_MSG = "Quantum array slice must be of the form [<int-value>:<int-value>]."
|
24
|
-
ILLEGAL_SLICE_BOUNDS_MSG = (
|
25
|
-
"The quantum array slice start value ({}) must be lower than its stop value ({})."
|
26
|
-
)
|
27
25
|
|
28
26
|
|
29
27
|
class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
@@ -48,7 +46,7 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
48
46
|
if isinstance(index, Integer):
|
49
47
|
index = int(index)
|
50
48
|
if index < 0 or index >= self._length:
|
51
|
-
raise
|
49
|
+
raise ClassiqInternalExpansionError
|
52
50
|
|
53
51
|
return self._element_type.get_proxy(
|
54
52
|
SubscriptHandleBinding(
|
@@ -66,12 +64,12 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
66
64
|
slice_ = slice(slice_.start, int(slice_.stop))
|
67
65
|
if not isinstance(slice_.start, int) or not isinstance(slice_.stop, int):
|
68
66
|
raise ClassiqValueError(ILLEGAL_SLICE_MSG)
|
69
|
-
if
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
raise
|
67
|
+
if (
|
68
|
+
slice_.start >= slice_.stop
|
69
|
+
or slice_.start < 0
|
70
|
+
or slice_.stop > self._length
|
71
|
+
):
|
72
|
+
raise ClassiqInternalExpansionError
|
75
73
|
|
76
74
|
return QmodQArrayProxy(
|
77
75
|
SlicedHandleBinding(
|
@@ -75,6 +75,12 @@ class TypeName(ClassicalType, QuantumType):
|
|
75
75
|
field_type.is_instantiated for field_type in self.fields.values()
|
76
76
|
)
|
77
77
|
|
78
|
+
@property
|
79
|
+
def is_evaluated(self) -> bool:
|
80
|
+
return self.has_fields and all(
|
81
|
+
field_type.is_evaluated for field_type in self.fields.values()
|
82
|
+
)
|
83
|
+
|
78
84
|
|
79
85
|
class Enum(TypeName):
|
80
86
|
pass
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from typing import Literal, Optional
|
3
|
+
|
4
|
+
from classiq.interface.generator.expressions.expression import Expression
|
5
|
+
from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
|
6
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
7
|
+
|
8
|
+
|
9
|
+
class Allocate(QuantumOperation):
|
10
|
+
kind: Literal["Allocate"]
|
11
|
+
size: Optional[Expression] = None
|
12
|
+
target: ConcreteHandleBinding
|
13
|
+
|
14
|
+
@property
|
15
|
+
def wiring_outputs(self) -> Mapping[str, HandleBinding]:
|
16
|
+
return {"out": self.target}
|
@@ -63,6 +63,10 @@ class QuantumType(HashableASTNode):
|
|
63
63
|
def is_instantiated(self) -> bool:
|
64
64
|
raise NotImplementedError
|
65
65
|
|
66
|
+
@property
|
67
|
+
def is_evaluated(self) -> bool:
|
68
|
+
raise NotImplementedError
|
69
|
+
|
66
70
|
|
67
71
|
class QuantumScalar(QuantumType):
|
68
72
|
def get_proxy(self, handle: "HandleBinding") -> QmodQScalarProxy:
|
@@ -96,6 +100,10 @@ class QuantumBit(QuantumScalar):
|
|
96
100
|
def is_instantiated(self) -> bool:
|
97
101
|
return True
|
98
102
|
|
103
|
+
@property
|
104
|
+
def is_evaluated(self) -> bool:
|
105
|
+
return True
|
106
|
+
|
99
107
|
|
100
108
|
class QuantumBitvector(QuantumType):
|
101
109
|
element_type: "ConcreteQuantumType" = Field(
|
@@ -154,6 +162,14 @@ class QuantumBitvector(QuantumType):
|
|
154
162
|
def is_instantiated(self) -> bool:
|
155
163
|
return self.length is not None and self.element_type.is_instantiated
|
156
164
|
|
165
|
+
@property
|
166
|
+
def is_evaluated(self) -> bool:
|
167
|
+
return (
|
168
|
+
self.length is not None
|
169
|
+
and self.length.is_evaluated()
|
170
|
+
and self.element_type.is_evaluated
|
171
|
+
)
|
172
|
+
|
157
173
|
|
158
174
|
class QuantumNumeric(QuantumScalar):
|
159
175
|
kind: Literal["qnum"]
|
@@ -227,6 +243,16 @@ class QuantumNumeric(QuantumScalar):
|
|
227
243
|
def is_instantiated(self) -> bool:
|
228
244
|
return self.size is not None
|
229
245
|
|
246
|
+
@property
|
247
|
+
def is_evaluated(self) -> bool:
|
248
|
+
if self.size is None or not self.size.is_evaluated():
|
249
|
+
return False
|
250
|
+
if self.is_signed is not None and not self.is_signed.is_evaluated():
|
251
|
+
return False
|
252
|
+
return not (
|
253
|
+
self.fraction_digits is not None and not self.fraction_digits.is_evaluated()
|
254
|
+
)
|
255
|
+
|
230
256
|
|
231
257
|
class RegisterQuantumType(BaseModel):
|
232
258
|
quantum_types: "ConcreteQuantumType"
|
@@ -2,6 +2,7 @@ from typing import Annotated, Union
|
|
2
2
|
|
3
3
|
from pydantic import Field
|
4
4
|
|
5
|
+
from classiq.interface.model.allocate import Allocate
|
5
6
|
from classiq.interface.model.bind_operation import BindOperation
|
6
7
|
from classiq.interface.model.classical_if import ClassicalIf
|
7
8
|
from classiq.interface.model.control import Control
|
@@ -26,6 +27,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
26
27
|
|
27
28
|
ConcreteQuantumStatement = Annotated[
|
28
29
|
Union[
|
30
|
+
Allocate,
|
29
31
|
QuantumFunctionCall,
|
30
32
|
ArithmeticOperation,
|
31
33
|
AmplitudeLoadingOperation,
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from collections.abc import Sequence
|
1
2
|
from typing import Optional
|
2
3
|
|
3
4
|
from classiq.interface.exceptions import (
|
@@ -11,6 +12,8 @@ from classiq.interface.generator.functions.type_name import (
|
|
11
12
|
)
|
12
13
|
from classiq.interface.model.bind_operation import BindOperation
|
13
14
|
from classiq.interface.model.inplace_binary_operation import BinaryOperation
|
15
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
16
|
+
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
14
17
|
from classiq.interface.model.quantum_type import (
|
15
18
|
QuantumBit,
|
16
19
|
QuantumBitvector,
|
@@ -227,3 +230,10 @@ def get_inplace_op_scalar_as_numeric(
|
|
227
230
|
fraction_digits=Expression(expr="0"),
|
228
231
|
)
|
229
232
|
raise ClassiqInternalExpansionError(f"Unexpected scalar type {var.quantum_type}")
|
233
|
+
|
234
|
+
|
235
|
+
def is_signature_monomorphic(params: Sequence[PositionalArg]) -> bool:
|
236
|
+
return all(
|
237
|
+
isinstance(param, PortDeclaration) and param.quantum_type.is_evaluated
|
238
|
+
for param in params
|
239
|
+
)
|
@@ -29,7 +29,14 @@ from classiq.model_expansions.capturing.captured_vars import (
|
|
29
29
|
CapturedVars,
|
30
30
|
validate_captured_directions,
|
31
31
|
)
|
32
|
-
from classiq.model_expansions.closure import
|
32
|
+
from classiq.model_expansions.closure import (
|
33
|
+
Closure,
|
34
|
+
FunctionClosure,
|
35
|
+
GenerativeFunctionClosure,
|
36
|
+
)
|
37
|
+
from classiq.model_expansions.evaluators.quantum_type_utils import (
|
38
|
+
is_signature_monomorphic,
|
39
|
+
)
|
33
40
|
from classiq.model_expansions.scope import Scope
|
34
41
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
35
42
|
|
@@ -200,16 +207,7 @@ class OperationBuilder:
|
|
200
207
|
def create_definition(
|
201
208
|
self, function_context: FunctionContext
|
202
209
|
) -> NativeFunctionDefinition:
|
203
|
-
name = function_context
|
204
|
-
if name != MAIN_FUNCTION_NAME:
|
205
|
-
for _ in self.current_scope:
|
206
|
-
name = self._counted_name_allocator.allocate(
|
207
|
-
f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}"
|
208
|
-
)
|
209
|
-
if name not in self.current_scope:
|
210
|
-
break
|
211
|
-
else:
|
212
|
-
raise ClassiqInternalExpansionError("Could not allocate function name")
|
210
|
+
name = self._get_expanded_function_name(function_context)
|
213
211
|
new_parameters: list[PortDeclaration] = [
|
214
212
|
param
|
215
213
|
for param in function_context.positional_arg_declarations
|
@@ -221,3 +219,29 @@ class OperationBuilder:
|
|
221
219
|
body=function_context.body,
|
222
220
|
positional_arg_declarations=new_parameters,
|
223
221
|
)
|
222
|
+
|
223
|
+
def _get_expanded_function_name(self, function_context: FunctionContext) -> str:
|
224
|
+
name = function_context.name
|
225
|
+
|
226
|
+
if name == MAIN_FUNCTION_NAME:
|
227
|
+
return name
|
228
|
+
|
229
|
+
if name in self.current_scope:
|
230
|
+
orig_func = self.current_scope[name].value
|
231
|
+
if (
|
232
|
+
isinstance(orig_func, FunctionClosure)
|
233
|
+
and not isinstance(orig_func, GenerativeFunctionClosure)
|
234
|
+
and is_signature_monomorphic(orig_func.positional_arg_declarations)
|
235
|
+
):
|
236
|
+
return name
|
237
|
+
|
238
|
+
for _ in self.current_scope:
|
239
|
+
name = self._counted_name_allocator.allocate(
|
240
|
+
f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}"
|
241
|
+
)
|
242
|
+
if name not in self.current_scope:
|
243
|
+
break
|
244
|
+
else:
|
245
|
+
raise ClassiqInternalExpansionError("Could not allocate function name")
|
246
|
+
|
247
|
+
return name
|
@@ -30,11 +30,13 @@ from classiq.qmod.quantum_expandable import (
|
|
30
30
|
QTerminalCallable,
|
31
31
|
)
|
32
32
|
from classiq.qmod.quantum_function import QFunc
|
33
|
-
from classiq.qmod.semantics.
|
33
|
+
from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
|
34
34
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
35
35
|
|
36
36
|
if TYPE_CHECKING:
|
37
|
-
from classiq.model_expansions.interpreters.
|
37
|
+
from classiq.model_expansions.interpreters.generative_interpreter import (
|
38
|
+
GenerativeInterpreter,
|
39
|
+
)
|
38
40
|
|
39
41
|
|
40
42
|
class LenList(list):
|
@@ -94,7 +96,7 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
|
|
94
96
|
|
95
97
|
|
96
98
|
class _InterpreterExpandable(QFunc):
|
97
|
-
def __init__(self, interpreter: "
|
99
|
+
def __init__(self, interpreter: "GenerativeInterpreter"):
|
98
100
|
super().__init__(lambda: None)
|
99
101
|
self._interpreter = interpreter
|
100
102
|
|
@@ -137,7 +139,7 @@ class _InterpreterExpandable(QFunc):
|
|
137
139
|
|
138
140
|
|
139
141
|
def emit_generative_statements(
|
140
|
-
interpreter: "
|
142
|
+
interpreter: "GenerativeInterpreter",
|
141
143
|
operation: GenerativeClosure,
|
142
144
|
args: list[Evaluated],
|
143
145
|
) -> None:
|