classiq 0.60.1__py3-none-any.whl → 0.62.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 (108) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/_internals/client.py +6 -1
  3. classiq/applications/__init__.py +1 -1
  4. classiq/applications/chemistry/__init__.py +7 -7
  5. classiq/applications/chemistry/chemistry_model_constructor.py +17 -6
  6. classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
  7. classiq/applications/combinatorial_helpers/pyomo_utils.py +60 -9
  8. classiq/applications/combinatorial_optimization/__init__.py +7 -1
  9. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
  10. classiq/applications/combinatorial_optimization/combinatorial_problem.py +230 -0
  11. classiq/applications/finance/finance_model_constructor.py +6 -6
  12. classiq/applications/grover/grover_model_constructor.py +3 -0
  13. classiq/applications/libraries/qmci_library.py +1 -10
  14. classiq/applications/qnn/__init__.py +1 -1
  15. classiq/applications/qnn/datasets/__init__.py +8 -8
  16. classiq/applications/qsvm/qsvm.py +1 -1
  17. classiq/execution/__init__.py +0 -2
  18. classiq/execution/execution_session.py +6 -0
  19. classiq/execution/jobs.py +9 -1
  20. classiq/executor.py +1 -1
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/backend/backend_preferences.py +33 -15
  23. classiq/interface/backend/quantum_backend_providers.py +3 -1
  24. classiq/interface/executor/execution_preferences.py +1 -1
  25. classiq/interface/generator/application_apis/chemistry_declarations.py +1 -1
  26. classiq/interface/generator/application_apis/finance_declarations.py +2 -2
  27. classiq/interface/generator/arith/arithmetic.py +16 -1
  28. classiq/interface/generator/arith/arithmetic_expression_validator.py +4 -3
  29. classiq/interface/generator/copy.py +47 -0
  30. classiq/interface/generator/expressions/expression_constants.py +3 -0
  31. classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
  32. classiq/interface/generator/generated_circuit_data.py +58 -20
  33. classiq/interface/generator/model/__init__.py +1 -1
  34. classiq/interface/generator/model/preferences/preferences.py +1 -1
  35. classiq/interface/generator/model/quantum_register.py +3 -3
  36. classiq/interface/generator/standard_gates/controlled_standard_gates.py +20 -32
  37. classiq/interface/generator/types/compilation_metadata.py +2 -1
  38. classiq/interface/ide/visual_model.py +1 -0
  39. classiq/interface/interface_version.py +1 -1
  40. classiq/interface/model/model.py +2 -3
  41. classiq/interface/model/quantum_function_call.py +4 -7
  42. classiq/interface/model/quantum_function_declaration.py +7 -0
  43. classiq/interface/model/quantum_lambda_function.py +10 -1
  44. classiq/interface/model/quantum_type.py +3 -1
  45. classiq/model_expansions/atomic_expression_functions_defs.py +3 -1
  46. classiq/model_expansions/capturing/captured_vars.py +36 -17
  47. classiq/model_expansions/capturing/mangling_utils.py +23 -15
  48. classiq/model_expansions/closure.py +6 -9
  49. classiq/model_expansions/evaluators/arg_type_match.py +7 -7
  50. classiq/model_expansions/expression_evaluator.py +5 -2
  51. classiq/model_expansions/function_builder.py +26 -4
  52. classiq/model_expansions/generative_functions.py +13 -91
  53. classiq/model_expansions/interpreter.py +75 -46
  54. classiq/model_expansions/quantum_operations/call_emitter.py +42 -29
  55. classiq/model_expansions/quantum_operations/classicalif.py +1 -1
  56. classiq/model_expansions/quantum_operations/control.py +5 -31
  57. classiq/model_expansions/quantum_operations/emitter.py +29 -17
  58. classiq/model_expansions/quantum_operations/expression_operation.py +3 -5
  59. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +57 -15
  60. classiq/model_expansions/quantum_operations/invert.py +1 -6
  61. classiq/model_expansions/quantum_operations/phase.py +2 -5
  62. classiq/model_expansions/quantum_operations/power.py +0 -4
  63. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +19 -30
  64. classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -2
  65. classiq/model_expansions/quantum_operations/shallow_emitter.py +161 -0
  66. classiq/model_expansions/quantum_operations/within_apply.py +0 -14
  67. classiq/model_expansions/scope.py +12 -16
  68. classiq/model_expansions/scope_initialization.py +0 -11
  69. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +7 -0
  70. classiq/model_expansions/sympy_conversion/sympy_to_python.py +12 -2
  71. classiq/model_expansions/transformers/ast_renamer.py +26 -0
  72. classiq/model_expansions/transformers/var_splitter.py +11 -12
  73. classiq/model_expansions/visitors/variable_references.py +20 -12
  74. classiq/qmod/builtins/classical_execution_primitives.py +6 -6
  75. classiq/qmod/builtins/classical_functions.py +10 -10
  76. classiq/qmod/builtins/functions/__init__.py +89 -103
  77. classiq/qmod/builtins/functions/amplitude_estimation.py +1 -1
  78. classiq/qmod/builtins/functions/arithmetic.py +1 -1
  79. classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +6 -6
  80. classiq/qmod/builtins/functions/grover.py +5 -5
  81. classiq/qmod/builtins/functions/hea.py +1 -1
  82. classiq/qmod/builtins/functions/linear_pauli_rotation.py +2 -2
  83. classiq/qmod/builtins/functions/modular_exponentiation.py +8 -8
  84. classiq/qmod/builtins/functions/operators.py +1 -1
  85. classiq/qmod/builtins/functions/qaoa_penalty.py +5 -5
  86. classiq/qmod/builtins/functions/qft_functions.py +2 -2
  87. classiq/qmod/builtins/functions/qpe.py +9 -12
  88. classiq/qmod/builtins/functions/qsvt.py +177 -15
  89. classiq/qmod/builtins/functions/state_preparation.py +9 -9
  90. classiq/qmod/builtins/functions/swap_test.py +1 -1
  91. classiq/qmod/builtins/functions/utility_functions.py +2 -2
  92. classiq/qmod/builtins/functions/variational.py +2 -2
  93. classiq/qmod/builtins/operations.py +22 -83
  94. classiq/qmod/builtins/structs.py +9 -9
  95. classiq/qmod/native/pretty_printer.py +17 -19
  96. classiq/qmod/pretty_print/pretty_printer.py +9 -6
  97. classiq/qmod/python_classical_type.py +1 -5
  98. classiq/qmod/qmod_variable.py +2 -5
  99. classiq/qmod/quantum_expandable.py +20 -5
  100. classiq/qmod/quantum_function.py +23 -10
  101. classiq/qmod/semantics/static_semantics_visitor.py +34 -16
  102. classiq/qmod/semantics/validation/func_call_validation.py +9 -5
  103. classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
  104. classiq/qmod/symbolic.py +47 -47
  105. {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/METADATA +2 -1
  106. {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/RECORD +107 -103
  107. classiq/execution/qaoa.py +0 -86
  108. {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/WHEEL +0 -0
classiq/execution/jobs.py CHANGED
@@ -112,7 +112,15 @@ class ExecutionJob:
112
112
  )
113
113
  return cls(details)
114
114
 
115
- from_id = syncify_function(from_id_async)
115
+ # `syncify_function` doesn't work well for class methods, so I wrote `from_id`
116
+ # explicitly
117
+ @classmethod
118
+ def from_id(
119
+ cls,
120
+ id: str,
121
+ _http_client: Optional[httpx.AsyncClient] = None,
122
+ ) -> "ExecutionJob":
123
+ return syncify_function(cls.from_id_async)(id, _http_client=_http_client)
116
124
 
117
125
  @property
118
126
  def _job_id(self) -> JobID:
classiq/executor.py CHANGED
@@ -62,8 +62,8 @@ def set_quantum_program_execution_preferences(
62
62
 
63
63
 
64
64
  __all__ = [
65
+ "OperatorsEstimation",
65
66
  "QuantumCode",
66
67
  "QuantumInstructionSet",
67
- "OperatorsEstimation",
68
68
  "set_quantum_program_execution_preferences",
69
69
  ]
@@ -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.60.1'
6
+ SEMVER_VERSION = '0.62.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -161,6 +161,20 @@ class ClassiqBackendPreferences(BackendPreferences):
161
161
  def is_nvidia_backend(self) -> bool:
162
162
  return self.backend_name in list(ClassiqNvidiaBackendNames)
163
163
 
164
+ # CAD-25390
165
+ @pydantic.field_validator("backend_name")
166
+ @classmethod
167
+ def _validate_nvidia_name_backwards_compatibility(cls, backend_name: str) -> str:
168
+ if backend_name == "nvidia_state_vector_simulator":
169
+ warnings.warn(
170
+ "The name 'nvidia_state_vector_simulator' is deprecated and "
171
+ "will be removed soon, no earlier than January 12th 2025. "
172
+ "Please use ClassiqNvidiaBackendNames.SIMULATOR instead",
173
+ ClassiqDeprecationWarning,
174
+ stacklevel=2,
175
+ )
176
+ return backend_name
177
+
164
178
 
165
179
  class AwsBackendPreferences(BackendPreferences):
166
180
  """
@@ -196,13 +210,17 @@ class AwsBackendPreferences(BackendPreferences):
196
210
  backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET = pydantic.Field(
197
211
  default=ProviderVendor.AMAZON_BRAKET
198
212
  )
199
- aws_role_arn: pydantic_backend.PydanticAwsRoleArn = pydantic.Field(
213
+ aws_role_arn: Optional[pydantic_backend.PydanticAwsRoleArn] = pydantic.Field(
200
214
  description="ARN of the role to be assumed for execution on your Braket account."
201
215
  )
202
- s3_bucket_name: str = pydantic.Field(description="S3 Bucket Name")
203
- s3_folder: pydantic_backend.PydanticS3BucketKey = pydantic.Field(
216
+ s3_bucket_name: Optional[str] = pydantic.Field(description="S3 Bucket Name")
217
+ s3_folder: Optional[pydantic_backend.PydanticS3BucketKey] = pydantic.Field(
204
218
  description="S3 Folder Path Within The S3 Bucket"
205
219
  )
220
+ run_through_classiq: bool = pydantic.Field(
221
+ default=False,
222
+ description="Run through Classiq's credentials while using user's allocated budget.",
223
+ )
206
224
 
207
225
  @pydantic.field_validator("s3_bucket_name", mode="before")
208
226
  @classmethod
@@ -513,25 +531,25 @@ BackendPreferencesTypes = Union[
513
531
  ]
514
532
 
515
533
  __all__ = [
534
+ "AQTBackendPreferences",
535
+ "AliceBobBackendNames",
536
+ "AliceBobBackendPreferences",
537
+ "AmazonBraketBackendNames",
538
+ "AwsBackendPreferences",
516
539
  "AzureBackendPreferences",
517
540
  "AzureCredential",
518
541
  "AzureQuantumBackendNames",
519
542
  "ClassiqBackendPreferences",
543
+ "ClassiqNvidiaBackendNames",
520
544
  "ClassiqSimulatorBackendNames",
545
+ "GCPBackendPreferences",
521
546
  "IBMBackendPreferences",
522
547
  "IBMBackendProvider",
523
- "AwsBackendPreferences",
524
- "AmazonBraketBackendNames",
525
- "IonqBackendPreferences",
526
- "IonqBackendNames",
527
- "ClassiqNvidiaBackendNames",
548
+ "IQCCBackendPreferences",
528
549
  "IntelBackendNames",
529
- "GCPBackendPreferences",
530
- "AliceBobBackendPreferences",
531
- "AliceBobBackendNames",
532
- "OQCBackendPreferences",
533
- "OQCBackendNames",
534
550
  "IntelBackendPreferences",
535
- "AQTBackendPreferences",
536
- "IQCCBackendPreferences",
551
+ "IonqBackendNames",
552
+ "IonqBackendPreferences",
553
+ "OQCBackendNames",
554
+ "OQCBackendPreferences",
537
555
  ]
@@ -170,7 +170,8 @@ class ClassiqNvidiaBackendNames(StrEnum):
170
170
  Classiq's Nvidia simulator backend names.
171
171
  """
172
172
 
173
- SIMULATOR = "nvidia_state_vector_simulator"
173
+ SIMULATOR = "nvidia_simulator"
174
+ SIMULATOR_STATEVECTOR = "nvidia_simulator_statevector"
174
175
 
175
176
 
176
177
  class IntelBackendNames(StrEnum):
@@ -186,6 +187,7 @@ class GoogleNvidiaBackendNames(StrEnum):
186
187
  """
187
188
 
188
189
  CUQUANTUM = "cuquantum"
190
+ CUQUANTUM_STATEVECTOR = "cuquantum_statevector"
189
191
 
190
192
 
191
193
  class AliceBobBackendNames(StrEnum):
@@ -65,7 +65,7 @@ class ExecutionPreferences(pydantic.BaseModel):
65
65
 
66
66
  __all__ = [
67
67
  "ExecutionPreferences",
68
- "OptimizerType",
69
68
  "NoiseProperties",
69
+ "OptimizerType",
70
70
  "QaeWithQpeEstimationMethod",
71
71
  ]
@@ -61,7 +61,7 @@ MOLECULE_GROUND_STATE_SOLUTION_POST_PROCESS = ClassicalFunctionDeclaration(
61
61
  )
62
62
 
63
63
  __all__ = [
64
- "MOLECULE_PROBLEM_TO_HAMILTONIAN",
65
64
  "FOCK_HAMILTONIAN_PROBLEM_TO_HAMILTONIAN",
66
65
  "MOLECULE_GROUND_STATE_SOLUTION_POST_PROCESS",
66
+ "MOLECULE_PROBLEM_TO_HAMILTONIAN",
67
67
  ]
@@ -98,8 +98,8 @@ GAUSSIAN_FINANCE_POST_PROCESS = ClassicalFunctionDeclaration(
98
98
  )
99
99
 
100
100
  __all__ = [
101
- "LOG_NORMAL_FINANCE_FUNCTION",
102
101
  "GAUSSIAN_FINANCE_FUNCTION",
103
- "LOG_NORMAL_FINANCE_POST_PROCESS",
104
102
  "GAUSSIAN_FINANCE_POST_PROCESS",
103
+ "LOG_NORMAL_FINANCE_FUNCTION",
104
+ "LOG_NORMAL_FINANCE_POST_PROCESS",
105
105
  ]
@@ -9,6 +9,9 @@ from classiq.interface.generator.arith import arithmetic_expression_parser
9
9
  from classiq.interface.generator.arith.arithmetic_expression_abc import (
10
10
  ArithmeticExpressionABC,
11
11
  )
12
+ from classiq.interface.generator.arith.arithmetic_expression_validator import (
13
+ is_constant,
14
+ )
12
15
  from classiq.interface.generator.arith.arithmetic_param_getters import (
13
16
  id2op,
14
17
  operation_allows_target,
@@ -17,7 +20,9 @@ from classiq.interface.generator.arith.arithmetic_result_builder import (
17
20
  ArithmeticResultBuilder,
18
21
  )
19
22
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
23
+ from classiq.interface.generator.expressions.expression import Expression
20
24
  from classiq.interface.model.quantum_type import (
25
+ QuantumNumeric,
21
26
  QuantumType,
22
27
  quantum_var_to_register,
23
28
  register_info_to_quantum_type,
@@ -28,6 +33,10 @@ ARITHMETIC_EXPRESSION_RESULT_NAME: Final[str] = "expression_result"
28
33
  ARITHMETIC_EXPRESSION_GARBAGE_NAME: Final[str] = "expression_garbage"
29
34
 
30
35
 
36
+ def is_zero(expr: str) -> bool:
37
+ return is_constant(expr) and float(expr) == 0
38
+
39
+
31
40
  class Arithmetic(ArithmeticExpressionABC):
32
41
  target: Optional[RegisterArithmeticInfo] = None
33
42
  inputs_to_save: set[str] = pydantic.Field(default_factory=set)
@@ -99,7 +108,13 @@ def get_arithmetic_params(
99
108
 
100
109
  def compute_arithmetic_result_type(
101
110
  expr_str: str, var_types: dict[str, QuantumType], machine_precision: int
102
- ) -> QuantumType:
111
+ ) -> QuantumNumeric:
112
+ if is_zero(expr_str):
113
+ return QuantumNumeric(
114
+ size=Expression(expr="1"),
115
+ is_signed=Expression(expr="False"),
116
+ fraction_digits=Expression(expr="0"),
117
+ )
103
118
  arith_param = get_arithmetic_params(expr_str, var_types, machine_precision)
104
119
  return register_info_to_quantum_type(
105
120
  arith_param.outputs[ARITHMETIC_EXPRESSION_RESULT_NAME]
@@ -3,6 +3,7 @@ import re
3
3
  from _ast import AST
4
4
  from typing import Any, Optional, Union
5
5
 
6
+ from sympy import Expr
6
7
  from typing_extensions import TypeAlias, get_args
7
8
 
8
9
  from classiq.interface.exceptions import ClassiqArithmeticError, ClassiqValueError
@@ -54,11 +55,11 @@ SupportedNodesTypes = Union[
54
55
  DEFAULT_SUPPORTED_NODE_TYPES = get_args(SupportedNodesTypes)
55
56
 
56
57
 
57
- def _is_constant(expr: str) -> bool:
58
+ def is_constant(expr: Union[str, Expr]) -> bool:
58
59
  try:
59
60
  float(expr)
60
61
  return True
61
- except ValueError:
62
+ except (ValueError, TypeError):
62
63
  return False
63
64
 
64
65
 
@@ -94,7 +95,7 @@ class ExpressionValidator(ast.NodeVisitor):
94
95
  @staticmethod
95
96
  def _get_adjusted_expression(expression: str) -> str:
96
97
  # This works around the simplification of the trivial expressions such as a + 0, 1 * a, etc.
97
- if IDENITIFIER_REGEX.fullmatch(expression) or _is_constant(expression):
98
+ if IDENITIFIER_REGEX.fullmatch(expression) or is_constant(expression):
98
99
  return f"0 + {expression}"
99
100
  return expression
100
101
 
@@ -0,0 +1,47 @@
1
+ from typing import Optional
2
+
3
+ import pydantic
4
+
5
+ from classiq.interface.generator.arith import argument_utils
6
+ from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
7
+ from classiq.interface.generator.function_params import FunctionParams
8
+
9
+
10
+ class Copy(FunctionParams):
11
+ source: argument_utils.RegisterOrConst
12
+ target: RegisterArithmeticInfo
13
+ output_size: Optional[pydantic.PositiveInt] = pydantic.Field(default=None)
14
+
15
+ @property
16
+ def source_size(self) -> int:
17
+ return argument_utils.size(self.source)
18
+
19
+ @property
20
+ def source_reg_size(self) -> int:
21
+ return (
22
+ self.source.size if isinstance(self.source, RegisterArithmeticInfo) else 0
23
+ )
24
+
25
+ @property
26
+ def source_fraction_places(self) -> int:
27
+ return argument_utils.fraction_places(self.source)
28
+
29
+ @property
30
+ def offset(self) -> int:
31
+ return self.target.fraction_places - self.source_fraction_places
32
+
33
+ @property
34
+ def source_name(self) -> str:
35
+ return "source"
36
+
37
+ @property
38
+ def target_name(self) -> str:
39
+ return "target"
40
+
41
+ def _create_ios(self) -> None:
42
+ self._inputs = {
43
+ self.target_name: self.target,
44
+ }
45
+ if isinstance(self.source, RegisterArithmeticInfo):
46
+ self._inputs[self.source_name] = self.source
47
+ self._outputs = {**self._inputs}
@@ -20,3 +20,6 @@ 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
+ )
@@ -28,6 +28,7 @@ from classiq.interface.generator.arith.unary_ops import BitwiseInvert, Negation,
28
28
  from classiq.interface.generator.commuting_pauli_exponentiation import (
29
29
  CommutingPauliExponentiation,
30
30
  )
31
+ from classiq.interface.generator.copy import Copy
31
32
  from classiq.interface.generator.entangler_params import (
32
33
  GridEntangler,
33
34
  HypercubeEntangler,
@@ -148,6 +149,7 @@ function_param_library_without_self_reference: FunctionParamLibrary = (
148
149
  PiecewiseLinearAmplitudeLoading,
149
150
  PiecewiseLinearRotationAmplitudeLoading,
150
151
  HadamardTransform,
152
+ Copy,
151
153
  },
152
154
  standard_gate_function_param_library.param_list,
153
155
  oracle_function_param_library.param_list,
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Literal, Optional, Union
2
+ from typing import Literal, Optional, Union
3
3
 
4
4
  import pydantic
5
5
  from pydantic import ConfigDict
@@ -12,6 +12,12 @@ from classiq.interface.generator.synthesis_metadata.synthesis_execution_data imp
12
12
  ExecutionData,
13
13
  )
14
14
 
15
+ from classiq.model_expansions.capturing.mangling_utils import (
16
+ demangle_capture_name,
17
+ demangle_name,
18
+ is_captured_var_name,
19
+ )
20
+
15
21
  _logger = logging.getLogger(__name__)
16
22
  ParameterName = str
17
23
  IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
@@ -52,6 +58,16 @@ class GeneratedRegister(pydantic.BaseModel):
52
58
  def width(self) -> int:
53
59
  return len(self)
54
60
 
61
+ @property
62
+ def is_captured(self) -> bool:
63
+ return is_captured_var_name(self.name)
64
+
65
+ @staticmethod
66
+ def demangle_name(name: str) -> str:
67
+ if is_captured_var_name(name):
68
+ return demangle_capture_name(name)
69
+ return demangle_name(name)
70
+
55
71
 
56
72
  class GeneratedFunction(pydantic.BaseModel):
57
73
  name: str
@@ -157,32 +173,54 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
157
173
  for key, value in parameters.items()
158
174
  ]
159
175
 
160
- def update(self, **kwargs: Any) -> None:
161
- for key, value in kwargs.items():
162
- setattr(self, key, value)
163
-
164
- def propagate_absolute_qubits(self) -> None:
176
+ def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
165
177
  if self.absolute_qubits is None:
166
- return
167
-
168
- for register in self.registers:
169
- register.qubit_indexes_absolute = list(
170
- _get_absolute_from_relative(
171
- self.absolute_qubits, tuple(register.qubit_indexes_relative)
178
+ return self
179
+
180
+ updated_registers = [
181
+ register.model_copy(
182
+ update=dict(
183
+ qubit_indexes_absolute=list(
184
+ _get_absolute_from_relative(
185
+ self.absolute_qubits, tuple(register.qubit_indexes_relative)
186
+ )
187
+ )
172
188
  )
173
189
  )
190
+ for register in self.registers
191
+ ]
192
+ updated_generated_function = (
193
+ self.generated_function.model_copy(update=dict(registers=updated_registers))
194
+ if self.generated_function
195
+ else None
196
+ )
174
197
 
198
+ updated_children: list[FunctionDebugInfoInterface] = []
175
199
  for child in self.children:
176
- child.absolute_qubits = _get_absolute_from_relative(
177
- self.absolute_qubits, child.relative_qubits
200
+ updated_child = child.model_copy(
201
+ update=dict(
202
+ absolute_qubits=_get_absolute_from_relative(
203
+ self.absolute_qubits, child.relative_qubits
204
+ )
205
+ )
178
206
  )
179
- child.propagate_absolute_qubits()
207
+ updated_children.append(updated_child.propagate_absolute_qubits())
180
208
 
181
- def inverse(self) -> None:
182
- self.is_inverse = not self.is_inverse
183
- for child in self.children:
184
- child.inverse()
185
- self.children = self.children[::-1]
209
+ return self.model_copy(
210
+ update=dict(
211
+ generated_function=updated_generated_function,
212
+ children=updated_children,
213
+ )
214
+ )
215
+
216
+ def inverse(self) -> "FunctionDebugInfoInterface":
217
+ inverted_children = [child.inverse() for child in self.children[::-1]]
218
+ return self.model_copy(
219
+ update=dict(
220
+ is_inverse=not self.is_inverse,
221
+ children=inverted_children,
222
+ )
223
+ )
186
224
 
187
225
 
188
226
  def _get_absolute_from_relative(
@@ -10,8 +10,8 @@ from classiq.interface.generator.model.preferences import (
10
10
 
11
11
  __all__: list[str] = [
12
12
  "Constraints",
13
- "Preferences",
14
13
  "CustomHardwareSettings",
15
14
  "OptimizationParameter",
15
+ "Preferences",
16
16
  "TranspilerBasisGates",
17
17
  ]
@@ -156,7 +156,7 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
156
156
  )
157
157
  synthesize_all_separately: bool = pydantic.Field(
158
158
  default=False,
159
- description="If true, all functions will be synthesized separately",
159
+ description="If true, a heuristic is used to determine if a function should be synthesized separately",
160
160
  )
161
161
  output_format: PydanticConstrainedQuantumFormatList = pydantic.Field(
162
162
  default=[QuantumFormat.QASM],
@@ -250,11 +250,11 @@ def get_type_and_size_dict(
250
250
 
251
251
 
252
252
  __all__ = [
253
+ "AuxQReg",
253
254
  "QReg",
254
- "QSInt",
255
- "QUInt",
256
255
  "QSFixed",
256
+ "QSInt",
257
257
  "QUFixed",
258
+ "QUInt",
258
259
  "ZeroQReg",
259
- "AuxQReg",
260
260
  ]
@@ -26,26 +26,6 @@ class ControlledGate(_StandardGate): # type: ignore[misc]
26
26
  num_ctrl_qubits: pydantic.PositiveInt = pydantic.Field(
27
27
  default=DEFAULT_NUM_CTRL_QUBITS
28
28
  )
29
-
30
- def _create_ios(self) -> None:
31
- _StandardGate._create_ios(self)
32
- control = RegisterUserInput(
33
- name=CONTROLLED_GATE_CONTROL, size=self.num_ctrl_qubits
34
- )
35
- self._inputs[CONTROLLED_GATE_CONTROL] = control
36
- self._outputs[CONTROLLED_GATE_CONTROL] = control
37
-
38
- def to_control_state(self) -> ControlState:
39
- return ControlState(
40
- name=CONTROLLED_GATE_CONTROL, num_ctrl_qubits=self.num_ctrl_qubits
41
- )
42
-
43
-
44
- class ControlledGateWithState(ControlledGate): # type: ignore[misc]
45
- """
46
- Base model for controlled Gates with control over the controlled_state
47
- """
48
-
49
29
  ctrl_state: CtrlState = pydantic.Field(
50
30
  description="The control state in decimal or as a bit string (e.g. '1011'). If not specified, the control "
51
31
  "state is 2**num_ctrl_qubits - 1.\n"
@@ -82,12 +62,20 @@ class ControlledGateWithState(ControlledGate): # type: ignore[misc]
82
62
  )
83
63
  return ControlState(name=CONTROLLED_GATE_CONTROL, ctrl_state=ctrl_state_str)
84
64
 
65
+ def _create_ios(self) -> None:
66
+ _StandardGate._create_ios(self)
67
+ control = RegisterUserInput(
68
+ name=CONTROLLED_GATE_CONTROL, size=self.num_ctrl_qubits
69
+ )
70
+ self._inputs[CONTROLLED_GATE_CONTROL] = control
71
+ self._outputs[CONTROLLED_GATE_CONTROL] = control
72
+
85
73
 
86
74
  def _num_to_control_string(ctrl_state_int: int, num_ctrl_qubits: int) -> str:
87
75
  return format(ctrl_state_int, f"0{num_ctrl_qubits}b")
88
76
 
89
77
 
90
- class CXGate(ControlledGateWithState): # type: ignore[misc]
78
+ class CXGate(ControlledGate): # type: ignore[misc]
91
79
  """
92
80
  The Controlled-X Gate
93
81
  """
@@ -98,7 +86,7 @@ class CXGate(ControlledGateWithState): # type: ignore[misc]
98
86
  return 2
99
87
 
100
88
 
101
- class CCXGate(ControlledGateWithState): # type: ignore[misc]
89
+ class CCXGate(ControlledGate): # type: ignore[misc]
102
90
  """
103
91
  The Double Controlled-X Gate
104
92
  """
@@ -109,7 +97,7 @@ class CCXGate(ControlledGateWithState): # type: ignore[misc]
109
97
  return 2
110
98
 
111
99
 
112
- class C3XGate(ControlledGateWithState): # type: ignore[misc]
100
+ class C3XGate(ControlledGate): # type: ignore[misc]
113
101
  """
114
102
  The X Gate controlled on 3 qubits
115
103
  """
@@ -121,7 +109,7 @@ class C3XGate(ControlledGateWithState): # type: ignore[misc]
121
109
  return 2
122
110
 
123
111
 
124
- class C4XGate(ControlledGateWithState): # type: ignore[misc]
112
+ class C4XGate(ControlledGate): # type: ignore[misc]
125
113
  """
126
114
  The X Gate controlled on 4 qubits
127
115
  """
@@ -133,7 +121,7 @@ class C4XGate(ControlledGateWithState): # type: ignore[misc]
133
121
  return 2
134
122
 
135
123
 
136
- class CYGate(ControlledGateWithState): # type: ignore[misc]
124
+ class CYGate(ControlledGate): # type: ignore[misc]
137
125
  """
138
126
  The Controlled-Y Gate
139
127
  """
@@ -142,7 +130,7 @@ class CYGate(ControlledGateWithState): # type: ignore[misc]
142
130
  return 2
143
131
 
144
132
 
145
- class CZGate(ControlledGateWithState): # type: ignore[misc]
133
+ class CZGate(ControlledGate): # type: ignore[misc]
146
134
  """
147
135
  The Controlled-Z Gate
148
136
  """
@@ -151,7 +139,7 @@ class CZGate(ControlledGateWithState): # type: ignore[misc]
151
139
  return 2
152
140
 
153
141
 
154
- class CHGate(ControlledGateWithState): # type: ignore[misc]
142
+ class CHGate(ControlledGate): # type: ignore[misc]
155
143
  """
156
144
  The Controlled-H Gate
157
145
  """
@@ -160,7 +148,7 @@ class CHGate(ControlledGateWithState): # type: ignore[misc]
160
148
  return 2
161
149
 
162
150
 
163
- class CSXGate(ControlledGateWithState): # type: ignore[misc]
151
+ class CSXGate(ControlledGate): # type: ignore[misc]
164
152
  """
165
153
  The Controlled-SX Gate
166
154
  """
@@ -169,25 +157,25 @@ class CSXGate(ControlledGateWithState): # type: ignore[misc]
169
157
  return 4
170
158
 
171
159
 
172
- class CRXGate(ControlledGateWithState, angles=["theta"]): # type: ignore[misc]
160
+ class CRXGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
173
161
  """
174
162
  The Controlled-RX Gate
175
163
  """
176
164
 
177
165
 
178
- class CRYGate(ControlledGateWithState, angles=["theta"]): # type: ignore[misc]
166
+ class CRYGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
179
167
  """
180
168
  The Controlled-RY Gate
181
169
  """
182
170
 
183
171
 
184
- class CRZGate(ControlledGateWithState, angles=["theta"]): # type: ignore[misc]
172
+ class CRZGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
185
173
  """
186
174
  The Controlled-RZ Gate
187
175
  """
188
176
 
189
177
 
190
- class CPhaseGate(ControlledGateWithState, angles=["theta"]): # type: ignore[misc]
178
+ class CPhaseGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
191
179
  """
192
180
  The Controlled-Phase Gate
193
181
  """
@@ -1,5 +1,6 @@
1
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel, Field, NonNegativeInt
2
2
 
3
3
 
4
4
  class CompilationMetadata(BaseModel):
5
5
  should_synthesize_separately: bool = Field(default=False)
6
+ occurrences_number: NonNegativeInt = Field(default=1)
@@ -42,6 +42,7 @@ class OperationLink(pydantic.BaseModel):
42
42
  inner_label: Optional[str] = None
43
43
  qubits: tuple[int, ...]
44
44
  type: str
45
+ is_captured: bool = False
45
46
 
46
47
  model_config = ConfigDict(frozen=True)
47
48
 
@@ -1 +1 @@
1
- INTERFACE_VERSION = "5"
1
+ INTERFACE_VERSION = "6"
@@ -180,9 +180,8 @@ class Model(VersionedModel, ASTNode):
180
180
  )
181
181
  return constants
182
182
 
183
- def json_no_preferences_and_constraints(self) -> str:
184
- return self.model_dump_json(
185
- indent=2,
183
+ def dump_no_preferences_and_constraints(self) -> dict[str, Any]:
184
+ return self.model_dump(
186
185
  exclude={
187
186
  "constraints",
188
187
  "execution_preferences",
@@ -7,7 +7,6 @@ from typing import (
7
7
 
8
8
  import pydantic
9
9
 
10
- from classiq.interface.ast_node import ASTNode
11
10
  from classiq.interface.exceptions import ClassiqError, ClassiqValueError
12
11
  from classiq.interface.generator.expressions.expression import Expression
13
12
  from classiq.interface.generator.functions.port_declaration import (
@@ -21,7 +20,10 @@ from classiq.interface.model.port_declaration import AnonPortDeclaration
21
20
  from classiq.interface.model.quantum_function_declaration import (
22
21
  QuantumFunctionDeclaration,
23
22
  )
24
- from classiq.interface.model.quantum_lambda_function import QuantumOperand
23
+ from classiq.interface.model.quantum_lambda_function import (
24
+ OperandIdentifier,
25
+ QuantumOperand,
26
+ )
25
27
  from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
26
28
 
27
29
  ArgValue = Union[
@@ -31,11 +33,6 @@ ArgValue = Union[
31
33
  ]
32
34
 
33
35
 
34
- class OperandIdentifier(ASTNode):
35
- name: str
36
- index: Expression
37
-
38
-
39
36
  class QuantumFunctionCall(QuantumOperation):
40
37
  kind: Literal["QuantumFunctionCall"]
41
38