classiq 0.39.0__py3-none-any.whl → 0.41.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 (100) hide show
  1. classiq/__init__.py +5 -2
  2. classiq/_internals/api_wrapper.py +3 -21
  3. classiq/applications/chemistry/chemistry_model_constructor.py +87 -101
  4. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +7 -26
  5. classiq/applications/combinatorial_helpers/optimization_model.py +7 -6
  6. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +33 -55
  7. classiq/applications/combinatorial_optimization/__init__.py +4 -0
  8. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +29 -26
  9. classiq/applications/finance/finance_model_constructor.py +23 -26
  10. classiq/applications/grover/grover_model_constructor.py +37 -38
  11. classiq/applications/qsvm/qsvm.py +1 -2
  12. classiq/applications/qsvm/qsvm_model_constructor.py +15 -16
  13. classiq/execution/__init__.py +4 -0
  14. classiq/execution/execution_session.py +151 -0
  15. classiq/execution/qnn.py +80 -0
  16. classiq/executor.py +2 -109
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +11 -0
  19. classiq/interface/applications/qsvm.py +0 -8
  20. classiq/interface/ast_node.py +12 -2
  21. classiq/interface/backend/backend_preferences.py +30 -6
  22. classiq/interface/backend/quantum_backend_providers.py +11 -11
  23. classiq/interface/executor/execution_preferences.py +7 -67
  24. classiq/interface/executor/execution_result.py +22 -1
  25. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
  26. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  27. classiq/interface/generator/arith/binary_ops.py +88 -25
  28. classiq/interface/generator/arith/unary_ops.py +28 -19
  29. classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
  30. classiq/interface/generator/expressions/enums/__init__.py +10 -0
  31. classiq/interface/generator/expressions/enums/classical_enum.py +5 -1
  32. classiq/interface/generator/expressions/expression.py +9 -2
  33. classiq/interface/generator/expressions/qmod_qarray_proxy.py +89 -0
  34. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +20 -0
  35. classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
  36. classiq/interface/generator/expressions/sympy_supported_expressions.py +10 -1
  37. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +8 -6
  38. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +10 -4
  39. classiq/interface/generator/functions/builtins/internal_operators.py +7 -62
  40. classiq/interface/generator/functions/builtins/open_lib_functions.py +1627 -271
  41. classiq/interface/generator/functions/classical_type.py +27 -17
  42. classiq/interface/generator/model/preferences/preferences.py +4 -2
  43. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
  44. classiq/interface/model/bind_operation.py +3 -1
  45. classiq/interface/model/call_synthesis_data.py +2 -13
  46. classiq/interface/model/classical_if.py +3 -1
  47. classiq/interface/model/classical_parameter_declaration.py +13 -0
  48. classiq/interface/model/control.py +6 -8
  49. classiq/interface/model/inplace_binary_operation.py +3 -1
  50. classiq/interface/model/invert.py +3 -1
  51. classiq/interface/model/port_declaration.py +8 -1
  52. classiq/interface/model/power.py +3 -1
  53. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +4 -2
  54. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
  55. classiq/interface/model/quantum_expressions/quantum_expression.py +11 -1
  56. classiq/interface/model/quantum_function_call.py +4 -10
  57. classiq/interface/model/quantum_function_declaration.py +26 -4
  58. classiq/interface/model/quantum_lambda_function.py +1 -20
  59. classiq/interface/model/quantum_statement.py +9 -2
  60. classiq/interface/model/quantum_type.py +6 -5
  61. classiq/interface/model/repeat.py +3 -1
  62. classiq/interface/model/resolvers/function_call_resolver.py +0 -5
  63. classiq/interface/model/statement_block.py +19 -16
  64. classiq/interface/model/validations/handles_validator.py +8 -2
  65. classiq/interface/model/variable_declaration_statement.py +3 -1
  66. classiq/interface/model/within_apply_operation.py +3 -1
  67. classiq/interface/server/routes.py +0 -5
  68. classiq/qmod/__init__.py +5 -2
  69. classiq/qmod/builtins/classical_execution_primitives.py +22 -2
  70. classiq/qmod/builtins/classical_functions.py +30 -35
  71. classiq/qmod/builtins/functions.py +263 -153
  72. classiq/qmod/builtins/operations.py +50 -26
  73. classiq/qmod/builtins/structs.py +50 -48
  74. classiq/qmod/declaration_inferrer.py +32 -27
  75. classiq/qmod/native/__init__.py +9 -0
  76. classiq/qmod/native/expression_to_qmod.py +8 -4
  77. classiq/qmod/native/pretty_printer.py +11 -18
  78. classiq/qmod/pretty_print/__init__.py +9 -0
  79. classiq/qmod/pretty_print/expression_to_python.py +221 -0
  80. classiq/qmod/pretty_print/pretty_printer.py +421 -0
  81. classiq/qmod/qmod_constant.py +7 -7
  82. classiq/qmod/qmod_parameter.py +57 -33
  83. classiq/qmod/qmod_struct.py +2 -2
  84. classiq/qmod/qmod_variable.py +40 -29
  85. classiq/qmod/quantum_callable.py +8 -4
  86. classiq/qmod/quantum_expandable.py +22 -15
  87. classiq/qmod/quantum_function.py +15 -4
  88. classiq/qmod/symbolic.py +73 -68
  89. classiq/qmod/symbolic_expr.py +1 -1
  90. classiq/qmod/symbolic_type.py +1 -4
  91. classiq/qmod/utilities.py +29 -0
  92. classiq/synthesis.py +15 -16
  93. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/METADATA +5 -4
  94. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/RECORD +95 -94
  95. classiq/interface/executor/error_mitigation.py +0 -6
  96. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  97. classiq/interface/model/common_model_types.py +0 -23
  98. classiq/interface/model/quantum_expressions/control_state.py +0 -38
  99. classiq/interface/model/quantum_if_operation.py +0 -94
  100. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/WHEEL +0 -0
@@ -1,10 +1,11 @@
1
1
  import inspect
2
+ import sys
2
3
  from types import FrameType
3
- from typing import Any, Callable, Final, List, Mapping, Union
4
+ from typing import Any, Callable, Final, List, Mapping, Union, overload
4
5
 
5
6
  from classiq.interface.generator.expressions.expression import Expression
6
7
  from classiq.interface.generator.functions.builtins.internal_operators import (
7
- REPEAT_OPERATOR,
8
+ REPEAT_OPERATOR_NAME,
8
9
  )
9
10
  from classiq.interface.model.bind_operation import BindOperation
10
11
  from classiq.interface.model.classical_if import ClassicalIf
@@ -19,17 +20,18 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
19
20
  from classiq.interface.model.quantum_function_declaration import (
20
21
  QuantumOperandDeclaration,
21
22
  )
22
- from classiq.interface.model.quantum_if_operation import QuantumIf
23
23
  from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
24
24
  from classiq.interface.model.repeat import Repeat
25
25
  from classiq.interface.model.statement_block import StatementBlock
26
26
  from classiq.interface.model.within_apply_operation import WithinApply
27
27
 
28
+ from classiq import Integer
28
29
  from classiq.exceptions import ClassiqValueError
29
30
  from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QVar
30
31
  from classiq.qmod.quantum_callable import QCallable
31
32
  from classiq.qmod.quantum_expandable import prepare_arg
32
33
  from classiq.qmod.symbolic_expr import SymbolicExpr
34
+ from classiq.qmod.utilities import get_source_ref
33
35
 
34
36
  _MISSING_VALUE: Final[int] = -1
35
37
 
@@ -39,6 +41,7 @@ def bind(
39
41
  destination: Union[Output[QVar], List[Output[QVar]]],
40
42
  ) -> None:
41
43
  assert QCallable.CURRENT_EXPANDABLE is not None
44
+ source_ref = get_source_ref(sys._getframe(1))
42
45
  if not isinstance(source, list):
43
46
  source = [source]
44
47
  if not isinstance(destination, list):
@@ -47,19 +50,7 @@ def bind(
47
50
  BindOperation(
48
51
  in_handles=[src_var.get_handle_binding() for src_var in source],
49
52
  out_handles=[dst_var.get_handle_binding() for dst_var in destination],
50
- )
51
- )
52
-
53
-
54
- def control(
55
- operand: Union[QCallable, Callable[[], None]], ctrl: Union[QBit, QArray[QBit]]
56
- ) -> None:
57
- _validate_operand(operand)
58
- assert QCallable.CURRENT_EXPANDABLE is not None
59
- QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
60
- Control(
61
- control=ctrl.get_handle_binding(),
62
- body=_operand_to_body(operand),
53
+ source_ref=source_ref,
63
54
  )
64
55
  )
65
56
 
@@ -73,24 +64,41 @@ def if_(
73
64
  if else_ != _MISSING_VALUE:
74
65
  _validate_operand(else_)
75
66
  assert QCallable.CURRENT_EXPANDABLE is not None
67
+ source_ref = get_source_ref(sys._getframe(1))
76
68
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
77
69
  ClassicalIf(
78
70
  condition=Expression(expr=str(condition)),
79
71
  then=_operand_to_body(then),
80
72
  else_=_operand_to_body(else_) if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
73
+ source_ref=source_ref,
81
74
  )
82
75
  )
83
76
 
84
77
 
85
- def quantum_if(
86
- condition: SymbolicExpr, then: Union[QCallable, Callable[[], None]]
78
+ @overload
79
+ def control(
80
+ ctrl: Union[QBit, QArray[QBit]], operand: Union[QCallable, Callable[[], None]]
87
81
  ) -> None:
88
- _validate_operand(then)
82
+ pass
83
+
84
+
85
+ @overload
86
+ def control(ctrl: SymbolicExpr, operand: Union[QCallable, Callable[[], None]]) -> None:
87
+ pass
88
+
89
+
90
+ def control(
91
+ ctrl: Union[SymbolicExpr, QBit, QArray[QBit]],
92
+ operand: Union[QCallable, Callable[[], None]],
93
+ ) -> None:
94
+ _validate_operand(operand)
89
95
  assert QCallable.CURRENT_EXPANDABLE is not None
96
+ source_ref = get_source_ref(sys._getframe(1))
90
97
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
91
- QuantumIf(
92
- expression=Expression(expr=str(condition)),
93
- then=_operand_to_body(then),
98
+ Control(
99
+ expression=Expression(expr=str(ctrl)),
100
+ body=_operand_to_body(operand),
101
+ source_ref=source_ref,
94
102
  )
95
103
  )
96
104
 
@@ -100,11 +108,13 @@ def inplace_add(
100
108
  target: QNum,
101
109
  ) -> None:
102
110
  assert QCallable.CURRENT_EXPANDABLE is not None
111
+ source_ref = get_source_ref(sys._getframe(1))
103
112
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
104
113
  InplaceBinaryOperation(
105
114
  target=target.get_handle_binding(),
106
115
  value=value.get_handle_binding(),
107
116
  operation=BinaryOperation.Addition,
117
+ source_ref=source_ref,
108
118
  )
109
119
  )
110
120
 
@@ -114,11 +124,13 @@ def inplace_xor(
114
124
  target: QNum,
115
125
  ) -> None:
116
126
  assert QCallable.CURRENT_EXPANDABLE is not None
127
+ source_ref = get_source_ref(sys._getframe(1))
117
128
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
118
129
  InplaceBinaryOperation(
119
130
  target=target.get_handle_binding(),
120
131
  value=value.get_handle_binding(),
121
132
  operation=BinaryOperation.Xor,
133
+ source_ref=source_ref,
122
134
  )
123
135
  )
124
136
 
@@ -130,10 +142,12 @@ def within_apply(
130
142
  _validate_operand(compute)
131
143
  _validate_operand(action)
132
144
  assert QCallable.CURRENT_EXPANDABLE is not None
145
+ source_ref = get_source_ref(sys._getframe(1))
133
146
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
134
147
  WithinApply(
135
148
  compute=_operand_to_body(compute),
136
149
  action=_operand_to_body(action),
150
+ source_ref=source_ref,
137
151
  )
138
152
  )
139
153
 
@@ -141,14 +155,19 @@ def within_apply(
141
155
  def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) -> None:
142
156
  _validate_operand(iteration)
143
157
  assert QCallable.CURRENT_EXPANDABLE is not None
158
+ source_ref = get_source_ref(sys._getframe(1))
144
159
  iteration_operand = prepare_arg(
145
- REPEAT_OPERATOR.operand_declarations["iteration"], iteration
160
+ QuantumOperandDeclaration(
161
+ name=REPEAT_OPERATOR_NAME, param_decls={"index": Integer()}
162
+ ),
163
+ iteration,
146
164
  )
147
165
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
148
166
  Repeat(
149
167
  iter_var=inspect.getfullargspec(iteration).args[0],
150
168
  count=Expression(expr=str(count)),
151
169
  body=iteration_operand.body,
170
+ source_ref=source_ref,
152
171
  )
153
172
  )
154
173
 
@@ -159,8 +178,13 @@ def power(
159
178
  ) -> None:
160
179
  _validate_operand(operand)
161
180
  assert QCallable.CURRENT_EXPANDABLE is not None
181
+ source_ref = get_source_ref(sys._getframe(1))
162
182
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
163
- Power(power=Expression(expr=str(power)), body=_operand_to_body(operand))
183
+ Power(
184
+ power=Expression(expr=str(power)),
185
+ body=_operand_to_body(operand),
186
+ source_ref=source_ref,
187
+ )
164
188
  )
165
189
 
166
190
 
@@ -169,8 +193,9 @@ def invert(
169
193
  ) -> None:
170
194
  _validate_operand(operand)
171
195
  assert QCallable.CURRENT_EXPANDABLE is not None
196
+ source_ref = get_source_ref(sys._getframe(1))
172
197
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
173
- Invert(body=_operand_to_body(operand))
198
+ Invert(body=_operand_to_body(operand), source_ref=source_ref)
174
199
  )
175
200
 
176
201
 
@@ -240,7 +265,6 @@ __all__ = [
240
265
  "control",
241
266
  "invert",
242
267
  "if_",
243
- "quantum_if",
244
268
  "inplace_add",
245
269
  "inplace_xor",
246
270
  "power",
@@ -1,113 +1,115 @@
1
1
  # This file was generated automatically - do not edit manually
2
2
 
3
- from typing import List
3
+ from classiq.interface.generator.expressions.enums.ladder_operator import LadderOperator
4
+ from classiq.interface.generator.expressions.enums.pauli import Pauli
4
5
 
6
+ from classiq.qmod.qmod_parameter import CArray, CBool, CInt, CReal
5
7
  from classiq.qmod.qmod_struct import struct
6
8
 
7
9
 
8
10
  @struct
9
11
  class PauliTerm:
10
- pauli: List[int]
11
- coefficient: float
12
+ pauli: CArray[Pauli]
13
+ coefficient: CReal
12
14
 
13
15
 
14
16
  @struct
15
17
  class MoleculeProblem:
16
- mapping: int
17
- z2_symmetries: bool
18
+ mapping: CInt
19
+ z2_symmetries: CBool
18
20
  molecule: "Molecule"
19
- freeze_core: bool
20
- remove_orbitals: List[int]
21
+ freeze_core: CBool
22
+ remove_orbitals: CArray[CInt]
21
23
 
22
24
 
23
25
  @struct
24
26
  class Molecule:
25
- atoms: List["ChemistryAtom"]
26
- spin: int
27
- charge: int
27
+ atoms: CArray["ChemistryAtom"]
28
+ spin: CInt
29
+ charge: CInt
28
30
 
29
31
 
30
32
  @struct
31
33
  class ChemistryAtom:
32
- element: int
34
+ element: CInt
33
35
  position: "Position"
34
36
 
35
37
 
36
38
  @struct
37
39
  class Position:
38
- x: float
39
- y: float
40
- z: float
40
+ x: CReal
41
+ y: CReal
42
+ z: CReal
41
43
 
42
44
 
43
45
  @struct
44
46
  class FockHamiltonianProblem:
45
- mapping: int
46
- z2_symmetries: bool
47
- terms: List["LadderTerm"]
48
- num_particles: List[int]
47
+ mapping: CInt
48
+ z2_symmetries: CBool
49
+ terms: CArray["LadderTerm"]
50
+ num_particles: CArray[CInt]
49
51
 
50
52
 
51
53
  @struct
52
54
  class LadderTerm:
53
- coefficient: float
54
- ops: List["LadderOp"]
55
+ coefficient: CReal
56
+ ops: CArray["LadderOp"]
55
57
 
56
58
 
57
59
  @struct
58
60
  class LadderOp:
59
- op: int
60
- index: int
61
+ op: LadderOperator
62
+ index: CInt
61
63
 
62
64
 
63
65
  @struct
64
66
  class CombinatorialOptimizationSolution:
65
- probability: float
66
- cost: float
67
- solution: List[int]
68
- count: int
67
+ probability: CReal
68
+ cost: CReal
69
+ solution: CArray[CInt]
70
+ count: CInt
69
71
 
70
72
 
71
73
  @struct
72
74
  class GaussianModel:
73
- num_qubits: int
74
- normal_max_value: float
75
- default_probabilities: List[float]
76
- rhos: List[float]
77
- loss: List[int]
78
- min_loss: int
75
+ num_qubits: CInt
76
+ normal_max_value: CReal
77
+ default_probabilities: CArray[CReal]
78
+ rhos: CArray[CReal]
79
+ loss: CArray[CInt]
80
+ min_loss: CInt
79
81
 
80
82
 
81
83
  @struct
82
84
  class LogNormalModel:
83
- num_qubits: int
84
- mu: float
85
- sigma: float
85
+ num_qubits: CInt
86
+ mu: CReal
87
+ sigma: CReal
86
88
 
87
89
 
88
90
  @struct
89
91
  class FinanceFunction:
90
- f: int
91
- threshold: float
92
- larger: bool
93
- polynomial_degree: int
94
- use_chebyshev_polynomial_approximation: bool
95
- tail_probability: float
92
+ f: CInt
93
+ threshold: CReal
94
+ larger: CBool
95
+ polynomial_degree: CInt
96
+ use_chebyshev_polynomial_approximation: CBool
97
+ tail_probability: CReal
96
98
 
97
99
 
98
100
  @struct
99
101
  class QsvmResult:
100
- test_score: float
101
- predicted_labels: List[float]
102
+ test_score: CReal
103
+ predicted_labels: CArray[CReal]
102
104
 
103
105
 
104
106
  @struct
105
107
  class QSVMFeatureMapPauli:
106
- feature_dimension: int
107
- reps: int
108
- entanglement: int
109
- alpha: float
110
- paulis: List[List[int]]
108
+ feature_dimension: CInt
109
+ reps: CInt
110
+ entanglement: CInt
111
+ alpha: CReal
112
+ paulis: CArray[CArray[Pauli]]
111
113
 
112
114
 
113
115
  __all__ = [
@@ -9,8 +9,8 @@ from classiq.interface.generator.functions.classical_type import (
9
9
  ClassicalArray,
10
10
  ClassicalList,
11
11
  ConcreteClassicalType,
12
+ CStructBase,
12
13
  Integer,
13
- QStructBase,
14
14
  Real,
15
15
  Struct,
16
16
  )
@@ -27,7 +27,7 @@ from classiq.interface.model.quantum_function_declaration import (
27
27
  from classiq import StructDeclaration
28
28
  from classiq.exceptions import ClassiqValueError
29
29
  from classiq.qmod.model_state_container import ModelStateContainer
30
- from classiq.qmod.qmod_parameter import Array, QParam
30
+ from classiq.qmod.qmod_parameter import CArray, CBool, CInt, CParam, CReal
31
31
  from classiq.qmod.qmod_variable import QVar, get_type_hint_expr
32
32
  from classiq.qmod.quantum_callable import QCallable, QCallableList
33
33
  from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
@@ -38,34 +38,39 @@ OPERAND_ARG_NAME = "arg{i}"
38
38
  def python_type_to_qmod(
39
39
  py_type: type, *, qmodule: ModelStateContainer
40
40
  ) -> Optional[ConcreteClassicalType]:
41
- if py_type == int:
41
+ if py_type == int or py_type is CInt:
42
42
  return Integer()
43
- elif py_type == float:
43
+ elif py_type == float or py_type is CReal:
44
44
  return Real()
45
- elif py_type == bool:
45
+ elif py_type == bool or py_type is CBool:
46
46
  return Bool()
47
47
  elif get_origin(py_type) == list:
48
48
  return ClassicalList(
49
49
  element_type=python_type_to_qmod(get_args(py_type)[0], qmodule=qmodule)
50
50
  )
51
- elif get_origin(py_type) == Array:
51
+ elif get_origin(py_type) == CArray:
52
52
  array_args = version_portable_get_args(py_type)
53
- if len(array_args) != 2:
54
- raise ClassiqValueError(
55
- "Array accepts two generic parameters in the form 'Array[<element-type>, <size>]'"
53
+ if len(array_args) == 1:
54
+ return ClassicalList(
55
+ element_type=python_type_to_qmod(array_args[0], qmodule=qmodule)
56
56
  )
57
- return ClassicalArray(
58
- element_type=python_type_to_qmod(array_args[0], qmodule=qmodule),
59
- size=get_type_hint_expr(array_args[1]),
57
+ elif len(array_args) == 2:
58
+ return ClassicalArray(
59
+ element_type=python_type_to_qmod(array_args[0], qmodule=qmodule),
60
+ size=get_type_hint_expr(array_args[1]),
61
+ )
62
+ raise ClassiqValueError(
63
+ "CArray accepts one or two generic parameters in the form "
64
+ "`CArray[<element-type>]` or `CArray[<element-type>, <size>]`"
60
65
  )
61
- elif inspect.isclass(py_type) and issubclass(py_type, QStructBase):
66
+ elif inspect.isclass(py_type) and issubclass(py_type, CStructBase):
62
67
  _add_qmod_struct(py_type, qmodule=qmodule)
63
68
  return Struct(name=py_type.__name__)
64
69
  return None
65
70
 
66
71
 
67
72
  def _add_qmod_struct(
68
- py_type: Type[QStructBase], *, qmodule: ModelStateContainer
73
+ py_type: Type[CStructBase], *, qmodule: ModelStateContainer
69
74
  ) -> None:
70
75
  if (
71
76
  py_type.__name__ in StructDeclaration.BUILTIN_STRUCT_DECLARATIONS
@@ -82,17 +87,6 @@ def _add_qmod_struct(
82
87
  )
83
88
 
84
89
 
85
- def _extract_param_decl(
86
- name: str, py_type: Any, *, qmodule: ModelStateContainer
87
- ) -> ClassicalParameterDeclaration:
88
- if len(get_args(py_type)) != 1:
89
- raise ClassiqValueError("QParam takes exactly one generic argument")
90
- py_type = get_args(py_type)[0]
91
- return ClassicalParameterDeclaration(
92
- name=name, classical_type=python_type_to_qmod(py_type, qmodule=qmodule)
93
- )
94
-
95
-
96
90
  def _extract_port_decl(name: str, py_type: Any) -> PortDeclaration:
97
91
  # FIXME: CAD-13409
98
92
  qtype: Type[QVar] = QVar.from_type_hint(py_type) # type:ignore[assignment]
@@ -128,8 +122,19 @@ def _extract_positional_args(
128
122
  if name == "return":
129
123
  continue
130
124
  name = unmangle_keyword(name)
131
- if get_origin(py_type) is QParam:
132
- result.append(_extract_param_decl(name, py_type, qmodule=qmodule))
125
+ if (
126
+ inspect.isclass(py_type)
127
+ and issubclass(py_type, CParam)
128
+ or inspect.isclass(py_type)
129
+ and issubclass(py_type, CStructBase)
130
+ or get_origin(py_type) == CArray
131
+ ):
132
+ result.append(
133
+ ClassicalParameterDeclaration(
134
+ name=name,
135
+ classical_type=python_type_to_qmod(py_type, qmodule=qmodule),
136
+ )
137
+ )
133
138
  elif QVar.from_type_hint(py_type) is not None:
134
139
  result.append(_extract_port_decl(name, py_type))
135
140
  else:
@@ -0,0 +1,9 @@
1
+ from typing import List
2
+
3
+ from .pretty_printer import DSLPrettyPrinter
4
+
5
+ __all__ = ["DSLPrettyPrinter"]
6
+
7
+
8
+ def __dir__() -> List[str]:
9
+ return __all__
@@ -1,7 +1,7 @@
1
1
  import ast
2
2
  import re
3
3
  from dataclasses import dataclass
4
- from typing import Callable, Dict, List, Mapping, Type
4
+ from typing import Callable, Dict, List, Mapping, Optional, Type
5
5
 
6
6
  import numpy as np
7
7
 
@@ -42,7 +42,7 @@ LIST_FORMAT_CHAR_LIMIT = 20
42
42
  @dataclass
43
43
  class ASTToQMODCode:
44
44
  level: int
45
- decimal_precision: int
45
+ decimal_precision: Optional[int]
46
46
  indent_seq: str = " "
47
47
 
48
48
  @property
@@ -65,6 +65,8 @@ class ASTToQMODCode:
65
65
  elif isinstance(node, ast.Name):
66
66
  return node.id
67
67
  elif isinstance(node, ast.Num):
68
+ if self.decimal_precision is None:
69
+ return str(node.n)
68
70
  return str(np.round(node.n, self.decimal_precision))
69
71
  elif isinstance(node, ast.Str):
70
72
  return repr(node.s)
@@ -122,7 +124,7 @@ class ASTToQMODCode:
122
124
  keywords = node.keywords
123
125
  initializer_list = self.indent_items(
124
126
  lambda: [
125
- f"{keyword.arg} = {self._cleaned_ast_to_code(keyword.value)}"
127
+ f"{keyword.arg}={self._cleaned_ast_to_code(keyword.value)}"
126
128
  for keyword in keywords
127
129
  if keyword.arg is not None
128
130
  ]
@@ -182,7 +184,9 @@ def _remove_redundant_parentheses(expr: str) -> str:
182
184
 
183
185
 
184
186
  def transform_expression(
185
- expr: str, level: int = 0, decimal_precision: int = DEFAULT_DECIMAL_PRECISION
187
+ expr: str,
188
+ level: int = 0,
189
+ decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION,
186
190
  ) -> str:
187
191
  return ASTToQMODCode(level=level, decimal_precision=decimal_precision).visit(
188
192
  ast.parse(expr)
@@ -1,4 +1,4 @@
1
- from typing import Dict, List
1
+ from typing import Dict, List, Optional
2
2
 
3
3
  from classiq.interface.generator.constant import Constant
4
4
  from classiq.interface.generator.expressions.expression import Expression
@@ -41,7 +41,6 @@ from classiq.interface.model.quantum_function_declaration import (
41
41
  QuantumFunctionDeclaration,
42
42
  QuantumOperandDeclaration,
43
43
  )
44
- from classiq.interface.model.quantum_if_operation import QuantumIf
45
44
  from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
46
45
  from classiq.interface.model.quantum_type import (
47
46
  QuantumBit,
@@ -64,7 +63,9 @@ from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
64
63
 
65
64
 
66
65
  class DSLPrettyPrinter(Visitor):
67
- def __init__(self, decimal_precision: int = DEFAULT_DECIMAL_PRECISION) -> None:
66
+ def __init__(
67
+ self, decimal_precision: Optional[int] = DEFAULT_DECIMAL_PRECISION
68
+ ) -> None:
68
69
  self._level = 0
69
70
  self._decimal_precision = decimal_precision
70
71
 
@@ -137,8 +138,6 @@ class DSLPrettyPrinter(Visitor):
137
138
 
138
139
  def visit_QuantumBitvector(self, qtype: QuantumBitvector) -> str:
139
140
  if qtype.length is not None:
140
- if qtype.length.is_evaluated() and qtype.length.to_int_value() == 1:
141
- return "qbit"
142
141
  return f"qbit[{self.visit(qtype.length)}]"
143
142
  return "qbit[]"
144
143
 
@@ -213,17 +212,11 @@ class DSLPrettyPrinter(Visitor):
213
212
  )
214
213
  return f"{self._indent}{func_call.func_name}{f'[{self.visit(func_call.function.index)}]' if isinstance(func_call.function, OperandIdentifier) else ''}{gen_time_arg_list}({quantum_args});\n"
215
214
 
216
- def visit_Control(self, control: Control) -> str:
217
- control_code = f"{self._indent}control ({self.visit(control.control)}) {{\n"
218
- control_code += self._visit_body(control.body)
219
- control_code += f"{self._indent}}}\n"
220
- return control_code
221
-
222
- def visit_QuantumIf(self, op: QuantumIf) -> str:
223
- quantum_if = f"{self._indent}quantum_if ({self.visit(op.expression)}) {{\n"
224
- quantum_if += self._visit_body(op.then)
225
- quantum_if += f"{self._indent}}}\n"
226
- return quantum_if
215
+ def visit_Control(self, op: Control) -> str:
216
+ control = f"{self._indent}control ({self.visit(op.expression)}) {{\n"
217
+ control += self._visit_body(op.body)
218
+ control += f"{self._indent}}}\n"
219
+ return control
227
220
 
228
221
  def visit_ClassicalIf(self, op: ClassicalIf) -> str:
229
222
  classical_if = f"{self._indent}if ({self.visit(op.condition)}) {{\n"
@@ -309,10 +302,10 @@ class DSLPrettyPrinter(Visitor):
309
302
  return var_ref.name
310
303
 
311
304
  def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
312
- return str(var_ref)
305
+ return f"{var_ref.name}[{self.visit(var_ref.start)}:{self.visit(var_ref.end)}]"
313
306
 
314
307
  def visit_SubscriptHandleBinding(self, var_ref: SubscriptHandleBinding) -> str:
315
- return str(var_ref)
308
+ return f"{var_ref.name}[{self.visit(var_ref.index)}]"
316
309
 
317
310
  def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
318
311
  op = "^=" if arith_op.inplace_result else "="
@@ -0,0 +1,9 @@
1
+ from typing import List
2
+
3
+ from .pretty_printer import PythonPrettyPrinter
4
+
5
+ __all__ = ["PythonPrettyPrinter"]
6
+
7
+
8
+ def __dir__() -> List[str]:
9
+ return __all__