classiq 0.86.0__py3-none-any.whl → 0.87.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 (96) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/applications/chemistry/hartree_fock.py +5 -1
  3. classiq/applications/chemistry/op_utils.py +2 -2
  4. classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
  5. classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
  6. classiq/applications/combinatorial_helpers/memory.py +4 -4
  7. classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
  8. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
  9. classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
  10. classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
  11. classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
  12. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
  13. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
  14. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
  15. classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
  16. classiq/applications/hamiltonian/pauli_decomposition.py +33 -1
  17. classiq/evaluators/argument_types.py +15 -6
  18. classiq/evaluators/parameter_types.py +43 -39
  19. classiq/evaluators/qmod_annotated_expression.py +88 -11
  20. classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
  21. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +54 -11
  22. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +40 -25
  23. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +29 -59
  24. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +12 -5
  25. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
  26. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +21 -14
  27. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +9 -5
  28. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +20 -1
  29. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
  30. classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
  31. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
  32. classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
  33. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +2 -3
  34. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +48 -21
  35. classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
  36. classiq/evaluators/qmod_node_evaluators/utils.py +27 -5
  37. classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
  38. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +292 -0
  39. classiq/evaluators/quantum_type_utils.py +0 -131
  40. classiq/execution/execution_session.py +1 -1
  41. classiq/execution/qnn.py +4 -1
  42. classiq/execution/user_budgets.py +1 -1
  43. classiq/interface/_version.py +1 -1
  44. classiq/interface/backend/backend_preferences.py +10 -30
  45. classiq/interface/backend/quantum_backend_providers.py +63 -52
  46. classiq/interface/generator/arith/binary_ops.py +107 -115
  47. classiq/interface/generator/arith/extremum_operations.py +33 -45
  48. classiq/interface/generator/arith/number_utils.py +4 -1
  49. classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
  50. classiq/interface/generator/compiler_keywords.py +2 -0
  51. classiq/interface/generator/function_param_list.py +133 -5
  52. classiq/interface/generator/functions/classical_type.py +59 -2
  53. classiq/interface/generator/functions/qmod_python_interface.py +15 -0
  54. classiq/interface/generator/functions/type_name.py +6 -0
  55. classiq/interface/generator/model/preferences/preferences.py +1 -17
  56. classiq/interface/generator/quantum_program.py +1 -13
  57. classiq/interface/helpers/model_normalizer.py +2 -2
  58. classiq/interface/helpers/text_utils.py +7 -2
  59. classiq/interface/interface_version.py +1 -1
  60. classiq/interface/model/classical_if.py +40 -0
  61. classiq/interface/model/handle_binding.py +28 -16
  62. classiq/interface/model/quantum_type.py +61 -2
  63. classiq/interface/pretty_print/expression_to_qmod.py +24 -11
  64. classiq/interface/pyomo_extension/__init__.py +0 -4
  65. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
  66. classiq/model_expansions/arithmetic.py +43 -1
  67. classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
  68. classiq/model_expansions/capturing/captured_vars.py +2 -5
  69. classiq/model_expansions/quantum_operations/allocate.py +22 -15
  70. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
  71. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
  72. classiq/model_expansions/quantum_operations/bind.py +15 -7
  73. classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
  74. classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
  75. classiq/open_library/functions/__init__.py +3 -0
  76. classiq/open_library/functions/lcu.py +117 -0
  77. classiq/qmod/builtins/enums.py +2 -2
  78. classiq/qmod/builtins/structs.py +33 -18
  79. classiq/qmod/pretty_print/expression_to_python.py +7 -9
  80. {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/METADATA +3 -3
  81. {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/RECORD +83 -89
  82. classiq/interface/generator/amplitude_estimation.py +0 -34
  83. classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
  84. classiq/interface/generator/grover_diffuser.py +0 -93
  85. classiq/interface/generator/grover_operator.py +0 -106
  86. classiq/interface/generator/oracles/__init__.py +0 -3
  87. classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
  88. classiq/interface/generator/oracles/custom_oracle.py +0 -65
  89. classiq/interface/generator/oracles/oracle_abc.py +0 -76
  90. classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
  91. classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
  92. classiq/interface/generator/qpe.py +0 -169
  93. classiq/interface/grover/grover_modelling_params.py +0 -13
  94. classiq/model_expansions/transformers/var_splitter.py +0 -224
  95. /classiq/{interface/grover → evaluators/qmod_type_inference}/__init__.py +0 -0
  96. {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/WHEEL +0 -0
@@ -3,7 +3,6 @@ from typing_extensions import TypeAlias
3
3
  from classiq.interface.enum_utils import StrEnum
4
4
  from classiq.interface.executor.quantum_instruction_set import QuantumInstructionSet
5
5
  from classiq.interface.generator.model.preferences.preferences import QuantumFormat
6
- from classiq.interface.hardware import Provider
7
6
 
8
7
  Code: TypeAlias = str
9
8
  CodeAndSyntax: TypeAlias = tuple[Code, QuantumInstructionSet]
@@ -14,14 +13,6 @@ INSTRUCTION_SET_TO_FORMAT: dict[QuantumInstructionSet, QuantumFormat] = {
14
13
  QuantumInstructionSet.IONQ: QuantumFormat.IONQ,
15
14
  QuantumInstructionSet.INTERNAL: QuantumFormat.EXECUTION_SERIALIZATION,
16
15
  }
17
- VENDOR_TO_INSTRUCTION_SET: dict[Provider, QuantumInstructionSet] = {
18
- Provider.CLASSIQ: QuantumInstructionSet.QASM,
19
- Provider.IONQ: QuantumInstructionSet.IONQ,
20
- Provider.AZURE_QUANTUM: QuantumInstructionSet.QSHARP,
21
- Provider.IBM_QUANTUM: QuantumInstructionSet.QASM,
22
- Provider.AMAZON_BRAKET: QuantumInstructionSet.QASM,
23
- }
24
- DEFAULT_INSTRUCTION_SET = QuantumInstructionSet.QASM
25
16
  _MAXIMUM_STRING_LENGTH = 250
26
17
 
27
18
 
@@ -2,6 +2,8 @@ EXPANDED_KEYWORD = "expanded__"
2
2
  CAPTURE_SUFFIX = "_captured__"
3
3
  LAMBDA_KEYWORD = "lambda__"
4
4
  INPLACE_ARITH_AUX_VAR_PREFIX = "_tmp"
5
+ THEN_KEYWORD = "then"
6
+ ELSE_KEYWORD = "else"
5
7
 
6
8
 
7
9
  def generate_original_function_name(name: str) -> str:
@@ -1,14 +1,142 @@
1
1
  import itertools
2
2
 
3
+ from classiq.interface.generator.amplitude_loading import AmplitudeLoading
4
+ from classiq.interface.generator.arith.arithmetic import Arithmetic
5
+ from classiq.interface.generator.arith.binary_ops import (
6
+ Adder,
7
+ BitwiseAnd,
8
+ BitwiseOr,
9
+ BitwiseXor,
10
+ CyclicShift,
11
+ Equal,
12
+ GreaterEqual,
13
+ GreaterThan,
14
+ LessEqual,
15
+ LessThan,
16
+ LShift,
17
+ Modulo,
18
+ Multiplier,
19
+ NotEqual,
20
+ Power,
21
+ RShift,
22
+ Subtractor,
23
+ )
24
+ from classiq.interface.generator.arith.extremum_operations import Max, Min
25
+ from classiq.interface.generator.arith.logical_ops import LogicalAnd, LogicalOr
26
+ from classiq.interface.generator.arith.unary_ops import BitwiseInvert, Negation, Sign
27
+ from classiq.interface.generator.commuting_pauli_exponentiation import (
28
+ CommutingPauliExponentiation,
29
+ )
30
+ from classiq.interface.generator.copy import Copy
31
+ from classiq.interface.generator.entangler_params import (
32
+ GridEntangler,
33
+ HypercubeEntangler,
34
+ TwoDimensionalEntangler,
35
+ )
36
+ from classiq.interface.generator.finance import Finance, FinanceModels, FinancePayoff
3
37
  from classiq.interface.generator.function_param_library import FunctionParamLibrary
4
- from classiq.interface.generator.function_param_list_without_self_reference import (
5
- function_param_library_without_self_reference,
38
+ from classiq.interface.generator.hadamard_transform import HadamardTransform
39
+ from classiq.interface.generator.hamiltonian_evolution.exponentiation import (
40
+ Exponentiation,
41
+ )
42
+ from classiq.interface.generator.hamiltonian_evolution.qdrift import QDrift
43
+ from classiq.interface.generator.hamiltonian_evolution.suzuki_trotter import (
44
+ SuzukiTrotter,
45
+ )
46
+ from classiq.interface.generator.hardware_efficient_ansatz import (
47
+ HardwareEfficientAnsatz,
48
+ )
49
+ from classiq.interface.generator.hartree_fock import HartreeFock
50
+ from classiq.interface.generator.hva import HVA
51
+ from classiq.interface.generator.identity import Identity
52
+ from classiq.interface.generator.linear_pauli_rotations import LinearPauliRotations
53
+ from classiq.interface.generator.mcu import Mcu
54
+ from classiq.interface.generator.mcx import Mcx
55
+ from classiq.interface.generator.qft import QFT
56
+ from classiq.interface.generator.qsvm import QSVMFeatureMap
57
+ from classiq.interface.generator.randomized_benchmarking import RandomizedBenchmarking
58
+ from classiq.interface.generator.reset import Reset
59
+ from classiq.interface.generator.standard_gates.standard_gates_param_list import (
60
+ standard_gate_function_param_library,
61
+ )
62
+ from classiq.interface.generator.standard_gates.u_gate import UGate
63
+ from classiq.interface.generator.state_preparation import (
64
+ BellStatePreparation,
65
+ ComputationalBasisStatePreparation,
66
+ ExponentialStatePreparation,
67
+ GHZStatePreparation,
68
+ StatePreparation,
69
+ UniformDistributionStatePreparation,
70
+ WStatePreparation,
6
71
  )
7
- from classiq.interface.generator.qpe import PhaseEstimation
72
+ from classiq.interface.generator.ucc import UCC
73
+ from classiq.interface.generator.unitary_gate import UnitaryGate
74
+ from classiq.interface.generator.user_defined_function_params import CustomFunction
8
75
 
9
76
  function_param_library: FunctionParamLibrary = FunctionParamLibrary(
10
77
  param_list=itertools.chain(
11
- function_param_library_without_self_reference.param_list,
12
- {PhaseEstimation},
78
+ {
79
+ StatePreparation,
80
+ ComputationalBasisStatePreparation,
81
+ UniformDistributionStatePreparation,
82
+ BellStatePreparation,
83
+ GHZStatePreparation,
84
+ WStatePreparation,
85
+ ExponentialStatePreparation,
86
+ QFT,
87
+ BitwiseAnd,
88
+ BitwiseOr,
89
+ BitwiseXor,
90
+ BitwiseInvert,
91
+ Adder,
92
+ Arithmetic,
93
+ Sign,
94
+ Equal,
95
+ NotEqual,
96
+ GreaterThan,
97
+ GreaterEqual,
98
+ LessThan,
99
+ LessEqual,
100
+ Negation,
101
+ LogicalAnd,
102
+ LogicalOr,
103
+ Subtractor,
104
+ RShift,
105
+ LShift,
106
+ CyclicShift,
107
+ Modulo,
108
+ TwoDimensionalEntangler,
109
+ Finance,
110
+ FinanceModels,
111
+ FinancePayoff,
112
+ HypercubeEntangler,
113
+ GridEntangler,
114
+ Mcx,
115
+ Mcu,
116
+ CustomFunction,
117
+ HardwareEfficientAnsatz,
118
+ UnitaryGate,
119
+ LinearPauliRotations,
120
+ Multiplier,
121
+ Power,
122
+ HartreeFock,
123
+ UCC,
124
+ Min,
125
+ Max,
126
+ Exponentiation,
127
+ CommutingPauliExponentiation,
128
+ SuzukiTrotter,
129
+ QDrift,
130
+ Identity,
131
+ RandomizedBenchmarking,
132
+ HVA,
133
+ UGate,
134
+ AmplitudeLoading,
135
+ QSVMFeatureMap,
136
+ HadamardTransform,
137
+ Copy,
138
+ Reset,
139
+ },
140
+ standard_gate_function_param_library.param_list,
13
141
  )
14
142
  )
@@ -58,6 +58,14 @@ class ClassicalType(HashableASTNode):
58
58
  def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
59
59
  return ClassicalScalarProxy(handle, self)
60
60
 
61
+ @property
62
+ def qmod_type_name(self) -> str:
63
+ raise NotImplementedError
64
+
65
+ @property
66
+ def raw_qmod_type_name(self) -> str:
67
+ return self.qmod_type_name
68
+
61
69
  @property
62
70
  def expressions(self) -> list[Expression]:
63
71
  return []
@@ -79,6 +87,10 @@ class Integer(ClassicalType):
79
87
  def _set_kind(cls, values: Any) -> dict[str, Any]:
80
88
  return values_with_discriminator(values, "kind", "int")
81
89
 
90
+ @property
91
+ def qmod_type_name(self) -> str:
92
+ return "CInt"
93
+
82
94
 
83
95
  class Real(ClassicalType):
84
96
  kind: Literal["real"]
@@ -88,6 +100,10 @@ class Real(ClassicalType):
88
100
  def _set_kind(cls, values: Any) -> dict[str, Any]:
89
101
  return values_with_discriminator(values, "kind", "real")
90
102
 
103
+ @property
104
+ def qmod_type_name(self) -> str:
105
+ return "CReal"
106
+
91
107
 
92
108
  class Bool(ClassicalType):
93
109
  kind: Literal["bool"]
@@ -97,6 +113,10 @@ class Bool(ClassicalType):
97
113
  def _set_kind(cls, values: Any) -> dict[str, Any]:
98
114
  return values_with_discriminator(values, "kind", "bool")
99
115
 
116
+ @property
117
+ def qmod_type_name(self) -> str:
118
+ return "CBool"
119
+
100
120
 
101
121
  class StructMetaType(ClassicalType):
102
122
  kind: Literal["type_proxy"]
@@ -163,6 +183,18 @@ class ClassicalArray(ClassicalType):
163
183
  raw_type.set_generative()
164
184
  return raw_type
165
185
 
186
+ @property
187
+ def qmod_type_name(self) -> str:
188
+ if self.length is None:
189
+ length = ""
190
+ else:
191
+ length = f", {self.length.expr}"
192
+ return f"CArray[{self.element_type.qmod_type_name}{length}]"
193
+
194
+ @property
195
+ def raw_qmod_type_name(self) -> str:
196
+ return "CArray"
197
+
166
198
 
167
199
  class ClassicalTuple(ClassicalType):
168
200
  kind: Literal["tuple"]
@@ -196,10 +228,24 @@ class ClassicalTuple(ClassicalType):
196
228
  element_type.is_purely_generative for element_type in self.element_types
197
229
  )
198
230
 
199
- def get_raw_type(self) -> "ConcreteClassicalType":
231
+ def get_raw_type(self, *, preserve_length: bool = False) -> "ConcreteClassicalType":
200
232
  if len(self.element_types) == 0:
201
233
  return self
202
- raw_type = ClassicalArray(element_type=self.element_types[0].get_raw_type())
234
+ chosen_element = self.element_types[0]
235
+ for element in self.element_types:
236
+ if (
237
+ not isinstance(element, ClassicalTuple)
238
+ or len(element.element_types) > 0
239
+ ):
240
+ chosen_element = element
241
+ break
242
+ if preserve_length:
243
+ length = Expression(expr=str(len(self.element_types)))
244
+ else:
245
+ length = None
246
+ raw_type = ClassicalArray(
247
+ element_type=chosen_element.get_raw_type(), length=length
248
+ )
203
249
  if self._is_generative:
204
250
  raw_type.set_generative()
205
251
  return raw_type
@@ -208,6 +254,17 @@ class ClassicalTuple(ClassicalType):
208
254
  def length(self) -> int:
209
255
  return len(self.element_types)
210
256
 
257
+ @property
258
+ def qmod_type_name(self) -> str:
259
+ raw_type = self.get_raw_type(preserve_length=True)
260
+ if isinstance(raw_type, ClassicalTuple):
261
+ return "CArray[0]"
262
+ return raw_type.qmod_type_name
263
+
264
+ @property
265
+ def raw_qmod_type_name(self) -> str:
266
+ return "CArray"
267
+
211
268
 
212
269
  class OpaqueHandle(ClassicalType):
213
270
  pass
@@ -1,4 +1,19 @@
1
1
  from collections.abc import Mapping
2
2
  from typing import Any
3
3
 
4
+ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
5
+ QmodStructInstance,
6
+ )
7
+
4
8
  QmodPyStruct = Mapping[str, Any]
9
+
10
+
11
+ def qmod_value_to_dict(qmod_value: Any) -> Any:
12
+ if isinstance(qmod_value, QmodStructInstance):
13
+ return {
14
+ field_name: qmod_value_to_dict(field_value)
15
+ for field_name, field_value in qmod_value.fields.items()
16
+ }
17
+ if isinstance(qmod_value, list):
18
+ return [qmod_value_to_dict(item) for item in qmod_value]
19
+ return qmod_value
@@ -177,6 +177,12 @@ class TypeName(ClassicalType, QuantumType):
177
177
  raw_type.set_classical_struct_decl(raw_decl)
178
178
  return raw_type
179
179
 
180
+ @property
181
+ def minimal_size_in_bits(self) -> int:
182
+ return sum(
183
+ field_type.minimal_size_in_bits for field_type in self.fields.values()
184
+ )
185
+
180
186
 
181
187
  class Enum(TypeName):
182
188
  pass
@@ -50,14 +50,6 @@ class QuantumFormat(StrEnum):
50
50
  EXECUTION_SERIALIZATION = "_execution_serialization"
51
51
 
52
52
 
53
- _SERVICE_PROVIDER_TO_FORMAT: dict[Provider, QuantumFormat] = {
54
- Provider.CLASSIQ: QuantumFormat.QASM,
55
- Provider.IONQ: QuantumFormat.IONQ,
56
- Provider.AZURE_QUANTUM: QuantumFormat.QSHARP,
57
- Provider.IBM_QUANTUM: QuantumFormat.QASM,
58
- Provider.AMAZON_BRAKET: QuantumFormat.QASM,
59
- }
60
-
61
53
  if TYPE_CHECKING:
62
54
  PydanticConstrainedQuantumFormatList = list[QuantumFormat]
63
55
  else:
@@ -176,7 +168,7 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
176
168
  deprecated=True,
177
169
  )
178
170
  optimization_level: OptimizationLevel = pydantic.Field(
179
- default=OptimizationLevel.HIGH,
171
+ default=OptimizationLevel.LIGHT,
180
172
  description="The optimization level used during synthesis; determines the trade-off between synthesis speed and the quality of the results",
181
173
  )
182
174
  output_format: PydanticConstrainedQuantumFormatList = pydantic.Field(
@@ -260,14 +252,6 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
260
252
  "has at least one format that appears twice or more"
261
253
  )
262
254
 
263
- service_provider = info.data.get("backend_service_provider")
264
- if service_provider is None:
265
- return output_format
266
-
267
- provider_format = _SERVICE_PROVIDER_TO_FORMAT.get(service_provider)
268
- if provider_format is not None and provider_format not in output_format:
269
- output_format.append(provider_format)
270
-
271
255
  return output_format
272
256
 
273
257
  @pydantic.field_validator("backend_name")
@@ -19,9 +19,7 @@ from classiq.interface.executor.quantum_instruction_set import QuantumInstructio
19
19
  from classiq.interface.executor.register_initialization import RegisterInitialization
20
20
  from classiq.interface.generator.circuit_code.circuit_code import CircuitCodeInterface
21
21
  from classiq.interface.generator.circuit_code.types_and_constants import (
22
- DEFAULT_INSTRUCTION_SET,
23
22
  INSTRUCTION_SET_TO_FORMAT,
24
- VENDOR_TO_INSTRUCTION_SET,
25
23
  CodeAndSyntax,
26
24
  )
27
25
  from classiq.interface.generator.generated_circuit_data import (
@@ -82,7 +80,7 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
82
80
  def __str__(self) -> str:
83
81
  return self.model_dump_json(indent=2)
84
82
 
85
- def _hardware_agnostic_program_code(self) -> CodeAndSyntax:
83
+ def _default_program_code(self) -> CodeAndSyntax:
86
84
  circuit_code = self.program_circuit.get_code_by_priority()
87
85
  if circuit_code is not None:
88
86
  return circuit_code
@@ -91,16 +89,6 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
91
89
  missing_formats=list(INSTRUCTION_SET_TO_FORMAT.values())
92
90
  )
93
91
 
94
- def _default_program_code(self) -> CodeAndSyntax:
95
- if self.hardware_data.backend_data is None:
96
- return self._hardware_agnostic_program_code()
97
-
98
- backend_provider = self.hardware_data.backend_data.hw_provider
99
- instruction_set: QuantumInstructionSet = VENDOR_TO_INSTRUCTION_SET.get(
100
- backend_provider, DEFAULT_INSTRUCTION_SET
101
- )
102
- return self.program_circuit.get_code(instruction_set), instruction_set
103
-
104
92
  def to_base_program(self) -> quantum_code.QuantumBaseCode:
105
93
  code, syntax = self._default_program_code()
106
94
  return quantum_code.QuantumBaseCode(code=code, syntax=syntax)
@@ -37,8 +37,8 @@ class ModelNormalizer(Visitor):
37
37
 
38
38
  class ClearModelInternals(Transformer):
39
39
  def visit_Expression(self, expr: Expression) -> Expression:
40
- if expr._evaluated_expr is not None and not expr._evaluated_expr.is_constant():
41
- expr._evaluated_expr = None
40
+ expr._evaluated_expr = None
41
+ expr._try_to_immediate_evaluate()
42
42
  return expr
43
43
 
44
44
  def visit_ClassicalType(self, classical_type: ClassicalType) -> ClassicalType:
@@ -1,5 +1,10 @@
1
- def s(items: list) -> str:
2
- return "" if len(items) == 1 else "s"
1
+ from typing import Union
2
+
3
+
4
+ def s(items: Union[list, int]) -> str:
5
+ if isinstance(items, list):
6
+ items = len(items)
7
+ return "" if items == 1 else "s"
3
8
 
4
9
 
5
10
  def are(items: list) -> str:
@@ -1 +1 @@
1
- INTERFACE_VERSION = "11"
1
+ INTERFACE_VERSION = "12"
@@ -1,7 +1,11 @@
1
+ import functools
2
+ import operator
3
+ from collections.abc import Mapping
1
4
  from typing import TYPE_CHECKING, Literal
2
5
 
3
6
  from classiq.interface.ast_node import ASTNodeType, reset_lists
4
7
  from classiq.interface.generator.expressions.expression import Expression
8
+ from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
5
9
  from classiq.interface.model.quantum_statement import QuantumOperation
6
10
 
7
11
  if TYPE_CHECKING:
@@ -21,3 +25,39 @@ class ClassicalIf(QuantumOperation):
21
25
  @property
22
26
  def expressions(self) -> list[Expression]:
23
27
  return [self.condition]
28
+
29
+ @property
30
+ def wiring_inputs(self) -> Mapping[str, HandleBinding]:
31
+ return functools.reduce(
32
+ operator.ior,
33
+ (
34
+ op.wiring_inputs
35
+ for op in (*self.then, *self.else_)
36
+ if isinstance(op, QuantumOperation)
37
+ ),
38
+ dict(),
39
+ )
40
+
41
+ @property
42
+ def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
43
+ return functools.reduce(
44
+ operator.ior,
45
+ (
46
+ op.wiring_inouts
47
+ for op in (*self.then, *self.else_)
48
+ if isinstance(op, QuantumOperation)
49
+ ),
50
+ dict(),
51
+ )
52
+
53
+ @property
54
+ def wiring_outputs(self) -> Mapping[str, HandleBinding]:
55
+ return functools.reduce(
56
+ operator.ior,
57
+ (
58
+ op.wiring_outputs
59
+ for op in (*self.then, *self.else_)
60
+ if isinstance(op, QuantumOperation)
61
+ ),
62
+ dict(),
63
+ )
@@ -156,7 +156,12 @@ class SubscriptHandleBinding(NestedHandleBinding):
156
156
  def _get_collapsed_index(self) -> Expression:
157
157
  if TYPE_CHECKING:
158
158
  assert isinstance(self.base_handle, SlicedHandleBinding)
159
- if self.index.is_evaluated() and self.base_handle.start.is_evaluated():
159
+ if (
160
+ self.index.is_evaluated()
161
+ and self.index.is_constant()
162
+ and self.base_handle.start.is_evaluated()
163
+ and self.base_handle.start.is_constant()
164
+ ):
160
165
  return Expression(
161
166
  expr=str(
162
167
  self.base_handle.start.to_int_value() + self.index.to_int_value()
@@ -170,7 +175,8 @@ class SubscriptHandleBinding(NestedHandleBinding):
170
175
  if (
171
176
  isinstance(other_handle, SlicedHandleBinding)
172
177
  and self.index.is_evaluated()
173
- and other_handle._is_evaluated()
178
+ and self.index.is_constant()
179
+ and other_handle.is_constant()
174
180
  ):
175
181
  return (
176
182
  other_handle.start.to_int_value()
@@ -186,7 +192,8 @@ class SubscriptHandleBinding(NestedHandleBinding):
186
192
  isinstance(prefix, SlicedHandleBinding)
187
193
  and self.base_handle == prefix.base_handle
188
194
  and self.index.is_evaluated()
189
- and prefix._is_evaluated()
195
+ and self.index.is_constant()
196
+ and prefix.is_constant()
190
197
  and prefix.start.to_int_value()
191
198
  <= self.index.to_int_value()
192
199
  < prefix.end.to_int_value()
@@ -243,19 +250,17 @@ class SlicedHandleBinding(NestedHandleBinding):
243
250
  )
244
251
 
245
252
  def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
246
- if not self._is_evaluated():
253
+ if not self.is_constant():
247
254
  return False
248
255
  start = self.start.to_int_value()
249
256
  end = self.end.to_int_value()
250
257
  if (
251
258
  isinstance(other_handle, SubscriptHandleBinding)
252
259
  and other_handle.index.is_evaluated()
260
+ and other_handle.index.is_constant()
253
261
  ):
254
262
  return start <= other_handle.index.to_int_value() < end
255
- if (
256
- isinstance(other_handle, SlicedHandleBinding)
257
- and other_handle._is_evaluated()
258
- ):
263
+ if isinstance(other_handle, SlicedHandleBinding) and other_handle.is_constant():
259
264
  other_start = other_handle.start.to_int_value()
260
265
  other_end = other_handle.end.to_int_value()
261
266
  return start <= other_start < end or other_start <= start < other_end
@@ -264,7 +269,12 @@ class SlicedHandleBinding(NestedHandleBinding):
264
269
  def _get_collapsed_start(self) -> Expression:
265
270
  if TYPE_CHECKING:
266
271
  assert isinstance(self.base_handle, SlicedHandleBinding)
267
- if self.start.is_evaluated() and self.base_handle.start.is_evaluated():
272
+ if (
273
+ self.start.is_evaluated()
274
+ and self.start.is_constant()
275
+ and self.base_handle.start.is_evaluated()
276
+ and self.base_handle.start.is_constant()
277
+ ):
268
278
  return Expression(
269
279
  expr=str(
270
280
  self.base_handle.start.to_int_value() + self.start.to_int_value()
@@ -275,7 +285,11 @@ class SlicedHandleBinding(NestedHandleBinding):
275
285
  def _get_collapsed_stop(self) -> Expression:
276
286
  if TYPE_CHECKING:
277
287
  assert isinstance(self.base_handle, SlicedHandleBinding)
278
- if self._is_evaluated() and self.base_handle.start.is_evaluated():
288
+ if (
289
+ self.is_constant()
290
+ and self.base_handle.start.is_evaluated()
291
+ and self.base_handle.start.is_constant()
292
+ ):
279
293
  return Expression(
280
294
  expr=str(
281
295
  self.end.to_int_value()
@@ -295,8 +309,8 @@ class SlicedHandleBinding(NestedHandleBinding):
295
309
  if (
296
310
  isinstance(prefix, SlicedHandleBinding)
297
311
  and self.base_handle == prefix.base_handle
298
- and self._is_evaluated()
299
- and prefix._is_evaluated()
312
+ and self.is_constant()
313
+ and prefix.is_constant()
300
314
  ):
301
315
  prefix_start = prefix.start.to_int_value()
302
316
  prefix_end = prefix.end.to_int_value()
@@ -313,14 +327,12 @@ class SlicedHandleBinding(NestedHandleBinding):
313
327
  )
314
328
  return super().replace_prefix(prefix, replacement)
315
329
 
316
- def _is_evaluated(self) -> bool:
317
- return self.start.is_evaluated() and self.end.is_evaluated()
318
-
319
330
  def is_constant(self) -> bool:
320
331
  return (
321
332
  super().is_constant()
322
- and self._is_evaluated()
333
+ and self.start.is_evaluated()
323
334
  and self.start.is_constant()
335
+ and self.end.is_evaluated()
324
336
  and self.end.is_constant()
325
337
  )
326
338