classiq 0.56.1__py3-none-any.whl → 0.58.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 (46) hide show
  1. classiq/analyzer/show_interactive_hack.py +16 -4
  2. classiq/applications/combinatorial_helpers/encoding_utils.py +1 -0
  3. classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -1
  4. classiq/execution/jobs.py +8 -1
  5. classiq/executor.py +1 -1
  6. classiq/interface/_version.py +1 -1
  7. classiq/interface/backend/backend_preferences.py +27 -5
  8. classiq/interface/backend/pydantic_backend.py +0 -1
  9. classiq/interface/execution/jobs.py +4 -1
  10. classiq/interface/executor/execution_request.py +19 -5
  11. classiq/interface/generator/arith/arithmetic_expression_validator.py +28 -9
  12. classiq/interface/generator/functions/type_name.py +7 -9
  13. classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
  14. classiq/model_expansions/closure.py +24 -6
  15. classiq/model_expansions/evaluators/parameter_types.py +1 -2
  16. classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
  17. classiq/model_expansions/function_builder.py +13 -0
  18. classiq/model_expansions/interpreter.py +9 -14
  19. classiq/model_expansions/quantum_operations/call_emitter.py +207 -0
  20. classiq/model_expansions/quantum_operations/classicalif.py +2 -2
  21. classiq/model_expansions/quantum_operations/control.py +7 -5
  22. classiq/model_expansions/quantum_operations/emitter.py +1 -186
  23. classiq/model_expansions/quantum_operations/expression_operation.py +26 -189
  24. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +2 -2
  25. classiq/model_expansions/quantum_operations/invert.py +2 -2
  26. classiq/model_expansions/quantum_operations/phase.py +3 -1
  27. classiq/model_expansions/quantum_operations/power.py +2 -2
  28. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -9
  29. classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -2
  30. classiq/model_expansions/quantum_operations/repeat.py +2 -2
  31. classiq/model_expansions/transformers/__init__.py +0 -0
  32. classiq/model_expansions/transformers/var_splitter.py +237 -0
  33. classiq/qmod/builtins/classical_functions.py +1 -0
  34. classiq/qmod/builtins/functions/state_preparation.py +1 -1
  35. classiq/qmod/create_model_function.py +25 -20
  36. classiq/qmod/native/pretty_printer.py +19 -4
  37. classiq/qmod/pretty_print/pretty_printer.py +53 -28
  38. classiq/qmod/qfunc.py +18 -16
  39. classiq/qmod/quantum_function.py +30 -24
  40. classiq/qmod/semantics/qstruct_annotator.py +23 -0
  41. classiq/qmod/semantics/static_semantics_visitor.py +4 -1
  42. classiq/qmod/write_qmod.py +3 -1
  43. classiq/synthesis.py +3 -1
  44. {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/METADATA +1 -1
  45. {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/RECORD +46 -42
  46. {classiq-0.56.1.dist-info → classiq-0.58.0.dist-info}/WHEEL +0 -0
@@ -71,7 +71,6 @@ def create_model(
71
71
  constraints,
72
72
  execution_preferences,
73
73
  preferences,
74
- classical_execution_function,
75
74
  )
76
75
  else:
77
76
  if TYPE_CHECKING:
@@ -95,26 +94,21 @@ def _expand_generative_model(
95
94
  constraints: Optional[Constraints] = None,
96
95
  execution_preferences: Optional[ExecutionPreferences] = None,
97
96
  preferences: Optional[Preferences] = None,
98
- classical_execution_function: Optional[CFunc] = None,
99
97
  ) -> Model:
100
98
  @QFunc
101
99
  def _dummy() -> None:
102
100
  pass
103
101
 
104
- functions_compilation_metadata = {
105
- dec_func._py_callable.__name__: dec_func.compilation_metadata
106
- for dec_func in DEC_QFUNCS
107
- if dec_func.compilation_metadata is not None
108
- }
109
102
  model = _dummy.create_model(
110
103
  constraints,
111
104
  execution_preferences,
112
105
  preferences,
113
- classical_execution_function,
114
- functions_compilation_metadata,
115
106
  )
116
- generative_functions = _get_generative_functions(gen_main, preferences)
117
- model.functions = generative_functions
107
+ gen_expand_model = _get_generative_functions(gen_main, preferences)
108
+ model.functions = gen_expand_model.functions
109
+ model.functions_compilation_metadata = (
110
+ gen_expand_model.functions_compilation_metadata
111
+ )
118
112
  model.types = list(QMODULE.type_decls.values())
119
113
  model.enums = list(QMODULE.enum_decls.values())
120
114
  model.qstructs = list(QMODULE.qstruct_decls.values())
@@ -122,8 +116,9 @@ def _expand_generative_model(
122
116
 
123
117
 
124
118
  def _get_generative_functions(
125
- gen_main: QFunc, preferences: Optional[Preferences]
126
- ) -> list[NativeFunctionDefinition]:
119
+ gen_main: QFunc,
120
+ preferences: Optional[Preferences],
121
+ ) -> Model:
127
122
  # The Interpreter accepts a model and a list of generative functions.
128
123
  # Since the main function is generative, it can only be expanded using the
129
124
  # Interpreter.
@@ -132,14 +127,21 @@ def _get_generative_functions(
132
127
  # passing them to the Interpreter.
133
128
  gen_model = _get_wrapper_main(gen_main, preferences)
134
129
  gen_functions = _get_all_model_functions_as_generative_functions()
135
- functions_dict = _interpret_generative_model(gen_model, gen_functions)
136
- return list(functions_dict.values())
130
+ return _interpret_generative_model(gen_model, gen_functions)
137
131
 
138
132
 
139
- def _get_wrapper_main(gen_main: QFunc, preferences: Optional[Preferences]) -> Model:
133
+ def _get_wrapper_main(
134
+ gen_main: QFunc,
135
+ preferences: Optional[Preferences],
136
+ ) -> Model:
140
137
  extra_args = {}
141
138
  if preferences is not None:
142
139
  extra_args["preferences"] = preferences
140
+ functions_compilation_metadata = {
141
+ qfunc._py_callable.__name__: qfunc.compilation_metadata
142
+ for qfunc in DEC_QFUNCS + GEN_QFUNCS
143
+ if qfunc.compilation_metadata is not None
144
+ }
143
145
  return Model(
144
146
  functions=[
145
147
  NativeFunctionDefinition(
@@ -157,6 +159,7 @@ def _get_wrapper_main(gen_main: QFunc, preferences: Optional[Preferences]) -> Mo
157
159
  ],
158
160
  ),
159
161
  ],
162
+ functions_compilation_metadata=functions_compilation_metadata,
160
163
  **extra_args,
161
164
  )
162
165
 
@@ -164,7 +167,9 @@ def _get_wrapper_main(gen_main: QFunc, preferences: Optional[Preferences]) -> Mo
164
167
  def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
165
168
 
166
169
  gen_functions = list(GEN_QFUNCS) + [
167
- GenerativeQFunc(dec_func._py_callable, dec_func.func_decl)
170
+ GenerativeQFunc(
171
+ dec_func._py_callable, dec_func.func_decl, dec_func.compilation_metadata
172
+ )
168
173
  for dec_func in DEC_QFUNCS
169
174
  ]
170
175
  return [
@@ -174,6 +179,7 @@ def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
174
179
  else GenerativeQFunc(
175
180
  gen_func._py_callable,
176
181
  gen_func.func_decl.model_copy(update={"name": GEN_MAIN_NAME}),
182
+ gen_func.compilation_metadata,
177
183
  )
178
184
  )
179
185
  for gen_func in gen_functions
@@ -183,7 +189,7 @@ def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
183
189
 
184
190
  def _interpret_generative_model(
185
191
  gen_model: Model, gen_functions: list[GenerativeQFunc]
186
- ) -> dict[str, NativeFunctionDefinition]:
192
+ ) -> Model:
187
193
  resolve_function_calls(
188
194
  gen_model,
189
195
  {gen_func.func_decl.name: gen_func.func_decl for gen_func in gen_functions},
@@ -201,5 +207,4 @@ def _interpret_generative_model(
201
207
  expanded_gen_main_name
202
208
  ].model_copy(update={"name": MAIN_FUNCTION_NAME})
203
209
  functions_dict.pop(expanded_gen_main_name)
204
-
205
- return functions_dict
210
+ return expand_model.model_copy(update={"functions": list(functions_dict.values())})
@@ -83,10 +83,13 @@ from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
83
83
 
84
84
  class DSLPrettyPrinter(Visitor):
85
85
  def __init__(
86
- self, decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION
86
+ self,
87
+ decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION,
88
+ rename_phase: bool = False,
87
89
  ) -> None:
88
90
  self._level = 0
89
91
  self._decimal_precision = decimal_precision
92
+ self._rename_phase = rename_phase
90
93
 
91
94
  def visit(self, node: NodeType) -> str:
92
95
  res = super().visit(node)
@@ -165,7 +168,10 @@ class DSLPrettyPrinter(Visitor):
165
168
  def visit_QuantumVariableDeclaration(
166
169
  self, var_decl: QuantumVariableDeclaration
167
170
  ) -> str:
168
- return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
171
+ var_name = var_decl.name
172
+ if self._rename_phase and var_name == "phase":
173
+ var_name = "phase_var"
174
+ return f"{var_name}: {self.visit(var_decl.quantum_type)}"
169
175
 
170
176
  def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
171
177
  dir_str = (
@@ -173,7 +179,12 @@ class DSLPrettyPrinter(Visitor):
173
179
  if port_decl.direction != PortDeclarationDirection.Inout
174
180
  else ""
175
181
  )
176
- param_name = f"{port_decl.name}: " if port_decl.name is not None else ""
182
+ port_name = (
183
+ port_decl.name
184
+ if not (self._rename_phase and port_decl.name == "phase")
185
+ else "phase_var"
186
+ )
187
+ param_name = f"{port_name}: " if port_decl.name is not None else ""
177
188
  return f"{dir_str}{param_name}{self.visit(port_decl.quantum_type)}"
178
189
 
179
190
  def visit_QuantumBit(self, qtype: QuantumBit) -> str:
@@ -339,7 +350,11 @@ class DSLPrettyPrinter(Visitor):
339
350
  return f"lambda({positional_args}) {{\n{body}{self._indent}}}"
340
351
 
341
352
  def visit_HandleBinding(self, var_ref: HandleBinding) -> str:
342
- return var_ref.name
353
+ return (
354
+ var_ref.name
355
+ if not (self._rename_phase and var_ref.name == "phase")
356
+ else "phase_var"
357
+ )
343
358
 
344
359
  def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
345
360
  return f"{self.visit(var_ref.base_handle)}[{self.visit(var_ref.start)}:{self.visit(var_ref.end)}]"
@@ -3,6 +3,7 @@ from typing import Optional, Union, cast
3
3
 
4
4
  import black
5
5
 
6
+ from classiq.interface.exceptions import ClassiqInternalError
6
7
  from classiq.interface.generator.constant import Constant
7
8
  from classiq.interface.generator.expressions.expression import Expression
8
9
  from classiq.interface.generator.functions.classical_type import (
@@ -86,16 +87,15 @@ class VariableDeclarationAssignment(Visitor):
86
87
  def __init__(self, pretty_printer: "PythonPrettyPrinter") -> None:
87
88
  self.pretty_printer = pretty_printer
88
89
 
89
- def visit(self, node: NodeType) -> tuple[str, Optional[list[str]]]:
90
+ def visit(self, node: NodeType) -> tuple[str, list[str]]:
90
91
  res = super().visit(node)
91
92
  if not isinstance(res, tuple):
92
93
  raise AssertionError(f"Pretty printing for {type(node)} is not supported ")
93
94
  return res # type: ignore[return-value]
94
95
 
95
- def visit_QuantumBit(self, qtype: QuantumBit) -> tuple[str, Optional[list[str]]]:
96
+ def visit_QuantumBit(self, qtype: QuantumBit) -> tuple[str, list[str]]:
96
97
  self.pretty_printer._imports["QBit"] = 1
97
-
98
- return "QBit", None
98
+ return "QBit", []
99
99
 
100
100
  def visit_QuantumBitvector(
101
101
  self, qtype: QuantumBitvector
@@ -111,19 +111,10 @@ class VariableDeclarationAssignment(Visitor):
111
111
  self, qtype: QuantumNumeric
112
112
  ) -> tuple[str, Optional[list[str]]]:
113
113
  self.pretty_printer._imports["QNum"] = 1
114
+ return "QNum", self.pretty_printer._get_qnum_properties(qtype)
114
115
 
115
- params = []
116
- if qtype.size is not None:
117
- params = [
118
- self.pretty_printer.visit(param)
119
- for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
120
- if param is not None
121
- ]
122
-
123
- return "QNum", params
124
-
125
- def visit_TypeName(self, qtype: TypeName) -> tuple[str, None]:
126
- return qtype.name, None
116
+ def visit_TypeName(self, qtype: TypeName) -> tuple[str, list[str]]:
117
+ return qtype.name, []
127
118
 
128
119
 
129
120
  class PythonPrettyPrinter(Visitor):
@@ -269,21 +260,46 @@ class PythonPrettyPrinter(Visitor):
269
260
  return f"QArray[{element_type}]"
270
261
 
271
262
  def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
272
- params = ""
273
263
  self._imports["QNum"] = 1
274
- if qtype.size is not None:
275
- assert qtype.is_signed is not None
276
- assert qtype.fraction_digits is not None
277
-
264
+ params = ""
265
+ qnum_properties = self._get_qnum_properties(qtype)
266
+ if len(qnum_properties) > 0:
278
267
  params = "[{}]".format(
279
- ", ".join(
280
- _add_quotes(self.visit(param))
281
- for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
282
- )
268
+ ", ".join(_add_quotes(param) for param in qnum_properties)
283
269
  )
284
-
285
270
  return f"QNum{params}"
286
271
 
272
+ def _get_qnum_properties(self, qtype: QuantumNumeric) -> list[str]:
273
+ params: list[str] = []
274
+ if qtype.size is None:
275
+ return params
276
+ params.append(self.visit(qtype.size))
277
+
278
+ is_signed_expr = qtype.is_signed
279
+ fraction_digits_expr = qtype.fraction_digits
280
+ if is_signed_expr is None:
281
+ if fraction_digits_expr is not None:
282
+ raise ClassiqInternalError
283
+ return params
284
+ if fraction_digits_expr is None:
285
+ raise ClassiqInternalError
286
+
287
+ is_unsigned = (
288
+ is_signed_expr.is_evaluated()
289
+ and not is_signed_expr.to_bool_value()
290
+ or is_signed_expr.expr == "UNSIGNED"
291
+ )
292
+ is_integer = (
293
+ fraction_digits_expr.is_evaluated()
294
+ and fraction_digits_expr.to_int_value() == 0
295
+ )
296
+ if is_unsigned and is_integer:
297
+ return params
298
+ params.append(self.visit(is_signed_expr))
299
+ params.append(self.visit(fraction_digits_expr))
300
+
301
+ return params
302
+
287
303
  def visit_AnonClassicalParameterDeclaration(
288
304
  self, cparam: AnonClassicalParameterDeclaration
289
305
  ) -> str:
@@ -325,7 +341,7 @@ class PythonPrettyPrinter(Visitor):
325
341
  type_name, params = VariableDeclarationAssignment(self).visit(
326
342
  local_decl.quantum_type
327
343
  )
328
- params = [f'"{local_decl.name}"'] + (params or [])
344
+ params = [f'"{local_decl.name}"'] + params
329
345
  param_args = ", ".join(params)
330
346
  return f"{self._indent}{self.visit_QuantumVariableDeclaration(local_decl)} = {type_name}({param_args})\n"
331
347
 
@@ -516,7 +532,12 @@ class PythonPrettyPrinter(Visitor):
516
532
 
517
533
 
518
534
  def _add_quotes(exp: str) -> str:
519
- if exp.lower() == "true" or exp.lower() == "false" or _convertible_to_number(exp):
535
+ if (
536
+ exp.lower() == "true"
537
+ or exp.lower() == "false"
538
+ or _convertible_to_number(exp)
539
+ or _is_constant(exp)
540
+ ):
520
541
  return exp
521
542
 
522
543
  return f'"{exp}"'
@@ -531,3 +552,7 @@ def _convertible_to_number(exp: str) -> bool:
531
552
  else:
532
553
  return True
533
554
  return False
555
+
556
+
557
+ def _is_constant(exp: str) -> bool:
558
+ return exp in ("SIGNED", "UNSIGNED")
classiq/qmod/qfunc.py CHANGED
@@ -1,9 +1,14 @@
1
1
  from typing import Callable, Literal, Optional, Union, overload
2
2
 
3
- from classiq.interface.exceptions import ClassiqError
3
+ from classiq.interface.exceptions import ClassiqInternalError
4
4
 
5
5
  from classiq.qmod.quantum_callable import QCallable
6
- from classiq.qmod.quantum_function import ExternalQFunc, GenerativeQFunc, QFunc
6
+ from classiq.qmod.quantum_function import (
7
+ BaseQFunc,
8
+ ExternalQFunc,
9
+ GenerativeQFunc,
10
+ QFunc,
11
+ )
7
12
 
8
13
  GEN_QFUNCS: list[GenerativeQFunc] = []
9
14
  DEC_QFUNCS: list[QFunc] = []
@@ -54,25 +59,22 @@ def qfunc(
54
59
  synthesize_separately: bool = False,
55
60
  ) -> Union[Callable[[Callable], QCallable], QCallable]:
56
61
  def wrapper(func: Callable) -> QCallable:
62
+ qfunc: BaseQFunc
57
63
  if generative:
58
- gen_qfunc = GenerativeQFunc(func)
64
+ qfunc = GenerativeQFunc(func)
65
+ GEN_QFUNCS.append(qfunc)
66
+ elif external:
59
67
  if synthesize_separately:
60
- raise ClassiqError(
61
- "Generative functions can not be synthesized separately"
62
- )
63
- GEN_QFUNCS.append(gen_qfunc)
64
- return gen_qfunc
65
- if external:
66
- if synthesize_separately:
67
- raise ClassiqError(
68
- "External functions can not be synthesized separately"
68
+ raise ClassiqInternalError(
69
+ "External functions can't be marked as synthesized separately"
69
70
  )
70
71
  return ExternalQFunc(func)
71
- dec_qfunc = QFunc(func)
72
+ else:
73
+ qfunc = QFunc(func)
74
+ DEC_QFUNCS.append(qfunc)
72
75
  if synthesize_separately:
73
- dec_qfunc.should_synthesize_separately = True
74
- DEC_QFUNCS.append(dec_qfunc)
75
- return dec_qfunc
76
+ qfunc.update_compilation_metadata(should_synthesize_separately=True)
77
+ return qfunc
76
78
 
77
79
  if func is not None:
78
80
  return wrapper(func)
@@ -28,12 +28,35 @@ from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
28
28
  from classiq.qmod.utilities import mangle_keyword
29
29
 
30
30
 
31
- class QFunc(QExpandable):
31
+ class BaseQFunc(QExpandable):
32
+ def __init__(
33
+ self,
34
+ py_callable: Callable,
35
+ compilation_metadata: Optional[CompilationMetadata] = None,
36
+ ) -> None:
37
+ super().__init__(py_callable)
38
+ self.compilation_metadata = compilation_metadata
39
+
40
+ def update_compilation_metadata(self, **kwargs: Any) -> None:
41
+ self.compilation_metadata = self._compilation_metadata.model_copy(update=kwargs)
42
+
43
+ @property
44
+ def _compilation_metadata(self) -> CompilationMetadata:
45
+ if self.compilation_metadata is None:
46
+ return CompilationMetadata()
47
+ return self.compilation_metadata
48
+
49
+
50
+ class QFunc(BaseQFunc):
32
51
  FRAME_DEPTH = 2
33
52
 
34
- def __init__(self, py_callable: Callable) -> None:
53
+ def __init__(
54
+ self,
55
+ py_callable: Callable,
56
+ compilation_metadata: Optional[CompilationMetadata] = None,
57
+ ) -> None:
35
58
  _validate_no_gen_params(py_callable.__annotations__)
36
- super().__init__(py_callable)
59
+ super().__init__(py_callable, compilation_metadata)
37
60
  functools.update_wrapper(self, py_callable)
38
61
  self.compilation_metadata: Optional[CompilationMetadata] = None
39
62
 
@@ -44,21 +67,6 @@ class QFunc(QExpandable):
44
67
  infer_func_decl(self._py_callable, qmodule=self._qmodule),
45
68
  )
46
69
 
47
- @property
48
- def should_synthesize_separately(self) -> bool:
49
- if self.compilation_metadata is None:
50
- return False
51
- return self.compilation_metadata.should_synthesize_separately
52
-
53
- @should_synthesize_separately.setter
54
- def should_synthesize_separately(self, value: bool) -> None:
55
- if self.compilation_metadata is None:
56
- self.compilation_metadata = CompilationMetadata(
57
- should_synthesize_separately=value
58
- )
59
- else:
60
- self.compilation_metadata.should_synthesize_separately = value
61
-
62
70
  def __call__(self, *args: Any, **kwargs: Any) -> None:
63
71
  super().__call__(*args, **kwargs)
64
72
  self.expand()
@@ -69,16 +77,13 @@ class QFunc(QExpandable):
69
77
  execution_preferences: Optional[ExecutionPreferences] = None,
70
78
  preferences: Optional[Preferences] = None,
71
79
  classical_execution_function: Optional[CFunc] = None,
72
- functions_compilation_metadata: Optional[dict[str, CompilationMetadata]] = None,
73
80
  ) -> Model:
74
- if functions_compilation_metadata is None:
75
- functions_compilation_metadata = dict()
76
81
  self._qmodule.enum_decls = dict()
77
82
  self._qmodule.type_decls = dict()
78
83
  self._qmodule.qstruct_decls = dict()
79
84
  self._qmodule.native_defs = dict()
80
85
  self._qmodule.constants = dict()
81
- self._qmodule.functions_compilation_metadata = functions_compilation_metadata
86
+ self._qmodule.functions_compilation_metadata = dict()
82
87
  QConstant.set_current_model(self._qmodule)
83
88
  self.expand()
84
89
  model_extra_settings: list[tuple[str, Any]] = [
@@ -167,13 +172,14 @@ class ExternalQFunc(QTerminalCallable):
167
172
  ][0]
168
173
 
169
174
 
170
- class GenerativeQFunc(QExpandable):
175
+ class GenerativeQFunc(BaseQFunc):
171
176
  def __init__(
172
177
  self,
173
178
  py_callable: Callable,
174
179
  func_decl: Optional[NamedParamsQuantumFunctionDeclaration] = None,
180
+ compilation_metadata: Optional[CompilationMetadata] = None,
175
181
  ) -> None:
176
- super().__init__(py_callable)
182
+ super().__init__(py_callable, compilation_metadata)
177
183
  self._func_decl = func_decl
178
184
 
179
185
  @property
@@ -0,0 +1,23 @@
1
+ from classiq.interface.generator.functions.type_name import TypeName
2
+ from classiq.interface.generator.visitor import Visitor
3
+
4
+ from classiq.qmod.model_state_container import QMODULE
5
+
6
+
7
+ class QStructAnnotator(Visitor):
8
+ def __init__(self) -> None:
9
+ self._visited: set[TypeName] = set()
10
+
11
+ def visit_TypeName(self, type_name: TypeName) -> None:
12
+ decl = QMODULE.qstruct_decls.get(type_name.name)
13
+ if decl is None or type_name.has_fields or (type_name in self._visited):
14
+ return
15
+ self._visited.add(type_name)
16
+ new_fields = {
17
+ field_name: field_type.model_copy()
18
+ for field_name, field_type in decl.fields.items()
19
+ }
20
+ # We first visit the new fields and then set to deal with recursive
21
+ # qstructs
22
+ self.visit(new_fields)
23
+ type_name.set_fields(new_fields)
@@ -44,6 +44,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
44
44
  from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
45
45
  from classiq.qmod.semantics.annotation import annotate_function_call_decl
46
46
  from classiq.qmod.semantics.error_manager import ErrorManager
47
+ from classiq.qmod.semantics.qstruct_annotator import QStructAnnotator
47
48
  from classiq.qmod.semantics.validation.constants_validation import (
48
49
  check_duplicate_constants,
49
50
  )
@@ -70,7 +71,6 @@ HANDLE_BINDING_PART_MESSAGE = {
70
71
 
71
72
 
72
73
  class StaticScope:
73
-
74
74
  def __init__(
75
75
  self,
76
76
  parameters: list[str],
@@ -363,6 +363,8 @@ def resolve_function_calls(
363
363
  quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
364
364
  ) -> None:
365
365
  with ErrorManager().ignore_errors_context():
366
+ QStructAnnotator().visit(quantum_function_dict)
367
+ QStructAnnotator().visit(root)
366
368
  StaticSemanticsVisitor(
367
369
  {**BUILTIN_FUNCTION_DECLARATIONS, **quantum_function_dict},
368
370
  [],
@@ -372,6 +374,7 @@ def resolve_function_calls(
372
374
  def static_semantics_analysis_pass(
373
375
  model: Model, error_type: Optional[type[Exception]] = ClassiqSemanticError
374
376
  ) -> None:
377
+ QStructAnnotator().visit(model)
375
378
  StaticSemanticsVisitor(
376
379
  {**BUILTIN_FUNCTION_DECLARATIONS, **model.function_dict},
377
380
  [const.name for const in model.constants],
@@ -36,7 +36,9 @@ def write_qmod(
36
36
  model
37
37
  )
38
38
 
39
- synthesis_options = model.model_dump(include={"constraints", "preferences"})
39
+ synthesis_options = model.model_dump(
40
+ include={"constraints", "preferences"}, exclude_none=True
41
+ )
40
42
 
41
43
  synthesis_options_path = Path(f"{name}.{_SYNTHESIS_OPTIONS_SUFFIX}")
42
44
  if directory is not None:
classiq/synthesis.py CHANGED
@@ -20,13 +20,15 @@ CANT_PARSE_QUANTUM_PROGRAM_MSG = (
20
20
  )
21
21
 
22
22
 
23
- def show(quantum_program: SerializedQuantumProgram) -> None:
23
+ def show(quantum_program: SerializedQuantumProgram, display_url: bool = True) -> None:
24
24
  """
25
25
  Displays the interactive representation of the quantum program in the Classiq IDE.
26
26
 
27
27
  Args:
28
28
  quantum_program:
29
29
  The serialized quantum program to be displayed.
30
+ display_url:
31
+ Whether to print the url
30
32
 
31
33
  Links:
32
34
  [Visualization tool](https://docs.classiq.io/latest/reference-manual/analyzer/quantum-program-visualization-tool/)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: classiq
3
- Version: 0.56.1
3
+ Version: 0.58.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  Home-page: https://classiq.io
6
6
  License: Proprietary