classiq 0.69.0__py3-none-any.whl → 0.71.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. classiq/analyzer/analyzer.py +0 -18
  2. classiq/analyzer/url_utils.py +9 -4
  3. classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
  4. classiq/interface/_version.py +1 -1
  5. classiq/interface/backend/quantum_backend_providers.py +6 -0
  6. classiq/interface/chemistry/operator.py +1 -21
  7. classiq/interface/debug_info/debug_info.py +4 -0
  8. classiq/interface/executor/quantum_instruction_set.py +1 -0
  9. classiq/interface/generator/arith/arithmetic.py +21 -6
  10. classiq/interface/generator/circuit_code/circuit_code.py +4 -0
  11. classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
  12. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
  13. classiq/interface/generator/expressions/expression_constants.py +0 -3
  14. classiq/interface/generator/expressions/expression_types.py +12 -4
  15. classiq/interface/generator/expressions/proxies/__init__.py +0 -0
  16. classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
  17. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +79 -0
  18. classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
  19. classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
  20. classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +35 -0
  21. classiq/interface/generator/expressions/proxies/classical/utils.py +34 -0
  22. classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
  23. classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
  24. classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
  25. classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
  26. classiq/interface/generator/functions/classical_type.py +24 -30
  27. classiq/interface/generator/functions/type_name.py +42 -2
  28. classiq/interface/generator/functions/type_qualifier.py +7 -0
  29. classiq/interface/generator/generated_circuit_data.py +22 -4
  30. classiq/interface/generator/model/preferences/preferences.py +1 -0
  31. classiq/interface/generator/quantum_function_call.py +8 -1
  32. classiq/interface/generator/quantum_program.py +0 -1
  33. classiq/interface/generator/synthesis_execution_parameter.py +1 -0
  34. classiq/interface/generator/types/compilation_metadata.py +1 -0
  35. classiq/interface/ide/visual_model.py +1 -0
  36. classiq/interface/interface_version.py +1 -1
  37. classiq/interface/model/allocate.py +7 -0
  38. classiq/interface/model/block.py +12 -0
  39. classiq/interface/model/classical_if.py +4 -0
  40. classiq/interface/model/inplace_binary_operation.py +4 -0
  41. classiq/interface/model/model.py +3 -1
  42. classiq/interface/model/native_function_definition.py +0 -10
  43. classiq/interface/model/phase_operation.py +4 -0
  44. classiq/interface/model/port_declaration.py +3 -0
  45. classiq/interface/model/power.py +4 -0
  46. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -0
  47. classiq/interface/model/quantum_function_call.py +4 -0
  48. classiq/interface/model/quantum_function_declaration.py +1 -1
  49. classiq/interface/model/quantum_statement.py +5 -0
  50. classiq/interface/model/quantum_type.py +37 -3
  51. classiq/interface/model/repeat.py +4 -0
  52. classiq/interface/model/statement_block.py +3 -0
  53. classiq/interface/model/variable_declaration_statement.py +5 -0
  54. classiq/model_expansions/atomic_expression_functions_defs.py +9 -3
  55. classiq/model_expansions/capturing/captured_vars.py +156 -34
  56. classiq/model_expansions/evaluators/arg_type_match.py +4 -2
  57. classiq/model_expansions/evaluators/classical_expression.py +2 -2
  58. classiq/model_expansions/evaluators/classical_type_inference.py +70 -0
  59. classiq/model_expansions/evaluators/control.py +1 -1
  60. classiq/model_expansions/evaluators/parameter_types.py +72 -16
  61. classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
  62. classiq/model_expansions/expression_evaluator.py +3 -12
  63. classiq/model_expansions/function_builder.py +2 -8
  64. classiq/model_expansions/generative_functions.py +39 -3
  65. classiq/model_expansions/interpreters/base_interpreter.py +3 -4
  66. classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
  67. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
  68. classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
  69. classiq/model_expansions/quantum_operations/call_emitter.py +46 -6
  70. classiq/model_expansions/quantum_operations/emitter.py +41 -0
  71. classiq/model_expansions/quantum_operations/expression_evaluator.py +4 -0
  72. classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
  73. classiq/model_expansions/scope.py +7 -14
  74. classiq/model_expansions/scope_initialization.py +32 -39
  75. classiq/model_expansions/transformers/model_renamer.py +13 -4
  76. classiq/model_expansions/visitors/variable_references.py +8 -4
  77. classiq/open_library/functions/__init__.py +2 -0
  78. classiq/open_library/functions/lookup_table.py +58 -0
  79. classiq/qmod/__init__.py +3 -1
  80. classiq/qmod/declaration_inferrer.py +55 -25
  81. classiq/qmod/native/pretty_printer.py +25 -3
  82. classiq/qmod/pretty_print/pretty_printer.py +31 -14
  83. classiq/qmod/python_classical_type.py +12 -1
  84. classiq/qmod/qfunc.py +33 -8
  85. classiq/qmod/qmod_parameter.py +8 -0
  86. classiq/qmod/qmod_variable.py +189 -151
  87. classiq/qmod/quantum_function.py +3 -4
  88. classiq/qmod/semantics/annotation/call_annotation.py +0 -28
  89. classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
  90. classiq/qmod/semantics/validation/main_validation.py +1 -1
  91. classiq/qmod/semantics/validation/type_hints.py +38 -0
  92. classiq/qmod/utilities.py +38 -1
  93. {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/METADATA +10 -12
  94. {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/RECORD +97 -82
  95. {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/WHEEL +1 -1
  96. /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
  97. /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -5,7 +5,6 @@ import webbrowser
5
5
  from collections.abc import Sequence
6
6
  from importlib.util import find_spec
7
7
  from typing import Any, Optional, Union
8
- from urllib.parse import urljoin
9
8
 
10
9
  import plotly.graph_objects as go
11
10
 
@@ -21,7 +20,6 @@ from classiq.analyzer.analyzer_utilities import (
21
20
  DeviceName,
22
21
  ProviderNameEnum,
23
22
  )
24
- from classiq.analyzer.url_utils import circuit_page_uri, client_ide_base_url
25
23
 
26
24
  find_ipywidgets = find_spec("ipywidgets")
27
25
  VBox = Any
@@ -63,22 +61,6 @@ class Analyzer(AnalyzerUtilities):
63
61
  transpilation_option=self.circuit.model.execution_preferences.transpile_to_hardware,
64
62
  )
65
63
 
66
- def analyzer_app(self) -> None:
67
- """Opens the analyzer app with synthesis interactive results.
68
-
69
- Returns:
70
- None.
71
- """
72
- result = async_utils.run(ApiWrapper.call_analyzer_app(self.circuit))
73
- webbrowser.open_new_tab(
74
- urljoin(
75
- client_ide_base_url(),
76
- circuit_page_uri(
77
- circuit_id=result.id, circuit_version=self.circuit.version
78
- ),
79
- )
80
- )
81
-
82
64
  def get_available_devices(
83
65
  self, providers: Optional[list[ProviderNameEnum]] = None
84
66
  ) -> dict[ProviderNameEnum, list[DeviceName]]:
@@ -7,6 +7,7 @@ import classiq
7
7
 
8
8
  QUERY_START_MARK = "?"
9
9
  VERSION_QUERY_PARAM = "version"
10
+ LOGIN_QUERY_PARAM = "login"
10
11
 
11
12
 
12
13
  def client_ide_base_url() -> str:
@@ -14,13 +15,17 @@ def client_ide_base_url() -> str:
14
15
  return str(client.config.ide)
15
16
 
16
17
 
17
- def versioned_url_params(circuit_version: str) -> str:
18
- return QUERY_START_MARK + urllib.parse.urlencode(
19
- {VERSION_QUERY_PARAM: circuit_version}
18
+ def circuit_page_search_params(circuit_version: str) -> str:
19
+ return urllib.parse.urlencode(
20
+ {
21
+ LOGIN_QUERY_PARAM: True,
22
+ VERSION_QUERY_PARAM: circuit_version,
23
+ }
20
24
  )
21
25
 
22
26
 
23
27
  def circuit_page_uri(circuit_id: str, circuit_version: str) -> str:
24
28
  url = urljoin(f"{routes.ANALYZER_CIRCUIT_PAGE}/", circuit_id)
25
- url += versioned_url_params(circuit_version=circuit_version)
29
+ query_string = circuit_page_search_params(circuit_version)
30
+ url += QUERY_START_MARK + query_string
26
31
  return url
@@ -1,3 +1,4 @@
1
+ import copy
1
2
  import math
2
3
  import re
3
4
  from collections import defaultdict
@@ -209,6 +210,7 @@ def convert_pyomo_to_global_presentation(
209
210
  def pyomo2qmod(
210
211
  struct_name: str, pyo_model: ConcreteModel
211
212
  ) -> CombinatorialOptimizationStructDeclaration:
213
+ pyo_model = copy.deepcopy(pyo_model)
212
214
  symbols_map = PyomoSympyBimap()
213
215
 
214
216
  variables: list[sympy.Symbol] = []
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.69.0'
6
+ SEMVER_VERSION = '0.71.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -175,6 +175,12 @@ class ClassiqNvidiaBackendNames(StrEnum):
175
175
  BRAKET_NVIDIA_SIMULATOR = "braket_nvidia_simulator"
176
176
  BRAKET_NVIDIA_SIMULATOR_STATEVECTOR = "braket_nvidia_simulator_statevector"
177
177
 
178
+ def is_braket_nvidia_backend(self) -> bool:
179
+ return self in (
180
+ self.BRAKET_NVIDIA_SIMULATOR,
181
+ self.BRAKET_NVIDIA_SIMULATOR_STATEVECTOR,
182
+ )
183
+
178
184
 
179
185
  class IntelBackendNames(StrEnum):
180
186
  SIMULATOR = "intel_qsdk_simulator"
@@ -85,31 +85,11 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
85
85
  raise ClassiqValueError("Pauli strings have incompatible lengths.")
86
86
  return pauli_list
87
87
 
88
- @staticmethod
89
- def check_if_hermitian(pauli_list: PydanticPauliList) -> bool:
90
- if all(isinstance(summand[1], (float, int, complex)) for summand in pauli_list):
91
- if all(np.isclose(summand[1].imag, 0) for summand in pauli_list): # type: ignore[union-attr]
92
- return True
93
-
94
- for pauli_string, coeff in pauli_list:
95
- reverse_string = pauli_string[::-1]
96
- reverse_found = False
97
- for other_string, other_coeff in pauli_list:
98
- if other_string == reverse_string and np.isclose(
99
- coeff, other_coeff.conjugate() # type: ignore[union-attr]
100
- ):
101
- reverse_found = True
102
- break
103
- if not reverse_found:
104
- return False
105
- return True
106
- return False
107
-
108
88
  @pydantic.model_validator(mode="before")
109
89
  @classmethod
110
90
  def _validate_hermitianity(cls, values: dict[str, Any]) -> dict[str, Any]:
111
91
  pauli_list = values.get("pauli_list", [])
112
- if PauliOperator.check_if_hermitian(pauli_list):
92
+ if all(isinstance(summand[1], (float, int, complex)) for summand in pauli_list):
113
93
  values["is_hermitian"] = all(
114
94
  np.isclose(complex(summand[1]).real, summand[1])
115
95
  for summand in pauli_list
@@ -10,6 +10,7 @@ from classiq.interface.generator.generated_circuit_data import (
10
10
  OperationLevel,
11
11
  StatementType,
12
12
  )
13
+ from classiq.interface.model.block import Block
13
14
  from classiq.interface.model.statement_block import ConcreteQuantumStatement
14
15
 
15
16
  ParameterValue = Union[float, int, str, None]
@@ -84,6 +85,9 @@ def get_back_refs(
84
85
  ) -> list[ConcreteQuantumStatement]:
85
86
  back_refs: list[ConcreteQuantumStatement] = []
86
87
  while (node := debug_info.node) is not None:
88
+ # For backwards compatibility, we make sure that the back_ref is not a block
89
+ # Remove this check when we start saving blocks in the debug info collection.
90
+ assert not isinstance(node, Block)
87
91
  back_refs.insert(0, node)
88
92
  if node.back_ref is None:
89
93
  break
@@ -6,6 +6,7 @@ class QuantumInstructionSet(StrEnum):
6
6
  QASM = "qasm"
7
7
  QSHARP = "qsharp"
8
8
  IONQ = "ionq"
9
+ INTERNAL = "_internal"
9
10
 
10
11
  @classmethod
11
12
  def from_suffix(cls, suffix: str) -> "QuantumInstructionSet":
@@ -22,6 +22,9 @@ from classiq.interface.generator.arith.arithmetic_result_builder import (
22
22
  )
23
23
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
24
24
  from classiq.interface.generator.expressions.expression import Expression
25
+ from classiq.interface.generator.expressions.expression_constants import (
26
+ BOOLEAN_LITERALS,
27
+ )
25
28
  from classiq.interface.model.quantum_type import (
26
29
  QuantumNumeric,
27
30
  QuantumType,
@@ -40,6 +43,10 @@ def is_zero(expr: str) -> bool:
40
43
  return is_constant(expr) and float(expr) == 0
41
44
 
42
45
 
46
+ def is_bool(expr: str) -> bool:
47
+ return expr in BOOLEAN_LITERALS
48
+
49
+
43
50
  class Arithmetic(ArithmeticExpressionABC):
44
51
  target: Optional[RegisterArithmeticInfo] = None
45
52
  inputs_to_save: set[str] = pydantic.Field(default_factory=set)
@@ -115,7 +122,7 @@ def get_arithmetic_params(
115
122
  def compute_arithmetic_result_type(
116
123
  expr_str: str, var_types: dict[str, QuantumType], machine_precision: int
117
124
  ) -> QuantumNumeric:
118
- if is_zero(expr_str):
125
+ if is_zero(expr_str) or is_bool(expr_str):
119
126
  return QuantumNumeric(
120
127
  size=Expression(expr="1"),
121
128
  is_signed=Expression(expr="False"),
@@ -153,6 +160,17 @@ def aggregate_numeric_types(
153
160
  )
154
161
 
155
162
 
163
+ def _eval_num(val: ast.AST) -> float:
164
+ if isinstance(val, ast.Num):
165
+ return cast(float, val.value)
166
+ if isinstance(val, ast.UnaryOp) and isinstance(val.op, ast.USub):
167
+ return -_eval_num(val.operand)
168
+ raise ClassiqValueError(
169
+ "Classical lists with quantum subscripts must contain compile-time classical "
170
+ "real numbers"
171
+ )
172
+
173
+
156
174
  class _QuantumSubscriptRemover(ast.NodeTransformer):
157
175
  def __init__(self, machine_precision: int) -> None:
158
176
  self._machine_precision = machine_precision
@@ -161,10 +179,7 @@ class _QuantumSubscriptRemover(ast.NodeTransformer):
161
179
  def visit_Call(self, node: ast.Call) -> ast.expr:
162
180
  if not isinstance(node.func, ast.Name) or node.func.id != "Piecewise":
163
181
  return node
164
- items = [
165
- cast(float, cast(ast.Num, cast(ast.Tuple, arg).elts[0]).value)
166
- for arg in node.args
167
- ]
182
+ items = [_eval_num(cast(ast.Tuple, arg).elts[0]) for arg in node.args]
168
183
  numeric_types = [
169
184
  compute_arithmetic_result_type(str(num), {}, self._machine_precision)
170
185
  for num in items
@@ -172,7 +187,7 @@ class _QuantumSubscriptRemover(ast.NodeTransformer):
172
187
  unified_numeric_type = register_info_to_quantum_type(
173
188
  aggregate_numeric_types(numeric_types)
174
189
  )
175
- substitution_var_name = f"__lut__{len(self.substitutions_types)}__"
190
+ substitution_var_name = f"lut__{len(self.substitutions_types)}__"
176
191
  self.substitutions_types[substitution_var_name] = unified_numeric_type
177
192
  return ast.Name(id=substitution_var_name)
178
193
 
@@ -49,6 +49,10 @@ class CircuitCodeInterface(pydantic.BaseModel):
49
49
  def qasm_cirq_compatible(self) -> Optional[Code]:
50
50
  return self.outputs.get(QuantumFormat.QASM_CIRQ_COMPATIBLE)
51
51
 
52
+ @property
53
+ def _execution_serialization(self) -> Optional[Code]:
54
+ return self.outputs.get(QuantumFormat.EXECUTION_SERIALIZATION)
55
+
52
56
  def get_code(self, instruction_set: QuantumInstructionSet) -> Code:
53
57
  quantum_format: QuantumFormat = INSTRUCTION_SET_TO_FORMAT[instruction_set]
54
58
  code = self.outputs.get(quantum_format)
@@ -12,6 +12,7 @@ INSTRUCTION_SET_TO_FORMAT: dict[QuantumInstructionSet, QuantumFormat] = {
12
12
  QuantumInstructionSet.QASM: QuantumFormat.QASM,
13
13
  QuantumInstructionSet.QSHARP: QuantumFormat.QSHARP,
14
14
  QuantumInstructionSet.IONQ: QuantumFormat.IONQ,
15
+ QuantumInstructionSet.INTERNAL: QuantumFormat.EXECUTION_SERIALIZATION,
15
16
  }
16
17
  VENDOR_TO_INSTRUCTION_SET: dict[Provider, QuantumInstructionSet] = {
17
18
  Provider.CLASSIQ: QuantumInstructionSet.QASM,
@@ -1,5 +1,3 @@
1
- from classiq.interface.generator.functions.classical_type import CLASSICAL_ATTRIBUTES
2
-
3
1
  SUPPORTED_PYTHON_BUILTIN_FUNCTIONS = {"len", "sum", "print"}
4
2
 
5
3
  SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
@@ -33,6 +31,7 @@ SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
33
31
  *SUPPORTED_PYTHON_BUILTIN_FUNCTIONS,
34
32
  }
35
33
 
34
+ CLASSICAL_ATTRIBUTES = {"len", "size", "is_signed", "fraction_digits"}
36
35
  SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS_QMOD = (
37
36
  SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS - CLASSICAL_ATTRIBUTES
38
37
  )
@@ -20,6 +20,3 @@ BOOLEAN_LITERALS = {"True", "False"}
20
20
  FORBIDDEN_LITERALS: set[str] = set(keyword.kwlist) - SUPPORTED_FUNC_NAMES
21
21
  CPARAM_EXECUTION_SUFFIX: Final[str] = "_param"
22
22
  RESERVED_EXPRESSIONS: frozenset[str] = frozenset({"i"})
23
- CPARAM_EXECUTION_SUFFIX_PATTERN = (
24
- rf"({CPARAM_EXECUTION_SUFFIX}|^({'|'.join(RESERVED_EXPRESSIONS)}))(_\d+)*$"
25
- )
@@ -4,10 +4,15 @@ from sympy import Expr
4
4
  from sympy.logic.boolalg import Boolean
5
5
 
6
6
  from classiq.interface.generator.expressions.handle_identifier import HandleIdentifier
7
- from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
8
- from classiq.interface.generator.expressions.qmod_struct_instance import (
7
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
8
+ ClassicalProxy,
9
+ )
10
+ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
9
11
  QmodStructInstance,
10
12
  )
13
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
14
+ QmodSizedProxy,
15
+ )
11
16
  from classiq.interface.generator.expressions.type_proxy import TypeProxy
12
17
 
13
18
  RuntimeConstant = Union[
@@ -16,9 +21,12 @@ RuntimeConstant = Union[
16
21
  list,
17
22
  bool,
18
23
  QmodStructInstance,
19
- QmodSizedProxy,
20
24
  TypeProxy,
21
25
  HandleIdentifier,
22
26
  ]
27
+ Proxies = Union[
28
+ QmodSizedProxy,
29
+ ClassicalProxy,
30
+ ]
23
31
  RuntimeExpression = Union[Expr, Boolean]
24
- ExpressionValue = Union[RuntimeConstant, RuntimeExpression]
32
+ ExpressionValue = Union[RuntimeConstant, Proxies, RuntimeExpression]
@@ -0,0 +1,79 @@
1
+ from collections.abc import Mapping
2
+ from typing import TYPE_CHECKING, Union
3
+
4
+ from sympy import Integer
5
+
6
+ from classiq.interface.exceptions import ClassiqValueError
7
+ from classiq.interface.generator.expressions.expression import Expression
8
+ from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
9
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
10
+ ClassicalProxy,
11
+ )
12
+ from classiq.interface.model.handle_binding import (
13
+ HandleBinding,
14
+ SlicedHandleBinding,
15
+ SubscriptHandleBinding,
16
+ )
17
+
18
+ if TYPE_CHECKING:
19
+ from classiq.interface.generator.expressions.expression_types import ExpressionValue
20
+ from classiq.interface.generator.functions.concrete_types import (
21
+ ConcreteClassicalType,
22
+ )
23
+
24
+
25
+ class ClassicalArrayProxy(NonSymbolicExpr, ClassicalProxy):
26
+ def __init__(
27
+ self, handle: HandleBinding, element_type: "ConcreteClassicalType", length: int
28
+ ) -> None:
29
+ super().__init__(handle)
30
+ self._element_type = element_type
31
+ self._length = length
32
+
33
+ @property
34
+ def fields(self) -> Mapping[str, "ExpressionValue"]:
35
+ return {"len": self._length}
36
+
37
+ @property
38
+ def type_name(self) -> str:
39
+ return "Array"
40
+
41
+ @property
42
+ def length(self) -> int:
43
+ return self._length
44
+
45
+ def __getitem__(self, key: Union[slice, int, Integer]) -> ClassicalProxy:
46
+ return (
47
+ self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
48
+ )
49
+
50
+ def _get_slice(self, slice_: slice) -> ClassicalProxy:
51
+ start = int(slice_.start)
52
+ stop = int(slice_.stop)
53
+ if start >= stop:
54
+ raise ClassiqValueError("Array slice has non-positive length")
55
+ if start < 0 or stop > self._length:
56
+ raise ClassiqValueError("Array slice is out of bounds")
57
+ return ClassicalArrayProxy(
58
+ SlicedHandleBinding(
59
+ base_handle=self.handle,
60
+ start=Expression(expr=str(start)),
61
+ end=Expression(expr=str(stop)),
62
+ ),
63
+ self._element_type,
64
+ stop - start,
65
+ )
66
+
67
+ def _get_subscript(self, index_: Union[int, Integer]) -> ClassicalProxy:
68
+ index = int(index_)
69
+ if index < 0:
70
+ raise ClassiqValueError(
71
+ "Array index is out of bounds (negative indices are not supported)"
72
+ )
73
+ if index >= self._length:
74
+ raise ClassiqValueError("Array index is out of bounds")
75
+ return self._element_type.get_classical_proxy(
76
+ SubscriptHandleBinding(
77
+ base_handle=self._handle, index=Expression(expr=str(index_))
78
+ )
79
+ )
@@ -0,0 +1,26 @@
1
+ from collections.abc import Mapping
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from classiq.interface.generator.expressions.expression_types import ExpressionValue
6
+ from classiq.interface.model.handle_binding import HandleBinding
7
+
8
+
9
+ class ClassicalProxy:
10
+ def __init__(self, handle: "HandleBinding") -> None:
11
+ self._handle = handle
12
+
13
+ @property
14
+ def handle(self) -> "HandleBinding":
15
+ return self._handle
16
+
17
+ def __str__(self) -> str:
18
+ return str(self.handle)
19
+
20
+ @property
21
+ def fields(self) -> Mapping[str, "ExpressionValue"]:
22
+ raise NotImplementedError
23
+
24
+ @property
25
+ def type_name(self) -> str:
26
+ raise NotImplementedError
@@ -0,0 +1,32 @@
1
+ from collections.abc import Mapping
2
+ from typing import TYPE_CHECKING, Any
3
+
4
+ from sympy import Symbol
5
+
6
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
7
+ ClassicalProxy,
8
+ )
9
+ from classiq.interface.model.handle_binding import HandleBinding
10
+
11
+ if TYPE_CHECKING:
12
+ from classiq.interface.generator.expressions.expression_types import ExpressionValue
13
+ from classiq.interface.generator.functions.classical_type import ClassicalType
14
+
15
+
16
+ class ClassicalScalarProxy(Symbol, ClassicalProxy):
17
+ def __new__(
18
+ cls, handle: HandleBinding, *args: Any, **assumptions: bool
19
+ ) -> "ClassicalScalarProxy":
20
+ return super().__new__(cls, str(handle), **assumptions)
21
+
22
+ def __init__(self, handle: HandleBinding, classical_type: "ClassicalType") -> None:
23
+ super().__init__(handle)
24
+ self._classical_type = classical_type
25
+
26
+ @property
27
+ def fields(self) -> Mapping[str, "ExpressionValue"]:
28
+ return {}
29
+
30
+ @property
31
+ def type_name(self) -> str:
32
+ return type(self._classical_type).__name__
@@ -0,0 +1,35 @@
1
+ from collections.abc import Mapping
2
+ from typing import TYPE_CHECKING
3
+
4
+ from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
5
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
6
+ ClassicalProxy,
7
+ )
8
+ from classiq.interface.model.handle_binding import FieldHandleBinding, HandleBinding
9
+
10
+ if TYPE_CHECKING:
11
+ from classiq.interface.generator.expressions.expression_types import ExpressionValue
12
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
13
+
14
+
15
+ class ClassicalStructProxy(NonSymbolicExpr, ClassicalProxy):
16
+ def __init__(self, handle: HandleBinding, decl: "StructDeclaration") -> None:
17
+ super().__init__(handle)
18
+ self._decl = decl
19
+
20
+ @property
21
+ def struct_declaration(self) -> "StructDeclaration":
22
+ return self._decl
23
+
24
+ @property
25
+ def fields(self) -> Mapping[str, "ExpressionValue"]:
26
+ return {
27
+ field_name: field_type.get_classical_proxy(
28
+ FieldHandleBinding(base_handle=self.handle, field=field_name)
29
+ )
30
+ for field_name, field_type in self._decl.variables.items()
31
+ }
32
+
33
+ @property
34
+ def type_name(self) -> str:
35
+ return f"Struct {self._decl.name}"
@@ -0,0 +1,34 @@
1
+ from classiq.interface.exceptions import ClassiqInternalExpansionError
2
+ from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
3
+ ClassicalArrayProxy,
4
+ )
5
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
6
+ ClassicalProxy,
7
+ )
8
+ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
9
+ ClassicalScalarProxy,
10
+ )
11
+ from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
12
+ ClassicalStructProxy,
13
+ )
14
+ from classiq.interface.generator.functions.classical_type import (
15
+ ClassicalArray,
16
+ ClassicalType,
17
+ )
18
+ from classiq.interface.generator.functions.type_name import TypeName
19
+
20
+
21
+ def get_proxy_type(proxy: ClassicalProxy) -> ClassicalType:
22
+ if isinstance(proxy, ClassicalScalarProxy):
23
+ classical_type = proxy._classical_type
24
+ elif isinstance(proxy, ClassicalArrayProxy):
25
+ classical_type = ClassicalArray(
26
+ element_type=proxy._element_type, size=proxy.length
27
+ )
28
+ elif isinstance(proxy, ClassicalStructProxy):
29
+ classical_type = TypeName(name=proxy._decl.name)
30
+ else:
31
+ raise ClassiqInternalExpansionError(
32
+ f"Unrecognized classical proxy {type(proxy).__name__}"
33
+ )
34
+ return classical_type
@@ -6,7 +6,9 @@ from sympy import Integer
6
6
  from classiq.interface.exceptions import ClassiqValueError
7
7
  from classiq.interface.generator.expressions.expression import Expression
8
8
  from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
9
- from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
9
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
10
+ QmodSizedProxy,
11
+ )
10
12
  from classiq.interface.model.handle_binding import (
11
13
  HandleBinding,
12
14
  SlicedHandleBinding,
@@ -4,7 +4,9 @@ from typing import Any
4
4
  from sympy import Symbol
5
5
 
6
6
  from classiq.interface.exceptions import ClassiqValueError
7
- from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
7
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
8
+ QmodSizedProxy,
9
+ )
8
10
  from classiq.interface.model.handle_binding import HandleBinding
9
11
 
10
12
 
@@ -2,7 +2,9 @@ from collections.abc import Mapping
2
2
  from typing import TYPE_CHECKING
3
3
 
4
4
  from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
5
- from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
5
+ from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
6
+ QmodSizedProxy,
7
+ )
6
8
  from classiq.interface.model.handle_binding import (
7
9
  FieldHandleBinding,
8
10
  HandleBinding,