classiq 0.63.1__py3-none-any.whl → 0.65.1__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 (77) hide show
  1. classiq/_internals/api_wrapper.py +30 -0
  2. classiq/analyzer/url_utils.py +2 -3
  3. classiq/applications/chemistry/chemistry_model_constructor.py +8 -9
  4. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
  5. classiq/applications/combinatorial_optimization/combinatorial_problem.py +2 -5
  6. classiq/applications/finance/finance_model_constructor.py +7 -12
  7. classiq/applications/grover/grover_model_constructor.py +4 -6
  8. classiq/applications/qsvm/qsvm_model_constructor.py +6 -4
  9. classiq/execution/execution_session.py +14 -13
  10. classiq/interface/_version.py +1 -1
  11. classiq/interface/analyzer/result.py +1 -2
  12. classiq/interface/backend/backend_preferences.py +1 -9
  13. classiq/interface/executor/result.py +6 -3
  14. classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
  15. classiq/interface/generator/functions/type_name.py +6 -0
  16. classiq/interface/helpers/datastructures.py +26 -0
  17. classiq/interface/interface_version.py +1 -1
  18. classiq/interface/model/allocate.py +16 -0
  19. classiq/interface/model/handle_binding.py +11 -3
  20. classiq/interface/model/quantum_type.py +26 -0
  21. classiq/interface/model/statement_block.py +2 -0
  22. classiq/interface/server/routes.py +5 -0
  23. classiq/model_expansions/atomic_expression_functions_defs.py +6 -6
  24. classiq/model_expansions/capturing/captured_vars.py +27 -10
  25. classiq/model_expansions/evaluators/arg_type_match.py +4 -7
  26. classiq/model_expansions/evaluators/quantum_type_utils.py +25 -8
  27. classiq/model_expansions/expression_evaluator.py +8 -2
  28. classiq/model_expansions/function_builder.py +35 -11
  29. classiq/model_expansions/generative_functions.py +6 -4
  30. classiq/model_expansions/interpreters/__init__.py +0 -0
  31. classiq/model_expansions/interpreters/base_interpreter.py +263 -0
  32. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
  33. classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
  34. classiq/model_expansions/model_tables.py +1 -92
  35. classiq/model_expansions/quantum_operations/__init__.py +0 -10
  36. classiq/model_expansions/quantum_operations/call_emitter.py +45 -93
  37. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
  38. classiq/model_expansions/quantum_operations/emitter.py +7 -2
  39. classiq/model_expansions/quantum_operations/quantum_function_call.py +11 -2
  40. classiq/model_expansions/quantum_operations/shallow_emitter.py +22 -3
  41. classiq/model_expansions/scope.py +15 -15
  42. classiq/model_expansions/scope_initialization.py +11 -5
  43. classiq/open_library/functions/discrete_sine_cosine_transform.py +8 -2
  44. classiq/open_library/functions/grover.py +1 -1
  45. classiq/open_library/functions/modular_exponentiation.py +8 -2
  46. classiq/open_library/functions/state_preparation.py +23 -13
  47. classiq/open_library/functions/swap_test.py +1 -2
  48. classiq/open_library/functions/variational.py +1 -2
  49. classiq/qmod/builtins/__init__.py +1 -1
  50. classiq/qmod/builtins/operations.py +51 -0
  51. classiq/qmod/declaration_inferrer.py +0 -3
  52. classiq/qmod/generative.py +4 -4
  53. classiq/qmod/native/pretty_printer.py +9 -1
  54. classiq/qmod/pretty_print/pretty_printer.py +12 -1
  55. classiq/qmod/qfunc.py +4 -2
  56. classiq/qmod/qmod_variable.py +55 -48
  57. classiq/qmod/quantum_function.py +7 -5
  58. classiq/qmod/semantics/annotation/__init__.py +0 -0
  59. classiq/qmod/semantics/annotation/call_annotation.py +92 -0
  60. classiq/qmod/semantics/lambdas.py +25 -0
  61. classiq/qmod/semantics/static_semantics_visitor.py +8 -46
  62. classiq/qmod/utilities.py +23 -1
  63. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
  64. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/RECORD +66 -67
  65. classiq/interface/helpers/dotdict.py +0 -18
  66. classiq/model_expansions/interpreter.py +0 -475
  67. classiq/model_expansions/quantum_operations/control.py +0 -290
  68. classiq/model_expansions/quantum_operations/expression_operation.py +0 -103
  69. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +0 -535
  70. classiq/model_expansions/quantum_operations/invert.py +0 -36
  71. classiq/model_expansions/quantum_operations/phase.py +0 -187
  72. classiq/model_expansions/quantum_operations/power.py +0 -71
  73. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +0 -230
  74. classiq/model_expansions/quantum_operations/within_apply.py +0 -25
  75. classiq/qmod/semantics/annotation.py +0 -36
  76. /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
  77. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
@@ -23,11 +23,8 @@ from typing_extensions import ParamSpec, Self, _AnnotatedAlias
23
23
  from classiq.interface.exceptions import ClassiqValueError
24
24
  from classiq.interface.generator.expressions.expression import Expression
25
25
  from classiq.interface.generator.expressions.qmod_qarray_proxy import (
26
- ILLEGAL_SLICE_BOUNDS_MSG,
27
26
  ILLEGAL_SLICE_MSG,
28
27
  ILLEGAL_SLICING_STEP_MSG,
29
- SLICE_OUT_OF_BOUNDS_MSG,
30
- SUBSCRIPT_OUT_OF_BOUNDS_MSG,
31
28
  )
32
29
  from classiq.interface.generator.functions.port_declaration import (
33
30
  PortDeclarationDirection,
@@ -66,7 +63,12 @@ from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
66
63
  from classiq.qmod.quantum_callable import QCallable
67
64
  from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
68
65
  from classiq.qmod.symbolic_type import SymbolicTypes
69
- from classiq.qmod.utilities import get_source_ref, version_portable_get_args
66
+ from classiq.qmod.utilities import (
67
+ get_source_ref,
68
+ unwrap_forward_ref,
69
+ varname,
70
+ version_portable_get_args,
71
+ )
70
72
 
71
73
 
72
74
  def _is_input_output_typehint(type_hint: Any) -> bool:
@@ -94,28 +96,42 @@ def _no_current_expandable() -> Iterator[None]:
94
96
  QCallable.CURRENT_EXPANDABLE = current_expandable
95
97
 
96
98
 
99
+ def _infer_variable_name(name: Any, depth: int) -> Any:
100
+ if name is not None:
101
+ return name
102
+ name = varname(depth + 1)
103
+ if name is None:
104
+ raise ClassiqValueError(
105
+ "Could not infer variable name. Please specify the variable name explicitly"
106
+ )
107
+ return name
108
+
109
+
97
110
  class QVar(Symbolic):
111
+ CONSTRUCTOR_DEPTH: int = 1
112
+
98
113
  def __init__(
99
114
  self,
100
- origin: Union[str, HandleBinding],
115
+ origin: Union[None, str, HandleBinding] = None,
101
116
  *,
102
117
  expr_str: Optional[str] = None,
103
118
  depth: int = 2,
104
119
  ) -> None:
105
- super().__init__(str(origin), True)
120
+ name = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
121
+ super().__init__(str(name), True)
106
122
  source_ref = (
107
123
  get_source_ref(sys._getframe(depth))
108
- if isinstance(origin, str)
109
- else origin.source_ref
124
+ if isinstance(name, str)
125
+ else name.source_ref
110
126
  )
111
127
  self._base_handle: HandleBinding = (
112
- HandleBinding(name=origin) if isinstance(origin, str) else origin
128
+ HandleBinding(name=name) if isinstance(name, str) else name
113
129
  )
114
- if isinstance(origin, str) and QCallable.CURRENT_EXPANDABLE is not None:
130
+ if isinstance(name, str) and QCallable.CURRENT_EXPANDABLE is not None:
115
131
  QCallable.CURRENT_EXPANDABLE.add_local_handle(
116
- origin, self.get_qmod_type(), source_ref
132
+ name, self.get_qmod_type(), source_ref
117
133
  )
118
- self._expr_str = expr_str if expr_str is not None else str(origin)
134
+ self._expr_str = expr_str if expr_str is not None else str(name)
119
135
 
120
136
  def get_handle_binding(self) -> HandleBinding:
121
137
  return self._base_handle
@@ -176,13 +192,16 @@ Input = Annotated[_Q, PortDeclarationDirection.Input]
176
192
 
177
193
 
178
194
  class QScalar(QVar, SymbolicExpr):
195
+ CONSTRUCTOR_DEPTH: int = 2
196
+
179
197
  def __init__(
180
198
  self,
181
- origin: Union[str, HandleBinding],
199
+ origin: Union[None, str, HandleBinding] = None,
182
200
  *,
183
201
  _expr_str: Optional[str] = None,
184
202
  depth: int = 2,
185
203
  ) -> None:
204
+ origin = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
186
205
  QVar.__init__(self, origin, expr_str=_expr_str, depth=depth)
187
206
  SymbolicExpr.__init__(self, str(origin), True)
188
207
 
@@ -282,9 +301,11 @@ _P = ParamSpec("_P")
282
301
 
283
302
 
284
303
  class QNum(Generic[_P], QScalar):
304
+ CONSTRUCTOR_DEPTH: int = 3
305
+
285
306
  def __init__(
286
307
  self,
287
- name: Union[str, HandleBinding],
308
+ name: Union[None, str, HandleBinding] = None,
288
309
  size: Union[int, CInt, Expression, SymbolicExpr, None] = None,
289
310
  is_signed: Union[bool, Expression, SymbolicExpr, None] = None,
290
311
  fraction_digits: Union[int, CInt, Expression, None] = None,
@@ -330,8 +351,12 @@ class QNum(Generic[_P], QScalar):
330
351
  "is_signed: bool | CBool, fraction_digits: int | CInt]"
331
352
  )
332
353
  if len(type_args) == 1:
333
- return type_args[0], None, None
334
- return type_args[0], type_args[1], type_args[2]
354
+ return unwrap_forward_ref(type_args[0]), None, None
355
+ return (
356
+ unwrap_forward_ref(type_args[0]),
357
+ unwrap_forward_ref(type_args[1]),
358
+ unwrap_forward_ref(type_args[2]),
359
+ )
335
360
 
336
361
  @classmethod
337
362
  def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
@@ -390,10 +415,12 @@ class QNum(Generic[_P], QScalar):
390
415
 
391
416
 
392
417
  class QArray(ArrayBase[_P], QVar):
418
+ CONSTRUCTOR_DEPTH: int = 3
419
+
393
420
  # TODO [CAD-18620]: improve type hints
394
421
  def __init__(
395
422
  self,
396
- name: Union[str, HandleBinding],
423
+ name: Union[None, str, HandleBinding] = None,
397
424
  element_type: Union[_GenericAlias, QuantumType] = QBit,
398
425
  length: Optional[Union[int, SymbolicExpr, Expression]] = None,
399
426
  _expr_str: Optional[str] = None,
@@ -417,14 +444,6 @@ class QArray(ArrayBase[_P], QVar):
417
444
  def _get_subscript(self, index: Union[slice, int, SymbolicExpr]) -> Any:
418
445
  if isinstance(index, SymbolicExpr) and index.is_quantum:
419
446
  raise ClassiqValueError("Non-classical parameter for slicing")
420
- if (
421
- isinstance(index, int)
422
- and self._length is not None
423
- and self._length.is_evaluated()
424
- ):
425
- length = self._length.to_int_value()
426
- if index < 0 or index >= length:
427
- raise ClassiqValueError(SUBSCRIPT_OUT_OF_BOUNDS_MSG)
428
447
 
429
448
  return _create_qvar_for_qtype(
430
449
  self.get_qmod_type().element_type,
@@ -442,20 +461,6 @@ class QArray(ArrayBase[_P], QVar):
442
461
  slice_.stop, (int, SymbolicExpr)
443
462
  ):
444
463
  raise ClassiqValueError(ILLEGAL_SLICE_MSG)
445
- if (
446
- isinstance(slice_.start, int)
447
- and isinstance(slice_.stop, int)
448
- and slice_.start >= slice_.stop
449
- ):
450
- raise ClassiqValueError(
451
- ILLEGAL_SLICE_BOUNDS_MSG.format(slice_.start, slice_.stop)
452
- )
453
- if self._length is not None and self._length.is_evaluated():
454
- length = self._length.to_int_value()
455
- if (isinstance(slice_.start, int) and slice_.start < 0) or (
456
- isinstance(slice_.stop, int) and slice_.stop > length
457
- ):
458
- raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
459
464
 
460
465
  return QArray(
461
466
  name=SlicedHandleBinding(
@@ -492,16 +497,18 @@ class QArray(ArrayBase[_P], QVar):
492
497
  type_args = version_portable_get_args(type_hint)
493
498
  if len(type_args) == 0:
494
499
  return QBit, None
500
+ first_arg = unwrap_forward_ref(type_args[0])
495
501
  if len(type_args) == 1:
496
- if isinstance(type_args[0], (str, int)):
497
- return QBit, type_args[0]
498
- return type_args[0], None
502
+ if isinstance(first_arg, (str, int)):
503
+ return QBit, first_arg
504
+ return first_arg, None
499
505
  if len(type_args) != 2:
500
506
  raise ClassiqValueError(
501
507
  "QArray receives two type arguments: QArray[element_type: QVar, "
502
508
  "length: int | CInt]"
503
509
  )
504
- return cast(tuple[type[QVar], Any], type_args)
510
+ second_arg = unwrap_forward_ref(type_args[1])
511
+ return cast(tuple[type[QVar], Any], (first_arg, second_arg))
505
512
 
506
513
  @classmethod
507
514
  def to_qmod_quantum_type(cls, type_hint: Any) -> QuantumType:
@@ -537,16 +544,19 @@ class QArray(ArrayBase[_P], QVar):
537
544
 
538
545
 
539
546
  class QStruct(QVar):
547
+ CONSTRUCTOR_DEPTH: int = 2
548
+
540
549
  _struct_name: str
541
550
  _fields: Mapping[str, QVar]
542
551
 
543
552
  def __init__(
544
553
  self,
545
- name: Union[str, HandleBinding],
554
+ origin: Union[None, str, HandleBinding] = None,
546
555
  _struct_name: Optional[str] = None,
547
556
  _fields: Optional[Mapping[str, QVar]] = None,
548
557
  _expr_str: Optional[str] = None,
549
558
  ) -> None:
559
+ name = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
550
560
  if _struct_name is None or _fields is None:
551
561
  with _no_current_expandable():
552
562
  temp_var = QStruct.to_qvar(name, type(self), _expr_str)
@@ -601,15 +611,13 @@ class QStruct(QVar):
601
611
  for field_name, (field_class, field_type) in field_types.items()
602
612
  }
603
613
  return QStruct(
604
- name=origin,
614
+ origin,
605
615
  _struct_name=type_hint.__name__,
606
616
  _fields=field_vars,
607
617
  _expr_str=expr_str,
608
618
  )
609
619
 
610
620
  def _add_qmod_qstruct(self, *, qmodule: ModelStateContainer) -> None:
611
- from classiq.model_expansions.model_tables import SymbolTable
612
-
613
621
  if self._struct_name in qmodule.qstruct_decls:
614
622
  return
615
623
 
@@ -618,7 +626,6 @@ class QStruct(QVar):
618
626
  fields={name: qvar.get_qmod_type() for name, qvar in self._fields.items()},
619
627
  )
620
628
  qmodule.qstruct_decls[self._struct_name] = struct_decl
621
- SymbolTable.qstruct_table[self._struct_name] = struct_decl
622
629
 
623
630
 
624
631
  def create_qvar_for_port_decl(port: AnonPortDeclaration, name: str) -> QVar:
@@ -153,8 +153,10 @@ class QFunc(BaseQFunc):
153
153
  return model
154
154
 
155
155
  def _create_generative_model(self, model_stub: Model) -> Model:
156
- from classiq.model_expansions.interpreter import Interpreter
157
- from classiq.qmod.semantics.static_semantics_visitor import (
156
+ from classiq.model_expansions.interpreters.frontend_generative_interpreter import (
157
+ FrontendGenerativeInterpreter,
158
+ )
159
+ from classiq.qmod.semantics.annotation.call_annotation import (
158
160
  resolve_function_calls,
159
161
  )
160
162
 
@@ -167,9 +169,7 @@ class QFunc(BaseQFunc):
167
169
  for gen_func in generative_functions
168
170
  },
169
171
  )
170
- interpreter = Interpreter(
171
- model_stub, generative_functions, is_normalizer=True, is_shallow=True
172
- )
172
+ interpreter = FrontendGenerativeInterpreter(model_stub, generative_functions)
173
173
  set_frontend_interpreter(interpreter)
174
174
  return interpreter.expand()
175
175
 
@@ -244,6 +244,8 @@ class ExternalQFunc(QTerminalCallable):
244
244
 
245
245
 
246
246
  class GenerativeQFunc(BaseQFunc):
247
+ FRAME_DEPTH = 3
248
+
247
249
  def __init__(
248
250
  self,
249
251
  py_callable: Callable,
File without changes
@@ -0,0 +1,92 @@
1
+ from collections.abc import Iterator, Mapping
2
+ from contextlib import contextmanager
3
+ from typing import Any
4
+
5
+ from classiq.interface.exceptions import ClassiqError
6
+ from classiq.interface.generator.visitor import Visitor
7
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
8
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
9
+ from classiq.interface.model.quantum_function_declaration import (
10
+ AnonQuantumOperandDeclaration,
11
+ QuantumFunctionDeclaration,
12
+ QuantumOperandDeclaration,
13
+ )
14
+ from classiq.interface.model.quantum_lambda_function import (
15
+ QuantumLambdaFunction,
16
+ )
17
+
18
+ from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
19
+ from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
20
+ from classiq.qmod.semantics.error_manager import ErrorManager
21
+ from classiq.qmod.semantics.lambdas import get_renamed_parameters
22
+
23
+
24
+ def _annotate_function_call_decl(
25
+ fc: QuantumFunctionCall,
26
+ function_dict: Mapping[str, QuantumFunctionDeclaration],
27
+ ) -> None:
28
+ if fc._func_decl is None:
29
+ func_decl = function_dict.get(fc.func_name)
30
+ if func_decl is None:
31
+ raise ClassiqError(
32
+ f"Error resolving function {fc.func_name}, the function is not found in included library."
33
+ )
34
+ fc.set_func_decl(func_decl)
35
+
36
+ for arg, param in zip(fc.positional_args, fc.func_decl.positional_arg_declarations):
37
+ if not isinstance(param, AnonQuantumOperandDeclaration):
38
+ continue
39
+ args: list
40
+ if isinstance(arg, list):
41
+ args = arg
42
+ else:
43
+ args = [arg]
44
+ for qlambda in args:
45
+ if isinstance(qlambda, QuantumLambdaFunction):
46
+ qlambda.set_op_decl(param)
47
+
48
+
49
+ class _CallLambdaAnnotator(Visitor):
50
+ def __init__(
51
+ self, quantum_functions: Mapping[str, QuantumFunctionDeclaration]
52
+ ) -> None:
53
+ self._quantum_functions = dict(quantum_functions)
54
+ self._current_operands: dict[str, QuantumOperandDeclaration] = {}
55
+
56
+ @contextmanager
57
+ def set_operands(
58
+ self, operands: dict[str, QuantumOperandDeclaration]
59
+ ) -> Iterator[None]:
60
+ previous_operands = self._current_operands
61
+ self._current_operands = operands
62
+ yield
63
+ self._current_operands = previous_operands
64
+
65
+ def visit_NativeFunctionDefinition(self, func: NativeFunctionDefinition) -> None:
66
+ with self.set_operands(func.operand_declarations_dict):
67
+ self.generic_visit(func)
68
+
69
+ def visit_QuantumLambdaFunction(self, lambda_func: QuantumLambdaFunction) -> None:
70
+ lambda_operands = get_renamed_parameters(lambda_func)[1]
71
+ with self.set_operands(self._current_operands | lambda_operands):
72
+ self.generic_visit(lambda_func)
73
+
74
+ def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
75
+ _annotate_function_call_decl(
76
+ call, self._quantum_functions | self._current_operands
77
+ )
78
+ self.generic_visit(call)
79
+
80
+
81
+ def resolve_function_calls(
82
+ root: Any,
83
+ quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
84
+ ) -> None:
85
+ all_functions: Mapping[str, QuantumFunctionDeclaration] = {
86
+ **BUILTIN_FUNCTION_DECLARATIONS,
87
+ **quantum_function_dict,
88
+ }
89
+ with ErrorManager().ignore_errors_context():
90
+ QStructAnnotator().visit(quantum_function_dict)
91
+ QStructAnnotator().visit(root)
92
+ _CallLambdaAnnotator(all_functions).visit(root)
@@ -0,0 +1,25 @@
1
+ from classiq.interface.model.port_declaration import PortDeclaration
2
+ from classiq.interface.model.quantum_function_declaration import (
3
+ AnonQuantumOperandDeclaration,
4
+ QuantumOperandDeclaration,
5
+ )
6
+ from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
7
+
8
+ from classiq import AnonClassicalParameterDeclaration
9
+
10
+
11
+ def get_renamed_parameters(
12
+ lambda_func: QuantumLambdaFunction,
13
+ ) -> tuple[list[str], dict[str, QuantumOperandDeclaration], list[PortDeclaration]]:
14
+ renamed_parameters: list[str] = []
15
+ renamed_operands: dict[str, QuantumOperandDeclaration] = {}
16
+ renamed_ports: list[PortDeclaration] = []
17
+ for idx, param in enumerate(lambda_func.func_decl.positional_arg_declarations):
18
+ param_name = lambda_func.pos_rename_params[idx]
19
+ if isinstance(param, AnonClassicalParameterDeclaration):
20
+ renamed_parameters.append(param_name)
21
+ elif isinstance(param, AnonQuantumOperandDeclaration):
22
+ renamed_operands[param_name] = param.rename(param_name)
23
+ else:
24
+ renamed_ports.append(param.rename(param_name))
25
+ return renamed_parameters, renamed_operands, renamed_ports
@@ -2,7 +2,6 @@ import ast
2
2
  from collections.abc import Iterator, Mapping, Sequence
3
3
  from contextlib import contextmanager
4
4
  from typing import (
5
- Any,
6
5
  Optional,
7
6
  )
8
7
 
@@ -15,9 +14,6 @@ from classiq.interface.generator.functions.port_declaration import (
15
14
  PortDeclarationDirection,
16
15
  )
17
16
  from classiq.interface.generator.visitor import Visitor
18
- from classiq.interface.model.classical_parameter_declaration import (
19
- AnonClassicalParameterDeclaration,
20
- )
21
17
  from classiq.interface.model.handle_binding import (
22
18
  FieldHandleBinding,
23
19
  HandleBinding,
@@ -33,7 +29,6 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
33
29
  )
34
30
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
35
31
  from classiq.interface.model.quantum_function_declaration import (
36
- AnonQuantumOperandDeclaration,
37
32
  QuantumFunctionDeclaration,
38
33
  QuantumOperandDeclaration,
39
34
  )
@@ -51,9 +46,10 @@ from classiq.model_expansions.visitors.variable_references import VarRefCollecto
51
46
  from classiq.qmod.builtins.functions import (
52
47
  BUILTIN_FUNCTION_DECLARATIONS,
53
48
  )
54
- from classiq.qmod.semantics.annotation import annotate_function_call_decl
49
+ from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
50
+ from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
55
51
  from classiq.qmod.semantics.error_manager import ErrorManager
56
- from classiq.qmod.semantics.qstruct_annotator import QStructAnnotator
52
+ from classiq.qmod.semantics.lambdas import get_renamed_parameters
57
53
  from classiq.qmod.semantics.validation.constants_validation import (
58
54
  check_duplicate_constants,
59
55
  )
@@ -202,13 +198,6 @@ class StaticSemanticsVisitor(Visitor):
202
198
  def visit_QuantumOperation(self, op: QuantumOperation) -> None:
203
199
  with self._error_manager.node_context(op):
204
200
  if isinstance(op, QuantumFunctionCall):
205
- annotate_function_call_decl(
206
- op,
207
- {
208
- **self._functions_dict,
209
- **self.current_scope.operands,
210
- },
211
- )
212
201
  validate_call_arguments(
213
202
  op,
214
203
  {
@@ -243,8 +232,8 @@ class StaticSemanticsVisitor(Visitor):
243
232
  )
244
233
 
245
234
  def visit_QuantumLambdaFunction(self, lambda_func: QuantumLambdaFunction) -> None:
246
- renamed_parameters, renamed_operands, renamed_ports = (
247
- self._get_renamed_parameters(lambda_func)
235
+ renamed_parameters, renamed_operands, renamed_ports = get_renamed_parameters(
236
+ lambda_func
248
237
  )
249
238
  scope = StaticScope(
250
239
  parameters=self.current_scope.parameters + renamed_parameters,
@@ -259,22 +248,6 @@ class StaticSemanticsVisitor(Visitor):
259
248
  with self.scoped_visit(scope):
260
249
  self.generic_visit(lambda_func)
261
250
 
262
- def _get_renamed_parameters(
263
- self, lambda_func: QuantumLambdaFunction
264
- ) -> tuple[list[str], dict[str, QuantumOperandDeclaration], list[PortDeclaration]]:
265
- renamed_parameters: list[str] = []
266
- renamed_operands: dict[str, QuantumOperandDeclaration] = {}
267
- renamed_ports: list[PortDeclaration] = []
268
- for idx, param in enumerate(lambda_func.func_decl.positional_arg_declarations):
269
- param_name = lambda_func.pos_rename_params[idx]
270
- if isinstance(param, AnonClassicalParameterDeclaration):
271
- renamed_parameters.append(param_name)
272
- elif isinstance(param, AnonQuantumOperandDeclaration):
273
- renamed_operands[param_name] = param.rename(param_name)
274
- else:
275
- renamed_ports.append(param.rename(param_name))
276
- return renamed_parameters, renamed_operands, renamed_ports
277
-
278
251
  def visit_HandleBinding(self, handle: HandleBinding) -> None:
279
252
  resolve_handle(self.current_scope, handle)
280
253
 
@@ -375,26 +348,15 @@ class StaticSemanticsVisitor(Visitor):
375
348
  )
376
349
 
377
350
 
378
- def resolve_function_calls(
379
- root: Any,
380
- quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
381
- ) -> None:
382
- with ErrorManager().ignore_errors_context():
383
- QStructAnnotator().visit(quantum_function_dict)
384
- QStructAnnotator().visit(root)
385
- StaticSemanticsVisitor(
386
- {**BUILTIN_FUNCTION_DECLARATIONS, **quantum_function_dict},
387
- [],
388
- ).visit(root)
389
-
390
-
391
351
  def static_semantics_analysis_pass(
392
352
  model: Model, error_type: Optional[type[Exception]] = ClassiqSemanticError
393
353
  ) -> None:
394
354
  _check_function_name_collisions(model, error_type)
395
355
  QStructAnnotator().visit(model)
356
+ functions = {**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict}
357
+ resolve_function_calls(model, functions)
396
358
  StaticSemanticsVisitor(
397
- {**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict},
359
+ functions,
398
360
  [const.name for const in model.constants],
399
361
  ).visit(model)
400
362
  if error_type is not None:
classiq/qmod/utilities.py CHANGED
@@ -5,7 +5,7 @@ import keyword
5
5
  import sys
6
6
  from enum import Enum as PythonEnum
7
7
  from types import FrameType
8
- from typing import Any, Literal, Optional, get_args, get_origin, overload
8
+ from typing import Any, ForwardRef, Literal, Optional, get_args, get_origin, overload
9
9
 
10
10
  from classiq.interface.source_reference import SourceReference
11
11
 
@@ -97,3 +97,25 @@ def qmod_val_to_expr_str(val: Any) -> str:
97
97
  return f"{type(val).__name__}.{val.name}"
98
98
 
99
99
  return str(val)
100
+
101
+
102
+ def unwrap_forward_ref(x: Any) -> Any:
103
+ if isinstance(x, ForwardRef):
104
+ return x.__forward_arg__
105
+ return x
106
+
107
+
108
+ def varname(depth: int) -> Optional[str]:
109
+ frame = sys._getframe(depth)
110
+ codes = inspect.getframeinfo(frame).code_context
111
+ if codes is None or len(codes) != 1:
112
+ return None
113
+ code = codes[0]
114
+ if "=" not in code:
115
+ return None
116
+ var_name = code.split("=")[0].strip()
117
+ if ":" in var_name:
118
+ var_name = var_name.split(":")[0].strip()
119
+ if not var_name.isidentifier():
120
+ return None
121
+ return var_name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: classiq
3
- Version: 0.63.1
3
+ Version: 0.65.1
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  Home-page: https://classiq.io
6
6
  License: Proprietary