classiq 0.79.1__py3-none-any.whl → 0.80.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 (46) hide show
  1. classiq/__init__.py +7 -0
  2. classiq/_internals/api_wrapper.py +95 -19
  3. classiq/analyzer/show_interactive_hack.py +63 -48
  4. classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
  5. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +3 -3
  6. classiq/interface/_version.py +1 -1
  7. classiq/interface/analyzer/result.py +1 -1
  8. classiq/interface/chemistry/operator.py +3 -8
  9. classiq/interface/executor/quantum_program_params.py +18 -0
  10. classiq/interface/generator/application_apis/chemistry_declarations.py +3 -3
  11. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +3 -3
  12. classiq/interface/generator/application_apis/entangler_declarations.py +3 -3
  13. classiq/interface/generator/arith/number_utils.py +8 -0
  14. classiq/interface/generator/expressions/proxies/classical/utils.py +8 -3
  15. classiq/interface/generator/functions/classical_type.py +63 -7
  16. classiq/interface/generator/generated_circuit_data.py +10 -1
  17. classiq/interface/helpers/custom_pydantic_types.py +2 -3
  18. classiq/interface/model/allocate.py +6 -0
  19. classiq/interface/model/quantum_type.py +26 -5
  20. classiq/interface/server/routes.py +6 -0
  21. classiq/model_expansions/atomic_expression_functions_defs.py +9 -1
  22. classiq/model_expansions/capturing/captured_vars.py +1 -1
  23. classiq/model_expansions/evaluators/classical_type_inference.py +39 -27
  24. classiq/model_expansions/evaluators/parameter_types.py +65 -3
  25. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +1 -1
  26. classiq/model_expansions/quantum_operations/allocate.py +121 -34
  27. classiq/model_expansions/quantum_operations/call_emitter.py +1 -1
  28. classiq/model_expansions/scope.py +1 -2
  29. classiq/open_library/functions/__init__.py +2 -0
  30. classiq/open_library/functions/state_preparation.py +86 -3
  31. classiq/qmod/builtins/classical_execution_primitives.py +2 -4
  32. classiq/qmod/builtins/functions/__init__.py +3 -0
  33. classiq/qmod/builtins/functions/arithmetic.py +21 -1
  34. classiq/qmod/builtins/functions/exponentiation.py +24 -0
  35. classiq/qmod/builtins/operations.py +32 -2
  36. classiq/qmod/builtins/structs.py +47 -1
  37. classiq/qmod/native/pretty_printer.py +15 -6
  38. classiq/qmod/pretty_print/pretty_printer.py +15 -6
  39. classiq/qmod/python_classical_type.py +4 -4
  40. classiq/qmod/qmod_parameter.py +5 -1
  41. classiq/qmod/semantics/validation/main_validation.py +5 -0
  42. classiq/quantum_program.py +69 -0
  43. {classiq-0.79.1.dist-info → classiq-0.80.1.dist-info}/METADATA +1 -1
  44. {classiq-0.79.1.dist-info → classiq-0.80.1.dist-info}/RECORD +46 -44
  45. {classiq-0.79.1.dist-info → classiq-0.80.1.dist-info}/WHEEL +1 -1
  46. /classiq/{model_expansions/utils → interface/helpers}/text_utils.py +0 -0
@@ -30,6 +30,7 @@ from classiq.interface.generator.functions.port_declaration import (
30
30
  )
31
31
  from classiq.interface.generator.functions.type_qualifier import TypeQualifier
32
32
  from classiq.interface.helpers.backward_compatibility import zip_strict
33
+ from classiq.interface.helpers.text_utils import are, readable_list, s
33
34
  from classiq.interface.model.classical_parameter_declaration import (
34
35
  ClassicalParameterDeclaration,
35
36
  )
@@ -82,7 +83,6 @@ from classiq.model_expansions.transformers.type_qualifier_inference import (
82
83
  TypeQualifierInference,
83
84
  )
84
85
  from classiq.model_expansions.transformers.var_splitter import VarSplitter
85
- from classiq.model_expansions.utils.text_utils import are, readable_list, s
86
86
  from classiq.qmod.pretty_print.expression_to_python import transform_expression
87
87
  from classiq.qmod.semantics.validation.signature_validation import (
88
88
  validate_function_signature,
@@ -22,6 +22,7 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
22
22
  QmodStructInstance,
23
23
  )
24
24
  from classiq.interface.generator.functions.type_name import TypeName
25
+ from classiq.interface.helpers.text_utils import readable_list, s
25
26
  from classiq.interface.model.handle_binding import (
26
27
  FieldHandleBinding,
27
28
  GeneralHandle,
@@ -41,8 +42,6 @@ from classiq.interface.model.quantum_type import (
41
42
  QuantumType,
42
43
  )
43
44
 
44
- from classiq.model_expansions.utils.text_utils import readable_list, s
45
-
46
45
  if TYPE_CHECKING:
47
46
  from classiq.model_expansions.closure import FunctionClosure
48
47
 
@@ -107,6 +107,8 @@ __all__ = [
107
107
  "phase_oracle",
108
108
  "prepare_bell_state",
109
109
  "prepare_complex_amplitudes",
110
+ "prepare_dicke_state",
111
+ "prepare_dicke_state_unary_input",
110
112
  "prepare_exponential_state",
111
113
  "prepare_ghz_state",
112
114
  "prepare_int",
@@ -6,7 +6,10 @@ import sympy
6
6
 
7
7
  from classiq.interface.exceptions import ClassiqDeprecationWarning
8
8
 
9
- from classiq.open_library.functions.utility_functions import hadamard_transform
9
+ from classiq.open_library.functions.utility_functions import (
10
+ apply_to_all,
11
+ hadamard_transform,
12
+ )
10
13
  from classiq.qmod.builtins.functions import (
11
14
  CX,
12
15
  IDENTITY,
@@ -16,11 +19,19 @@ from classiq.qmod.builtins.functions import (
16
19
  X,
17
20
  inplace_prepare_amplitudes,
18
21
  )
19
- from classiq.qmod.builtins.operations import allocate, control, if_, inplace_add, repeat
22
+ from classiq.qmod.builtins.operations import (
23
+ allocate,
24
+ control,
25
+ if_,
26
+ inplace_add,
27
+ repeat,
28
+ within_apply,
29
+ )
20
30
  from classiq.qmod.cparam import CArray, CBool, CInt, CReal
21
31
  from classiq.qmod.qfunc import qfunc
22
32
  from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
23
33
  from classiq.qmod.symbolic import (
34
+ acos,
24
35
  asin,
25
36
  atan,
26
37
  exp,
@@ -375,7 +386,7 @@ def inplace_prepare_complex_amplitudes(
375
386
  @qfunc
376
387
  def prepare_complex_amplitudes(
377
388
  magnitudes: CArray[CReal],
378
- phases: CArray[CReal],
389
+ phases: list[float],
379
390
  out: Output[QArray[QBit, Literal["log(get_field(magnitudes, 'len'), 2)"]]],
380
391
  ) -> None:
381
392
  """
@@ -391,3 +402,75 @@ def prepare_complex_amplitudes(
391
402
  """
392
403
  allocate(out)
393
404
  inplace_prepare_complex_amplitudes(magnitudes, phases, out)
405
+
406
+
407
+ @qfunc
408
+ def _dicke_split_cycle_shift(k: int, qvar: QArray[QBit]) -> None:
409
+ """
410
+ internal function, assumes the input is in the form |11..100..0> with up to k ones.
411
+ transforms the state to: sqrt(1/n)*|11..100..0> + sqrt((n-1)/n)*|01..110..0>.
412
+ """
413
+ for i in range(k):
414
+ within_apply(
415
+ lambda i=i: CX(qvar[i + 1], qvar[0]), # type: ignore[misc]
416
+ lambda i=i: ( # type: ignore[misc]
417
+ control(
418
+ qvar[0],
419
+ lambda i=i: RY(2 * acos(sqrt((i + 1) / qvar.len)), qvar[i + 1]), # type: ignore[misc]
420
+ )
421
+ if i == 0
422
+ else control(
423
+ qvar[0] & qvar[i],
424
+ lambda i=i: RY(2 * acos(sqrt((i + 1) / qvar.len)), qvar[i + 1]), # type: ignore[misc]
425
+ )
426
+ ),
427
+ )
428
+
429
+
430
+ @qfunc
431
+ def prepare_dicke_state_unary_input(max_k: int, qvar: QArray[QBit]) -> None:
432
+ """
433
+ [Qmod Classiq-library function]
434
+
435
+ Prepares a Dicke state with a variable number of excitations based on an unary-encoded input.
436
+
437
+ The Dicke state is defined to be:
438
+
439
+ $$\\mathrm{Dicke}(n, k) = \\frac{1}{\\sqrt{\\binom{n}{k}}} \\sum_{x \\in \\{0,1\\}^n,\\, |x| = k} |x\\rangle$$
440
+
441
+ The input register `qvar` is expected to already be initialized in a unary encoding:
442
+ the value k is represented by a string of k ones followed by zeros, e.g., k = 3 -> |11100...0>.
443
+ The function generates a Dicke state with k excitations over a new quantum register,
444
+ where 0 <= k < max_k.
445
+
446
+ Args:
447
+ max_k: The maximum number of allowed excitations (upper bound for k).
448
+ qvar: Unary-encoded quantum input register of length >= max_k. Must be pre-initialized.
449
+ """
450
+ if qvar.len > max(1, max_k):
451
+ _dicke_split_cycle_shift(max_k, qvar)
452
+ prepare_dicke_state_unary_input(qmin(max_k, qvar.len - 2), qvar[1 : qvar.len])
453
+
454
+
455
+ @qfunc
456
+ def prepare_dicke_state(k: int, qvar: QArray[QBit]) -> None:
457
+ """
458
+ [Qmod Classiq-library function]
459
+
460
+ Prepares a Dicke state with k excitations over the provided quantum register.
461
+
462
+ A Dicke state of n qubits with k excitations is an equal superposition of all basis states
463
+ with exactly k qubits in the $|1\\rangle$ state and $(n - k)$ qubits in the $|0\\rangle$ state.
464
+ For example, $\\mathrm{Dicke}(2, 1) = (|01\\rangle + |10\\rangle) / \\sqrt(2)$.
465
+
466
+ In the general case it is defined to be:
467
+
468
+ $$\\mathrm{Dicke}(n, k) = \\frac{1}{\\sqrt{\\binom{n}{k}}} \\sum_{x \\in \\{0,1\\}^n,\\, |x| = k} |x\\rangle$$
469
+
470
+ Args:
471
+ k: The number of excitations (i.e., number of qubits in state $|1\\rangle$).
472
+ qvar: The quantum register (array of qubits) to initialize. Must be uninitialized and have length >= k.
473
+ """
474
+ if k > 0:
475
+ apply_to_all(X, qvar[0:k])
476
+ prepare_dicke_state_unary_input(k, qvar)
@@ -1,8 +1,9 @@
1
- from typing import Final, Optional, Union
1
+ from typing import Final, Optional
2
2
 
3
3
  from classiq.interface.applications.iqae.iqae_result import IQAEResult
4
4
  from classiq.interface.exceptions import ClassiqError
5
5
  from classiq.interface.executor.execution_preferences import QaeWithQpeEstimationMethod
6
+ from classiq.interface.executor.quantum_program_params import ExecutionParams
6
7
  from classiq.interface.executor.result import (
7
8
  EstimationResult,
8
9
  EstimationResults,
@@ -15,8 +16,6 @@ from classiq.interface.generator.functions.qmod_python_interface import QmodPySt
15
16
  from classiq.applications.qsvm.qsvm import Data, Labels
16
17
  from classiq.qmod.builtins.enums import Optimizer
17
18
 
18
- ExecutionParams = dict[str, Union[float, int, list[int], list[float]]]
19
-
20
19
  _CALL_IN_QFUNC_ERROR = (
21
20
  'Cannot call "{}" in a quantum context. "{}" is a classical execution primitive.'
22
21
  )
@@ -104,7 +103,6 @@ def molecule_ground_state_solution_post_process( # type: ignore[return]
104
103
 
105
104
 
106
105
  __all__ = [
107
- "ExecutionParams",
108
106
  "batch_estimate",
109
107
  "batch_sample",
110
108
  "estimate",
@@ -55,6 +55,7 @@ CORE_LIB_DECLS = [
55
55
  prepare_amplitudes_approx,
56
56
  unitary,
57
57
  add,
58
+ add_inplace_right,
58
59
  modular_add,
59
60
  integer_xor,
60
61
  modular_add_constant,
@@ -69,6 +70,7 @@ CORE_LIB_DECLS = [
69
70
  inplace_prepare_amplitudes_approx,
70
71
  single_pauli_exponent,
71
72
  commuting_paulis_exponent,
73
+ sparse_suzuki_trotter,
72
74
  suzuki_trotter,
73
75
  qdrift,
74
76
  exponentiation_with_depth_constraint,
@@ -109,6 +111,7 @@ __all__ = [ # noqa: RUF022
109
111
  "Y",
110
112
  "Z",
111
113
  "add",
114
+ "add_inplace_right",
112
115
  "apply",
113
116
  "bloch_sphere_feature_map",
114
117
  "exponentiation_with_depth_constraint",
@@ -2,7 +2,7 @@ from typing import Literal
2
2
 
3
3
  from classiq.qmod.qfunc import qfunc
4
4
  from classiq.qmod.qmod_parameter import CArray, CBool, CReal
5
- from classiq.qmod.qmod_variable import Const, Output, QArray, QBit, QFree, QNum
5
+ from classiq.qmod.qmod_variable import Const, Input, Output, QArray, QBit, QFree, QNum
6
6
 
7
7
 
8
8
  @qfunc(external=True)
@@ -42,6 +42,26 @@ def add(
42
42
  pass
43
43
 
44
44
 
45
+ @qfunc(external=True)
46
+ def add_inplace_right(
47
+ left: Const[QNum],
48
+ right: QFree[Input[QNum]],
49
+ result: QFree[
50
+ Output[
51
+ QNum[
52
+ Literal["result_size"],
53
+ Literal["result_is_signed"],
54
+ Literal["result_fraction_places"],
55
+ ]
56
+ ]
57
+ ],
58
+ result_size: CReal,
59
+ result_is_signed: CBool,
60
+ result_fraction_places: CReal,
61
+ ) -> None:
62
+ pass
63
+
64
+
45
65
  @qfunc(external=True)
46
66
  def modular_add(left: Const[QArray[QBit]], right: QFree[QArray[QBit]]) -> None:
47
67
  pass
@@ -3,6 +3,7 @@ from typing import Literal
3
3
  from classiq.qmod.builtins.enums import Pauli
4
4
  from classiq.qmod.builtins.structs import (
5
5
  PauliTerm,
6
+ SparsePauliOp,
6
7
  )
7
8
  from classiq.qmod.qfunc import qfunc
8
9
  from classiq.qmod.qmod_parameter import CArray, CInt, CReal
@@ -79,6 +80,29 @@ def suzuki_trotter(
79
80
  pass
80
81
 
81
82
 
83
+ @qfunc(external=True)
84
+ def sparse_suzuki_trotter(
85
+ pauli_operator: SparsePauliOp,
86
+ evolution_coefficient: CReal,
87
+ order: CInt,
88
+ repetitions: CInt,
89
+ qbv: QArray[QBit, Literal["get_field(pauli_operator, 'num_qubits')"]],
90
+ ) -> None:
91
+ """
92
+ Applies the Suzuki-Trotter decomposition to a sparse Pauli operator. For more details,
93
+ See about Suzuki-Trotter decomposition in `suzuki_trotter` `qfunc`.
94
+
95
+ Args:
96
+ pauli_operator: The Pauli operator to be exponentiated, in sparse representation (See: SparsePauliOp).
97
+ evolution_coefficient: A global evolution coefficient multiplying the Pauli operator.
98
+ order: The order of the Suzuki-Trotter decomposition.
99
+ repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
100
+ qbv: The target quantum variable of the exponentiation.
101
+ """
102
+
103
+ pass
104
+
105
+
82
106
  @qfunc(external=True)
83
107
  def qdrift(
84
108
  pauli_operator: CArray[PauliTerm],
@@ -63,6 +63,16 @@ def allocate(out: Output[QVar]) -> None:
63
63
  pass
64
64
 
65
65
 
66
+ @overload
67
+ def allocate(
68
+ num_qubits: Union[int, SymbolicExpr],
69
+ is_signed: Union[bool, SymbolicExpr],
70
+ fraction_digits: Union[int, SymbolicExpr],
71
+ out: Output[QVar],
72
+ ) -> None:
73
+ pass
74
+
75
+
66
76
  @suppress_return_value
67
77
  def allocate(*args: Any, **kwargs: Any) -> None:
68
78
  """
@@ -73,34 +83,54 @@ def allocate(*args: Any, **kwargs: Any) -> None:
73
83
  $$
74
84
 
75
85
  If 'num_qubits' is not specified, it will be inferred according to the type of 'out'.
86
+ In case the quantum variable is of type `QNum`, its numeric attributes can be specified as
87
+ well.
76
88
 
77
89
  Args:
78
90
  num_qubits: The number of qubits to allocate (positive integer, optional).
79
91
  out: The quantum variable that will receive the allocated qubits. Must be uninitialized before allocation.
92
+ is_signed: The sign of the allocated variable, valid only for `QNum` (boolean, optional).
93
+ fraction_digits: The number of fraction digits in the allocated variable, valid only for `QNum` (positive integer, optional).
80
94
 
81
95
  Notes:
82
- 1. If the output variable has been declared with a specific number of qubits, the number of qubits allocated must match the declared number.
96
+ 1. If the output variable has been declared with a specific number of qubits or numeric attributes, the passed values must match the declared values.
83
97
  2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
84
98
  """
85
99
  assert QCallable.CURRENT_EXPANDABLE is not None
86
100
  source_ref = get_source_ref(sys._getframe(1))
87
101
  if len(args) == 0:
88
102
  size = kwargs.get("num_qubits", None)
103
+ is_signed = kwargs.get("is_signed", None)
104
+ fraction_digits = kwargs.get("fraction_digits", None)
89
105
  target = kwargs["out"]
90
106
  elif len(args) == 1:
91
107
  if "out" in kwargs:
92
108
  size = args[0]
109
+ is_signed = kwargs.get("is_signed", None)
110
+ fraction_digits = kwargs.get("fraction_digits", None)
93
111
  target = kwargs["out"]
94
112
  else:
95
113
  size = None
114
+ is_signed = None
115
+ fraction_digits = None
96
116
  target = args[0]
97
- else:
117
+ elif len(args) == 2:
98
118
  size, target = args
119
+ is_signed = kwargs.get("is_signed", None)
120
+ fraction_digits = kwargs.get("fraction_digits", None)
121
+ else:
122
+ size, is_signed, fraction_digits, target = args
99
123
  if isinstance(size, QConstant):
100
124
  size.add_to_model()
101
125
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
102
126
  Allocate(
103
127
  size=None if size is None else Expression(expr=str(size)),
128
+ is_signed=None if is_signed is None else Expression(expr=str(is_signed)),
129
+ fraction_digits=(
130
+ None
131
+ if fraction_digits is None
132
+ else Expression(expr=str(fraction_digits))
133
+ ),
104
134
  target=target.get_handle_binding(),
105
135
  source_ref=source_ref,
106
136
  )
@@ -10,7 +10,7 @@ from classiq.qmod.python_classical_type import PythonClassicalType
10
10
  @dataclass
11
11
  class PauliTerm:
12
12
  """
13
- A term in a Hamiltonian, represented as a product of Pauli operators.
13
+ A term in a Hamiltonian, represented as a product of single-qubit Pauli matrices.
14
14
 
15
15
  Attributes:
16
16
  pauli (CArray[Pauli]): The list of the chosen Pauli operators in the term, corresponds to a product of them.
@@ -21,6 +21,49 @@ class PauliTerm:
21
21
  coefficient: CReal
22
22
 
23
23
 
24
+ @dataclass
25
+ class IndexedPauli:
26
+ """
27
+ A single-qubit Pauli matrix on a specific qubit given by its index.
28
+
29
+ Attributes:
30
+ pauli (Pauli): The Pauli operator.
31
+ index (CInt): The index of the qubit being operated on.
32
+ """
33
+
34
+ pauli: Pauli
35
+ index: CInt
36
+
37
+
38
+ @dataclass
39
+ class SparsePauliTerm:
40
+ """
41
+ A term in the Hamiltonian, represented as a sparse product of single-qubit Pauli
42
+ matrices.
43
+
44
+ Attributes:
45
+ paulis (CArray[IndexedPauli]): The list of chosen sparse Pauli operators in the term corresponds to a product of them. (See IndexedPauli)
46
+ coefficient (CReal): The coefficient of the term (floating number).
47
+ """
48
+
49
+ paulis: CArray[IndexedPauli]
50
+ coefficient: CReal
51
+
52
+
53
+ @dataclass
54
+ class SparsePauliOp:
55
+ """
56
+ Represents a collection of sparse Pauli operators.
57
+
58
+ Attributes:
59
+ paulis (CArray[SparsePauliTerm]): The list of chosen sparse Pauli operators in the term, corresponds to a product of them. (See: SparsePauliTerm)
60
+ num_qubits (CInt): The number of qubits in the Hamiltonian.
61
+ """
62
+
63
+ paulis: CArray[SparsePauliTerm]
64
+ num_qubits: CInt
65
+
66
+
24
67
  @dataclass
25
68
  class Position:
26
69
  x: CReal
@@ -139,6 +182,7 @@ __all__ = [
139
182
  "FinanceFunction",
140
183
  "FockHamiltonianProblem",
141
184
  "GaussianModel",
185
+ "IndexedPauli",
142
186
  "LadderOp",
143
187
  "LadderTerm",
144
188
  "LogNormalModel",
@@ -148,4 +192,6 @@ __all__ = [
148
192
  "Position",
149
193
  "QSVMFeatureMapPauli",
150
194
  "QsvmResult",
195
+ "SparsePauliOp",
196
+ "SparsePauliTerm",
151
197
  ]
@@ -250,7 +250,10 @@ class DSLPrettyPrinter(ModelVisitor):
250
250
  return f"{self.visit(ctlist.element_type)}[]"
251
251
 
252
252
  def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
253
- return f"{self.visit(ctarray.element_type)}[{ctarray.size}]"
253
+ element_type = self.visit(ctarray.element_type)
254
+ if ctarray.length is not None:
255
+ return f"{element_type}[{self.visit(ctarray.length)}]"
256
+ return f"{element_type}[]"
254
257
 
255
258
  def visit_ClassicalTuple(self, classical_tuple: ClassicalTuple) -> str:
256
259
  raw_type = classical_tuple.get_raw_type()
@@ -288,11 +291,17 @@ class DSLPrettyPrinter(ModelVisitor):
288
291
  return f"{self.visit_QuantumFunctionDeclaration(func_def)} {{\n{body}}}\n"
289
292
 
290
293
  def visit_Allocate(self, allocate: Allocate) -> str:
291
- if allocate.size is not None:
292
- size = f"{self.visit(allocate.size)}, "
293
- else:
294
- size = ""
295
- return f"{self._indent}allocate({size}{self.visit(allocate.target)});\n"
294
+ params = ", ".join(
295
+ self.visit(param)
296
+ for param in [
297
+ allocate.size,
298
+ allocate.is_signed,
299
+ allocate.fraction_digits,
300
+ allocate.target,
301
+ ]
302
+ if param is not None
303
+ )
304
+ return f"{self._indent}allocate({params});\n"
296
305
 
297
306
  def visit_QuantumFunctionCall(self, func_call: QuantumFunctionCall) -> str:
298
307
  positional_args = ", ".join(
@@ -344,7 +344,10 @@ class PythonPrettyPrinter(ModelVisitor):
344
344
 
345
345
  def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
346
346
  self._imports["CArray"] = 1
347
- return f"CArray[{self.visit(ctarray.element_type)}, {ctarray.size}]"
347
+ element_type = self.visit(ctarray.element_type)
348
+ if ctarray.length is not None:
349
+ return f"CArray[{element_type}, {_add_quotes(self.visit(ctarray.length))}]"
350
+ return f"CArray[{element_type}]"
348
351
 
349
352
  def visit_ClassicalTuple(self, classical_tuple: ClassicalTuple) -> str:
350
353
  raw_type = classical_tuple.get_raw_type()
@@ -434,11 +437,17 @@ class PythonPrettyPrinter(ModelVisitor):
434
437
 
435
438
  def visit_Allocate(self, allocate: Allocate) -> str:
436
439
  self._imports["allocate"] = 1
437
- if allocate.size is not None:
438
- size = f"{self.visit(allocate.size)}, "
439
- else:
440
- size = ""
441
- return f"{self._indent}allocate({size}{self.visit(allocate.target)})\n"
440
+ params = ", ".join(
441
+ self.visit(param)
442
+ for param in [
443
+ allocate.size,
444
+ allocate.is_signed,
445
+ allocate.fraction_digits,
446
+ allocate.target,
447
+ ]
448
+ if param is not None
449
+ )
450
+ return f"{self._indent}allocate({params})\n"
442
451
 
443
452
  def visit_Control(self, op: Control) -> str:
444
453
  self._imports["control"] = 1
@@ -11,10 +11,10 @@ from typing import (
11
11
  )
12
12
 
13
13
  from classiq.interface.exceptions import ClassiqValueError
14
+ from classiq.interface.generator.expressions.expression import Expression
14
15
  from classiq.interface.generator.functions.classical_type import (
15
16
  Bool,
16
17
  ClassicalArray,
17
- ClassicalList,
18
18
  Integer,
19
19
  Real,
20
20
  )
@@ -47,15 +47,15 @@ class PythonClassicalType:
47
47
  elif get_origin(py_type) is list:
48
48
  element_type = self.convert(get_args(py_type)[0])
49
49
  if element_type is not None:
50
- return ClassicalList(element_type=element_type).set_generative()
50
+ return ClassicalArray(element_type=element_type).set_generative()
51
51
  elif get_origin(py_type) is CArray:
52
52
  array_args = version_portable_get_args(py_type)
53
53
  if len(array_args) == 1:
54
- return ClassicalList(element_type=self.convert(array_args[0]))
54
+ return ClassicalArray(element_type=self.convert(array_args[0]))
55
55
  elif len(array_args) == 2:
56
56
  return ClassicalArray(
57
57
  element_type=self.convert(array_args[0]),
58
- size=get_type_hint_expr(array_args[1]),
58
+ length=Expression(expr=get_type_hint_expr(array_args[1])),
59
59
  )
60
60
  raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
61
61
  elif inspect.isclass(py_type) and dataclasses.is_dataclass(py_type):
@@ -167,7 +167,11 @@ def get_qmod_type(ctype: ClassicalType) -> type:
167
167
  elif isinstance(ctype, ClassicalList):
168
168
  return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
169
169
  elif isinstance(ctype, ClassicalArray):
170
- return CArray[get_qmod_type(ctype.element_type), ctype.size] # type: ignore[misc]
170
+ if ctype.length is None:
171
+ return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
172
+ if ctype.has_length and isinstance(ctype.length.value.value, int):
173
+ return CArray[get_qmod_type(ctype.element_type), ctype.length.value.value] # type: ignore[misc]
174
+ return CArray[get_qmod_type(ctype.element_type), ctype.length.expr] # type: ignore[misc]
171
175
  elif isinstance(ctype, ClassicalTuple):
172
176
  raw_type = ctype.get_raw_type()
173
177
  if isinstance(raw_type, ClassicalTuple):
@@ -37,6 +37,11 @@ def _validate_main_classical_param_type(
37
37
  f"specify array length",
38
38
  )
39
39
  if isinstance(param, ClassicalArray):
40
+ if param.length is None:
41
+ raise ClassiqExpansionError(
42
+ f"Classical array parameter {param_name!r} of function 'main' must "
43
+ f"specify array length",
44
+ )
40
45
  _validate_main_classical_param_type(param.element_type, param_name)
41
46
 
42
47
 
@@ -0,0 +1,69 @@
1
+ from typing import Optional
2
+
3
+ from classiq.interface.executor.quantum_program_params import (
4
+ ParameterAssignmentsParams,
5
+ TranspilationParams,
6
+ )
7
+ from classiq.interface.generator.model.preferences.preferences import Preferences
8
+ from classiq.interface.generator.quantum_program import (
9
+ QuantumProgram,
10
+ )
11
+
12
+ from classiq._internals import async_utils
13
+ from classiq._internals.api_wrapper import ApiWrapper
14
+ from classiq.qmod.builtins.classical_execution_primitives import ExecutionParams
15
+
16
+
17
+ async def transpile_async(params: TranspilationParams) -> QuantumProgram:
18
+ return await ApiWrapper.call_transpilation_task(params)
19
+
20
+
21
+ def transpile(
22
+ quantum_program: QuantumProgram, preferences: Optional[Preferences] = None
23
+ ) -> QuantumProgram:
24
+ """
25
+ Transpiles a quantum program.
26
+
27
+ Args:
28
+ quantum_program: The quantum program to transpile. This is the result of the synthesize method.
29
+ preferences: The transpilation preferences.
30
+
31
+ Returns:
32
+ QuantumProgram: The result of the transpilation (Optional).
33
+ """
34
+ if preferences is None:
35
+ preferences = Preferences()
36
+ return async_utils.run(
37
+ transpile_async(
38
+ TranspilationParams(
39
+ quantum_program=quantum_program, preferences=preferences
40
+ )
41
+ )
42
+ )
43
+
44
+
45
+ async def assign_parameters_async(params: ParameterAssignmentsParams) -> QuantumProgram:
46
+ return await ApiWrapper.call_assign_parameters_task(params)
47
+
48
+
49
+ def assign_parameters(
50
+ quantum_program: QuantumProgram, parameters: ExecutionParams
51
+ ) -> QuantumProgram:
52
+ """
53
+ Assign parameters to a parametric quantum program.
54
+
55
+ Args:
56
+ quantum_program: The quantum program to be assigned. This is the result of the synthesize method.
57
+ parameters: The parameter assignments.
58
+
59
+ Returns:
60
+ QuantumProgram: The quantum program after assigning parameters.
61
+ """
62
+
63
+ return async_utils.run(
64
+ assign_parameters_async(
65
+ ParameterAssignmentsParams(
66
+ quantum_program=quantum_program, parameters=parameters
67
+ )
68
+ )
69
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: classiq
3
- Version: 0.79.1
3
+ Version: 0.80.1
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  License: Proprietary
6
6
  Keywords: quantum computing,quantum circuits,quantum algorithms,QAD,QDL