classiq 0.74.0__py3-none-any.whl → 0.75.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 (37) hide show
  1. classiq/analyzer/show_interactive_hack.py +1 -1
  2. classiq/applications/qnn/qlayer.py +9 -0
  3. classiq/interface/_version.py +1 -1
  4. classiq/interface/debug_info/debug_info.py +2 -11
  5. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +5 -5
  6. classiq/interface/generator/expressions/proxies/classical/utils.py +2 -2
  7. classiq/interface/generator/functions/classical_type.py +30 -0
  8. classiq/interface/generator/functions/type_name.py +25 -3
  9. classiq/interface/generator/generated_circuit_data.py +11 -25
  10. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +10 -13
  11. classiq/interface/helpers/versioned_model.py +12 -0
  12. classiq/interface/interface_version.py +1 -1
  13. classiq/interface/model/handle_binding.py +12 -0
  14. classiq/interface/model/statement_block.py +9 -1
  15. classiq/interface/model/within_apply_operation.py +12 -0
  16. classiq/model_expansions/atomic_expression_functions_defs.py +24 -8
  17. classiq/model_expansions/closure.py +13 -0
  18. classiq/model_expansions/evaluators/argument_types.py +6 -5
  19. classiq/model_expansions/evaluators/type_type_match.py +2 -2
  20. classiq/model_expansions/generative_functions.py +14 -8
  21. classiq/model_expansions/interpreters/base_interpreter.py +10 -13
  22. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +21 -0
  23. classiq/model_expansions/interpreters/generative_interpreter.py +12 -0
  24. classiq/model_expansions/quantum_operations/allocate.py +22 -11
  25. classiq/model_expansions/quantum_operations/assignment_result_processor.py +2 -0
  26. classiq/model_expansions/quantum_operations/call_emitter.py +0 -5
  27. classiq/model_expansions/quantum_operations/emitter.py +1 -5
  28. classiq/model_expansions/quantum_operations/expression_evaluator.py +1 -0
  29. classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -0
  30. classiq/model_expansions/transformers/model_renamer.py +3 -1
  31. classiq/model_expansions/visitors/symbolic_param_inference.py +197 -0
  32. classiq/qmod/qmod_variable.py +23 -1
  33. classiq/qmod/symbolic_expr.py +8 -2
  34. classiq/qmod/write_qmod.py +5 -1
  35. {classiq-0.74.0.dist-info → classiq-0.75.0.dist-info}/METADATA +1 -1
  36. {classiq-0.74.0.dist-info → classiq-0.75.0.dist-info}/RECORD +37 -36
  37. {classiq-0.74.0.dist-info → classiq-0.75.0.dist-info}/WHEEL +1 -1
@@ -4,21 +4,42 @@ import os
4
4
  from pydantic import ValidationError
5
5
 
6
6
  from classiq.interface.exceptions import ClassiqError
7
+ from classiq.interface.model.allocate import Allocate
8
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
7
9
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
10
+ from classiq.interface.model.quantum_function_declaration import (
11
+ NamedParamsQuantumFunctionDeclaration,
12
+ )
8
13
  from classiq.interface.source_reference import SourceReference
9
14
 
10
15
  from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
11
16
  from classiq.model_expansions.interpreters.generative_interpreter import (
12
17
  GenerativeInterpreter,
13
18
  )
19
+ from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
14
20
  from classiq.model_expansions.quantum_operations.quantum_function_call import (
15
21
  DeclarativeQuantumFunctionCallEmitter,
16
22
  )
17
23
  from classiq.model_expansions.scope import Scope
24
+ from classiq.model_expansions.visitors.symbolic_param_inference import (
25
+ SymbolicParamInference,
26
+ )
18
27
  from classiq.qmod.model_state_container import QMODULE
19
28
 
20
29
 
21
30
  class FrontendGenerativeInterpreter(GenerativeInterpreter):
31
+ def infer_symbolic_parameters(
32
+ self,
33
+ functions: list[NativeFunctionDefinition],
34
+ additional_signatures: (
35
+ list[NamedParamsQuantumFunctionDeclaration] | None
36
+ ) = None,
37
+ ) -> None:
38
+ SymbolicParamInference(functions, additional_signatures).infer()
39
+
40
+ def emit_allocate(self, allocate: Allocate) -> None:
41
+ AllocateEmitter(self, allow_symbolic_size=True).emit(allocate)
42
+
22
43
  def emit_quantum_function_call(self, call: QuantumFunctionCall) -> None:
23
44
  DeclarativeQuantumFunctionCallEmitter(self).emit(call)
24
45
 
@@ -93,6 +93,18 @@ class GenerativeInterpreter(BaseInterpreter):
93
93
  add_generative_functions_to_scope(
94
94
  generative_functions, self._top_level_scope, override_atomic=True
95
95
  )
96
+ self.infer_symbolic_parameters(
97
+ model.functions, [gen_func.func_decl for gen_func in generative_functions]
98
+ )
99
+
100
+ def infer_symbolic_parameters(
101
+ self,
102
+ functions: list[NativeFunctionDefinition],
103
+ additional_signatures: (
104
+ list[NamedParamsQuantumFunctionDeclaration] | None
105
+ ) = None,
106
+ ) -> None:
107
+ pass
96
108
 
97
109
  def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
98
110
  func_decl = NamedParamsQuantumFunctionDeclaration(
@@ -1,7 +1,10 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ import sympy
4
+
1
5
  from classiq.interface.debug_info.debug_info import FunctionDebugInfo
2
6
  from classiq.interface.exceptions import ClassiqValueError
3
7
  from classiq.interface.generator.expressions.expression import Expression
4
- from classiq.interface.generator.generated_circuit_data import OperationLevel
5
8
  from classiq.interface.model.allocate import Allocate
6
9
  from classiq.interface.model.handle_binding import NestedHandleBinding
7
10
  from classiq.interface.model.quantum_type import QuantumBitvector
@@ -10,8 +13,17 @@ from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_inf
10
13
  from classiq.model_expansions.quantum_operations.emitter import Emitter
11
14
  from classiq.model_expansions.scope import QuantumSymbol
12
15
 
16
+ if TYPE_CHECKING:
17
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
18
+
13
19
 
14
20
  class AllocateEmitter(Emitter[Allocate]):
21
+ def __init__(
22
+ self, interpreter: "BaseInterpreter", allow_symbolic_size: bool = False
23
+ ) -> None:
24
+ super().__init__(interpreter)
25
+ self._allow_symbolic_size = allow_symbolic_size
26
+
15
27
  def emit(self, allocate: Allocate, /) -> bool:
16
28
  target: QuantumSymbol = self._interpreter.evaluate(allocate.target).as_type(
17
29
  QuantumSymbol
@@ -22,10 +34,10 @@ class AllocateEmitter(Emitter[Allocate]):
22
34
  f"Cannot allocate partial quantum variable {str(target.handle)!r}"
23
35
  )
24
36
 
25
- size = self._get_var_size(target, allocate.size)
37
+ size_expr = self._get_var_size(target, allocate.size)
26
38
  allocate = allocate.model_copy(
27
39
  update=dict(
28
- size=Expression(expr=str(size)),
40
+ size=Expression(expr=size_expr),
29
41
  target=target.handle,
30
42
  back_ref=allocate.uuid,
31
43
  )
@@ -34,27 +46,29 @@ class AllocateEmitter(Emitter[Allocate]):
34
46
  self.emit_statement(allocate)
35
47
  return True
36
48
 
37
- def _get_var_size(self, target: QuantumSymbol, size: Expression | None) -> int:
49
+ def _get_var_size(self, target: QuantumSymbol, size: Expression | None) -> str:
38
50
  if size is None:
39
51
  if not target.quantum_type.is_evaluated:
40
52
  raise ClassiqValueError(
41
53
  f"Could not infer the size of variable {str(target.handle)!r}"
42
54
  )
43
- return target.quantum_type.size_in_bits
55
+ return str(target.quantum_type.size_in_bits)
44
56
 
45
57
  size_value = self._interpreter.evaluate(size).value
58
+ if self._allow_symbolic_size and isinstance(size_value, sympy.Basic):
59
+ return str(size_value)
46
60
  if not isinstance(size_value, (int, float)):
47
61
  raise ClassiqValueError(
48
62
  f"The number of allocated qubits must be an integer. Got "
49
63
  f"{str(size_value)!r}"
50
64
  )
51
- size_value = int(size_value)
65
+ size_expr = str(size_value)
52
66
  copy_type_information(
53
- QuantumBitvector(length=Expression(expr=str(size_value))),
67
+ QuantumBitvector(length=Expression(expr=size_expr)),
54
68
  target.quantum_type,
55
69
  str(target.handle),
56
70
  )
57
- return size_value
71
+ return size_expr
58
72
 
59
73
  def _register_debug_info(self, allocate: Allocate) -> None:
60
74
  if (
@@ -67,9 +81,6 @@ class AllocateEmitter(Emitter[Allocate]):
67
81
  parameters["num_qubits"] = allocate.size.expr
68
82
  self._debug_info[allocate.uuid] = FunctionDebugInfo(
69
83
  name="allocate",
70
- parameters=parameters,
71
- level=OperationLevel.QMOD_STATEMENT,
72
- is_allocate_or_free=True,
73
84
  port_to_passed_variable_map={"ARG": str(allocate.target)},
74
85
  node=allocate._as_back_ref(),
75
86
  )
@@ -36,6 +36,8 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
36
36
 
37
37
  def _update_result_type(self, op: ArithmeticOperation) -> None:
38
38
  expr = self._evaluate_expression(op.expression)
39
+ if len(self._get_classical_vars_in_expression(expr)):
40
+ return
39
41
  symbols = self._get_symbols_in_expression(expr)
40
42
  expr_str = rename_variables(
41
43
  expr.expr,
@@ -24,7 +24,6 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
24
24
  from classiq.interface.generator.functions.port_declaration import (
25
25
  PortDeclarationDirection,
26
26
  )
27
- from classiq.interface.generator.generated_circuit_data import OperationLevel
28
27
  from classiq.interface.model.classical_parameter_declaration import (
29
28
  ClassicalParameterDeclaration,
30
29
  )
@@ -63,7 +62,6 @@ from classiq.model_expansions.quantum_operations.emitter import (
63
62
  from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
64
63
  from classiq.model_expansions.transformers.var_splitter import VarSplitter
65
64
  from classiq.model_expansions.utils.text_utils import are, readable_list, s
66
- from classiq.qmod.builtins.functions import free
67
65
  from classiq.qmod.semantics.validation.signature_validation import (
68
66
  validate_function_signature,
69
67
  )
@@ -188,7 +186,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
188
186
  positional_args=new_positional_args,
189
187
  back_ref=self._get_back_ref(propagated_debug_info),
190
188
  )
191
- is_allocate_or_free = new_call.func_name == free.func_decl.name
192
189
 
193
190
  port_to_passed_variable_map = {
194
191
  arg_decl.name: str(evaluated_arg.value.handle)
@@ -197,8 +194,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
197
194
  }
198
195
  self._debug_info[new_call.uuid] = FunctionDebugInfo(
199
196
  name=new_call.func_name,
200
- level=OperationLevel.QMOD_FUNCTION_CALL,
201
- is_allocate_or_free=is_allocate_or_free,
202
197
  port_to_passed_variable_map=port_to_passed_variable_map,
203
198
  node=new_call._as_back_ref(),
204
199
  )
@@ -13,7 +13,6 @@ import sympy
13
13
 
14
14
  from classiq.interface.debug_info.debug_info import (
15
15
  DebugInfoCollection,
16
- new_function_debug_info_by_node,
17
16
  )
18
17
  from classiq.interface.exceptions import ClassiqInternalExpansionError
19
18
  from classiq.interface.generator.expressions.evaluated_expression import (
@@ -161,10 +160,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
161
160
  self._update_captured_classical_vars(statement)
162
161
  if isinstance(statement, QuantumOperation):
163
162
  self._update_captured_vars(statement)
164
- if statement.uuid not in self._interpreter._model.debug_info:
165
- self._interpreter._model.debug_info[statement.uuid] = (
166
- new_function_debug_info_by_node(statement) # type:ignore[arg-type]
167
- )
163
+ self._interpreter.add_to_debug_info(statement)
168
164
  self._builder.emit_statement(statement)
169
165
 
170
166
  def _update_captured_classical_vars(self, stmt: QuantumStatement) -> None:
@@ -33,5 +33,6 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
33
33
  op = op.model_copy(
34
34
  update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
35
35
  )
36
+ self._interpreter.add_to_debug_info(op)
36
37
  self._interpreter.emit(op)
37
38
  return True
@@ -24,5 +24,6 @@ class HandleEvaluator(Emitter[QuantumOperation]):
24
24
  op = op.model_copy(
25
25
  update={self._handle_name: evaluated_handle, "back_ref": op.uuid}
26
26
  )
27
+ self._interpreter.add_to_debug_info(op)
27
28
  self._interpreter.emit(op)
28
29
  return True
@@ -92,7 +92,9 @@ class _ReplaceSplitVarsExpressions(ModelTransformer):
92
92
  ) -> QuantumExpressionOperation:
93
93
  op = cast(QuantumExpressionOperation, self.generic_visit(op))
94
94
  previous_var_handles = list(op._var_handles)
95
- op._var_handles = self.visit(op._var_handles)
95
+ op._var_handles = _ReplaceSplitVarsHandles(self._symbol_mapping).visit(
96
+ op._var_handles
97
+ )
96
98
  op._var_types = {
97
99
  new_handle.name: op._var_types.get(
98
100
  new_handle.name, op._var_types[previous_handle.name]
@@ -0,0 +1,197 @@
1
+ import ast
2
+ from collections.abc import Iterator, Mapping, Sequence
3
+ from contextlib import contextmanager
4
+ from itertools import chain, zip_longest
5
+ from typing import Optional, cast
6
+
7
+ from classiq.interface.generator.expressions.atomic_expression_functions import (
8
+ CLASSICAL_ATTRIBUTES,
9
+ )
10
+ from classiq.interface.generator.expressions.expression import Expression
11
+ from classiq.interface.generator.functions.classical_type import ClassicalType
12
+ from classiq.interface.generator.functions.type_name import TypeName
13
+ from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
14
+ from classiq.interface.model.classical_parameter_declaration import (
15
+ AnonClassicalParameterDeclaration,
16
+ )
17
+ from classiq.interface.model.handle_binding import FieldHandleBinding, HandleBinding
18
+ from classiq.interface.model.model_visitor import ModelVisitor
19
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
20
+ from classiq.interface.model.quantum_function_call import ArgValue, QuantumFunctionCall
21
+ from classiq.interface.model.quantum_function_declaration import (
22
+ AnonPositionalArg,
23
+ AnonQuantumFunctionDeclaration,
24
+ AnonQuantumOperandDeclaration,
25
+ NamedParamsQuantumFunctionDeclaration,
26
+ QuantumOperandDeclaration,
27
+ )
28
+ from classiq.interface.model.quantum_lambda_function import (
29
+ OperandIdentifier,
30
+ QuantumLambdaFunction,
31
+ )
32
+
33
+ from classiq.model_expansions.visitors.variable_references import VarRefCollector
34
+
35
+
36
+ def _get_expressions(arg: ArgValue) -> list[Expression]:
37
+ if isinstance(arg, Expression):
38
+ return [arg]
39
+ if isinstance(arg, HandleBinding):
40
+ return arg.expressions()
41
+ if isinstance(arg, OperandIdentifier):
42
+ return [arg.index]
43
+ if isinstance(arg, list):
44
+ return list(chain.from_iterable(_get_expressions(item) for item in arg))
45
+ return []
46
+
47
+
48
+ def _get_param_expressions(param: AnonPositionalArg) -> list[Expression]:
49
+ if isinstance(param, AnonClassicalParameterDeclaration):
50
+ return param.classical_type.expressions
51
+ if isinstance(param, AnonQuantumOperandDeclaration):
52
+ return list(
53
+ chain.from_iterable(
54
+ _get_param_expressions(nested_param)
55
+ for nested_param in param.positional_arg_declarations
56
+ )
57
+ )
58
+ return param.quantum_type.expressions
59
+
60
+
61
+ class SymbolicParamInference(ModelVisitor):
62
+ def __init__(
63
+ self,
64
+ functions: list[NativeFunctionDefinition],
65
+ additional_signatures: (
66
+ list[NamedParamsQuantumFunctionDeclaration] | None
67
+ ) = None,
68
+ ) -> None:
69
+ self._functions = nameables_to_dict(functions)
70
+ self._additional_signatures = (
71
+ {}
72
+ if additional_signatures is None
73
+ else nameables_to_dict(additional_signatures)
74
+ )
75
+ self._inferred_funcs: set[str] = set()
76
+ self._call_stack: list[str] = []
77
+ self._scope: Mapping[str, ClassicalType] = {}
78
+ self._scope_operands: dict[str, QuantumOperandDeclaration] = {}
79
+
80
+ def infer(self) -> None:
81
+ for func in self._functions.values():
82
+ self._infer_func_params(func)
83
+
84
+ def _is_recursive_call(self, func: str) -> bool:
85
+ return func in self._call_stack
86
+
87
+ @contextmanager
88
+ def function_context(
89
+ self,
90
+ func_name: Optional[str],
91
+ scope: Mapping[str, ClassicalType],
92
+ scope_operands: dict[str, QuantumOperandDeclaration],
93
+ ) -> Iterator[None]:
94
+ if func_name is not None:
95
+ self._call_stack.append(func_name)
96
+ prev_scope = self._scope
97
+ self._scope = scope
98
+ prev_scope_ops = self._scope_operands
99
+ self._scope_operands = scope_operands
100
+ yield
101
+ self._scope = prev_scope
102
+ self._scope_operands = prev_scope_ops
103
+ if func_name is not None:
104
+ self._call_stack.pop()
105
+
106
+ def _infer_func_params(self, func: NativeFunctionDefinition) -> None:
107
+ if func.name in self._inferred_funcs:
108
+ return
109
+ scope = {param.name: param.classical_type for param in func.param_decls}
110
+ scope_operands = func.operand_declarations_dict
111
+ with self.function_context(func.name, scope, scope_operands):
112
+ for param in func.positional_arg_declarations:
113
+ for expr in _get_param_expressions(param):
114
+ self._process_compile_time_expression(expr.expr)
115
+ self._set_enums_generative(func)
116
+ self.visit(func.body)
117
+ self._inferred_funcs.add(func.name)
118
+
119
+ def _set_enums_generative(self, decl: AnonQuantumFunctionDeclaration) -> None:
120
+ for param in decl.positional_arg_declarations:
121
+ if (
122
+ isinstance(param, AnonClassicalParameterDeclaration)
123
+ and param.name is not None
124
+ and isinstance(param.classical_type, TypeName)
125
+ and param.classical_type.is_enum
126
+ ):
127
+ self._scope[param.name].set_generative()
128
+
129
+ def visit_QuantumLambdaFunction(self, func: QuantumLambdaFunction) -> None:
130
+ func.set_op_decl(func.func_decl.model_copy(deep=True))
131
+ scope = dict(self._scope) | {
132
+ cast(str, param.name): param.classical_type
133
+ for param in func.named_func_decl.param_decls
134
+ }
135
+ scope_operands = self._scope_operands | nameables_to_dict(
136
+ cast(
137
+ Sequence[QuantumOperandDeclaration],
138
+ func.named_func_decl.operand_declarations,
139
+ )
140
+ )
141
+ with self.function_context(None, scope, scope_operands):
142
+ self._set_enums_generative(func.named_func_decl)
143
+ self.visit(func.body)
144
+
145
+ def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
146
+ self._process_compile_time_expressions(call.function)
147
+ name = call.func_name
148
+ if self._is_recursive_call(name):
149
+ return # Recursion is not fully supported
150
+ params = self._get_params(call)
151
+ for param, arg in zip_longest(params, call.positional_args):
152
+ if (
153
+ not isinstance(param, AnonClassicalParameterDeclaration)
154
+ or param.classical_type.is_generative
155
+ ):
156
+ self._process_compile_time_expressions(arg)
157
+ else:
158
+ for expr in _get_expressions(arg):
159
+ self._process_nested_compile_time_expression(expr.expr)
160
+ self.generic_visit(call)
161
+
162
+ def _get_params(self, call: QuantumFunctionCall) -> Sequence[AnonPositionalArg]:
163
+ name = call.func_name
164
+ if name in self._scope_operands:
165
+ return self._scope_operands[name].positional_arg_declarations
166
+ elif name in self._functions:
167
+ func = self._functions[name]
168
+ self._infer_func_params(func)
169
+ return func.positional_arg_declarations
170
+ elif name in self._additional_signatures:
171
+ return self._additional_signatures[name].positional_arg_declarations
172
+ return call.func_decl.positional_arg_declarations
173
+
174
+ def _process_compile_time_expressions(self, arg: ArgValue) -> None:
175
+ for expr in _get_expressions(arg):
176
+ self._process_compile_time_expression(expr.expr)
177
+
178
+ def _process_compile_time_expression(self, expr: str) -> None:
179
+ vrc = VarRefCollector(
180
+ ignore_duplicated_handles=True, ignore_sympy_symbols=True, unevaluated=True
181
+ )
182
+ vrc.visit(ast.parse(expr))
183
+ for handle in vrc.var_handles:
184
+ if handle.name in self._scope and (
185
+ not isinstance(handle, FieldHandleBinding)
186
+ or handle.field not in CLASSICAL_ATTRIBUTES
187
+ ):
188
+ self._scope[handle.name].set_generative()
189
+
190
+ def _process_nested_compile_time_expression(self, expr: str) -> None:
191
+ vrc = VarRefCollector(
192
+ ignore_duplicated_handles=True, ignore_sympy_symbols=True, unevaluated=True
193
+ )
194
+ vrc.visit(ast.parse(expr))
195
+ for handle in vrc.var_handles:
196
+ for nested_expr in handle.expressions():
197
+ self._process_compile_time_expression(nested_expr.expr)
@@ -22,7 +22,12 @@ from typing import ( # type: ignore[attr-defined]
22
22
 
23
23
  from typing_extensions import ParamSpec, Self, _AnnotatedAlias
24
24
 
25
- from classiq.interface.exceptions import ClassiqInternalError, ClassiqValueError
25
+ from classiq.interface.exceptions import (
26
+ ClassiqInternalError,
27
+ ClassiqNotImplementedError,
28
+ ClassiqValueError,
29
+ )
30
+ from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
26
31
  from classiq.interface.generator.expressions.expression import Expression
27
32
  from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
28
33
  from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy import (
@@ -340,6 +345,23 @@ class QNum(Generic[_P], QScalar):
340
345
  return interpret_expression(str(self.is_signed))
341
346
  return CParamScalar(f"get_field({self}, 'is_signed')")
342
347
 
348
+ def get_maximal_bounds(self) -> tuple[float, float]:
349
+ if not is_generative_mode():
350
+ raise ClassiqNotImplementedError(
351
+ "get_maximal_bounds() is supported in generative mode only"
352
+ )
353
+
354
+ if TYPE_CHECKING:
355
+ assert isinstance(self.size, int)
356
+ assert isinstance(self.is_signed, bool)
357
+ assert isinstance(self.fraction_digits, int)
358
+
359
+ return RegisterArithmeticInfo.get_maximal_bounds(
360
+ size=self.size,
361
+ is_signed=self.is_signed,
362
+ fraction_places=self.fraction_digits,
363
+ )
364
+
343
365
  # Support comma-separated generic args in older Python versions
344
366
  if sys.version_info[0:2] < (3, 10):
345
367
 
@@ -4,6 +4,8 @@ import ast
4
4
  from enum import Enum as PythonEnum
5
5
  from typing import Any
6
6
 
7
+ import sympy
8
+
7
9
  from classiq.qmod.utilities import qmod_val_to_expr_str
8
10
 
9
11
 
@@ -33,10 +35,14 @@ class SymbolicExpr(Symbolic):
33
35
 
34
36
  @staticmethod
35
37
  def _binary_op(lhs: Any, rhs: Any, op: str) -> SymbolicExpr:
36
- if not isinstance(lhs, (SymbolicExpr, int, float, bool, PythonEnum)):
38
+ if not isinstance(
39
+ lhs, (SymbolicExpr, int, float, bool, PythonEnum, sympy.Basic)
40
+ ):
37
41
  raise TypeError(f"Invalid lhs argument {lhs!r} for binary operation {op!r}")
38
42
 
39
- if not isinstance(rhs, (SymbolicExpr, int, float, bool, PythonEnum)):
43
+ if not isinstance(
44
+ rhs, (SymbolicExpr, int, float, bool, PythonEnum, sympy.Basic)
45
+ ):
40
46
  raise TypeError(f"Invalid lhs argument {rhs!r} for binary operation {op!r}")
41
47
 
42
48
  lhs_str = qmod_val_to_expr_str(lhs)
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from pathlib import Path
3
- from typing import Optional, Union
3
+ from typing import Any, Optional, Union
4
4
 
5
5
  from classiq.interface.model.model import Model, SerializedModel
6
6
 
@@ -17,6 +17,8 @@ def write_qmod(
17
17
  name: str,
18
18
  directory: Optional[Path] = None,
19
19
  decimal_precision: int = DEFAULT_DECIMAL_PRECISION,
20
+ *args: Any,
21
+ **kwargs: Any,
20
22
  ) -> None:
21
23
  """
22
24
  Creates a native Qmod file from a serialized model and outputs the synthesis options (Preferences and Constraints) to a file.
@@ -27,6 +29,8 @@ def write_qmod(
27
29
  name: The name to save the file by.
28
30
  directory: The directory to save the files in. If None, the current working directory is used.
29
31
  decimal_precision: The number of decimal places to use for numbers, set to 4 by default.
32
+ args: (placeholder)
33
+ kwargs: (placeholder)
30
34
 
31
35
  Returns:
32
36
  None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: classiq
3
- Version: 0.74.0
3
+ Version: 0.75.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  License: Proprietary
6
6
  Keywords: quantum computing,quantum circuits,quantum algorithms,QAD,QDL