classiq 0.45.1__py3-none-any.whl → 0.46.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 (146) hide show
  1. classiq/__init__.py +0 -1
  2. classiq/_internals/__init__.py +20 -0
  3. classiq/_internals/authentication/authentication.py +11 -0
  4. classiq/analyzer/analyzer.py +12 -10
  5. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
  6. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +1 -1
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  8. classiq/applications/libraries/qmci_library.py +4 -9
  9. classiq/execution/execution_session.py +68 -7
  10. classiq/executor.py +14 -2
  11. classiq/interface/_version.py +1 -1
  12. classiq/interface/backend/backend_preferences.py +189 -0
  13. classiq/interface/backend/quantum_backend_providers.py +38 -0
  14. classiq/interface/debug_info/debug_info.py +22 -2
  15. classiq/interface/exceptions.py +16 -1
  16. classiq/interface/executor/execution_preferences.py +18 -0
  17. classiq/interface/generator/application_apis/chemistry_declarations.py +1 -177
  18. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +0 -12
  19. classiq/interface/generator/application_apis/finance_declarations.py +8 -43
  20. classiq/interface/generator/application_apis/qsvm_declarations.py +0 -78
  21. classiq/interface/generator/builtin_api_builder.py +0 -3
  22. classiq/interface/generator/functions/__init__.py +0 -2
  23. classiq/interface/generator/functions/builtins/__init__.py +0 -15
  24. classiq/interface/generator/generated_circuit_data.py +2 -0
  25. classiq/interface/generator/hardware/hardware_data.py +37 -0
  26. classiq/interface/generator/model/constraints.py +18 -1
  27. classiq/interface/generator/model/preferences/preferences.py +53 -1
  28. classiq/interface/generator/model/quantum_register.py +1 -1
  29. classiq/interface/generator/quantum_program.py +10 -2
  30. classiq/interface/generator/transpiler_basis_gates.py +4 -0
  31. classiq/interface/generator/types/builtin_enum_declarations.py +136 -21
  32. classiq/interface/generator/types/enum_declaration.py +1 -3
  33. classiq/interface/generator/types/struct_declaration.py +1 -3
  34. classiq/interface/hardware.py +5 -0
  35. classiq/interface/ide/visual_model.py +1 -1
  36. classiq/interface/model/classical_parameter_declaration.py +6 -0
  37. classiq/interface/model/inplace_binary_operation.py +0 -14
  38. classiq/interface/model/model.py +1 -18
  39. classiq/interface/model/port_declaration.py +4 -2
  40. classiq/interface/model/quantum_function_declaration.py +19 -6
  41. classiq/interface/model/quantum_lambda_function.py +11 -1
  42. classiq/interface/model/quantum_variable_declaration.py +1 -1
  43. classiq/model_expansions/__init__.py +0 -0
  44. classiq/model_expansions/atomic_expression_functions_defs.py +250 -0
  45. classiq/model_expansions/capturing/__init__.py +0 -0
  46. classiq/model_expansions/capturing/captured_var_manager.py +50 -0
  47. classiq/model_expansions/capturing/mangling_utils.py +17 -0
  48. classiq/model_expansions/capturing/propagated_var_stack.py +180 -0
  49. classiq/model_expansions/closure.py +160 -0
  50. classiq/model_expansions/debug_flag.py +3 -0
  51. classiq/model_expansions/evaluators/__init__.py +0 -0
  52. classiq/model_expansions/evaluators/arg_type_match.py +160 -0
  53. classiq/model_expansions/evaluators/argument_types.py +42 -0
  54. classiq/model_expansions/evaluators/classical_expression.py +36 -0
  55. classiq/model_expansions/evaluators/control.py +144 -0
  56. classiq/model_expansions/evaluators/parameter_types.py +227 -0
  57. classiq/model_expansions/evaluators/quantum_type_utils.py +235 -0
  58. classiq/model_expansions/evaluators/type_type_match.py +90 -0
  59. classiq/model_expansions/expression_evaluator.py +125 -0
  60. classiq/model_expansions/expression_renamer.py +76 -0
  61. classiq/model_expansions/function_builder.py +192 -0
  62. classiq/model_expansions/generative_functions.py +101 -0
  63. classiq/model_expansions/interpreter.py +365 -0
  64. classiq/model_expansions/model_tables.py +105 -0
  65. classiq/model_expansions/quantum_operations/__init__.py +19 -0
  66. classiq/model_expansions/quantum_operations/bind.py +64 -0
  67. classiq/model_expansions/quantum_operations/classicalif.py +39 -0
  68. classiq/model_expansions/quantum_operations/control.py +235 -0
  69. classiq/model_expansions/quantum_operations/emitter.py +215 -0
  70. classiq/model_expansions/quantum_operations/expression_operation.py +218 -0
  71. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +250 -0
  72. classiq/model_expansions/quantum_operations/invert.py +38 -0
  73. classiq/model_expansions/quantum_operations/power.py +74 -0
  74. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +174 -0
  75. classiq/model_expansions/quantum_operations/quantum_function_call.py +15 -0
  76. classiq/model_expansions/quantum_operations/repeat.py +33 -0
  77. classiq/model_expansions/quantum_operations/variable_decleration.py +28 -0
  78. classiq/model_expansions/quantum_operations/within_apply.py +46 -0
  79. classiq/model_expansions/scope.py +226 -0
  80. classiq/model_expansions/scope_initialization.py +136 -0
  81. classiq/model_expansions/sympy_conversion/__init__.py +0 -0
  82. classiq/model_expansions/sympy_conversion/arithmetics.py +49 -0
  83. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +150 -0
  84. classiq/model_expansions/sympy_conversion/sympy_to_python.py +113 -0
  85. classiq/model_expansions/utils/__init__.py +0 -0
  86. classiq/model_expansions/utils/counted_name_allocator.py +11 -0
  87. classiq/model_expansions/visitors/__init__.py +0 -0
  88. classiq/model_expansions/visitors/boolean_expression_transformers.py +214 -0
  89. classiq/model_expansions/visitors/variable_references.py +115 -0
  90. classiq/qmod/__init__.py +1 -3
  91. classiq/qmod/builtins/enums.py +33 -2
  92. classiq/qmod/builtins/functions/__init__.py +251 -0
  93. classiq/qmod/builtins/functions/amplitude_estimation.py +27 -0
  94. classiq/qmod/builtins/functions/arithmetic.py +68 -0
  95. classiq/qmod/builtins/functions/benchmarking.py +8 -0
  96. classiq/qmod/builtins/functions/chemistry.py +91 -0
  97. classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +105 -0
  98. classiq/qmod/builtins/functions/exponentiation.py +111 -0
  99. classiq/qmod/builtins/functions/finance.py +34 -0
  100. classiq/qmod/builtins/functions/grover.py +178 -0
  101. classiq/qmod/builtins/functions/hea.py +59 -0
  102. classiq/qmod/builtins/functions/linear_pauli_rotation.py +65 -0
  103. classiq/qmod/builtins/functions/modular_exponentiation.py +137 -0
  104. classiq/qmod/builtins/functions/operators.py +22 -0
  105. classiq/qmod/builtins/functions/qaoa_penalty.py +116 -0
  106. classiq/qmod/builtins/functions/qft.py +23 -0
  107. classiq/qmod/builtins/functions/qpe.py +39 -0
  108. classiq/qmod/builtins/functions/qsvm.py +24 -0
  109. classiq/qmod/builtins/functions/qsvt.py +136 -0
  110. classiq/qmod/builtins/functions/standard_gates.py +739 -0
  111. classiq/qmod/builtins/functions/state_preparation.py +357 -0
  112. classiq/qmod/builtins/functions/swap_test.py +25 -0
  113. classiq/qmod/builtins/structs.py +50 -28
  114. classiq/qmod/cparam.py +64 -0
  115. classiq/qmod/create_model_function.py +190 -0
  116. classiq/qmod/declaration_inferrer.py +52 -81
  117. classiq/qmod/expression_query.py +16 -0
  118. classiq/qmod/generative.py +48 -0
  119. classiq/qmod/model_state_container.py +1 -2
  120. classiq/qmod/native/pretty_printer.py +7 -11
  121. classiq/qmod/pretty_print/pretty_printer.py +7 -11
  122. classiq/qmod/python_classical_type.py +67 -0
  123. classiq/qmod/qfunc.py +19 -4
  124. classiq/qmod/qmod_parameter.py +15 -64
  125. classiq/qmod/qmod_variable.py +27 -45
  126. classiq/qmod/quantum_callable.py +1 -1
  127. classiq/qmod/quantum_expandable.py +10 -4
  128. classiq/qmod/quantum_function.py +22 -40
  129. classiq/qmod/semantics/error_manager.py +22 -10
  130. classiq/qmod/semantics/static_semantics_visitor.py +10 -12
  131. classiq/qmod/semantics/validation/types_validation.py +6 -7
  132. classiq/qmod/utilities.py +2 -2
  133. classiq/qmod/write_qmod.py +14 -0
  134. classiq/show.py +10 -0
  135. classiq/synthesis.py +46 -2
  136. {classiq-0.45.1.dist-info → classiq-0.46.1.dist-info}/METADATA +1 -1
  137. {classiq-0.45.1.dist-info → classiq-0.46.1.dist-info}/RECORD +138 -74
  138. classiq/interface/generator/functions/builtins/core_library/__init__.py +0 -16
  139. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +0 -710
  140. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +0 -105
  141. classiq/interface/generator/functions/builtins/open_lib_functions.py +0 -2489
  142. classiq/interface/generator/functions/builtins/quantum_operators.py +0 -24
  143. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  144. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +0 -21
  145. classiq/qmod/builtins/functions.py +0 -1029
  146. {classiq-0.45.1.dist-info → classiq-0.46.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,190 @@
1
+ from typing import TYPE_CHECKING, Dict, List, Optional, Union, cast
2
+
3
+ from classiq.interface.exceptions import ClassiqError
4
+ from classiq.interface.executor.execution_preferences import ExecutionPreferences
5
+ from classiq.interface.generator.model.constraints import Constraints
6
+ from classiq.interface.generator.model.preferences.preferences import Preferences
7
+ from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
8
+ from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model, SerializedModel
9
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
10
+ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
11
+
12
+ from classiq.model_expansions.interpreter import Interpreter
13
+ from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
14
+ from classiq.qmod.classical_function import CFunc
15
+ from classiq.qmod.generative import (
16
+ is_generative_expansion_enabled,
17
+ set_frontend_interpreter,
18
+ )
19
+ from classiq.qmod.model_state_container import QMODULE
20
+ from classiq.qmod.qfunc import DEC_QFUNCS, GEN_QFUNCS
21
+ from classiq.qmod.quantum_expandable import _prepare_args
22
+ from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
23
+ from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
24
+ from classiq.qmod.write_qmod import write_qmod
25
+
26
+ GEN_MAIN_NAME = "_gen_main"
27
+
28
+
29
+ def create_model(
30
+ entry_point: Union[QFunc, GenerativeQFunc],
31
+ constraints: Optional[Constraints] = None,
32
+ execution_preferences: Optional[ExecutionPreferences] = None,
33
+ preferences: Optional[Preferences] = None,
34
+ classical_execution_function: Optional[CFunc] = None,
35
+ out_file: Optional[str] = None,
36
+ ) -> SerializedModel:
37
+ """
38
+ Create a serialized model from a given Qmod entry function and additional parameters.
39
+
40
+ Args:
41
+ entry_point: The entry point function for the model, which must be a QFunc named 'main'.
42
+ constraints: Constraints for the synthesis of the model. See Constraints (Optional).
43
+ execution_preferences: Preferences for the execution of the model. See ExecutionPreferences (Optional).
44
+ preferences: Preferences for the synthesis of the model. See Preferences (Optional).
45
+ classical_execution_function: A function for the classical execution logic, which must be a CFunc (Optional).
46
+ out_file: File path to write the Qmod model in native Qmod representation to (Optional).
47
+
48
+ Returns:
49
+ SerializedModel: A serialized model.
50
+
51
+ Raises:
52
+ ClassiqError: If the entry point function is not named 'main'.
53
+ """
54
+
55
+ if entry_point.func_decl.name != MAIN_FUNCTION_NAME:
56
+ raise ClassiqError(
57
+ f"The entry point function must be named 'main', got '{entry_point.func_decl.name}'"
58
+ )
59
+
60
+ user_gen_functions = {
61
+ gen_func._py_callable.__name__ for gen_func in GEN_QFUNCS
62
+ } - set(BUILTIN_FUNCTION_DECLARATIONS.keys())
63
+ if len(user_gen_functions) > 0 and is_generative_expansion_enabled():
64
+ model = _expand_generative_model(
65
+ (
66
+ entry_point
67
+ if isinstance(entry_point, QFunc)
68
+ else QFunc(entry_point._py_callable)
69
+ ),
70
+ constraints,
71
+ execution_preferences,
72
+ preferences,
73
+ classical_execution_function,
74
+ )
75
+ else:
76
+ if TYPE_CHECKING:
77
+ assert isinstance(entry_point, QFunc)
78
+ model = entry_point.create_model(
79
+ constraints,
80
+ execution_preferences,
81
+ preferences,
82
+ classical_execution_function,
83
+ )
84
+ result = model.get_model()
85
+
86
+ if out_file is not None:
87
+ write_qmod(result, out_file)
88
+
89
+ return result
90
+
91
+
92
+ def _expand_generative_model(
93
+ gen_main: QFunc,
94
+ constraints: Optional[Constraints] = None,
95
+ execution_preferences: Optional[ExecutionPreferences] = None,
96
+ preferences: Optional[Preferences] = None,
97
+ classical_execution_function: Optional[CFunc] = None,
98
+ ) -> Model:
99
+ @QFunc
100
+ def _dummy() -> None:
101
+ pass
102
+
103
+ model = _dummy.create_model(
104
+ constraints,
105
+ execution_preferences,
106
+ preferences,
107
+ classical_execution_function,
108
+ )
109
+ generative_functions = _get_generative_functions(gen_main)
110
+ model.functions = generative_functions
111
+ model.types = list(QMODULE.type_decls.values())
112
+ model.enums = list(QMODULE.enum_decls.values())
113
+ model.qstructs = list(QMODULE.qstruct_decls.values())
114
+ return model
115
+
116
+
117
+ def _get_generative_functions(gen_main: QFunc) -> List[NativeFunctionDefinition]:
118
+ # The Interpreter accepts a model and a list of generative functions.
119
+ # Since the main function is generative, it can only be expanded using the
120
+ # Interpreter.
121
+ # To solve this deadlock, we create a wrapper model
122
+ # `qfunc main(...) { _gen_main(...); }` and rename `main` to `_gen_main` before
123
+ # passing them to the Interpreter.
124
+ gen_model = _get_wrapper_main(gen_main)
125
+ gen_functions = _get_all_model_functions_as_generative_functions()
126
+ functions_dict = _interpret_generative_model(gen_model, gen_functions)
127
+ return list(functions_dict.values())
128
+
129
+
130
+ def _get_wrapper_main(gen_main: QFunc) -> Model:
131
+ return Model(
132
+ functions=[
133
+ NativeFunctionDefinition(
134
+ name=MAIN_FUNCTION_NAME,
135
+ positional_arg_declarations=gen_main.func_decl.positional_arg_declarations,
136
+ body=[
137
+ QuantumFunctionCall(
138
+ function=GEN_MAIN_NAME,
139
+ positional_args=_prepare_args(
140
+ gen_main.func_decl,
141
+ gen_main._get_positional_args(),
142
+ {},
143
+ ),
144
+ ),
145
+ ],
146
+ ),
147
+ ],
148
+ )
149
+
150
+
151
+ def _get_all_model_functions_as_generative_functions() -> List[GenerativeQFunc]:
152
+ gen_functions = list(GEN_QFUNCS) + [
153
+ GenerativeQFunc(dec_func._py_callable, dec_func.func_decl)
154
+ for dec_func in DEC_QFUNCS
155
+ ]
156
+ return [
157
+ (
158
+ gen_func
159
+ if gen_func.func_decl.name != MAIN_FUNCTION_NAME
160
+ else GenerativeQFunc(
161
+ gen_func._py_callable,
162
+ gen_func.func_decl.copy(update={"name": GEN_MAIN_NAME}),
163
+ )
164
+ )
165
+ for gen_func in gen_functions
166
+ if gen_func.func_decl.name not in BUILTIN_FUNCTION_DECLARATIONS
167
+ ]
168
+
169
+
170
+ def _interpret_generative_model(
171
+ gen_model: Model, gen_functions: List[GenerativeQFunc]
172
+ ) -> Dict[str, NativeFunctionDefinition]:
173
+ resolve_function_calls(
174
+ gen_model,
175
+ {gen_func.func_decl.name: gen_func.func_decl for gen_func in gen_functions},
176
+ )
177
+ interpreter = Interpreter(gen_model, gen_functions)
178
+ set_frontend_interpreter(interpreter)
179
+ functions_dict = nameables_to_dict(interpreter.expand().functions)
180
+
181
+ # Inline _gen_main call in main
182
+ expanded_gen_main_name = cast(
183
+ QuantumFunctionCall, functions_dict[MAIN_FUNCTION_NAME].body[0]
184
+ ).func_name
185
+ functions_dict[MAIN_FUNCTION_NAME] = functions_dict[expanded_gen_main_name].copy(
186
+ update={"name": MAIN_FUNCTION_NAME}
187
+ )
188
+ functions_dict.pop(expanded_gen_main_name)
189
+
190
+ return functions_dict
@@ -1,5 +1,4 @@
1
1
  import dataclasses
2
- import inspect
3
2
  import sys
4
3
  from enum import EnumMeta
5
4
  from typing import (
@@ -19,22 +18,12 @@ from typing import (
19
18
  from typing_extensions import _AnnotatedAlias
20
19
 
21
20
  from classiq.interface.exceptions import ClassiqValueError
22
- from classiq.interface.generator.functions.classical_type import (
23
- Bool,
24
- ClassicalArray,
25
- ClassicalList,
26
- Integer,
27
- Real,
28
- )
29
21
  from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
30
22
  from classiq.interface.generator.functions.port_declaration import (
31
23
  PortDeclarationDirection,
32
24
  )
33
- from classiq.interface.generator.functions.type_name import Enum
34
- from classiq.interface.generator.types.enum_declaration import (
35
- EnumDeclaration,
36
- declaration_from_enum,
37
- )
25
+ from classiq.interface.generator.types.enum_declaration import declaration_from_enum
26
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
38
27
  from classiq.interface.model.classical_parameter_declaration import (
39
28
  AnonClassicalParameterDeclaration,
40
29
  )
@@ -46,10 +35,12 @@ from classiq.interface.model.quantum_function_declaration import (
46
35
  PositionalArg,
47
36
  )
48
37
 
49
- from classiq import Struct, StructDeclaration
38
+ from classiq.model_expansions.model_tables import SymbolTable
39
+ from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
40
+ from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
50
41
  from classiq.qmod.model_state_container import ModelStateContainer
51
- from classiq.qmod.qmod_parameter import CArray, CBool, CInt, CReal
52
- from classiq.qmod.qmod_variable import QVar, get_type_hint_expr
42
+ from classiq.qmod.python_classical_type import PythonClassicalType
43
+ from classiq.qmod.qmod_variable import QVar
53
44
  from classiq.qmod.quantum_callable import QCallableList
54
45
  from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
55
46
 
@@ -57,67 +48,45 @@ if sys.version_info[0:2] >= (3, 9):
57
48
  from typing import Annotated
58
49
 
59
50
 
51
+ class _PythonClassicalType(PythonClassicalType):
52
+ def __init__(self, qmodule: Optional[ModelStateContainer]):
53
+ super().__init__()
54
+ self.qmodule = qmodule
55
+
56
+ def register_enum(self, py_type: EnumMeta) -> None:
57
+ if (
58
+ self.qmodule is None
59
+ or py_type.__name__ in BUILTIN_ENUM_DECLARATIONS
60
+ or py_type.__name__ in self.qmodule.enum_decls
61
+ ):
62
+ return
63
+
64
+ enum_decl = declaration_from_enum(py_type)
65
+ self.qmodule.enum_decls[py_type.__name__] = enum_decl
66
+ SymbolTable.enum_table[py_type.__name__] = enum_decl
67
+
68
+ def register_struct(self, py_type: type) -> None:
69
+ if (
70
+ self.qmodule is None
71
+ or py_type.__name__ in BUILTIN_STRUCT_DECLARATIONS
72
+ or py_type.__name__ in self.qmodule.type_decls
73
+ ):
74
+ return
75
+
76
+ struct_decl = StructDeclaration(
77
+ name=py_type.__name__,
78
+ variables={
79
+ f.name: self.convert(f.type) for f in dataclasses.fields(py_type)
80
+ },
81
+ )
82
+ self.qmodule.type_decls[py_type.__name__] = struct_decl
83
+ SymbolTable.type_table[py_type.__name__] = struct_decl
84
+
85
+
60
86
  def python_type_to_qmod(
61
- py_type: type, *, qmodule: ModelStateContainer
87
+ py_type: type, *, qmodule: Optional[ModelStateContainer]
62
88
  ) -> Optional[ConcreteClassicalType]:
63
- if py_type is int or py_type is CInt:
64
- return Integer()
65
- elif py_type in (float, complex) or py_type is CReal:
66
- return Real()
67
- elif py_type is bool or py_type is CBool:
68
- return Bool()
69
- elif get_origin(py_type) is list:
70
- element_type = python_type_to_qmod(get_args(py_type)[0], qmodule=qmodule)
71
- if element_type is not None:
72
- return ClassicalList(element_type=element_type)
73
- elif get_origin(py_type) is CArray:
74
- array_args = version_portable_get_args(py_type)
75
- if len(array_args) == 1:
76
- return ClassicalList(
77
- element_type=python_type_to_qmod(array_args[0], qmodule=qmodule)
78
- )
79
- elif len(array_args) == 2:
80
- return ClassicalArray(
81
- element_type=python_type_to_qmod(array_args[0], qmodule=qmodule),
82
- size=get_type_hint_expr(array_args[1]),
83
- )
84
- raise ClassiqValueError(
85
- "CArray accepts one or two generic parameters in the form "
86
- "`CArray[<element-type>]` or `CArray[<element-type>, <size>]`"
87
- )
88
- elif inspect.isclass(py_type) and dataclasses.is_dataclass(py_type):
89
- _add_qmod_struct(py_type, qmodule=qmodule)
90
- return Struct(name=py_type.__name__)
91
- elif inspect.isclass(py_type) and isinstance(py_type, EnumMeta):
92
- _add_qmod_enum(py_type, qmodule=qmodule)
93
- return Enum(name=py_type.__name__)
94
- return None
95
-
96
-
97
- def _add_qmod_enum(py_type: EnumMeta, *, qmodule: ModelStateContainer) -> None:
98
- if (
99
- py_type.__name__ in EnumDeclaration.BUILTIN_ENUM_DECLARATIONS
100
- or py_type.__name__ in qmodule.enum_decls
101
- ):
102
- return
103
-
104
- qmodule.enum_decls[py_type.__name__] = declaration_from_enum(py_type)
105
-
106
-
107
- def _add_qmod_struct(py_type: Type, *, qmodule: ModelStateContainer) -> None:
108
- if (
109
- py_type.__name__ in StructDeclaration.BUILTIN_STRUCT_DECLARATIONS
110
- or py_type.__name__ in qmodule.type_decls
111
- ):
112
- return
113
-
114
- qmodule.type_decls[py_type.__name__] = StructDeclaration(
115
- name=py_type.__name__,
116
- variables={
117
- f.name: python_type_to_qmod(f.type, qmodule=qmodule)
118
- for f in dataclasses.fields(py_type)
119
- },
120
- )
89
+ return _PythonClassicalType(qmodule).convert(py_type)
121
90
 
122
91
 
123
92
  def _extract_port_decl(name: Optional[str], py_type: Any) -> AnonPortDeclaration:
@@ -137,13 +106,15 @@ def _extract_port_decl(name: Optional[str], py_type: Any) -> AnonPortDeclaration
137
106
 
138
107
 
139
108
  def _extract_operand_decl(
140
- name: Optional[str], py_type: Any, qmodule: ModelStateContainer
109
+ name: Optional[str], py_type: Any, qmodule: Optional[ModelStateContainer]
141
110
  ) -> AnonQuantumOperandDeclaration:
142
111
  is_list = (get_origin(py_type) or py_type) is QCallableList
143
112
  if get_origin(py_type) is list:
144
113
  is_list = True
145
- py_type = version_portable_get_args(py_type)
114
+ py_type = version_portable_get_args(py_type)[0]
146
115
  type_args = version_portable_get_args(py_type)
116
+ if len(type_args) > 0 and isinstance(type_args[0], list): # Callable support
117
+ type_args = tuple(type_args[0])
147
118
  param_decls = [_extract_operand_param(arg_type) for arg_type in type_args]
148
119
  param = AnonQuantumOperandDeclaration(
149
120
  name=name,
@@ -181,20 +152,20 @@ def _extract_operand_param(py_type: Any) -> Tuple[Optional[str], Any]:
181
152
 
182
153
  @overload
183
154
  def _extract_positional_args(
184
- args: Sequence[Tuple[str, Any]], qmodule: ModelStateContainer
155
+ args: Sequence[Tuple[str, Any]], qmodule: Optional[ModelStateContainer]
185
156
  ) -> Sequence[PositionalArg]:
186
157
  pass
187
158
 
188
159
 
189
160
  @overload
190
161
  def _extract_positional_args(
191
- args: Sequence[Tuple[Optional[str], Any]], qmodule: ModelStateContainer
162
+ args: Sequence[Tuple[Optional[str], Any]], qmodule: Optional[ModelStateContainer]
192
163
  ) -> Sequence[AnonPositionalArg]:
193
164
  pass
194
165
 
195
166
 
196
167
  def _extract_positional_args(
197
- args: Sequence[Tuple[Optional[str], Any]], qmodule: ModelStateContainer
168
+ args: Sequence[Tuple[Optional[str], Any]], qmodule: Optional[ModelStateContainer]
198
169
  ) -> Sequence[AnonPositionalArg]:
199
170
  result: List[AnonPositionalArg] = []
200
171
  for name, py_type in args:
@@ -218,7 +189,7 @@ def _extract_positional_args(
218
189
 
219
190
 
220
191
  def infer_func_decl(
221
- py_func: Callable, qmodule: ModelStateContainer
192
+ py_func: Callable, qmodule: Optional[ModelStateContainer] = None
222
193
  ) -> NamedParamsQuantumFunctionDeclaration:
223
194
  return NamedParamsQuantumFunctionDeclaration(
224
195
  name=unmangle_keyword(py_func.__name__),
@@ -13,6 +13,22 @@ def get_expression_numeric_attributes(
13
13
  expr: SymbolicTypes,
14
14
  machine_precision: int = MAXIMAL_MACHINE_PRECISION,
15
15
  ) -> Tuple[int, bool, int]:
16
+ """
17
+ Computes and returns the numeric attributes of a given symbolic expression.
18
+
19
+ Args:
20
+ vars: A list of `QNum` variables used in the symbolic expression.
21
+ expr: The symbolic expression for which numeric attributes are to be computed.
22
+ machine_precision: The precision level of the machine for the computation. Defaults to MAXIMAL_MACHINE_PRECISION = 20.
23
+
24
+ Returns:
25
+ Tuple[int, bool, int]:
26
+ A tuple containing the following numeric attributes:
27
+ - The size in bits (int) required to represent the result.
28
+ - A boolean indicating whether the result is signed (bool).
29
+ - The number of fraction digits (int) in the result.
30
+
31
+ """
16
32
  res_type = compute_arithmetic_result_type(
17
33
  expr_str=str(expr),
18
34
  var_types={str(var.get_handle_binding()): var.get_qmod_type() for var in vars},
@@ -0,0 +1,48 @@
1
+ from contextlib import contextmanager
2
+ from typing import TYPE_CHECKING, Iterator, Optional
3
+
4
+ from classiq.interface.exceptions import ClassiqError
5
+
6
+ if TYPE_CHECKING:
7
+ from classiq.model_expansions.interpreter import Interpreter
8
+
9
+ _GENERATIVE_ENABLED_SWITCH: bool = True
10
+ _GENERATIVE_MODE: bool = False
11
+ _FRONTEND_INTERPRETER: Optional["Interpreter"] = None
12
+
13
+
14
+ def is_generative_mode() -> bool:
15
+ return _GENERATIVE_MODE
16
+
17
+
18
+ @contextmanager
19
+ def generative_mode_context(generative: bool) -> Iterator[None]:
20
+ global _GENERATIVE_MODE
21
+ previous = _GENERATIVE_MODE
22
+ _GENERATIVE_MODE = generative
23
+ yield
24
+ _GENERATIVE_MODE = previous
25
+
26
+
27
+ @contextmanager
28
+ def enable_generative_expansion(enabled: bool) -> Iterator[None]:
29
+ global _GENERATIVE_ENABLED_SWITCH
30
+ previous = _GENERATIVE_ENABLED_SWITCH
31
+ _GENERATIVE_ENABLED_SWITCH = enabled
32
+ yield
33
+ _GENERATIVE_ENABLED_SWITCH = previous
34
+
35
+
36
+ def is_generative_expansion_enabled() -> bool:
37
+ return _GENERATIVE_ENABLED_SWITCH
38
+
39
+
40
+ def set_frontend_interpreter(interpreter: "Interpreter") -> None:
41
+ global _FRONTEND_INTERPRETER
42
+ _FRONTEND_INTERPRETER = interpreter
43
+
44
+
45
+ def get_frontend_interpreter() -> "Interpreter":
46
+ if _FRONTEND_INTERPRETER is None:
47
+ raise ClassiqError("Interpreter was not set")
48
+ return _FRONTEND_INTERPRETER
@@ -3,10 +3,9 @@ from typing import Dict
3
3
  from classiq.interface.generator.constant import Constant
4
4
  from classiq.interface.generator.types.enum_declaration import EnumDeclaration
5
5
  from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
6
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
6
7
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
7
8
 
8
- from classiq import StructDeclaration
9
-
10
9
 
11
10
  class ModelStateContainer:
12
11
  enum_decls: Dict[str, EnumDeclaration]
@@ -3,7 +3,11 @@ from typing import Dict, List, Mapping, Optional, Union
3
3
  from classiq.interface.generator.constant import Constant
4
4
  from classiq.interface.generator.expressions.expression import Expression
5
5
  from classiq.interface.generator.functions.classical_type import (
6
+ Bool,
6
7
  ClassicalArray,
8
+ ClassicalList,
9
+ Integer,
10
+ Real,
7
11
  )
8
12
  from classiq.interface.generator.functions.concrete_types import (
9
13
  ConcreteClassicalType,
@@ -15,6 +19,7 @@ from classiq.interface.generator.functions.port_declaration import (
15
19
  from classiq.interface.generator.functions.type_name import TypeName
16
20
  from classiq.interface.generator.types.enum_declaration import EnumDeclaration
17
21
  from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
22
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
18
23
  from classiq.interface.generator.visitor import NodeType, Visitor
19
24
  from classiq.interface.model.bind_operation import BindOperation
20
25
  from classiq.interface.model.classical_if import ClassicalIf
@@ -68,17 +73,8 @@ from classiq.interface.model.variable_declaration_statement import (
68
73
  )
69
74
  from classiq.interface.model.within_apply_operation import WithinApply
70
75
 
71
- from classiq import (
72
- Bool,
73
- ClassicalList,
74
- Integer,
75
- Real,
76
- StructDeclaration,
77
- )
78
76
  from classiq.qmod.native.expression_to_qmod import transform_expression
79
- from classiq.qmod.semantics.static_semantics_visitor import (
80
- static_semantics_analysis_pass,
81
- )
77
+ from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
82
78
  from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
83
79
 
84
80
 
@@ -97,7 +93,7 @@ class DSLPrettyPrinter(Visitor):
97
93
 
98
94
  def visit_Model(self, model: Model) -> str:
99
95
  # FIXME - CAD-20149: Remove this line once the froggies are removed, and the visit of lambdas can be done without accessing the func_decl property (with rename_params values only).
100
- static_semantics_analysis_pass(model, None)
96
+ resolve_function_calls(model, model.function_dict)
101
97
  enum_decls = [self.visit(enum_decl) for enum_decl in model.enums]
102
98
  struct_decls = [self.visit(struct_decl) for struct_decl in model.types]
103
99
  qstruct_decls = [self.visit(qstruct_decl) for qstruct_decl in model.qstructs]
@@ -5,7 +5,11 @@ import black
5
5
  from classiq.interface.generator.constant import Constant
6
6
  from classiq.interface.generator.expressions.expression import Expression
7
7
  from classiq.interface.generator.functions.classical_type import (
8
+ Bool,
8
9
  ClassicalArray,
10
+ ClassicalList,
11
+ Integer,
12
+ Real,
9
13
  )
10
14
  from classiq.interface.generator.functions.concrete_types import (
11
15
  ConcreteClassicalType,
@@ -17,6 +21,7 @@ from classiq.interface.generator.functions.port_declaration import (
17
21
  from classiq.interface.generator.functions.type_name import TypeName
18
22
  from classiq.interface.generator.types.enum_declaration import EnumDeclaration
19
23
  from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
24
+ from classiq.interface.generator.types.struct_declaration import StructDeclaration
20
25
  from classiq.interface.generator.visitor import NodeType, Visitor
21
26
  from classiq.interface.model.bind_operation import BindOperation
22
27
  from classiq.interface.model.classical_if import ClassicalIf
@@ -72,13 +77,7 @@ from classiq.interface.model.variable_declaration_statement import (
72
77
  from classiq.interface.model.within_apply_operation import WithinApply
73
78
 
74
79
  import classiq
75
- from classiq import (
76
- Bool,
77
- ClassicalList,
78
- Integer,
79
- Real,
80
- StructDeclaration,
81
- )
80
+ from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
82
81
  from classiq.qmod.pretty_print.expression_to_python import transform_expression
83
82
  from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
84
83
 
@@ -147,10 +146,7 @@ class PythonPrettyPrinter(Visitor):
147
146
  return res
148
147
 
149
148
  def visit_Model(self, model: Model) -> str:
150
- self._functions = {
151
- **model.function_dict,
152
- **QuantumFunctionDeclaration.BUILTIN_FUNCTION_DECLARATIONS,
153
- }
149
+ self._functions = {**model.function_dict, **BUILTIN_FUNCTION_DECLARATIONS}
154
150
  enum_decls = [self.visit(decl) for decl in model.enums]
155
151
  struct_decls = [self.visit(decl) for decl in model.types]
156
152
  qstruct_decls = [self.visit(qstruct_decl) for qstruct_decl in model.qstructs]
@@ -0,0 +1,67 @@
1
+ import dataclasses
2
+ import inspect
3
+ import sys
4
+ from enum import EnumMeta
5
+ from typing import (
6
+ Optional,
7
+ get_args,
8
+ get_origin,
9
+ )
10
+
11
+ from classiq.interface.exceptions import ClassiqValueError
12
+ from classiq.interface.generator.functions.classical_type import (
13
+ Bool,
14
+ ClassicalArray,
15
+ ClassicalList,
16
+ Integer,
17
+ Real,
18
+ )
19
+ from classiq.interface.generator.functions.type_name import Enum, Struct
20
+
21
+ from classiq.qmod.cparam import CArray, CBool, CInt, CReal
22
+ from classiq.qmod.qmod_variable import get_type_hint_expr
23
+ from classiq.qmod.utilities import version_portable_get_args
24
+
25
+ if sys.version_info[0:2] >= (3, 9):
26
+ pass
27
+ from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
28
+
29
+
30
+ class PythonClassicalType:
31
+ def convert(self, py_type: type) -> Optional[ConcreteClassicalType]:
32
+ if py_type is int or py_type is CInt:
33
+ return Integer()
34
+ elif py_type in (float, complex) or py_type is CReal:
35
+ return Real()
36
+ elif py_type is bool or py_type is CBool:
37
+ return Bool()
38
+ elif get_origin(py_type) is list:
39
+ element_type = self.convert(get_args(py_type)[0])
40
+ if element_type is not None:
41
+ return ClassicalList(element_type=element_type)
42
+ elif get_origin(py_type) is CArray:
43
+ array_args = version_portable_get_args(py_type)
44
+ if len(array_args) == 1:
45
+ return ClassicalList(element_type=self.convert(array_args[0]))
46
+ elif len(array_args) == 2:
47
+ return ClassicalArray(
48
+ element_type=self.convert(array_args[0]),
49
+ size=get_type_hint_expr(array_args[1]),
50
+ )
51
+ raise ClassiqValueError(
52
+ "CArray accepts one or two generic parameters in the form "
53
+ "`CArray[<element-type>]` or `CArray[<element-type>, <size>]`"
54
+ )
55
+ elif inspect.isclass(py_type) and dataclasses.is_dataclass(py_type):
56
+ self.register_struct(py_type)
57
+ return Struct(name=py_type.__name__)
58
+ elif inspect.isclass(py_type) and isinstance(py_type, EnumMeta):
59
+ self.register_enum(py_type)
60
+ return Enum(name=py_type.__name__)
61
+ return None
62
+
63
+ def register_struct(self, py_type: type) -> None:
64
+ pass
65
+
66
+ def register_enum(self, py_type: EnumMeta) -> None:
67
+ pass
classiq/qmod/qfunc.py CHANGED
@@ -1,8 +1,20 @@
1
- from typing import Callable, Literal, Optional, Union, overload
1
+ from typing import Callable, List, Literal, Optional, Union, overload
2
2
 
3
3
  from classiq.qmod.quantum_callable import QCallable
4
4
  from classiq.qmod.quantum_function import ExternalQFunc, GenerativeQFunc, QFunc
5
5
 
6
+ GEN_QFUNCS: List[GenerativeQFunc] = []
7
+ DEC_QFUNCS: List[QFunc] = []
8
+
9
+
10
+ def set_discovered_functions(
11
+ dec_funcs: List[QFunc], gen_funcs: List[GenerativeQFunc]
12
+ ) -> None:
13
+ DEC_QFUNCS.clear()
14
+ DEC_QFUNCS.extend(dec_funcs)
15
+ GEN_QFUNCS.clear()
16
+ GEN_QFUNCS.extend(gen_funcs)
17
+
6
18
 
7
19
  @overload
8
20
  def qfunc(func: Callable) -> QFunc: ...
@@ -21,11 +33,14 @@ def qfunc(
21
33
  ) -> Union[Callable[[Callable], QCallable], QCallable]:
22
34
  def wrapper(func: Callable) -> QCallable:
23
35
  if generative:
24
- return GenerativeQFunc(func)
36
+ gen_qfunc = GenerativeQFunc(func)
37
+ GEN_QFUNCS.append(gen_qfunc)
38
+ return gen_qfunc
25
39
  if external:
26
40
  return ExternalQFunc(func)
27
-
28
- return QFunc(func)
41
+ dec_qfunc = QFunc(func)
42
+ DEC_QFUNCS.append(dec_qfunc)
43
+ return dec_qfunc
29
44
 
30
45
  if func is not None:
31
46
  return wrapper(func)