classiq 0.61.0__py3-none-any.whl → 0.63.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 (83) hide show
  1. classiq/__init__.py +3 -0
  2. classiq/_internals/api_wrapper.py +6 -26
  3. classiq/_internals/client.py +1 -9
  4. classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
  5. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -8
  6. classiq/applications/combinatorial_helpers/optimization_model.py +13 -2
  7. classiq/applications/combinatorial_helpers/pyomo_utils.py +143 -13
  8. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  9. classiq/applications/combinatorial_optimization/combinatorial_problem.py +58 -23
  10. classiq/applications/grover/grover_model_constructor.py +1 -1
  11. classiq/applications/libraries/qmci_library.py +2 -1
  12. classiq/execution/execution_session.py +66 -96
  13. classiq/execution/jobs.py +12 -10
  14. classiq/interface/_version.py +1 -1
  15. classiq/interface/backend/backend_preferences.py +26 -5
  16. classiq/interface/backend/pydantic_backend.py +1 -1
  17. classiq/interface/backend/quantum_backend_providers.py +3 -1
  18. classiq/interface/chemistry/operator.py +0 -204
  19. classiq/interface/execution/primitives.py +1 -0
  20. classiq/interface/generator/compiler_keywords.py +4 -0
  21. classiq/interface/generator/copy.py +47 -0
  22. classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
  23. classiq/interface/generator/functions/type_name.py +6 -0
  24. classiq/interface/generator/generated_circuit_data.py +22 -7
  25. classiq/interface/generator/model/model.py +3 -0
  26. classiq/interface/generator/model/preferences/preferences.py +14 -1
  27. classiq/interface/generator/quantum_function_call.py +4 -2
  28. classiq/interface/generator/types/compilation_metadata.py +2 -1
  29. classiq/interface/model/handle_binding.py +50 -5
  30. classiq/interface/model/quantum_type.py +16 -0
  31. classiq/interface/server/routes.py +1 -3
  32. classiq/model_expansions/capturing/captured_vars.py +114 -28
  33. classiq/model_expansions/closure.py +25 -65
  34. classiq/model_expansions/function_builder.py +19 -9
  35. classiq/model_expansions/generative_functions.py +16 -2
  36. classiq/model_expansions/interpreter.py +110 -66
  37. classiq/model_expansions/model_tables.py +4 -0
  38. classiq/model_expansions/quantum_operations/call_emitter.py +83 -20
  39. classiq/model_expansions/quantum_operations/classicalif.py +1 -1
  40. classiq/model_expansions/quantum_operations/control.py +3 -10
  41. classiq/model_expansions/quantum_operations/emitter.py +3 -4
  42. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +1 -2
  43. classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
  44. classiq/model_expansions/quantum_operations/repeat.py +4 -3
  45. classiq/model_expansions/quantum_operations/shallow_emitter.py +9 -3
  46. classiq/model_expansions/scope.py +9 -13
  47. classiq/model_expansions/scope_initialization.py +34 -25
  48. classiq/model_expansions/transformers/var_splitter.py +57 -7
  49. classiq/open_library/__init__.py +4 -0
  50. classiq/open_library/functions/__init__.py +130 -0
  51. classiq/{qmod/builtins → open_library}/functions/amplitude_estimation.py +2 -2
  52. classiq/{qmod/builtins → open_library}/functions/discrete_sine_cosine_transform.py +6 -4
  53. classiq/{qmod/builtins → open_library}/functions/grover.py +2 -2
  54. classiq/{qmod/builtins → open_library}/functions/linear_pauli_rotation.py +1 -1
  55. classiq/{qmod/builtins → open_library}/functions/modular_exponentiation.py +2 -2
  56. classiq/{qmod/builtins → open_library}/functions/qpe.py +2 -2
  57. classiq/{qmod/builtins → open_library}/functions/state_preparation.py +6 -149
  58. classiq/{qmod/builtins → open_library}/functions/swap_test.py +1 -1
  59. classiq/open_library/functions/utility_functions.py +81 -0
  60. classiq/{qmod/builtins → open_library}/functions/variational.py +1 -1
  61. classiq/qmod/builtins/functions/__init__.py +4 -130
  62. classiq/qmod/builtins/functions/allocation.py +150 -0
  63. classiq/qmod/builtins/functions/arithmetic.py +0 -34
  64. classiq/qmod/builtins/functions/operators.py +0 -6
  65. classiq/qmod/builtins/operations.py +19 -80
  66. classiq/qmod/create_model_function.py +8 -162
  67. classiq/qmod/generative.py +0 -16
  68. classiq/qmod/model_state_container.py +7 -0
  69. classiq/qmod/native/pretty_printer.py +10 -11
  70. classiq/qmod/pretty_print/pretty_printer.py +1 -1
  71. classiq/qmod/python_classical_type.py +1 -5
  72. classiq/qmod/qfunc.py +11 -12
  73. classiq/qmod/qmod_variable.py +1 -3
  74. classiq/qmod/quantum_expandable.py +23 -1
  75. classiq/qmod/quantum_function.py +69 -7
  76. {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/METADATA +2 -1
  77. {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/RECORD +82 -78
  78. classiq/qmod/builtins/functions/utility_functions.py +0 -43
  79. /classiq/{qmod/builtins → open_library}/functions/hea.py +0 -0
  80. /classiq/{qmod/builtins → open_library}/functions/qaoa_penalty.py +0 -0
  81. /classiq/{qmod/builtins → open_library}/functions/qft_functions.py +0 -0
  82. /classiq/{qmod/builtins → open_library}/functions/qsvt.py +0 -0
  83. {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/WHEEL +0 -0
@@ -412,7 +412,7 @@ class PythonPrettyPrinter(Visitor):
412
412
  def visit_PhaseOperation(self, op: PhaseOperation) -> str:
413
413
  self._imports["phase"] = 1
414
414
  theta = f", {self.visit(op.theta)}" if op.theta is not None else ""
415
- return f"{self._indent}phase({self.visit(op.expression)},{theta})\n"
415
+ return f"{self._indent}phase({self.visit(op.expression)}{theta})\n"
416
416
 
417
417
  def visit_ClassicalIf(self, op: ClassicalIf) -> str:
418
418
  self._imports["if_"] = 1
@@ -1,6 +1,5 @@
1
1
  import dataclasses
2
2
  import inspect
3
- import sys
4
3
  from enum import EnumMeta
5
4
  from typing import (
6
5
  Optional,
@@ -16,16 +15,13 @@ from classiq.interface.generator.functions.classical_type import (
16
15
  Integer,
17
16
  Real,
18
17
  )
18
+ from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
19
19
  from classiq.interface.generator.functions.type_name import Enum, Struct
20
20
 
21
21
  from classiq.qmod.cparam import CArray, CBool, CInt, CReal
22
22
  from classiq.qmod.qmod_variable import get_type_hint_expr
23
23
  from classiq.qmod.utilities import version_portable_get_args
24
24
 
25
- if sys.version_info[0:2] >= (3, 9):
26
- pass
27
- from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
28
-
29
25
  CARRAY_ERROR_MESSAGE = (
30
26
  "CArray accepts one or two generic parameters in the form "
31
27
  "`CArray[<element-type>]` or `CArray[<element-type>, <size>]`"
classiq/qmod/qfunc.py CHANGED
@@ -1,3 +1,5 @@
1
+ from collections.abc import Iterator
2
+ from contextlib import contextmanager
1
3
  from typing import Callable, Literal, Optional, Union, overload
2
4
 
3
5
  from classiq.interface.exceptions import ClassiqInternalError
@@ -10,17 +12,16 @@ from classiq.qmod.quantum_function import (
10
12
  QFunc,
11
13
  )
12
14
 
13
- GEN_QFUNCS: list[GenerativeQFunc] = []
14
- DEC_QFUNCS: list[QFunc] = []
15
+ _GENERATIVE_SWITCH = False
15
16
 
16
17
 
17
- def set_discovered_functions(
18
- dec_funcs: list[QFunc], gen_funcs: list[GenerativeQFunc]
19
- ) -> None:
20
- DEC_QFUNCS.clear()
21
- DEC_QFUNCS.extend(dec_funcs)
22
- GEN_QFUNCS.clear()
23
- GEN_QFUNCS.extend(gen_funcs)
18
+ @contextmanager
19
+ def set_global_generative_switch() -> Iterator[None]:
20
+ global _GENERATIVE_SWITCH
21
+ previous = _GENERATIVE_SWITCH
22
+ _GENERATIVE_SWITCH = True
23
+ yield
24
+ _GENERATIVE_SWITCH = previous
24
25
 
25
26
 
26
27
  @overload
@@ -56,9 +57,8 @@ def qfunc(
56
57
  ) -> Union[Callable[[Callable], QCallable], QCallable]:
57
58
  def wrapper(func: Callable) -> QCallable:
58
59
  qfunc: BaseQFunc
59
- if generative:
60
+ if generative or _GENERATIVE_SWITCH:
60
61
  qfunc = GenerativeQFunc(func)
61
- GEN_QFUNCS.append(qfunc)
62
62
  elif external:
63
63
  if synthesize_separately:
64
64
  raise ClassiqInternalError(
@@ -67,7 +67,6 @@ def qfunc(
67
67
  return ExternalQFunc(func)
68
68
  else:
69
69
  qfunc = QFunc(func)
70
- DEC_QFUNCS.append(qfunc)
71
70
  if synthesize_separately:
72
71
  qfunc.update_compilation_metadata(should_synthesize_separately=True)
73
72
  return qfunc
@@ -285,7 +285,7 @@ class QNum(Generic[_P], QScalar):
285
285
  def __init__(
286
286
  self,
287
287
  name: Union[str, HandleBinding],
288
- size: Union[int, CInt, Expression, None] = None,
288
+ size: Union[int, CInt, Expression, SymbolicExpr, None] = None,
289
289
  is_signed: Union[bool, Expression, SymbolicExpr, None] = None,
290
290
  fraction_digits: Union[int, CInt, Expression, None] = None,
291
291
  _expr_str: Optional[str] = None,
@@ -485,8 +485,6 @@ class QArray(ArrayBase[_P], QVar):
485
485
  if is_generative_mode():
486
486
  with generative_mode_context(False):
487
487
  return interpret_expression(str(self.len))
488
- if self._length is not None:
489
- return CParamScalar(f"{self._length}")
490
488
  return CParamScalar(f"get_field({self}, 'len')")
491
489
 
492
490
  @classmethod
@@ -101,6 +101,10 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
101
101
  QExpandable.STACK[-1] if QExpandable.STACK else None
102
102
  )
103
103
 
104
+ def __call__(self, *args: Any, **kwargs: Any) -> None:
105
+ super().__call__(*args, **kwargs)
106
+ self.add_function_dependencies()
107
+
104
108
  def expand(self) -> None:
105
109
  if self not in QExpandable.STACK:
106
110
  with self, generative_mode_context(False):
@@ -161,6 +165,17 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
161
165
  func_decl, None, source_ref_, *args, **kwargs
162
166
  )
163
167
 
168
+ def add_function_dependencies(self) -> None:
169
+ called_name = self.func_decl.name
170
+ if called_name is None:
171
+ return
172
+ for expandable in QExpandable.STACK:
173
+ caller_name = expandable.func_decl.name
174
+ if caller_name is not None:
175
+ caller_deps = self._qmodule.function_dependencies[caller_name]
176
+ if called_name not in caller_deps:
177
+ caller_deps.append(called_name)
178
+
164
179
 
165
180
  class QLambdaFunction(QExpandable):
166
181
  def __init__(
@@ -298,6 +313,12 @@ def prepare_arg(
298
313
  def prepare_arg(
299
314
  arg_decl: AnonPositionalArg, val: Any, func_name: Optional[str], param_name: str
300
315
  ) -> ArgValue:
316
+ from classiq.qmod.quantum_function import BaseQFunc, GenerativeQFunc
317
+
318
+ if isinstance(val, BaseQFunc):
319
+ val.add_function_dependencies()
320
+ if isinstance(val, GenerativeQFunc):
321
+ QMODULE.generative_functions[val.func_decl.name] = val
301
322
  if isinstance(val, QConstant):
302
323
  val.add_to_model()
303
324
  return Expression(expr=str(val.name))
@@ -336,7 +357,8 @@ def prepare_arg(
336
357
  pos_rename_params=val.infer_rename_params(),
337
358
  body=val.body,
338
359
  )
339
- qlambda.set_py_callable(val._py_callable)
360
+ if is_generative_mode():
361
+ qlambda.set_py_callable(val._py_callable)
340
362
  return qlambda
341
363
 
342
364
  if isinstance(val, QExpandable):
@@ -1,5 +1,7 @@
1
1
  import ast
2
2
  import functools
3
+ from abc import abstractmethod
4
+ from collections import defaultdict
3
5
  from dataclasses import is_dataclass
4
6
  from enum import EnumMeta
5
7
  from inspect import isclass
@@ -23,6 +25,7 @@ from classiq.interface.model.quantum_function_declaration import (
23
25
 
24
26
  from classiq.qmod.classical_function import CFunc
25
27
  from classiq.qmod.declaration_inferrer import infer_func_decl
28
+ from classiq.qmod.generative import set_frontend_interpreter
26
29
  from classiq.qmod.qmod_constant import QConstant
27
30
  from classiq.qmod.qmod_parameter import CArray, CParam
28
31
  from classiq.qmod.qmod_variable import QVar
@@ -62,9 +65,19 @@ class BaseQFunc(QExpandable):
62
65
  return CompilationMetadata()
63
66
  return self.compilation_metadata
64
67
 
68
+ @abstractmethod
69
+ def create_model(
70
+ self,
71
+ constraints: Optional[Constraints] = None,
72
+ execution_preferences: Optional[ExecutionPreferences] = None,
73
+ preferences: Optional[Preferences] = None,
74
+ classical_execution_function: Optional[CFunc] = None,
75
+ ) -> Model:
76
+ pass
77
+
65
78
 
66
79
  class QFunc(BaseQFunc):
67
- FRAME_DEPTH = 2
80
+ FRAME_DEPTH = 3
68
81
 
69
82
  def __init__(
70
83
  self,
@@ -90,14 +103,14 @@ class QFunc(BaseQFunc):
90
103
 
91
104
  @property
92
105
  def func_decl(self) -> NamedParamsQuantumFunctionDeclaration:
93
- return self._qmodule.native_defs.get(
94
- self._py_callable.__name__,
95
- infer_func_decl(self._py_callable, qmodule=self._qmodule),
96
- )
106
+ name = self._py_callable.__name__
107
+ if hasattr(self._qmodule, "native_defs") and name in self._qmodule.native_defs:
108
+ return self._qmodule.native_defs[name]
109
+ return infer_func_decl(self._py_callable, qmodule=self._qmodule)
97
110
 
98
111
  def __call__(self, *args: Any, **kwargs: Any) -> None:
99
- super().__call__(*args, **kwargs)
100
112
  self.expand()
113
+ super().__call__(*args, **kwargs)
101
114
 
102
115
  def create_model(
103
116
  self,
@@ -112,6 +125,8 @@ class QFunc(BaseQFunc):
112
125
  self._qmodule.native_defs = dict()
113
126
  self._qmodule.constants = dict()
114
127
  self._qmodule.functions_compilation_metadata = dict()
128
+ self._qmodule.generative_functions = dict()
129
+ self._qmodule.function_dependencies = defaultdict(list)
115
130
  QConstant.set_current_model(self._qmodule)
116
131
  self.expand()
117
132
  model_extra_settings: list[tuple[str, Any]] = [
@@ -124,7 +139,7 @@ class QFunc(BaseQFunc):
124
139
  model_extra_settings.append(
125
140
  ("classical_execution_code", classical_execution_function.code)
126
141
  )
127
- return Model(
142
+ model = Model(
128
143
  constants=list(self._qmodule.constants.values()),
129
144
  functions=list(self._qmodule.native_defs.values()),
130
145
  enums=list(self._qmodule.enum_decls.values()),
@@ -133,6 +148,30 @@ class QFunc(BaseQFunc):
133
148
  functions_compilation_metadata=self._qmodule.functions_compilation_metadata,
134
149
  **{key: value for key, value in model_extra_settings if value},
135
150
  )
151
+ if len(self._qmodule.generative_functions) > 0:
152
+ return self._create_generative_model(model)
153
+ return model
154
+
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 (
158
+ resolve_function_calls,
159
+ )
160
+
161
+ generative_functions = list(self._qmodule.generative_functions.values())
162
+ resolve_function_calls(
163
+ model_stub,
164
+ dict(model_stub.function_dict)
165
+ | {
166
+ gen_func.func_decl.name: gen_func.func_decl
167
+ for gen_func in generative_functions
168
+ },
169
+ )
170
+ interpreter = Interpreter(
171
+ model_stub, generative_functions, is_normalizer=True, is_shallow=True
172
+ )
173
+ set_frontend_interpreter(interpreter)
174
+ return interpreter.expand()
136
175
 
137
176
  def expand(self) -> None:
138
177
  if self.func_decl.name in self._qmodule.native_defs:
@@ -220,6 +259,29 @@ class GenerativeQFunc(BaseQFunc):
220
259
  self._func_decl = infer_func_decl(self._py_callable, self._qmodule)
221
260
  return self._func_decl
222
261
 
262
+ def __call__(self, *args: Any, **kwargs: Any) -> None:
263
+ self._qmodule.generative_functions[self.func_decl.name] = self
264
+ super().__call__(*args, **kwargs)
265
+
266
+ def create_model(
267
+ self,
268
+ constraints: Optional[Constraints] = None,
269
+ execution_preferences: Optional[ExecutionPreferences] = None,
270
+ preferences: Optional[Preferences] = None,
271
+ classical_execution_function: Optional[CFunc] = None,
272
+ ) -> Model:
273
+ def _dec_main(*args: Any, **kwargs: Any) -> None:
274
+ self(*args, **kwargs)
275
+
276
+ _dec_main.__annotations__ = self._py_callable.__annotations__
277
+
278
+ return QFunc(_dec_main).create_model(
279
+ constraints=constraints,
280
+ execution_preferences=execution_preferences,
281
+ preferences=preferences,
282
+ classical_execution_function=classical_execution_function,
283
+ )
284
+
223
285
 
224
286
  ILLEGAL_PARAM_ERROR = "Unsupported type hint '{annotation}' for argument '{name}'."
225
287
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: classiq
3
- Version: 0.61.0
3
+ Version: 0.63.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  Home-page: https://classiq.io
6
6
  License: Proprietary
@@ -53,6 +53,7 @@ Requires-Dist: sympy (>=1.13.0,<2.0.0)
53
53
  Requires-Dist: tabulate (>=0.8.9,<1)
54
54
  Requires-Dist: torch (>=2.0,<3.0) ; extra == "qml"
55
55
  Requires-Dist: torchvision (>=0.15,<1.0) ; extra == "qml"
56
+ Requires-Dist: tqdm (>=4.67.1,<5.0.0)
56
57
  Project-URL: Documentation, https://docs.classiq.io/
57
58
  Description-Content-Type: text/markdown
58
59