classiq 0.70.0__py3-none-any.whl → 0.72.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 (98) hide show
  1. classiq/__init__.py +0 -6
  2. classiq/_internals/client.py +11 -1
  3. classiq/applications/chemistry/chemistry_model_constructor.py +18 -16
  4. classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
  5. classiq/applications/combinatorial_helpers/pyomo_utils.py +6 -1
  6. classiq/applications/finance/__init__.py +0 -3
  7. classiq/applications/qsvm/__init__.py +0 -2
  8. classiq/interface/_version.py +1 -1
  9. classiq/interface/backend/backend_preferences.py +22 -0
  10. classiq/interface/backend/quantum_backend_providers.py +2 -0
  11. classiq/interface/debug_info/debug_info.py +4 -0
  12. classiq/interface/generator/expressions/expression_constants.py +0 -3
  13. classiq/interface/generator/expressions/expression_types.py +8 -3
  14. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +135 -0
  15. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +4 -0
  16. classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +5 -1
  17. classiq/interface/generator/expressions/proxies/classical/utils.py +34 -0
  18. classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
  19. classiq/interface/generator/functions/classical_type.py +1 -1
  20. classiq/interface/generator/functions/type_name.py +16 -0
  21. classiq/interface/generator/functions/type_qualifier.py +7 -0
  22. classiq/interface/generator/generated_circuit_data.py +14 -1
  23. classiq/interface/generator/hardware/hardware_data.py +3 -1
  24. classiq/interface/generator/quantum_function_call.py +8 -1
  25. classiq/interface/generator/synthesis_execution_parameter.py +1 -0
  26. classiq/interface/generator/transpiler_basis_gates.py +3 -1
  27. classiq/interface/generator/types/compilation_metadata.py +1 -0
  28. classiq/interface/hardware.py +1 -0
  29. classiq/interface/ide/visual_model.py +1 -0
  30. classiq/interface/interface_version.py +1 -1
  31. classiq/interface/model/allocate.py +7 -0
  32. classiq/interface/model/block.py +12 -0
  33. classiq/interface/model/classical_if.py +4 -0
  34. classiq/interface/model/handle_binding.py +21 -0
  35. classiq/interface/model/inplace_binary_operation.py +4 -0
  36. classiq/interface/model/model.py +3 -1
  37. classiq/interface/model/phase_operation.py +4 -0
  38. classiq/interface/model/port_declaration.py +3 -0
  39. classiq/interface/model/power.py +4 -0
  40. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -0
  41. classiq/interface/model/quantum_function_call.py +4 -0
  42. classiq/interface/model/quantum_function_declaration.py +1 -1
  43. classiq/interface/model/quantum_statement.py +5 -0
  44. classiq/interface/model/quantum_type.py +22 -0
  45. classiq/interface/model/repeat.py +4 -0
  46. classiq/interface/model/statement_block.py +3 -0
  47. classiq/interface/model/variable_declaration_statement.py +5 -0
  48. classiq/interface/server/routes.py +0 -2
  49. classiq/model_expansions/atomic_expression_functions_defs.py +35 -13
  50. classiq/model_expansions/capturing/captured_vars.py +156 -34
  51. classiq/model_expansions/closure.py +0 -9
  52. classiq/model_expansions/evaluators/classical_type_inference.py +70 -0
  53. classiq/model_expansions/evaluators/parameter_types.py +20 -10
  54. classiq/model_expansions/expression_evaluator.py +0 -11
  55. classiq/model_expansions/function_builder.py +2 -8
  56. classiq/model_expansions/generative_functions.py +7 -30
  57. classiq/model_expansions/interpreters/base_interpreter.py +7 -8
  58. classiq/model_expansions/interpreters/generative_interpreter.py +33 -5
  59. classiq/model_expansions/quantum_operations/__init__.py +0 -2
  60. classiq/model_expansions/quantum_operations/block_evaluator.py +16 -2
  61. classiq/model_expansions/quantum_operations/call_emitter.py +49 -6
  62. classiq/model_expansions/quantum_operations/emitter.py +64 -6
  63. classiq/model_expansions/quantum_operations/expression_evaluator.py +4 -0
  64. classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -1
  65. classiq/model_expansions/quantum_operations/quantum_function_call.py +49 -0
  66. classiq/model_expansions/quantum_operations/repeat_block_evaluator.py +34 -0
  67. classiq/model_expansions/scope.py +33 -21
  68. classiq/model_expansions/scope_initialization.py +28 -32
  69. classiq/model_expansions/transformers/model_renamer.py +69 -63
  70. classiq/model_expansions/utils/sympy_utils.py +24 -0
  71. classiq/model_expansions/visitors/variable_references.py +1 -0
  72. classiq/qmod/__init__.py +3 -1
  73. classiq/qmod/builtins/functions/__init__.py +8 -0
  74. classiq/qmod/builtins/functions/allocation.py +36 -0
  75. classiq/qmod/builtins/functions/arithmetic.py +10 -5
  76. classiq/qmod/builtins/functions/mid_circuit_measurement.py +3 -0
  77. classiq/qmod/builtins/operations.py +2 -2
  78. classiq/qmod/declaration_inferrer.py +52 -24
  79. classiq/qmod/model_state_container.py +9 -0
  80. classiq/qmod/native/pretty_printer.py +25 -3
  81. classiq/qmod/pretty_print/pretty_printer.py +31 -14
  82. classiq/qmod/python_classical_type.py +12 -1
  83. classiq/qmod/qfunc.py +33 -8
  84. classiq/qmod/qmod_variable.py +188 -147
  85. classiq/qmod/quantum_function.py +3 -4
  86. classiq/qmod/semantics/validation/type_hints.py +19 -10
  87. classiq/qmod/symbolic.py +16 -3
  88. {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/METADATA +1 -1
  89. {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/RECORD +90 -91
  90. classiq/applications/finance/finance_model_constructor.py +0 -137
  91. classiq/applications/grover/__init__.py +0 -9
  92. classiq/applications/grover/grover_model_constructor.py +0 -167
  93. classiq/applications/libraries/__init__.py +0 -0
  94. classiq/applications/libraries/qmci_library.py +0 -22
  95. classiq/applications/qsvm/qsvm_model_constructor.py +0 -131
  96. classiq/model_expansions/quantum_operations/classicalif.py +0 -57
  97. classiq/model_expansions/quantum_operations/repeat.py +0 -62
  98. {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/WHEEL +0 -0
@@ -63,7 +63,9 @@ THREE_QUBIT_GATES: BasisGates = frozenset(("ccx", "cswap"))
63
63
  DEFAULT_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | BASIC_TWO_QUBIT_GATES
64
64
  ALL_GATES: BasisGates = SINGLE_QUBIT_GATES | TWO_QUBIT_GATES | THREE_QUBIT_GATES
65
65
 
66
- ROUTING_TWO_QUBIT_BASIS_GATES: BasisGates = frozenset(("cx", "ecr", "rzx"))
66
+ ROUTING_TWO_QUBIT_BASIS_GATES: BasisGates = frozenset(
67
+ ("cx", "ecr", "rzx", "ryy", "rxx", "rzz", "cy", "cz", "cp", "swap")
68
+ )
67
69
  DEFAULT_ROUTING_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | frozenset(("cx",))
68
70
  # The Enum names are capitalized per recommendation in https://docs.python.org/3/library/enum.html#module-enum
69
71
  # The Enum values are lowered to keep consistency
@@ -4,3 +4,4 @@ from pydantic import BaseModel, Field, NonNegativeInt
4
4
  class CompilationMetadata(BaseModel):
5
5
  should_synthesize_separately: bool = Field(default=False)
6
6
  occurrences_number: NonNegativeInt = Field(default=1)
7
+ atomic_qualifiers: list[str] = Field(default_factory=list)
@@ -33,6 +33,7 @@ class Provider(StrEnum):
33
33
  INTEL = "Intel"
34
34
  AQT = "AQT"
35
35
  IQCC = "IQCC"
36
+ CINECA = "CINECA"
36
37
 
37
38
  @property
38
39
  def id(self) -> "ProviderIDEnum":
@@ -97,6 +97,7 @@ class AtomicGate(StrEnum):
97
97
  SWAP = "SWAP"
98
98
  IDENTITY = "IDENTITY"
99
99
  U = "U"
100
+ RESET = "RESET"
100
101
 
101
102
  @property
102
103
  def is_control_gate(self) -> bool:
@@ -1 +1 @@
1
- INTERFACE_VERSION = "8"
1
+ INTERFACE_VERSION = "9"
@@ -14,3 +14,10 @@ class Allocate(QuantumOperation):
14
14
  @property
15
15
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
16
16
  return {"out": self.target}
17
+
18
+ @property
19
+ def expressions(self) -> list[Expression]:
20
+ exprs = []
21
+ if self.size is not None:
22
+ exprs.append(self.size)
23
+ return exprs
@@ -0,0 +1,12 @@
1
+ from typing import TYPE_CHECKING, Literal
2
+
3
+ from classiq.interface.model.quantum_statement import QuantumOperation
4
+
5
+ if TYPE_CHECKING:
6
+ from classiq.interface.model.statement_block import StatementBlock
7
+
8
+
9
+ class Block(QuantumOperation):
10
+ kind: Literal["Block"]
11
+
12
+ statements: "StatementBlock"
@@ -17,3 +17,7 @@ class ClassicalIf(QuantumOperation):
17
17
 
18
18
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
19
19
  return reset_lists(self, ["then", "else_"])
20
+
21
+ @property
22
+ def expressions(self) -> list[Expression]:
23
+ return [self.condition]
@@ -64,6 +64,9 @@ class HandleBinding(ASTNode):
64
64
  def __contains__(self, other_handle: "HandleBinding") -> bool:
65
65
  return self.collapse() in other_handle.collapse().prefixes()
66
66
 
67
+ def is_constant(self) -> bool:
68
+ return True
69
+
67
70
 
68
71
  class NestedHandleBinding(HandleBinding):
69
72
  base_handle: "ConcreteHandleBinding"
@@ -105,6 +108,9 @@ class NestedHandleBinding(HandleBinding):
105
108
  )
106
109
  return self
107
110
 
111
+ def is_constant(self) -> bool:
112
+ return self.base_handle.is_constant()
113
+
108
114
 
109
115
  class SubscriptHandleBinding(NestedHandleBinding):
110
116
  index: Expression
@@ -178,6 +184,13 @@ class SubscriptHandleBinding(NestedHandleBinding):
178
184
  )
179
185
  return super().replace_prefix(prefix, replacement)
180
186
 
187
+ def is_constant(self) -> bool:
188
+ return (
189
+ super().is_constant()
190
+ and self.index.is_evaluated()
191
+ and self.index.is_constant()
192
+ )
193
+
181
194
 
182
195
  class SlicedHandleBinding(NestedHandleBinding):
183
196
  start: Expression
@@ -284,6 +297,14 @@ class SlicedHandleBinding(NestedHandleBinding):
284
297
  def _is_evaluated(self) -> bool:
285
298
  return self.start.is_evaluated() and self.end.is_evaluated()
286
299
 
300
+ def is_constant(self) -> bool:
301
+ return (
302
+ super().is_constant()
303
+ and self._is_evaluated()
304
+ and self.start.is_constant()
305
+ and self.end.is_constant()
306
+ )
307
+
287
308
 
288
309
  class FieldHandleBinding(NestedHandleBinding):
289
310
  field: str
@@ -41,3 +41,7 @@ class InplaceBinaryOperation(QuantumOperation):
41
41
  )
42
42
  )
43
43
  return readable_inouts
44
+
45
+ @property
46
+ def expressions(self) -> list[Expression]:
47
+ return [self.value] if isinstance(self.value, Expression) else []
@@ -103,7 +103,9 @@ class Model(VersionedModel, ASTNode):
103
103
  functions_compilation_metadata: dict[str, CompilationMetadata] = pydantic.Field(
104
104
  default_factory=dict
105
105
  )
106
- execution_parameters: Optional[dict[str, ConcreteClassicalType]] = None
106
+ execution_parameters: Optional[dict[str, ConcreteClassicalType]] = pydantic.Field(
107
+ default=None, exclude=True
108
+ )
107
109
 
108
110
  @property
109
111
  def main_func(self) -> NativeFunctionDefinition:
@@ -9,3 +9,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
9
9
  class PhaseOperation(QuantumExpressionOperation):
10
10
  kind: Literal["PhaseOperation"]
11
11
  theta: Expression
12
+
13
+ @property
14
+ def expressions(self) -> list[Expression]:
15
+ return super().expressions + [self.theta]
@@ -8,6 +8,7 @@ from classiq.interface.generator.functions.concrete_types import ConcreteQuantum
8
8
  from classiq.interface.generator.functions.port_declaration import (
9
9
  PortDeclarationDirection,
10
10
  )
11
+ from classiq.interface.generator.functions.type_qualifier import TypeQualifier
11
12
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
12
13
  from classiq.interface.model.parameter import Parameter
13
14
 
@@ -15,6 +16,8 @@ from classiq.interface.model.parameter import Parameter
15
16
  class AnonPortDeclaration(Parameter):
16
17
  quantum_type: ConcreteQuantumType
17
18
  direction: PortDeclarationDirection
19
+ # TODO remove default after BWC-breaking version
20
+ type_qualifier: TypeQualifier = pydantic.Field(default=TypeQualifier.Quantum)
18
21
  kind: Literal["PortDeclaration"]
19
22
 
20
23
  @pydantic.model_validator(mode="before")
@@ -16,3 +16,7 @@ class Power(QuantumOperation):
16
16
 
17
17
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
18
18
  return reset_lists(self, ["body"])
19
+
20
+ @property
21
+ def expressions(self) -> list[Expression]:
22
+ return [self.power]
@@ -46,6 +46,10 @@ class QuantumExpressionOperation(QuantumOperation):
46
46
  def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
47
47
  return nameables_to_dict(self.var_handles)
48
48
 
49
+ @property
50
+ def expressions(self) -> list[Expression]:
51
+ return [self.expression]
52
+
49
53
 
50
54
  class QuantumAssignmentOperation(QuantumExpressionOperation):
51
55
  result_var: ConcreteHandleBinding = pydantic.Field(
@@ -170,6 +170,10 @@ class QuantumFunctionCall(QuantumOperation):
170
170
  param for param in self.positional_args if isinstance(param, HandleBinding)
171
171
  ]
172
172
 
173
+ @property
174
+ def expressions(self) -> list[Expression]:
175
+ return [arg for arg in self.positional_args if isinstance(arg, Expression)]
176
+
173
177
  def _get_handles_by_direction(
174
178
  self, direction: PortDeclarationDirection
175
179
  ) -> list[tuple[int, AnonPortDeclaration, HandleBinding]]:
@@ -87,7 +87,7 @@ class AnonQuantumFunctionDeclaration(FunctionDeclaration):
87
87
  ]
88
88
 
89
89
  @property
90
- def param_names(self) -> Sequence[str]:
90
+ def param_names(self) -> list[str]:
91
91
  return [param.get_name() for param in self.param_decls]
92
92
 
93
93
  @property
@@ -8,6 +8,7 @@ from pydantic import ConfigDict
8
8
  from typing_extensions import Self
9
9
 
10
10
  from classiq.interface.ast_node import ASTNode
11
+ from classiq.interface.generator.expressions.expression import Expression
11
12
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
12
13
  from classiq.interface.model.handle_binding import (
13
14
  ConcreteHandleBinding,
@@ -39,6 +40,10 @@ class QuantumStatement(ASTNode):
39
40
  def _set_kind(cls, values: Any) -> dict[str, Any]:
40
41
  return values_with_discriminator(values, "kind", cls.__name__)
41
42
 
43
+ @property
44
+ def expressions(self) -> list[Expression]:
45
+ return []
46
+
42
47
 
43
48
  @dataclass
44
49
  class HandleMetadata:
@@ -71,6 +71,10 @@ class QuantumType(HashableASTNode):
71
71
  def is_evaluated(self) -> bool:
72
72
  raise NotImplementedError
73
73
 
74
+ @property
75
+ def expressions(self) -> list[Expression]:
76
+ return []
77
+
74
78
 
75
79
  class QuantumScalar(QuantumType):
76
80
  def get_proxy(self, handle: "HandleBinding") -> QmodQScalarProxy:
@@ -174,6 +178,13 @@ class QuantumBitvector(QuantumType):
174
178
  and self.element_type.is_evaluated
175
179
  )
176
180
 
181
+ @property
182
+ def expressions(self) -> list[Expression]:
183
+ exprs = self.element_type.expressions
184
+ if self.length is not None:
185
+ exprs.append(self.length)
186
+ return exprs
187
+
177
188
 
178
189
  class QuantumNumeric(QuantumScalar):
179
190
  kind: Literal["qnum"]
@@ -265,6 +276,17 @@ class QuantumNumeric(QuantumScalar):
265
276
  self.fraction_digits is not None and not self.fraction_digits.is_evaluated()
266
277
  )
267
278
 
279
+ @property
280
+ def expressions(self) -> list[Expression]:
281
+ exprs = []
282
+ if self.size is not None:
283
+ exprs.append(self.size)
284
+ if self.is_signed is not None:
285
+ exprs.append(self.is_signed)
286
+ if self.fraction_digits is not None:
287
+ exprs.append(self.fraction_digits)
288
+ return exprs
289
+
268
290
 
269
291
  class RegisterQuantumType(BaseModel):
270
292
  quantum_types: "ConcreteQuantumType"
@@ -17,3 +17,7 @@ class Repeat(QuantumOperation):
17
17
 
18
18
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
19
19
  return reset_lists(self, ["body"])
20
+
21
+ @property
22
+ def expressions(self) -> list[Expression]:
23
+ return [self.count]
@@ -4,6 +4,7 @@ from pydantic import Field
4
4
 
5
5
  from classiq.interface.model.allocate import Allocate
6
6
  from classiq.interface.model.bind_operation import BindOperation
7
+ from classiq.interface.model.block import Block
7
8
  from classiq.interface.model.classical_if import ClassicalIf
8
9
  from classiq.interface.model.control import Control
9
10
  from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
@@ -41,12 +42,14 @@ ConcreteQuantumStatement = Annotated[
41
42
  Control,
42
43
  WithinApply,
43
44
  PhaseOperation,
45
+ Block,
44
46
  ],
45
47
  Field(..., discriminator="kind"),
46
48
  ]
47
49
 
48
50
  StatementBlock = list[ConcreteQuantumStatement]
49
51
 
52
+ Block.model_rebuild()
50
53
  Control.model_rebuild()
51
54
  QuantumLambdaFunction.model_rebuild()
52
55
  Repeat.model_rebuild()
@@ -1,5 +1,6 @@
1
1
  from typing import Literal
2
2
 
3
+ from classiq.interface.generator.expressions.expression import Expression
3
4
  from classiq.interface.model.quantum_statement import QuantumStatement
4
5
  from classiq.interface.model.quantum_variable_declaration import (
5
6
  QuantumVariableDeclaration,
@@ -8,3 +9,7 @@ from classiq.interface.model.quantum_variable_declaration import (
8
9
 
9
10
  class VariableDeclarationStatement(QuantumStatement, QuantumVariableDeclaration):
10
11
  kind: Literal["VariableDeclarationStatement"]
12
+
13
+ @property
14
+ def expressions(self) -> list[Expression]:
15
+ return self.quantum_type.expressions
@@ -43,8 +43,6 @@ TASKS_VISUAL_MODEL_SUFFIX = TASKS_SUFFIX + "/visual_model"
43
43
  TASKS_SOLVE_SUFFIX = "/tasks/solve"
44
44
 
45
45
  CHEMISTRY_QMOD_PATH = "/generate_model/chemistry/qmod"
46
- GROVER_QMOD_PATH = "/generate_model/grover/qmod"
47
- FINANCE_QMOD_PATH = "/generate_model/finance/qmod"
48
46
 
49
47
 
50
48
  TASK_TRAIN_SUFFIX = TASKS_SUFFIX + "/train"
@@ -1,8 +1,8 @@
1
1
  from collections.abc import Mapping
2
2
  from enum import Enum
3
- from typing import Any, Callable, Union
3
+ from typing import Any, Callable, Union, get_args
4
4
 
5
- from sympy import Eq, Expr, Number, Piecewise, Symbol
5
+ from sympy import Eq, Expr, Piecewise, Symbol
6
6
 
7
7
  from classiq.interface.exceptions import (
8
8
  ClassiqExpansionError,
@@ -12,6 +12,9 @@ from classiq.interface.generator.expressions.expression_types import (
12
12
  ExpressionValue,
13
13
  QmodStructInstance,
14
14
  )
15
+ from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
16
+ AnyClassicalValue,
17
+ )
15
18
  from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
16
19
  QmodQNumProxy,
17
20
  )
@@ -54,6 +57,10 @@ from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
54
57
  from classiq.model_expansions.sympy_conversion.sympy_to_python import (
55
58
  sympy_to_python,
56
59
  )
60
+ from classiq.model_expansions.utils.sympy_utils import (
61
+ is_constant_subscript,
62
+ unwrap_sympy_numeric,
63
+ )
57
64
  from classiq.qmod.model_state_container import QMODULE
58
65
 
59
66
 
@@ -151,9 +158,13 @@ def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInsta
151
158
 
152
159
 
153
160
  def get_field(
154
- proxy: Union[QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list],
161
+ proxy: Union[
162
+ QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list, AnyClassicalValue
163
+ ],
155
164
  field: str,
156
165
  ) -> ExpressionValue:
166
+ if isinstance(proxy, AnyClassicalValue):
167
+ return AnyClassicalValue(f"({proxy}).{field}")
157
168
  if isinstance(proxy, type) and issubclass(proxy, Enum):
158
169
  return getattr(proxy, field)
159
170
  if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
@@ -189,20 +200,25 @@ def get_type(struct_type: Symbol) -> TypeProxy:
189
200
  return TypeProxy(QMODULE.type_decls[struct_type.name])
190
201
 
191
202
 
192
- def _unwrap_sympy_numeric(n: Any) -> Any:
193
- if not isinstance(n, Number) or not n.is_constant():
194
- return n
195
- if n.is_Integer:
196
- return int(n)
197
- return float(n)
198
-
199
-
200
203
  def do_div(lhs: Any, rhs: Any) -> Any:
201
- lhs = _unwrap_sympy_numeric(lhs)
202
- rhs = _unwrap_sympy_numeric(rhs)
204
+ lhs = unwrap_sympy_numeric(lhs)
205
+ rhs = unwrap_sympy_numeric(rhs)
203
206
  return lhs / rhs
204
207
 
205
208
 
209
+ _EXPRESSION_TYPES = get_args(ExpressionValue)
210
+
211
+
212
+ def _is_qmod_value(val: Any) -> bool:
213
+ if not isinstance(val, slice):
214
+ return isinstance(val, _EXPRESSION_TYPES)
215
+ if val.start is not None and not isinstance(val.start, _EXPRESSION_TYPES):
216
+ return False
217
+ if val.stop is not None and not isinstance(val.stop, _EXPRESSION_TYPES):
218
+ return False
219
+ return val.step is None or isinstance(val.step, _EXPRESSION_TYPES)
220
+
221
+
206
222
  def do_subscript(value: Any, index: Any) -> Any:
207
223
  if not isinstance(value, list) or not isinstance(index, QmodQNumProxy):
208
224
  if isinstance(index, (QmodSizedProxy, QmodStructInstance)):
@@ -214,6 +230,12 @@ def do_subscript(value: Any, index: Any) -> Any:
214
230
  f"\t2. `l[n]`, where `l` is a list of classical real numbers and `n` "
215
231
  f"is a classical or quantum integer."
216
232
  )
233
+ if (
234
+ isinstance(value, list)
235
+ and not is_constant_subscript(index)
236
+ and _is_qmod_value(index)
237
+ ):
238
+ return AnyClassicalValue(str(value))[index]
217
239
  return value[index]
218
240
  if index.is_signed or index.fraction_digits > 0:
219
241
  raise ClassiqExpansionError(