classiq 0.39.0__py3-none-any.whl → 0.40.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 (51) hide show
  1. classiq/__init__.py +1 -0
  2. classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
  3. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +5 -6
  4. classiq/applications/combinatorial_helpers/optimization_model.py +7 -6
  5. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +0 -10
  6. classiq/applications/combinatorial_optimization/__init__.py +2 -0
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
  8. classiq/interface/_version.py +1 -1
  9. classiq/interface/backend/backend_preferences.py +5 -5
  10. classiq/interface/backend/quantum_backend_providers.py +7 -7
  11. classiq/interface/executor/execution_preferences.py +4 -9
  12. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
  13. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  14. classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -0
  15. classiq/interface/generator/expressions/qmod_qarray_proxy.py +82 -0
  16. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +21 -0
  17. classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
  18. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +8 -6
  19. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +10 -4
  20. classiq/interface/generator/functions/builtins/open_lib_functions.py +624 -76
  21. classiq/interface/generator/functions/classical_type.py +29 -17
  22. classiq/interface/generator/model/preferences/preferences.py +4 -2
  23. classiq/interface/model/control.py +104 -8
  24. classiq/interface/model/quantum_type.py +6 -5
  25. classiq/interface/model/resolvers/function_call_resolver.py +0 -5
  26. classiq/interface/model/statement_block.py +1 -4
  27. classiq/qmod/__init__.py +6 -2
  28. classiq/qmod/builtins/classical_functions.py +30 -35
  29. classiq/qmod/builtins/functions.py +213 -153
  30. classiq/qmod/builtins/operations.py +78 -24
  31. classiq/qmod/builtins/structs.py +50 -48
  32. classiq/qmod/declaration_inferrer.py +30 -18
  33. classiq/qmod/native/expression_to_qmod.py +5 -4
  34. classiq/qmod/native/pretty_printer.py +7 -14
  35. classiq/qmod/qmod_constant.py +7 -7
  36. classiq/qmod/qmod_parameter.py +54 -33
  37. classiq/qmod/qmod_struct.py +2 -2
  38. classiq/qmod/qmod_variable.py +40 -29
  39. classiq/qmod/quantum_callable.py +7 -4
  40. classiq/qmod/quantum_expandable.py +19 -13
  41. classiq/qmod/quantum_function.py +25 -2
  42. classiq/qmod/symbolic.py +78 -68
  43. classiq/qmod/symbolic_expr.py +1 -1
  44. classiq/qmod/symbolic_type.py +1 -4
  45. classiq/qmod/utilities.py +29 -0
  46. {classiq-0.39.0.dist-info → classiq-0.40.0.dist-info}/METADATA +1 -1
  47. {classiq-0.39.0.dist-info → classiq-0.40.0.dist-info}/RECORD +48 -50
  48. classiq/interface/executor/error_mitigation.py +0 -6
  49. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  50. classiq/interface/model/quantum_if_operation.py +0 -94
  51. {classiq-0.39.0.dist-info → classiq-0.40.0.dist-info}/WHEEL +0 -0
@@ -14,6 +14,10 @@ from classiq.interface.generator.expressions.enums.pauli import Pauli as PauliEn
14
14
  from classiq.interface.generator.expressions.expression_types import RuntimeExpression
15
15
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
16
16
 
17
+ CLASSICAL_ATTRIBUTES = {
18
+ "len": len,
19
+ }
20
+
17
21
  NamedSymbol = Union[IndexedBase, Symbol]
18
22
 
19
23
 
@@ -29,9 +33,9 @@ class ClassicalType(HashableASTNode):
29
33
  )
30
34
 
31
35
  @property
32
- def python_type(self) -> type:
36
+ def qmod_type(self) -> type:
33
37
  raise NotImplementedError(
34
- f"{self.__class__.__name__!r} has no Python SDK equivalent"
38
+ f"{self.__class__.__name__!r} has no QMOD SDK equivalent"
35
39
  )
36
40
 
37
41
  class Config:
@@ -53,8 +57,10 @@ class Integer(ClassicalType):
53
57
  return values_with_discriminator(values, "kind", "int")
54
58
 
55
59
  @property
56
- def python_type(self) -> type:
57
- return int
60
+ def qmod_type(self) -> type:
61
+ from classiq.qmod.qmod_parameter import CInt
62
+
63
+ return CInt
58
64
 
59
65
 
60
66
  class Real(ClassicalType):
@@ -72,8 +78,10 @@ class Real(ClassicalType):
72
78
  return values_with_discriminator(values, "kind", "real")
73
79
 
74
80
  @property
75
- def python_type(self) -> type:
76
- return float
81
+ def qmod_type(self) -> type:
82
+ from classiq.qmod.qmod_parameter import CReal
83
+
84
+ return CReal
77
85
 
78
86
 
79
87
  class Bool(ClassicalType):
@@ -88,8 +96,10 @@ class Bool(ClassicalType):
88
96
  return values_with_discriminator(values, "kind", "bool")
89
97
 
90
98
  @property
91
- def python_type(self) -> type:
92
- return bool
99
+ def qmod_type(self) -> type:
100
+ from classiq.qmod.qmod_parameter import CBool
101
+
102
+ return CBool
93
103
 
94
104
 
95
105
  class ClassicalList(ClassicalType):
@@ -108,8 +118,10 @@ class ClassicalList(ClassicalType):
108
118
  return values_with_discriminator(values, "kind", "list")
109
119
 
110
120
  @property
111
- def python_type(self) -> type:
112
- return List[self.element_type.python_type] # type:ignore[name-defined]
121
+ def qmod_type(self) -> type:
122
+ from classiq.qmod.qmod_parameter import CArray
123
+
124
+ return CArray[self.element_type.qmod_type] # type:ignore[name-defined]
113
125
 
114
126
 
115
127
  class Pauli(ClassicalType):
@@ -124,8 +136,8 @@ class Pauli(ClassicalType):
124
136
  return values_with_discriminator(values, "kind", "pauli")
125
137
 
126
138
  @property
127
- def python_type(self) -> type:
128
- return int
139
+ def qmod_type(self) -> type:
140
+ return PauliEnum
129
141
 
130
142
 
131
143
  class StructMetaType(ClassicalType):
@@ -140,7 +152,7 @@ class StructMetaType(ClassicalType):
140
152
  return values_with_discriminator(values, "kind", "type_proxy")
141
153
 
142
154
 
143
- class QStructBase: # marker for Qmod structs in the Python SDK
155
+ class CStructBase: # marker for Qmod structs in the Python SDK
144
156
  pass
145
157
 
146
158
 
@@ -157,8 +169,8 @@ class Struct(ClassicalType):
157
169
  return values_with_discriminator(values, "kind", "struct_instance")
158
170
 
159
171
  @property
160
- def python_type(self) -> type:
161
- return type(self.name, (QStructBase,), dict())
172
+ def qmod_type(self) -> type:
173
+ return type(self.name, (CStructBase,), dict())
162
174
 
163
175
 
164
176
  class ClassicalArray(ClassicalType):
@@ -228,8 +240,8 @@ class LadderOperator(ClassicalType):
228
240
  return values_with_discriminator(values, "kind", "ladder_operator")
229
241
 
230
242
  @property
231
- def python_type(self) -> type:
232
- return int
243
+ def qmod_type(self) -> type:
244
+ return LadderOperatorEnum
233
245
 
234
246
 
235
247
  ConcreteClassicalType = Annotated[
@@ -11,7 +11,9 @@ from classiq.interface.backend.quantum_backend_providers import (
11
11
  AllBackendsNameByVendor,
12
12
  ProviderVendor,
13
13
  )
14
- from classiq.interface.generator.arith.number_utils import MAXIMAL_MACHINE_PRECISION
14
+ from classiq.interface.generator.arith.machine_precision import (
15
+ DEFAULT_MACHINE_PRECISION,
16
+ )
15
17
  from classiq.interface.generator.hardware.hardware_data import (
16
18
  BACKEND_VALIDATION_ERROR_MESSAGE,
17
19
  CustomHardwareSettings,
@@ -78,7 +80,7 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
78
80
  _backend_preferences: Optional[BackendPreferences] = pydantic.PrivateAttr(
79
81
  default=None
80
82
  )
81
- machine_precision: PydanticMachinePrecision = MAXIMAL_MACHINE_PRECISION
83
+ machine_precision: PydanticMachinePrecision = DEFAULT_MACHINE_PRECISION
82
84
 
83
85
  backend_service_provider: Optional[Union[Provider, ProviderVendor, str]] = (
84
86
  pydantic.Field(
@@ -1,16 +1,112 @@
1
- from typing import TYPE_CHECKING, Union
1
+ from typing import TYPE_CHECKING, Optional
2
2
 
3
- from classiq.interface.model.handle_binding import (
4
- HandleBinding,
5
- SlicedHandleBinding,
6
- SubscriptHandleBinding,
3
+ import pydantic
4
+ from sympy import Equality
5
+ from sympy.core.numbers import Integer
6
+
7
+ from classiq.interface.generator.expressions.expression import Expression
8
+ from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
9
+ QmodQNumProxy,
10
+ QmodSizedProxy,
11
+ )
12
+ from classiq.interface.model.quantum_expressions.control_state import (
13
+ min_bit_length,
14
+ to_twos_complement,
7
15
  )
8
- from classiq.interface.model.quantum_statement import QuantumOperation
16
+ from classiq.interface.model.quantum_expressions.quantum_expression import (
17
+ QuantumExpressionOperation,
18
+ )
19
+
20
+ from classiq.exceptions import ClassiqValueError
9
21
 
10
22
  if TYPE_CHECKING:
11
23
  from classiq.interface.model.statement_block import StatementBlock
12
24
 
25
+ CONTROL_INOUT_NAME = "ctrl"
26
+ CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT = (
27
+ "control condition must be of the form '<quantum-variable> == "
28
+ "<classical-integer-expression>', but condition's {}-hand side was {!r}"
29
+ )
30
+
13
31
 
14
- class Control(QuantumOperation):
15
- control: Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
32
+ class Control(QuantumExpressionOperation):
16
33
  body: "StatementBlock"
34
+ _ctrl: Optional[QmodSizedProxy] = pydantic.PrivateAttr(
35
+ default=None,
36
+ )
37
+ _ctrl_val: Optional[int] = pydantic.PrivateAttr(
38
+ default=None,
39
+ )
40
+
41
+ @property
42
+ def condition(self) -> Expression:
43
+ return self.expression
44
+
45
+ @property
46
+ def ctrl(self) -> QmodSizedProxy:
47
+ assert self._ctrl is not None
48
+ return self._ctrl
49
+
50
+ @property
51
+ def ctrl_val(self) -> int:
52
+ assert self._ctrl_val is not None
53
+ return self._ctrl_val
54
+
55
+ def resolve_condition(self) -> None:
56
+ condition = self.condition.value.value
57
+ if isinstance(condition, QmodSizedProxy):
58
+ self._resolve_port_condition(condition)
59
+ elif isinstance(condition, Equality):
60
+ self._resolve_num_condition(condition)
61
+ else:
62
+ raise ClassiqValueError(
63
+ f"control condition must be a qubit, an array of qubits, or a quantum "
64
+ f"numeric equality, was {str(condition)!r}"
65
+ )
66
+
67
+ def _resolve_port_condition(self, condition: QmodSizedProxy) -> None:
68
+ self._ctrl = condition
69
+
70
+ def _resolve_num_condition(self, condition: Equality) -> None:
71
+ ctrl, ctrl_val = condition.args
72
+ if isinstance(ctrl, Integer) and isinstance(ctrl_val, QmodQNumProxy):
73
+ ctrl, ctrl_val = ctrl_val, ctrl
74
+ if not isinstance(ctrl, QmodQNumProxy):
75
+ raise ClassiqValueError(
76
+ CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT.format("left", str(ctrl))
77
+ )
78
+ if not isinstance(ctrl_val, Integer):
79
+ raise ClassiqValueError(
80
+ CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT.format("right", str(ctrl_val))
81
+ )
82
+ self._ctrl, self._ctrl_val = ctrl, int(ctrl_val)
83
+
84
+ @property
85
+ def has_ctrl_state(self) -> bool:
86
+ assert self._ctrl is not None
87
+ return self._ctrl_val is not None
88
+
89
+ @property
90
+ def ctrl_state(self) -> str:
91
+ ctrl = self.ctrl
92
+ assert isinstance(ctrl, QmodQNumProxy)
93
+ is_signed = ctrl.is_signed
94
+ fraction_places = ctrl.fraction_digits
95
+ ctrl_size = len(ctrl)
96
+ if not is_signed and self.ctrl_val < 0:
97
+ raise ClassiqValueError(
98
+ f"Variable {str(ctrl)!r} is not signed but control value "
99
+ f"{self.ctrl_val} is negative"
100
+ )
101
+ required_qubits = min_bit_length(self.ctrl_val, is_signed)
102
+ if ctrl_size < required_qubits:
103
+ raise ClassiqValueError(
104
+ f"Variable {str(ctrl)!r} has {ctrl_size} qubits but control value "
105
+ f"{str(self.ctrl_val)!r} requires at least {required_qubits} qubits"
106
+ )
107
+ if fraction_places != 0:
108
+ raise ClassiqValueError(
109
+ f"Comparison (`==`) on a non-integer quantum variable {str(ctrl)!r} is "
110
+ f"not supported at the moment"
111
+ )
112
+ return to_twos_complement(self.ctrl_val, ctrl_size, is_signed)
@@ -10,6 +10,7 @@ from classiq.interface.generator.arith.register_user_input import (
10
10
  RegisterUserInput,
11
11
  )
12
12
  from classiq.interface.generator.expressions.expression import Expression
13
+ from classiq.interface.generator.expressions.qmod_qarray_proxy import QmodQArrayProxy
13
14
  from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
14
15
  QmodQNumProxy,
15
16
  QmodQScalarProxy,
@@ -65,12 +66,9 @@ class QuantumBit(QuantumScalar):
65
66
  return values_with_discriminator(values, "kind", "qbit")
66
67
 
67
68
 
68
- class QuantumArray(QuantumType):
69
- length: Optional[Expression]
70
-
71
-
72
- class QuantumBitvector(QuantumArray):
69
+ class QuantumBitvector(QuantumType):
73
70
  kind: Literal["qvec"]
71
+ length: Optional[Expression]
74
72
 
75
73
  @pydantic.root_validator(pre=True)
76
74
  def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@@ -80,6 +78,9 @@ class QuantumBitvector(QuantumArray):
80
78
  if self.length is not None and self.length.is_evaluated():
81
79
  self._size_in_bits = self.length.to_int_value()
82
80
 
81
+ def get_proxy(self, name: str) -> QmodQArrayProxy:
82
+ return QmodQArrayProxy(name, self.size_in_bits)
83
+
83
84
 
84
85
  class QuantumNumeric(QuantumScalar):
85
86
  kind: Literal["qnum"]
@@ -9,7 +9,6 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
9
9
  from classiq.interface.model.quantum_function_declaration import (
10
10
  QuantumFunctionDeclaration,
11
11
  )
12
- from classiq.interface.model.quantum_if_operation import QuantumIf
13
12
  from classiq.interface.model.repeat import Repeat
14
13
  from classiq.interface.model.within_apply_operation import WithinApply
15
14
 
@@ -33,10 +32,6 @@ class FunctionCallResolver(Visitor):
33
32
  for fc in control.body:
34
33
  self.visit(fc)
35
34
 
36
- def visit_QuantumIf(self, quantum_if: QuantumIf) -> None:
37
- for fc in quantum_if.then:
38
- self.visit(fc)
39
-
40
35
  def visit_WithinApply(self, within_apply: WithinApply) -> None:
41
36
  for fc in itertools.chain(within_apply.compute, within_apply.action):
42
37
  self.visit(fc)
@@ -13,7 +13,6 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
13
13
  ArithmeticOperation,
14
14
  )
15
15
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
16
- from classiq.interface.model.quantum_if_operation import QuantumIf
17
16
  from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
18
17
  from classiq.interface.model.repeat import Repeat
19
18
  from classiq.interface.model.variable_declaration_statement import (
@@ -28,19 +27,17 @@ ConcreteQuantumStatement = Union[
28
27
  VariableDeclarationStatement,
29
28
  BindOperation,
30
29
  InplaceBinaryOperation,
31
- Control,
32
30
  Repeat,
33
31
  Power,
34
32
  Invert,
35
33
  ClassicalIf,
36
- QuantumIf,
34
+ Control,
37
35
  WithinApply,
38
36
  ]
39
37
 
40
38
  StatementBlock = List[ConcreteQuantumStatement]
41
39
 
42
40
  Control.update_forward_refs(StatementBlock=StatementBlock)
43
- QuantumIf.update_forward_refs(StatementBlock=StatementBlock)
44
41
  QuantumLambdaFunction.update_forward_refs(StatementBlock=StatementBlock)
45
42
  Repeat.update_forward_refs(StatementBlock=StatementBlock)
46
43
  Power.update_forward_refs(StatementBlock=StatementBlock)
classiq/qmod/__init__.py CHANGED
@@ -5,7 +5,7 @@ from .cfunc import cfunc
5
5
  from .expression_query import get_expression_numeric_attributes
6
6
  from .qfunc import qfunc
7
7
  from .qmod_constant import QConstant
8
- from .qmod_parameter import Array, QParam
8
+ from .qmod_parameter import Array, CArray, CBool, CInt, CReal, QParam
9
9
  from .qmod_struct import struct
10
10
  from .qmod_variable import Input, Output, QArray, QBit, QNum
11
11
  from .quantum_callable import QCallable, QCallableList
@@ -13,8 +13,11 @@ from .quantum_function import create_model
13
13
  from .write_qmod import write_qmod
14
14
 
15
15
  __all__ = [
16
- "QParam",
17
16
  "Array",
17
+ "CArray",
18
+ "CBool",
19
+ "CInt",
20
+ "CReal",
18
21
  "Input",
19
22
  "Output",
20
23
  "QArray",
@@ -23,6 +26,7 @@ __all__ = [
23
26
  "QCallable",
24
27
  "QCallableList",
25
28
  "QConstant",
29
+ "QParam",
26
30
  "struct",
27
31
  "qfunc",
28
32
  "cfunc",
@@ -1,69 +1,64 @@
1
1
  # This file was generated automatically - do not edit manually
2
2
 
3
- from typing import List
4
-
5
- from classiq.qmod.qmod_parameter import QParam
3
+ from classiq.qmod.qmod_parameter import CArray, CBool, CInt, CReal
6
4
  from classiq.qmod.symbolic import symbolic_function
7
5
 
8
6
  from .structs import *
9
7
 
10
8
 
11
9
  def qft_const_adder_phase(
12
- bit_index: QParam[int],
13
- value: QParam[int],
14
- reg_len: QParam[int],
15
- ) -> QParam[float]:
16
- return symbolic_function(bit_index, value, reg_len, return_type=QParam[float])
10
+ bit_index: CInt,
11
+ value: CInt,
12
+ reg_len: CInt,
13
+ ) -> CReal:
14
+ return symbolic_function(bit_index, value, reg_len, return_type=CReal)
17
15
 
18
16
 
19
17
  def molecule_problem_to_hamiltonian(
20
- problem: QParam[MoleculeProblem],
21
- ) -> QParam[List[PauliTerm]]:
22
- return symbolic_function(problem, return_type=QParam[List[PauliTerm]])
18
+ problem: MoleculeProblem,
19
+ ) -> CArray[PauliTerm]:
20
+ return symbolic_function(problem, return_type=CArray[PauliTerm])
23
21
 
24
22
 
25
23
  def fock_hamiltonian_problem_to_hamiltonian(
26
- problem: QParam[FockHamiltonianProblem],
27
- ) -> QParam[List[PauliTerm]]:
28
- return symbolic_function(problem, return_type=QParam[List[PauliTerm]])
24
+ problem: FockHamiltonianProblem,
25
+ ) -> CArray[PauliTerm]:
26
+ return symbolic_function(problem, return_type=CArray[PauliTerm])
29
27
 
30
28
 
31
29
  def grid_entangler_graph(
32
- num_qubits: QParam[int],
33
- schmidt_rank: QParam[int],
34
- grid_randomization: QParam[bool],
35
- ) -> QParam[List[List[int]]]:
30
+ num_qubits: CInt,
31
+ schmidt_rank: CInt,
32
+ grid_randomization: CBool,
33
+ ) -> CArray[CArray[CInt]]:
36
34
  return symbolic_function(
37
- num_qubits,
38
- schmidt_rank,
39
- grid_randomization,
40
- return_type=QParam[List[List[int]]],
35
+ num_qubits, schmidt_rank, grid_randomization, return_type=CArray[CArray[CInt]]
41
36
  )
42
37
 
43
38
 
44
39
  def hypercube_entangler_graph(
45
- num_qubits: QParam[int],
46
- ) -> QParam[List[List[int]]]:
47
- return symbolic_function(num_qubits, return_type=QParam[List[List[int]]])
40
+ num_qubits: CInt,
41
+ ) -> CArray[CArray[CInt]]:
42
+ return symbolic_function(num_qubits, return_type=CArray[CArray[CInt]])
48
43
 
49
44
 
50
45
  def log_normal_finance_post_process(
51
- finance_model: QParam[LogNormalModel],
52
- estimation_method: QParam[FinanceFunction],
53
- probability: QParam[float],
54
- ) -> QParam[float]:
46
+ finance_model: LogNormalModel,
47
+ estimation_method: FinanceFunction,
48
+ probability: CReal,
49
+ ) -> CReal:
55
50
  return symbolic_function(
56
- finance_model, estimation_method, probability, return_type=QParam[float]
51
+ finance_model, estimation_method, probability, return_type=CReal
57
52
  )
58
53
 
59
54
 
60
55
  def gaussian_finance_post_process(
61
- finance_model: QParam[GaussianModel],
62
- estimation_method: QParam[FinanceFunction],
63
- probability: QParam[float],
64
- ) -> QParam[float]:
56
+ finance_model: GaussianModel,
57
+ estimation_method: FinanceFunction,
58
+ probability: CReal,
59
+ ) -> CReal:
65
60
  return symbolic_function(
66
- finance_model, estimation_method, probability, return_type=QParam[float]
61
+ finance_model, estimation_method, probability, return_type=CReal
67
62
  )
68
63
 
69
64