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.
- classiq/_internals/api_wrapper.py +36 -0
- classiq/analyzer/show_interactive_hack.py +58 -2
- classiq/applications/chemistry/chemistry_model_constructor.py +15 -7
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +11 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -7
- 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_qarray_proxy.py +6 -15
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +22 -6
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +9 -4
- 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/handle_binding.py +8 -0
- classiq/interface/model/model.py +3 -6
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_function_call.py +31 -1
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/model/quantum_statement.py +14 -1
- classiq/interface/server/routes.py +6 -0
- classiq/interface/source_reference.py +7 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
- classiq/model_expansions/capturing/captured_vars.py +18 -6
- classiq/model_expansions/closure.py +5 -0
- classiq/model_expansions/evaluators/arg_type_match.py +2 -2
- classiq/model_expansions/evaluators/argument_types.py +3 -3
- classiq/model_expansions/evaluators/classical_expression.py +9 -9
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +45 -24
- classiq/model_expansions/expression_evaluator.py +21 -12
- classiq/model_expansions/function_builder.py +45 -0
- classiq/model_expansions/generative_functions.py +62 -35
- classiq/model_expansions/interpreters/base_interpreter.py +32 -7
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +9 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +17 -5
- classiq/model_expansions/quantum_operations/allocate.py +8 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +221 -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 +35 -18
- 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 -9
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
- classiq/model_expansions/scope.py +63 -10
- 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/symbolic_param_inference.py +3 -3
- classiq/model_expansions/visitors/variable_references.py +45 -9
- classiq/open_library/functions/lookup_table.py +1 -1
- classiq/open_library/functions/state_preparation.py +1 -1
- 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/create_model_function.py +21 -3
- classiq/qmod/declaration_inferrer.py +19 -7
- classiq/qmod/generative.py +9 -1
- classiq/qmod/global_declarative_switch.py +19 -0
- classiq/qmod/native/expression_to_qmod.py +4 -0
- classiq/qmod/native/pretty_printer.py +12 -3
- classiq/qmod/pretty_print/pretty_printer.py +5 -1
- classiq/qmod/python_classical_type.py +4 -5
- classiq/qmod/qfunc.py +31 -23
- classiq/qmod/qmod_constant.py +15 -7
- classiq/qmod/qmod_variable.py +7 -1
- classiq/qmod/quantum_expandable.py +29 -1
- classiq/qmod/quantum_function.py +45 -25
- 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/qmod/write_qmod.py +36 -10
- classiq/synthesis.py +24 -37
- classiq/visualization.py +35 -0
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/METADATA +1 -1
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/RECORD +101 -96
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/WHEEL +0 -0
@@ -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
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import datetime
|
2
|
+
from collections import defaultdict
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
import pydantic
|
6
|
+
from pydantic import ConfigDict, Field
|
7
|
+
|
8
|
+
from classiq.interface.helpers.versioned_model import VersionedModel
|
9
|
+
|
10
|
+
|
11
|
+
class UserBudget(VersionedModel):
|
12
|
+
provider: str
|
13
|
+
currency_code: str
|
14
|
+
organization: Optional[str] = Field(default=None)
|
15
|
+
available_budget: float
|
16
|
+
used_budget: float
|
17
|
+
last_allocation_date: datetime.datetime
|
18
|
+
|
19
|
+
model_config = ConfigDict(extra="ignore")
|
20
|
+
|
21
|
+
|
22
|
+
class UserBudgets(VersionedModel):
|
23
|
+
budgets: list[UserBudget] = pydantic.Field(default=[])
|
24
|
+
|
25
|
+
def print_budgets(self) -> None:
|
26
|
+
def format_header() -> str:
|
27
|
+
return f"| {'Provider':<20} | {'Available Budget':<18} | {'Used Budget':<18} | {'Currency':<8} |"
|
28
|
+
|
29
|
+
def format_row(
|
30
|
+
provider: str, available: float, used: float, currency: str
|
31
|
+
) -> str:
|
32
|
+
return f"| {provider:<20} | {available:<18.0f} | {used:<18.0f} | {currency:<8} |"
|
33
|
+
|
34
|
+
table_data: dict = defaultdict(
|
35
|
+
lambda: {"used": 0.0, "available": 0.0, "currency": "USD"}
|
36
|
+
)
|
37
|
+
|
38
|
+
for budget in self.budgets:
|
39
|
+
provider = budget.provider
|
40
|
+
table_data[provider]["available"] += budget.available_budget
|
41
|
+
table_data[provider]["used"] += budget.used_budget
|
42
|
+
table_data[provider]["currency"] = budget.currency_code
|
43
|
+
|
44
|
+
line = "=" * 77
|
45
|
+
print(line) # noqa: T201
|
46
|
+
print(format_header()) # noqa: T201
|
47
|
+
print(line) # noqa: T201
|
48
|
+
|
49
|
+
for provider, values in table_data.items():
|
50
|
+
print( # noqa: T201
|
51
|
+
format_row(
|
52
|
+
provider, values["available"], values["used"], values["currency"]
|
53
|
+
)
|
54
|
+
)
|
55
|
+
|
56
|
+
print(line) # noqa: T201
|
@@ -10,6 +10,7 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
10
10
|
PortDeclarationDirection,
|
11
11
|
)
|
12
12
|
from classiq.interface.generator.functions.type_name import Struct
|
13
|
+
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
13
14
|
from classiq.interface.model.classical_parameter_declaration import (
|
14
15
|
ClassicalParameterDeclaration,
|
15
16
|
)
|
@@ -55,11 +56,13 @@ def _generate_finance_function(
|
|
55
56
|
)
|
56
57
|
),
|
57
58
|
direction=PortDeclarationDirection.Inout,
|
59
|
+
type_qualifier=TypeQualifier.Quantum,
|
58
60
|
),
|
59
61
|
PortDeclaration(
|
60
62
|
name=OBJECTIVE_PORT_NAME,
|
61
63
|
quantum_type=QuantumBit(),
|
62
64
|
direction=PortDeclarationDirection.Inout,
|
65
|
+
type_qualifier=TypeQualifier.Quantum,
|
63
66
|
),
|
64
67
|
],
|
65
68
|
)
|
@@ -15,6 +15,7 @@ SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
|
|
15
15
|
"molecule_problem_to_hamiltonian",
|
16
16
|
"fock_hamiltonian_problem_to_hamiltonian",
|
17
17
|
"molecule_ground_state_solution_post_process",
|
18
|
+
"mod_inverse",
|
18
19
|
}
|
19
20
|
|
20
21
|
SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
|
@@ -23,6 +24,8 @@ SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
|
|
23
24
|
"BitwiseNot",
|
24
25
|
"BitwiseOr",
|
25
26
|
"LogicalXor",
|
27
|
+
"RShift",
|
28
|
+
"LShift",
|
26
29
|
}
|
27
30
|
|
28
31
|
SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
|
@@ -1,135 +1,41 @@
|
|
1
|
+
import inspect
|
1
2
|
from typing import Any
|
2
3
|
|
4
|
+
import sympy
|
3
5
|
|
4
|
-
|
5
|
-
def __init__(self, expr: str) -> None:
|
6
|
-
self._expr = expr
|
6
|
+
_SYMPY_MEMBERS = [name for name, _ in inspect.getmembers(sympy.Symbol)] + ["precedence"]
|
7
7
|
|
8
|
-
def __str__(self) -> str:
|
9
|
-
return self._expr
|
10
8
|
|
11
|
-
|
12
|
-
|
9
|
+
def subscript_to_str(index: Any) -> str:
|
10
|
+
if not isinstance(index, slice):
|
11
|
+
return str(index)
|
12
|
+
expr = ""
|
13
|
+
if index.start is not None:
|
14
|
+
expr += str(index.start)
|
15
|
+
expr += ":"
|
16
|
+
if index.stop is not None:
|
17
|
+
expr += str(index.stop)
|
18
|
+
if index.step is not None:
|
19
|
+
expr += f":{index.step}"
|
20
|
+
return expr
|
13
21
|
|
14
|
-
def __getitem__(self, item: Any) -> "AnyClassicalValue":
|
15
|
-
if isinstance(item, slice):
|
16
|
-
subscript = ""
|
17
|
-
if item.start is not None:
|
18
|
-
subscript += str(item.start)
|
19
|
-
subscript += ":"
|
20
|
-
if item.stop is not None:
|
21
|
-
subscript += str(item.stop)
|
22
|
-
if item.step is not None:
|
23
|
-
subscript += f":{item.stop}"
|
24
|
-
item = subscript
|
25
|
-
return AnyClassicalValue(f"{self}[{item}]")
|
26
|
-
|
27
|
-
@staticmethod
|
28
|
-
def _binary_op(lhs: Any, rhs: Any, op: str) -> "AnyClassicalValue":
|
29
|
-
return AnyClassicalValue(f"{lhs} {op} {rhs}")
|
30
|
-
|
31
|
-
@staticmethod
|
32
|
-
def _unary_op(arg: Any, op: str) -> "AnyClassicalValue":
|
33
|
-
return AnyClassicalValue(f"{op}({arg})")
|
34
|
-
|
35
|
-
def __add__(self, other: Any) -> "AnyClassicalValue":
|
36
|
-
return AnyClassicalValue._binary_op(self, other, "+")
|
37
|
-
|
38
|
-
def __sub__(self, other: Any) -> "AnyClassicalValue":
|
39
|
-
return AnyClassicalValue._binary_op(self, other, "-")
|
40
|
-
|
41
|
-
def __mul__(self, other: Any) -> "AnyClassicalValue":
|
42
|
-
return AnyClassicalValue._binary_op(self, other, "*")
|
43
|
-
|
44
|
-
def __truediv__(self, other: Any) -> "AnyClassicalValue":
|
45
|
-
return AnyClassicalValue._binary_op(self, other, "/")
|
46
|
-
|
47
|
-
def __floordiv__(self, other: Any) -> "AnyClassicalValue":
|
48
|
-
return AnyClassicalValue._binary_op(self, other, "//")
|
49
|
-
|
50
|
-
def __mod__(self, other: Any) -> "AnyClassicalValue":
|
51
|
-
return AnyClassicalValue._binary_op(self, other, "%")
|
52
|
-
|
53
|
-
def __pow__(self, other: Any) -> "AnyClassicalValue":
|
54
|
-
return AnyClassicalValue._binary_op(self, other, "**")
|
55
|
-
|
56
|
-
def __lshift__(self, other: Any) -> "AnyClassicalValue":
|
57
|
-
return AnyClassicalValue._binary_op(self, other, "<<")
|
58
|
-
|
59
|
-
def __rshift__(self, other: Any) -> "AnyClassicalValue":
|
60
|
-
return AnyClassicalValue._binary_op(self, other, ">>")
|
61
|
-
|
62
|
-
def __and__(self, other: Any) -> "AnyClassicalValue":
|
63
|
-
return AnyClassicalValue._binary_op(self, other, "&")
|
64
|
-
|
65
|
-
def __xor__(self, other: Any) -> "AnyClassicalValue":
|
66
|
-
return AnyClassicalValue._binary_op(self, other, "^")
|
67
|
-
|
68
|
-
def __or__(self, other: Any) -> "AnyClassicalValue":
|
69
|
-
return AnyClassicalValue._binary_op(self, other, "|")
|
70
|
-
|
71
|
-
def __radd__(self, other: Any) -> "AnyClassicalValue":
|
72
|
-
return AnyClassicalValue._binary_op(other, self, "+")
|
73
|
-
|
74
|
-
def __rsub__(self, other: Any) -> "AnyClassicalValue":
|
75
|
-
return AnyClassicalValue._binary_op(other, self, "-")
|
76
22
|
|
77
|
-
|
78
|
-
return AnyClassicalValue._binary_op(other, self, "*")
|
23
|
+
class AnyClassicalValue(sympy.Symbol):
|
79
24
|
|
80
|
-
|
81
|
-
|
25
|
+
is_commutative = None
|
26
|
+
is_infinite = None
|
27
|
+
is_finite = None
|
28
|
+
is_extended_real = None
|
82
29
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
return AnyClassicalValue._binary_op(other, self, "%")
|
88
|
-
|
89
|
-
def __rpow__(self, other: Any) -> "AnyClassicalValue":
|
90
|
-
return AnyClassicalValue._binary_op(other, self, "**")
|
91
|
-
|
92
|
-
def __rlshift__(self, other: Any) -> "AnyClassicalValue":
|
93
|
-
return AnyClassicalValue._binary_op(other, self, "<<")
|
94
|
-
|
95
|
-
def __rrshift__(self, other: Any) -> "AnyClassicalValue":
|
96
|
-
return AnyClassicalValue._binary_op(other, self, ">>")
|
97
|
-
|
98
|
-
def __rand__(self, other: Any) -> "AnyClassicalValue":
|
99
|
-
return AnyClassicalValue._binary_op(other, self, "&")
|
100
|
-
|
101
|
-
def __rxor__(self, other: Any) -> "AnyClassicalValue":
|
102
|
-
return AnyClassicalValue._binary_op(other, self, "^")
|
103
|
-
|
104
|
-
def __ror__(self, other: Any) -> "AnyClassicalValue":
|
105
|
-
return AnyClassicalValue._binary_op(other, self, "|")
|
106
|
-
|
107
|
-
def __lt__(self, other: Any) -> "AnyClassicalValue":
|
108
|
-
return AnyClassicalValue._binary_op(self, other, "<")
|
109
|
-
|
110
|
-
def __le__(self, other: Any) -> "AnyClassicalValue":
|
111
|
-
return AnyClassicalValue._binary_op(self, other, "<=")
|
112
|
-
|
113
|
-
def __eq__(self, other: Any) -> "AnyClassicalValue": # type:ignore[override]
|
114
|
-
return AnyClassicalValue._binary_op(self, other, "==")
|
115
|
-
|
116
|
-
def __ne__(self, other: Any) -> "AnyClassicalValue": # type: ignore[override]
|
117
|
-
return AnyClassicalValue._binary_op(self, other, "!=")
|
118
|
-
|
119
|
-
def __gt__(self, other: Any) -> "AnyClassicalValue":
|
120
|
-
return AnyClassicalValue._binary_op(self, other, ">")
|
121
|
-
|
122
|
-
def __ge__(self, other: Any) -> "AnyClassicalValue":
|
123
|
-
return AnyClassicalValue._binary_op(self, other, ">=")
|
124
|
-
|
125
|
-
def __neg__(self) -> "AnyClassicalValue":
|
126
|
-
return AnyClassicalValue._unary_op(self, "-")
|
127
|
-
|
128
|
-
def __pos__(self) -> "AnyClassicalValue":
|
129
|
-
return AnyClassicalValue._unary_op(self, "+")
|
30
|
+
def __getitem__(self, item: Any) -> "AnyClassicalValue":
|
31
|
+
if isinstance(item, slice):
|
32
|
+
return AnyClassicalValue(f"{self}[{subscript_to_str(item)}]")
|
33
|
+
return AnyClassicalValue(f"do_subscript({self}, {item})")
|
130
34
|
|
131
|
-
def
|
132
|
-
|
35
|
+
def __getattribute__(self, attr: str) -> Any:
|
36
|
+
if attr.startswith("_") or attr in _SYMPY_MEMBERS:
|
37
|
+
return super().__getattribute__(attr)
|
38
|
+
return AnyClassicalValue(f"get_field({self}, '{attr}')")
|
133
39
|
|
134
|
-
def
|
135
|
-
return
|
40
|
+
def __len__(self) -> "AnyClassicalValue":
|
41
|
+
return self.len
|
@@ -1,11 +1,16 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
-
from typing import TYPE_CHECKING, Union
|
2
|
+
from typing import TYPE_CHECKING, Any, Union
|
3
3
|
|
4
|
+
import sympy
|
4
5
|
from sympy import Integer
|
6
|
+
from typing_extensions import TypeGuard
|
5
7
|
|
6
8
|
from classiq.interface.exceptions import ClassiqIndexError
|
7
9
|
from classiq.interface.generator.expressions.expression import Expression
|
8
10
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
11
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
12
|
+
AnyClassicalValue,
|
13
|
+
)
|
9
14
|
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
10
15
|
ClassicalProxy,
|
11
16
|
)
|
@@ -22,9 +27,20 @@ if TYPE_CHECKING:
|
|
22
27
|
)
|
23
28
|
|
24
29
|
|
30
|
+
def _is_int(val: Any) -> TypeGuard[Union[int, sympy.Basic]]:
|
31
|
+
if isinstance(val, AnyClassicalValue):
|
32
|
+
return False
|
33
|
+
if isinstance(val, sympy.Basic):
|
34
|
+
return val.is_Number
|
35
|
+
return isinstance(val, int)
|
36
|
+
|
37
|
+
|
25
38
|
class ClassicalArrayProxy(NonSymbolicExpr, ClassicalProxy):
|
26
39
|
def __init__(
|
27
|
-
self,
|
40
|
+
self,
|
41
|
+
handle: HandleBinding,
|
42
|
+
element_type: "ConcreteClassicalType",
|
43
|
+
length: "ExpressionValue",
|
28
44
|
) -> None:
|
29
45
|
super().__init__(handle)
|
30
46
|
self._element_type = element_type
|
@@ -39,39 +55,47 @@ class ClassicalArrayProxy(NonSymbolicExpr, ClassicalProxy):
|
|
39
55
|
return "Array"
|
40
56
|
|
41
57
|
@property
|
42
|
-
def length(self) ->
|
58
|
+
def length(self) -> "ExpressionValue":
|
43
59
|
return self._length
|
44
60
|
|
45
|
-
def __getitem__(
|
61
|
+
def __getitem__(
|
62
|
+
self, key: Union[slice, int, Integer, ClassicalProxy]
|
63
|
+
) -> ClassicalProxy:
|
46
64
|
return (
|
47
65
|
self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
|
48
66
|
)
|
49
67
|
|
50
68
|
def _get_slice(self, slice_: slice) -> ClassicalProxy:
|
51
|
-
|
52
|
-
|
53
|
-
if
|
54
|
-
|
55
|
-
|
56
|
-
|
69
|
+
start_ = slice_.start
|
70
|
+
stop_ = slice_.stop
|
71
|
+
if _is_int(start_) and _is_int(stop_):
|
72
|
+
start = int(start_)
|
73
|
+
stop = int(stop_)
|
74
|
+
if start >= stop:
|
75
|
+
raise ClassiqIndexError("Array slice has non-positive length")
|
76
|
+
if start < 0 or (isinstance(self._length, int) and stop > self._length):
|
77
|
+
raise ClassiqIndexError("Array slice is out of bounds")
|
57
78
|
return ClassicalArrayProxy(
|
58
79
|
SlicedHandleBinding(
|
59
80
|
base_handle=self.handle,
|
60
|
-
start=Expression(expr=str(
|
61
|
-
end=Expression(expr=str(
|
81
|
+
start=Expression(expr=str(start_)),
|
82
|
+
end=Expression(expr=str(stop_)),
|
62
83
|
),
|
63
84
|
self._element_type,
|
64
|
-
|
85
|
+
stop_ - start_,
|
65
86
|
)
|
66
87
|
|
67
|
-
def _get_subscript(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
88
|
+
def _get_subscript(
|
89
|
+
self, index_: Union[int, Integer, ClassicalProxy]
|
90
|
+
) -> ClassicalProxy:
|
91
|
+
if _is_int(index_):
|
92
|
+
index = int(index_)
|
93
|
+
if index < 0:
|
94
|
+
raise ClassiqIndexError(
|
95
|
+
"Array index is out of bounds (negative indices are not supported)"
|
96
|
+
)
|
97
|
+
if isinstance(self._length, int) and index >= self._length:
|
98
|
+
raise ClassiqIndexError("Array index is out of bounds")
|
75
99
|
return self._element_type.get_classical_proxy(
|
76
100
|
SubscriptHandleBinding(
|
77
101
|
base_handle=self._handle, index=Expression(expr=str(index_))
|
@@ -25,6 +25,13 @@ class QmodStructInstance:
|
|
25
25
|
def fields(self) -> Mapping[str, Any]:
|
26
26
|
return types.MappingProxyType(self._fields)
|
27
27
|
|
28
|
+
def __getattr__(self, item: str) -> Any:
|
29
|
+
if item == "_fields":
|
30
|
+
return super().__getattribute__(item)
|
31
|
+
if item in self._fields:
|
32
|
+
return self._fields[item]
|
33
|
+
return super().__getattribute__(item)
|
34
|
+
|
28
35
|
def __str__(self) -> str:
|
29
36
|
return repr(self)
|
30
37
|
|
@@ -13,6 +13,7 @@ from classiq.interface.generator.expressions.proxies.classical.classical_struct_
|
|
13
13
|
)
|
14
14
|
from classiq.interface.generator.functions.classical_type import (
|
15
15
|
ClassicalArray,
|
16
|
+
ClassicalList,
|
16
17
|
ClassicalType,
|
17
18
|
)
|
18
19
|
from classiq.interface.generator.functions.type_name import Struct
|
@@ -20,15 +21,15 @@ from classiq.interface.generator.functions.type_name import Struct
|
|
20
21
|
|
21
22
|
def get_proxy_type(proxy: ClassicalProxy) -> ClassicalType:
|
22
23
|
if isinstance(proxy, ClassicalScalarProxy):
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
element_type=proxy._element_type
|
27
|
-
)
|
28
|
-
|
24
|
+
return proxy._classical_type
|
25
|
+
if isinstance(proxy, ClassicalArrayProxy):
|
26
|
+
if not isinstance(proxy.length, int):
|
27
|
+
return ClassicalList(element_type=proxy._element_type)
|
28
|
+
return ClassicalArray(element_type=proxy._element_type, size=proxy.length)
|
29
|
+
if isinstance(proxy, ClassicalStructProxy):
|
29
30
|
classical_type = Struct(name=proxy._decl.name)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
)
|
34
|
-
|
31
|
+
classical_type.set_classical_struct_decl(proxy._decl)
|
32
|
+
return classical_type
|
33
|
+
raise ClassiqInternalExpansionError(
|
34
|
+
f"Unrecognized classical proxy {type(proxy).__name__}"
|
35
|
+
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
from typing import TYPE_CHECKING, Any, Union
|
3
3
|
|
4
|
-
|
4
|
+
import sympy
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqValueError
|
7
7
|
from classiq.interface.generator.expressions.expression import Expression
|
@@ -28,22 +28,20 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
28
28
|
self,
|
29
29
|
handle: HandleBinding,
|
30
30
|
element_type: "QuantumType",
|
31
|
-
element_size: int,
|
32
|
-
length: int,
|
31
|
+
element_size: Union[int, sympy.Basic],
|
32
|
+
length: Union[int, sympy.Basic],
|
33
33
|
) -> None:
|
34
34
|
super().__init__(handle, element_size * length)
|
35
35
|
self._length = length
|
36
36
|
self._element_type = element_type
|
37
37
|
self._element_size = element_size
|
38
38
|
|
39
|
-
def __getitem__(self, key:
|
39
|
+
def __getitem__(self, key: Any) -> "QmodSizedProxy":
|
40
40
|
return (
|
41
41
|
self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
|
42
42
|
)
|
43
43
|
|
44
|
-
def _get_subscript(self, index:
|
45
|
-
if isinstance(index, Integer):
|
46
|
-
index = int(index)
|
44
|
+
def _get_subscript(self, index: Any) -> "QmodSizedProxy":
|
47
45
|
return self._element_type.get_proxy(
|
48
46
|
SubscriptHandleBinding(
|
49
47
|
base_handle=self.handle,
|
@@ -54,13 +52,6 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
54
52
|
def _get_slice(self, slice_: slice) -> "QmodSizedProxy":
|
55
53
|
if slice_.step is not None:
|
56
54
|
raise ClassiqValueError(ILLEGAL_SLICING_STEP_MSG)
|
57
|
-
if isinstance(slice_.start, Integer):
|
58
|
-
slice_ = slice(int(slice_.start), slice_.stop)
|
59
|
-
if isinstance(slice_.stop, Integer):
|
60
|
-
slice_ = slice(slice_.start, int(slice_.stop))
|
61
|
-
if not isinstance(slice_.start, int) or not isinstance(slice_.stop, int):
|
62
|
-
raise ClassiqValueError(ILLEGAL_SLICE_MSG)
|
63
|
-
|
64
55
|
return QmodQArrayProxy(
|
65
56
|
SlicedHandleBinding(
|
66
57
|
base_handle=self.handle,
|
@@ -77,7 +68,7 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
77
68
|
return "Quantum array"
|
78
69
|
|
79
70
|
@property
|
80
|
-
def len(self) -> int:
|
71
|
+
def len(self) -> Union[int, sympy.Basic]:
|
81
72
|
return self._length
|
82
73
|
|
83
74
|
@property
|
@@ -1,7 +1,9 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any, Optional, Union
|
3
3
|
|
4
|
+
import sympy
|
4
5
|
from sympy import Symbol
|
6
|
+
from typing_extensions import Self
|
5
7
|
|
6
8
|
from classiq.interface.exceptions import ClassiqValueError
|
7
9
|
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
@@ -12,11 +14,17 @@ from classiq.interface.model.handle_binding import HandleBinding
|
|
12
14
|
|
13
15
|
class QmodQScalarProxy(Symbol, QmodSizedProxy):
|
14
16
|
def __new__(cls, handle: HandleBinding, **assumptions: bool) -> "QmodQScalarProxy":
|
15
|
-
return super().__new__(cls,
|
17
|
+
return super().__new__(cls, handle.qmod_expr, **assumptions)
|
16
18
|
|
17
19
|
def __init__(self, handle: HandleBinding, size: int) -> None:
|
18
20
|
super().__init__(handle, size)
|
19
21
|
|
22
|
+
def __copy__(self) -> Self:
|
23
|
+
return self
|
24
|
+
|
25
|
+
def __deepcopy__(self, memo: Optional[dict]) -> Self:
|
26
|
+
return self
|
27
|
+
|
20
28
|
|
21
29
|
class QmodQBitProxy(QmodQScalarProxy):
|
22
30
|
def __init__(self, handle: HandleBinding) -> None:
|
@@ -29,10 +37,18 @@ class QmodQBitProxy(QmodQScalarProxy):
|
|
29
37
|
|
30
38
|
class QmodQNumProxy(QmodQScalarProxy):
|
31
39
|
def __init__(
|
32
|
-
self,
|
40
|
+
self,
|
41
|
+
handle: HandleBinding,
|
42
|
+
size: Union[int, sympy.Basic],
|
43
|
+
fraction_digits: Union[int, sympy.Basic],
|
44
|
+
is_signed: Union[bool, sympy.Basic],
|
33
45
|
) -> None:
|
34
46
|
super().__init__(handle, size)
|
35
|
-
if
|
47
|
+
if (
|
48
|
+
isinstance(fraction_digits, int)
|
49
|
+
and isinstance(size, int)
|
50
|
+
and fraction_digits > size
|
51
|
+
):
|
36
52
|
raise ClassiqValueError(
|
37
53
|
f"Quantum numeric of size {size} cannot have {fraction_digits} "
|
38
54
|
f"fraction digits"
|
@@ -45,11 +61,11 @@ class QmodQNumProxy(QmodQScalarProxy):
|
|
45
61
|
return "Quantum numeric"
|
46
62
|
|
47
63
|
@property
|
48
|
-
def fraction_digits(self) -> int:
|
64
|
+
def fraction_digits(self) -> Union[int, sympy.Basic]:
|
49
65
|
return self._fraction_digits
|
50
66
|
|
51
67
|
@property
|
52
|
-
def is_signed(self) -> bool:
|
68
|
+
def is_signed(self) -> Union[bool, sympy.Basic]:
|
53
69
|
return self._is_signed
|
54
70
|
|
55
71
|
@property
|
@@ -1,21 +1,26 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
-
from typing import TYPE_CHECKING, Any
|
2
|
+
from typing import TYPE_CHECKING, Any, Union
|
3
|
+
|
4
|
+
import sympy
|
3
5
|
|
4
6
|
if TYPE_CHECKING:
|
5
7
|
from classiq.interface.model.handle_binding import HandleBinding
|
6
8
|
|
7
9
|
|
8
10
|
class QmodSizedProxy:
|
9
|
-
def __init__(self, handle: "HandleBinding", size: int) -> None:
|
11
|
+
def __init__(self, handle: "HandleBinding", size: Union[int, sympy.Basic]) -> None:
|
10
12
|
self._handle = handle
|
11
13
|
self._size = size
|
12
14
|
|
13
15
|
@property
|
14
|
-
def size(self) -> int:
|
16
|
+
def size(self) -> Union[int, sympy.Basic]:
|
15
17
|
return self._size
|
16
18
|
|
17
19
|
def __str__(self) -> str:
|
18
|
-
return
|
20
|
+
return self.handle.qmod_expr
|
21
|
+
|
22
|
+
def __repr__(self) -> str:
|
23
|
+
return str(self)
|
19
24
|
|
20
25
|
@property
|
21
26
|
def type_name(self) -> str:
|
@@ -6,6 +6,9 @@ from typing_extensions import Self
|
|
6
6
|
|
7
7
|
from classiq.interface.ast_node import HashableASTNode
|
8
8
|
from classiq.interface.generator.expressions.expression import Expression
|
9
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
10
|
+
AnyClassicalValue,
|
11
|
+
)
|
9
12
|
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
10
13
|
ClassicalArrayProxy,
|
11
14
|
)
|
@@ -94,7 +97,9 @@ class ClassicalList(ClassicalType):
|
|
94
97
|
return values_with_discriminator(values, "kind", "list")
|
95
98
|
|
96
99
|
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
97
|
-
|
100
|
+
return ClassicalArrayProxy(
|
101
|
+
handle, self.element_type, AnyClassicalValue(f"get_field({handle}, 'len')")
|
102
|
+
)
|
98
103
|
|
99
104
|
@property
|
100
105
|
def expressions(self) -> list[Expression]:
|
@@ -9,6 +9,9 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
9
9
|
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
10
10
|
ClassicalProxy,
|
11
11
|
)
|
12
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
13
|
+
ClassicalScalarProxy,
|
14
|
+
)
|
12
15
|
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
13
16
|
ClassicalStructProxy,
|
14
17
|
)
|
@@ -109,8 +112,10 @@ class TypeName(ClassicalType, QuantumType):
|
|
109
112
|
self._classical_struct_decl = decl
|
110
113
|
|
111
114
|
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
112
|
-
if self.
|
113
|
-
|
115
|
+
if self.is_enum:
|
116
|
+
return ClassicalScalarProxy(handle, self)
|
117
|
+
if TYPE_CHECKING:
|
118
|
+
assert self._classical_struct_decl is not None
|
114
119
|
return ClassicalStructProxy(handle, self._classical_struct_decl)
|
115
120
|
|
116
121
|
@property
|