classiq 0.43.2__py3-none-any.whl → 0.44.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 (112) hide show
  1. classiq/__init__.py +7 -1
  2. classiq/_internals/client.py +4 -7
  3. classiq/_internals/host_checker.py +34 -12
  4. classiq/_internals/jobs.py +2 -2
  5. classiq/applications/chemistry/chemistry_model_constructor.py +12 -6
  6. classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  8. classiq/applications/finance/finance_model_constructor.py +3 -2
  9. classiq/applications/grover/grover_model_constructor.py +7 -5
  10. classiq/applications/hamiltonian/__init__.py +0 -0
  11. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  12. classiq/applications/qnn/qlayer.py +1 -1
  13. classiq/exceptions.py +4 -0
  14. classiq/interface/_version.py +1 -1
  15. classiq/interface/ast_node.py +1 -18
  16. classiq/interface/backend/backend_preferences.py +15 -16
  17. classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
  18. classiq/interface/backend/pydantic_backend.py +0 -5
  19. classiq/interface/backend/quantum_backend_providers.py +3 -2
  20. classiq/interface/chemistry/operator.py +5 -1
  21. classiq/interface/debug_info/__init__.py +0 -0
  22. classiq/interface/debug_info/debug_info.py +32 -0
  23. classiq/interface/executor/execution_preferences.py +1 -45
  24. classiq/interface/executor/result.py +25 -12
  25. classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
  26. classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
  27. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
  28. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  29. classiq/interface/generator/application_apis/finance_declarations.py +36 -22
  30. classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
  31. classiq/interface/generator/arith/arithmetic_expression_abc.py +21 -1
  32. classiq/interface/generator/arith/binary_ops.py +5 -4
  33. classiq/interface/generator/arith/extremum_operations.py +43 -19
  34. classiq/interface/generator/constant.py +1 -1
  35. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
  36. classiq/interface/generator/expressions/expression_constants.py +3 -1
  37. classiq/interface/generator/expressions/qmod_qarray_proxy.py +52 -66
  38. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
  39. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  40. classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
  41. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
  42. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
  43. classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
  44. classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
  45. classiq/interface/generator/functions/classical_function_declaration.py +14 -6
  46. classiq/interface/generator/functions/classical_type.py +7 -76
  47. classiq/interface/generator/functions/concrete_types.py +55 -0
  48. classiq/interface/generator/functions/function_declaration.py +10 -10
  49. classiq/interface/generator/functions/type_name.py +104 -0
  50. classiq/interface/generator/generated_circuit_data.py +3 -3
  51. classiq/interface/generator/model/model.py +11 -0
  52. classiq/interface/generator/model/preferences/preferences.py +5 -0
  53. classiq/interface/generator/quantum_function_call.py +3 -0
  54. classiq/interface/generator/quantum_program.py +2 -2
  55. classiq/interface/generator/register_role.py +7 -1
  56. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
  57. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
  58. classiq/interface/generator/types/qstruct_declaration.py +17 -0
  59. classiq/interface/generator/types/struct_declaration.py +1 -1
  60. classiq/interface/helpers/validation_helpers.py +1 -17
  61. classiq/interface/ide/visual_model.py +9 -2
  62. classiq/interface/interface_version.py +1 -0
  63. classiq/interface/model/bind_operation.py +25 -5
  64. classiq/interface/model/classical_parameter_declaration.py +8 -5
  65. classiq/interface/model/control.py +5 -5
  66. classiq/interface/model/handle_binding.py +185 -12
  67. classiq/interface/model/inplace_binary_operation.py +16 -4
  68. classiq/interface/model/model.py +28 -5
  69. classiq/interface/model/native_function_definition.py +8 -4
  70. classiq/interface/model/parameter.py +14 -0
  71. classiq/interface/model/port_declaration.py +20 -2
  72. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +21 -6
  73. classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
  74. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
  75. classiq/interface/model/quantum_function_call.py +135 -192
  76. classiq/interface/model/quantum_function_declaration.py +147 -165
  77. classiq/interface/model/quantum_lambda_function.py +24 -6
  78. classiq/interface/model/quantum_statement.py +34 -8
  79. classiq/interface/model/quantum_type.py +61 -10
  80. classiq/interface/model/quantum_variable_declaration.py +1 -1
  81. classiq/interface/model/statement_block.py +2 -0
  82. classiq/interface/model/validation_handle.py +7 -0
  83. classiq/interface/server/global_versions.py +4 -4
  84. classiq/interface/server/routes.py +2 -0
  85. classiq/interface/source_reference.py +59 -0
  86. classiq/qmod/__init__.py +2 -3
  87. classiq/qmod/builtins/functions.py +39 -11
  88. classiq/qmod/builtins/operations.py +171 -40
  89. classiq/qmod/declaration_inferrer.py +99 -56
  90. classiq/qmod/expression_query.py +1 -1
  91. classiq/qmod/model_state_container.py +2 -0
  92. classiq/qmod/native/pretty_printer.py +71 -53
  93. classiq/qmod/pretty_print/pretty_printer.py +98 -52
  94. classiq/qmod/qfunc.py +11 -5
  95. classiq/qmod/qmod_parameter.py +1 -2
  96. classiq/qmod/qmod_variable.py +364 -172
  97. classiq/qmod/quantum_callable.py +3 -3
  98. classiq/qmod/quantum_expandable.py +119 -65
  99. classiq/qmod/quantum_function.py +15 -3
  100. classiq/qmod/semantics/annotation.py +12 -13
  101. classiq/qmod/semantics/error_manager.py +36 -10
  102. classiq/qmod/semantics/static_semantics_visitor.py +163 -75
  103. classiq/qmod/semantics/validation/func_call_validation.py +42 -96
  104. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  105. classiq/qmod/semantics/validation/types_validation.py +108 -1
  106. classiq/qmod/type_attribute_remover.py +32 -0
  107. classiq/qmod/utilities.py +26 -5
  108. {classiq-0.43.2.dist-info → classiq-0.44.0.dist-info}/METADATA +3 -3
  109. {classiq-0.43.2.dist-info → classiq-0.44.0.dist-info}/RECORD +111 -99
  110. classiq/qmod/qmod_struct.py +0 -13
  111. /classiq/{interface/ide/show.py → show.py} +0 -0
  112. {classiq-0.43.2.dist-info → classiq-0.44.0.dist-info}/WHEEL +0 -0
classiq/__init__.py CHANGED
@@ -14,7 +14,6 @@ from classiq.interface.generator.model import * # noqa: F403
14
14
  from classiq.interface.generator.model import __all__ as _md_all
15
15
  from classiq.interface.generator.quantum_program import QuantumProgram
16
16
  from classiq.interface.generator.types.builtin_enum_declarations import * # noqa: F403
17
- from classiq.interface.ide.show import show
18
17
 
19
18
  from classiq import applications, exceptions, execution, synthesis
20
19
  from classiq._internals import logger
@@ -38,6 +37,10 @@ from classiq.applications.combinatorial_optimization import (
38
37
  )
39
38
  from classiq.applications.finance import construct_finance_model
40
39
  from classiq.applications.grover import construct_grover_model
40
+ from classiq.applications.hamiltonian.pauli_decomposition import (
41
+ hamiltonian_to_matrix,
42
+ matrix_to_hamiltonian,
43
+ )
41
44
  from classiq.applications.qsvm import construct_qsvm_model
42
45
  from classiq.executor import (
43
46
  execute,
@@ -46,6 +49,7 @@ from classiq.executor import (
46
49
  )
47
50
  from classiq.qmod import * # noqa: F403
48
51
  from classiq.qmod import __all__ as _qmod_all
52
+ from classiq.show import show
49
53
  from classiq.synthesis import (
50
54
  set_constraints,
51
55
  set_execution_preferences,
@@ -95,6 +99,8 @@ __all__ = (
95
99
  "set_execution_preferences",
96
100
  "set_quantum_program_execution_preferences",
97
101
  "show",
102
+ "hamiltonian_to_matrix",
103
+ "matrix_to_hamiltonian",
98
104
  ]
99
105
  + _md_all
100
106
  + _sub_modules
@@ -19,10 +19,10 @@ from typing import (
19
19
  )
20
20
 
21
21
  import httpx
22
- from packaging.version import Version
23
22
  from typing_extensions import ParamSpec
24
23
 
25
24
  from classiq.interface._version import VERSION as _VERSION
25
+ from classiq.interface.interface_version import INTERFACE_VERSION
26
26
 
27
27
  from classiq._internals import config
28
28
  from classiq._internals.authentication import token_manager
@@ -161,12 +161,9 @@ class Client:
161
161
  self._api_prefix = self._make_api_prefix()
162
162
  self._session_id: Optional[str] = None
163
163
 
164
- @classmethod
165
- def _make_api_prefix(cls) -> str:
166
- if _VERSION == cls._UNKNOWN_VERSION:
167
- return cls._LATEST_VERSION_API_PREFIX
168
- parsed_version = Version(_VERSION)
169
- return f"/api/v{parsed_version.major}-{parsed_version.minor}"
164
+ @staticmethod
165
+ def _make_api_prefix() -> str:
166
+ return f"/api/v{INTERFACE_VERSION}"
170
167
 
171
168
  def make_versioned_url(self, url_postfix: str) -> str:
172
169
  return self._api_prefix + url_postfix
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import warnings
5
+ from datetime import datetime
4
6
  from typing import TYPE_CHECKING, Optional
5
7
 
6
8
  import httpx
@@ -8,9 +10,10 @@ import pydantic
8
10
  from packaging.version import Version
9
11
  from pydantic import BaseModel
10
12
 
13
+ from classiq.interface.interface_version import INTERFACE_VERSION
11
14
  from classiq.interface.server.global_versions import DeprecationInfo, GlobalVersions
12
15
 
13
- from classiq.exceptions import ClassiqAPIError
16
+ from classiq.exceptions import ClassiqAPIError, ClassiqDeprecationWarning
14
17
 
15
18
  if TYPE_CHECKING:
16
19
  from classiq._internals.client import Client
@@ -26,9 +29,23 @@ class HostVersions(BaseModel):
26
29
  class HostChecker:
27
30
  _UNKNOWN_VERSION = "0.0.0"
28
31
 
29
- def __init__(self, client: Client, client_version: str) -> None:
32
+ def __init__(
33
+ self,
34
+ client: Client,
35
+ client_version: str,
36
+ interface_version: str = INTERFACE_VERSION,
37
+ ) -> None:
30
38
  self._client = client
31
39
  self._client_version = client_version
40
+ self._interface_version = interface_version
41
+
42
+ def _get_interface_version(self) -> Optional[str]:
43
+ global_interfaces = GlobalVersions.parse_obj(
44
+ self._client.sync_call_api(
45
+ "get", "/interface_versions", use_versioned_url=False
46
+ )
47
+ )
48
+ return global_interfaces.deployed.get(self._interface_version, None)
32
49
 
33
50
  def _get_host_version(self) -> str:
34
51
  host = HostVersions.parse_obj(self._client.sync_call_api("get", "/versions"))
@@ -56,18 +73,16 @@ class HostChecker:
56
73
 
57
74
  def check_host_version(self) -> None:
58
75
  try:
59
- raw_host_version = self._get_host_version()
76
+ interface_version = self._get_interface_version()
60
77
  except httpx.ConnectError:
61
78
  _logger.warning(
62
79
  "Version check failed - host unavailable.",
63
80
  )
64
81
  else:
65
- if not self._check_matching_versions(
66
- raw_host_version, self._client_version
67
- ):
82
+ if interface_version is None:
68
83
  raise ClassiqAPIError(
69
- f"Classiq API version mismatch: 'classiq' version is "
70
- f"{self._client_version}, backend version is {raw_host_version}. {_VERSION_UPDATE_SUGGESTION}"
84
+ f"You are using an unsupported version of Classiq SDK - {self._client_version}. "
85
+ f"{_VERSION_UPDATE_SUGGESTION}"
71
86
  )
72
87
 
73
88
  def check_deprecated_version(self) -> None:
@@ -80,8 +95,15 @@ class HostChecker:
80
95
  else:
81
96
  if deprecation_info is None:
82
97
  return
83
- _logger.warning(
84
- "The current version of 'classiq' has been deprecated, and will not be supported as of %s. %s",
85
- deprecation_info.removal_date.date(),
86
- _VERSION_UPDATE_SUGGESTION,
98
+ removal_date = (
99
+ deprecation_info.removal_date.date()
100
+ if isinstance(deprecation_info.removal_date, datetime)
101
+ else deprecation_info.removal_date
102
+ )
103
+ warnings.warn(
104
+ f"The current version of 'classiq' has been deprecated, and"
105
+ f" will not be supported as of {removal_date}. "
106
+ f"{_VERSION_UPDATE_SUGGESTION}",
107
+ ClassiqDeprecationWarning,
108
+ stacklevel=2,
87
109
  )
@@ -169,7 +169,7 @@ class JobPoller:
169
169
  self, model: pydantic.BaseModel, timeout_sec: Optional[float]
170
170
  ) -> GeneralJobDescription:
171
171
  # TODO: we can't use model.dict() - it doesn't serialize complex class.
172
- # This was added because JSON serializer doesn't serialize complex type, and pydantic does.
173
- # We should add support for smarter json serialization.
172
+ # This was added because JSON serializer doesn't serialize complex and UUID,
173
+ # while pydantic does. We should add support for smarter json serialization.
174
174
  body = json.loads(model.json())
175
175
  return await self.run(body, timeout_sec)
@@ -154,7 +154,6 @@ _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
154
154
  ),
155
155
  "crx": QuantumFunctionCall(
156
156
  function="CRX",
157
- designated_params={"theta": Expression(expr="angle")},
158
157
  positional_args=[
159
158
  Expression(expr="angle"),
160
159
  HandleBinding(name="q1"),
@@ -325,11 +324,17 @@ def _get_hea_function(hea_parameters: HEAParameters) -> QuantumFunctionCall:
325
324
  ),
326
325
  Expression(expr=f"{hea_parameters.reps}"),
327
326
  [
328
- QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
327
+ QuantumLambdaFunction(
328
+ pos_rename_params=["angle", "q"],
329
+ body=[_HAE_GATE_MAPPING[gate]],
330
+ )
329
331
  for gate in hea_parameters.one_qubit_gates
330
332
  ],
331
333
  [
332
- QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
334
+ QuantumLambdaFunction(
335
+ pos_rename_params=["angle", "q1", "q2"],
336
+ body=[_HAE_GATE_MAPPING[gate]],
337
+ )
333
338
  for gate in hea_parameters.two_qubit_gates
334
339
  ],
335
340
  HandleBinding(name="qbv"),
@@ -378,9 +383,10 @@ save({{{_MOLECULE_PROBLEM_RESULT!r}: {_MOLECULE_PROBLEM_RESULT}}})
378
383
 
379
384
 
380
385
  def _is_parametric_gate(call: QuantumFunctionCall) -> bool:
381
- return len(call.designated_params) > 0 or any(
382
- isinstance(arg, Expression) for arg in call.positional_args
383
- )
386
+ # FIXME: call call.params instead (CAD-21568)
387
+ return any(
388
+ arg for arg in call.positional_args if isinstance(arg, Expression)
389
+ ) or any(isinstance(arg, Expression) for arg in call.positional_args)
384
390
 
385
391
 
386
392
  def _get_execution_result_post_processing_statements(
@@ -15,6 +15,9 @@ def is_constraint_sum_less_than_one(
15
15
  isinstance(expression, LessThan)
16
16
  and isinstance(expression.args[0], Add)
17
17
  and all(isinstance(arg, Symbol) for arg in expression.args[0].args)
18
- and expression.args[1] == _INEQUALITY_UPPER_LIMIT
18
+ and (
19
+ expression.args[1] == _INEQUALITY_UPPER_LIMIT
20
+ or expression.args[1] == float(_INEQUALITY_UPPER_LIMIT)
21
+ )
19
22
  and encoding_type is None
20
23
  )
@@ -9,7 +9,6 @@ from classiq.interface.generator.functions.classical_type import (
9
9
  ClassicalArray,
10
10
  ClassicalList,
11
11
  Real,
12
- Struct,
13
12
  )
14
13
  from classiq.interface.generator.functions.port_declaration import (
15
14
  PortDeclarationDirection,
@@ -24,6 +23,7 @@ from classiq.interface.model.port_declaration import PortDeclaration
24
23
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
25
24
  from classiq.interface.model.quantum_type import QuantumBitvector
26
25
 
26
+ from classiq import Struct
27
27
  from classiq.applications.combinatorial_helpers.combinatorial_problem_utils import (
28
28
  compute_qaoa_initial_point,
29
29
  convert_pyomo_to_global_presentation,
@@ -96,14 +96,15 @@ def construct_finance_model(
96
96
  function="qmci",
97
97
  positional_args=[
98
98
  QuantumLambdaFunction(
99
+ pos_rename_params=["state", "ind"],
99
100
  body=[
100
101
  QuantumFunctionCall(
101
102
  function=finance_function,
102
103
  positional_args=[
103
104
  Expression(expr=finance_model),
104
105
  Expression(expr=finance_function_object),
105
- HandleBinding(name="arg0"),
106
- HandleBinding(name="arg1"),
106
+ HandleBinding(name="state"),
107
+ HandleBinding(name="ind"),
107
108
  ],
108
109
  ),
109
110
  ],
@@ -34,7 +34,7 @@ def _arithmetic_oracle_ios(
34
34
  for _, reg in definitions:
35
35
  ios.append(
36
36
  SlicedHandleBinding(
37
- name=handle_name,
37
+ base_handle=HandleBinding(name=handle_name),
38
38
  start=Expression(expr=f"{cursor}"),
39
39
  end=Expression(expr=f"{cursor + reg.size}"),
40
40
  )
@@ -47,12 +47,13 @@ def _construct_arithmetic_oracle(
47
47
  predicate_function: str,
48
48
  definitions: List[Tuple[str, RegisterUserInput]],
49
49
  ) -> QuantumFunctionCall:
50
- predicate_var_binding = _arithmetic_oracle_ios(definitions, "arg0")
51
- predicate_var_binding.append(HandleBinding(name="arg1"))
50
+ predicate_var_binding = _arithmetic_oracle_ios(definitions, "state")
51
+ predicate_var_binding.append(HandleBinding(name="oracle"))
52
52
  return QuantumFunctionCall(
53
53
  function="phase_oracle",
54
54
  positional_args=[
55
55
  QuantumLambdaFunction(
56
+ pos_rename_params=["state", "oracle"],
56
57
  body=[
57
58
  QuantumFunctionCall(
58
59
  function=predicate_function,
@@ -60,7 +61,7 @@ def _construct_arithmetic_oracle(
60
61
  ),
61
62
  ],
62
63
  ),
63
- HandleBinding(name="arg0"),
64
+ HandleBinding(name="packed_vars"),
64
65
  ],
65
66
  )
66
67
 
@@ -132,12 +133,13 @@ def construct_grover_model(
132
133
  positional_args=[
133
134
  Expression(expr=f"{num_reps}"),
134
135
  QuantumLambdaFunction(
136
+ pos_rename_params=["packed_vars"],
135
137
  body=[
136
138
  _construct_arithmetic_oracle(
137
139
  _PREDICATE_FUNCTION_NAME,
138
140
  definitions,
139
141
  )
140
- ]
142
+ ],
141
143
  ),
142
144
  HandleBinding(name="packed_vars"),
143
145
  ],
File without changes
@@ -0,0 +1,113 @@
1
+ from typing import List, Tuple, Union
2
+
3
+ import numpy as np
4
+ from sympy import fwht
5
+
6
+ from classiq.qmod import ( # type:ignore[attr-defined]
7
+ Pauli,
8
+ PauliTerm,
9
+ )
10
+
11
+ ATOL = 1e-12
12
+ PAULI_MATRICES_DICT = {
13
+ Pauli.I: np.array([[1, 0], [0, 1]], dtype=np.complex128),
14
+ Pauli.Z: np.array([[1, 0], [0, -1]], dtype=np.complex128),
15
+ Pauli.X: np.array([[0, 1], [1, 0]], dtype=np.complex128),
16
+ Pauli.Y: np.array([[0, -1j], [1j, 0]], dtype=np.complex128),
17
+ }
18
+
19
+
20
+ def _get_pauli_string(set_index: int, term_index: int, num_qubits: int) -> List[Pauli]:
21
+ """
22
+ The basis of 4^N Pauli strings on N qubits can be partitioned to 2^N sets, each contains 2^N Pauli strings.
23
+ In the k-th set we have Pauli strings of the form s_1s_2...s_N, where s_j is in {I,Z} if k_j is 0,
24
+ and in {X,iY} if k_j=1. The function get_pauli_string returns the m-th Pauli string in the k-th set of Pauli strings
25
+ """
26
+
27
+ # returns the Pauli (I,Z) or (iY, X) appearing in the pauli_index position for a given set
28
+ def _get_paulis_for_set(set_index: int, pauli_index: int) -> Tuple[Pauli, Pauli]:
29
+ if (set_index >> pauli_index) & 1:
30
+ return Pauli.Y, Pauli.X
31
+ else:
32
+ return Pauli.Z, Pauli.I
33
+
34
+ return [
35
+ (
36
+ _get_paulis_for_set(set_index, s)[0]
37
+ if (term_index >> s) & 1
38
+ else _get_paulis_for_set(set_index, s)[1]
39
+ )
40
+ for s in range(num_qubits)
41
+ ][::-1]
42
+
43
+
44
+ def _coefficents_for_set(mat: np.ndarray, set_index: int) -> list:
45
+ """
46
+ The 2^N coefficients in a 2^N x 2^N matrix that are decomposed to the elements
47
+ in the k-th set are the indices [i,j] such that i^j=k
48
+ The function coefficents_for_set returns the matrix entries that are decomposed to the same Pauli strigs set
49
+ """
50
+ return [mat[k, k ^ set_index] / len(mat) for k in range(len(mat))]
51
+
52
+
53
+ def _get_signed_coefficient(
54
+ c: complex, k: int, i: int, is_hermitian: bool
55
+ ) -> Union[complex, float]:
56
+ # correct from iY to Y
57
+ coef = complex((1j) ** ((i & k).bit_count()) * c)
58
+ if is_hermitian:
59
+ return coef.real
60
+ else:
61
+ return coef
62
+
63
+
64
+ def matrix_to_hamiltonian(
65
+ mat: np.ndarray, tol: float = ATOL, is_hermitian: bool = True
66
+ ) -> List[PauliTerm]:
67
+ """
68
+ The decomposition per set is done by the Walsh-Hadamard transform,
69
+ since the transformation between {e_0,e_3} ({e_1,e_2}) to {I,Z} ({X,iY}) is the Hadamard matrix.
70
+ """
71
+ mat.shape[0] != 0, "matrix is of size 0"
72
+ if is_hermitian:
73
+ assert np.allclose(
74
+ mat, np.conjugate(mat.T)
75
+ ), "Matrix is not hermitian, please pass is_hermitian=False"
76
+ assert mat.shape[0] == mat.shape[1], "Matrix is not square"
77
+ mat_dimension = mat.shape[0]
78
+ assert mat_dimension.bit_count() == 1, "Matrix dimension is not a power of 2"
79
+ num_qubits = (mat_dimension - 1).bit_length()
80
+ hamiltonian = []
81
+ for k in range(2**num_qubits):
82
+ coef = fwht(
83
+ _coefficents_for_set(mat, k)
84
+ ) # the transformation per set is given by the Walsh-Hadamard transform
85
+ hamiltonian += [
86
+ PauliTerm(
87
+ pauli=_get_pauli_string(k, i, num_qubits),
88
+ coefficient=_get_signed_coefficient(coef[i], k, i, is_hermitian),
89
+ )
90
+ for i in range(2**num_qubits)
91
+ if abs(coef[i]) > tol
92
+ ]
93
+ return hamiltonian
94
+
95
+
96
+ # convert a single puali string of length N to 2**N X 2**N matrix
97
+ def pauli_string_to_mat(seq: List[Pauli]) -> np.ndarray:
98
+ real_matrix = PAULI_MATRICES_DICT[seq[0]]
99
+ for p in seq[1:]:
100
+ real_matrix = np.kron(real_matrix, PAULI_MATRICES_DICT[p])
101
+ return real_matrix
102
+
103
+
104
+ # return matrix from hamiltonian
105
+ def hamiltonian_to_matrix(hamiltonian: List[PauliTerm]) -> np.ndarray:
106
+ matrix = np.zeros(
107
+ [2 ** len(hamiltonian[0].pauli), 2 ** len(hamiltonian[0].pauli)],
108
+ dtype=np.complex_,
109
+ )
110
+ for p in hamiltonian:
111
+ matrix += p.coefficient * pauli_string_to_mat(p.pauli)
112
+
113
+ return matrix
@@ -181,6 +181,6 @@ class QLayer(nn.Module):
181
181
  self.weight = Parameter(value)
182
182
 
183
183
  def forward(self, x: Tensor) -> Tensor:
184
- return QLayerFunction.apply( # type: ignore[no-untyped-call]
184
+ return QLayerFunction.apply(
185
185
  x, self.weight, self.quantum_program, self._execute, self._post_process
186
186
  )
classiq/exceptions.py CHANGED
@@ -176,3 +176,7 @@ class ClassiqExecutorInvalidHamiltonianError(ClassiqCombOptError):
176
176
 
177
177
  class ClassiqSemanticError(ClassiqError):
178
178
  pass
179
+
180
+
181
+ class ClassiqDeprecationWarning(FutureWarning):
182
+ pass
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.43.2'
6
+ SEMVER_VERSION = '0.44.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -1,4 +1,3 @@
1
- import os
2
1
  from typing import Optional
3
2
 
4
3
  import pydantic
@@ -6,23 +5,7 @@ import pydantic
6
5
  from classiq.interface.helpers.hashable_pydantic_base_model import (
7
6
  HashablePydanticBaseModel,
8
7
  )
9
-
10
-
11
- class SourceReference(HashablePydanticBaseModel):
12
- start_line: int
13
- start_column: int
14
- end_line: int
15
- end_column: int
16
- file_name: Optional[str] = pydantic.Field(default=None)
17
-
18
- def __str__(self) -> str:
19
- file_string = (
20
- f"file {os.path.basename(self.file_name)} " if self.file_name else ""
21
- )
22
- start_character_string = (
23
- f" character {self.start_column + 1}" if self.start_column > 0 else ""
24
- )
25
- return f"{file_string}line {self.start_line + 1}{start_character_string}"
8
+ from classiq.interface.source_reference import SourceReference
26
9
 
27
10
 
28
11
  class ASTNode(HashablePydanticBaseModel):
@@ -1,10 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
- from datetime import timedelta
4
3
  from typing import Any, Dict, Iterable, List, Optional, Union
5
4
 
6
5
  import pydantic
7
- from pydantic import BaseModel, PrivateAttr, validator
6
+ from pydantic import BaseModel, validator
8
7
 
9
8
  from classiq.interface.backend import pydantic_backend
10
9
  from classiq.interface.backend.quantum_backend_providers import (
@@ -56,9 +55,6 @@ class BackendPreferences(BaseModel):
56
55
  return False
57
56
 
58
57
 
59
- AWS_DEFAULT_JOB_TIMEOUT_SECONDS = int(timedelta(minutes=240).total_seconds())
60
-
61
-
62
58
  class AliceBobBackendPreferences(BackendPreferences):
63
59
  backend_service_provider: ProviderTypeVendor.ALICE_BOB
64
60
  distance: Optional[int] = pydantic.Field(
@@ -76,7 +72,6 @@ class AliceBobBackendPreferences(BackendPreferences):
76
72
  api_key: pydantic_backend.PydanticAliceBobApiKeyType = pydantic.Field(
77
73
  ..., description="AliceBob API key"
78
74
  )
79
- _parameters: Dict[str, Any] = PrivateAttr(default_factory=dict)
80
75
 
81
76
  @pydantic.root_validator(pre=True)
82
77
  def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@@ -86,14 +81,13 @@ class AliceBobBackendPreferences(BackendPreferences):
86
81
 
87
82
  @property
88
83
  def parameters(self) -> Dict[str, Any]:
89
- self._parameters = {
84
+ parameters = {
90
85
  "distance": self.distance,
91
- "kappa_1": self.kappa_1,
92
- "kappa_2": self.kappa_2,
93
- "average_nb_photons": self.average_nb_photons,
86
+ "kappa1": self.kappa_1,
87
+ "kappa2": self.kappa_2,
88
+ "averageNbPhotons": self.average_nb_photons,
94
89
  }
95
- self._parameters = {k: v for k, v in self._parameters.items() if v is not None}
96
- return self._parameters
90
+ return {k: v for k, v in parameters.items() if v is not None}
97
91
 
98
92
 
99
93
  class ClassiqBackendPreferences(BackendPreferences):
@@ -118,10 +112,6 @@ class AwsBackendPreferences(BackendPreferences):
118
112
  s3_folder: pydantic_backend.PydanticS3BucketKey = pydantic.Field(
119
113
  description="S3 Folder Path Within The S3 Bucket"
120
114
  )
121
- job_timeout: pydantic_backend.PydanticExecutionTimeout = pydantic.Field(
122
- description="Timeout for Jobs sent for execution in seconds.",
123
- default=AWS_DEFAULT_JOB_TIMEOUT_SECONDS,
124
- )
125
115
 
126
116
  @validator("s3_bucket_name")
127
117
  def _validate_s3_bucket_name(
@@ -156,6 +146,10 @@ class IBMBackendPreferences(BackendPreferences):
156
146
  default_factory=IBMBackendProvider,
157
147
  description="Provider specs. for identifying a single IBM Quantum provider.",
158
148
  )
149
+ qctrl_api_key: Optional[str] = pydantic.Field(
150
+ default=None,
151
+ description="QCTRL API key to access QCTRL optimization abilities",
152
+ )
159
153
 
160
154
  @pydantic.root_validator(pre=True)
161
155
  def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@@ -191,6 +185,11 @@ class AzureBackendPreferences(BackendPreferences):
191
185
  description="The service principal credential to access personal quantum workspace",
192
186
  )
193
187
 
188
+ ionq_error_mitigation_flag: Optional[bool] = pydantic.Field(
189
+ default=False,
190
+ description="Error mitigation configuration upon running on IonQ through Azure.",
191
+ )
192
+
194
193
  @property
195
194
  def run_through_classiq(self) -> bool:
196
195
  return self.credentials is None
@@ -37,7 +37,7 @@ class IonqQuantumCircuit(BaseModel):
37
37
  circuit: List[Gate]
38
38
 
39
39
  # Ionq changes format sometimes.
40
- # One example is that `IonqQauntumCircuit` got a field name "gateset" with the value "qis"
40
+ # One example is that `IonqQuantumCircuit` got a field name "gateset" with the value "qis"
41
41
  # Another is that `Gate` got a field named "rotation"
42
42
  class Config:
43
43
  extra = pydantic.Extra.allow
@@ -1,4 +1,3 @@
1
- from datetime import timedelta
2
1
  from typing import TYPE_CHECKING
3
2
 
4
3
  import pydantic
@@ -11,12 +10,10 @@ INVALID_API_KEY: str = _IONQ_API_KEY_LENGTH * "a"
11
10
  INVALID_API_KEY_ALICE_BOB: str = _ALICE_BOB_API_KEY_LENGTH * "a"
12
11
  INVALID_EMAIL_OQC: str = "aa@aa.aa"
13
12
  INVALID_PASSWORD_OQC: str = "Aa1!Aa1!"
14
- MAX_EXECUTION_TIMEOUT_SECONDS = timedelta(hours=4).total_seconds()
15
13
 
16
14
  EXECUTION_PARAMETER_PATTERN = "[_a-z][_a-z0-9]*"
17
15
 
18
16
  if TYPE_CHECKING:
19
- PydanticExecutionTimeout = int
20
17
  PydanticAwsRoleArn = str
21
18
  PydanticS3BucketKey = str
22
19
  PydanticS3BucketName = str
@@ -42,8 +39,6 @@ else:
42
39
 
43
40
  PydanticAliceBobApiKeyType = pydantic.constr(min_length=1, strip_whitespace=True)
44
41
 
45
- PydanticExecutionTimeout = pydantic.conint(gt=0, le=MAX_EXECUTION_TIMEOUT_SECONDS)
46
-
47
42
  PydanticArgumentNameType = pydantic.constr(regex="[_a-zA-Z][_a-zA-Z0-9]*")
48
43
 
49
44
  PydanticExecutionParameter = pydantic.constr(regex=EXECUTION_PARAMETER_PATTERN)
@@ -41,8 +41,9 @@ class ClassiqSimulatorBackendNames(StrEnum):
41
41
  class IonqBackendNames(StrEnum):
42
42
  SIMULATOR = "simulator"
43
43
  HARMONY = "qpu.harmony"
44
- ARIA = "qpu.aria-1"
45
- S11 = "qpu.s11"
44
+ ARIA_1 = "qpu.aria-1"
45
+ ARIA_2 = "qpu.aria-2"
46
+ FORTE_1 = "qpu.forte-1"
46
47
 
47
48
 
48
49
  class AzureQuantumBackendNames(StrEnum):
@@ -140,8 +140,12 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
140
140
  def num_qubits(self) -> int:
141
141
  return len(self.pauli_list[0][0])
142
142
 
143
+ @property
144
+ def all_coefficients_numeric(self) -> bool:
145
+ return all(isinstance(summand[1], complex) for summand in self.pauli_list)
146
+
143
147
  def to_matrix(self) -> np.ndarray:
144
- if not all(isinstance(summand[1], complex) for summand in self.pauli_list):
148
+ if not self.all_coefficients_numeric:
145
149
  raise ClassiqValueError(
146
150
  "Supporting only Hamiltonian with numeric coefficients."
147
151
  )
File without changes
@@ -0,0 +1,32 @@
1
+ from typing import Dict, Optional, Union
2
+ from uuid import UUID
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+ from classiq.interface.ide.visual_model import OperationLevel
7
+
8
+
9
+ class FunctionDebugInfo(BaseModel):
10
+ name: str
11
+ parameters: Dict[str, Union[int, float, None]]
12
+ level: OperationLevel
13
+ is_allocate_or_free: bool = Field(default=False)
14
+
15
+
16
+ class DebugInfoCollection(BaseModel):
17
+ # Pydantic only started supporting UUID as keys in Pydantic V2
18
+ # See https://github.com/pydantic/pydantic/issues/2096#issuecomment-814860206
19
+ # For now, we use strings as keys in the raw data and use UUID in the wrapper logic
20
+ data: Dict[str, FunctionDebugInfo] = Field(default_factory=dict)
21
+
22
+ def __setitem__(self, key: UUID, value: FunctionDebugInfo) -> None:
23
+ self.data[str(key)] = value
24
+
25
+ def get(self, key: UUID) -> Optional[FunctionDebugInfo]:
26
+ return self.data.get(str(key))
27
+
28
+ def __getitem__(self, key: UUID) -> FunctionDebugInfo:
29
+ return self.data[str(key)]
30
+
31
+ def __contains__(self, key: UUID) -> bool:
32
+ return str(key) in self.data