classiq 0.71.0__py3-none-any.whl → 0.72.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 (54) hide show
  1. classiq/__init__.py +0 -6
  2. classiq/_internals/client.py +11 -1
  3. classiq/applications/chemistry/chemistry_model_constructor.py +18 -16
  4. classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
  5. classiq/applications/combinatorial_helpers/pyomo_utils.py +6 -1
  6. classiq/applications/finance/__init__.py +0 -3
  7. classiq/applications/qsvm/__init__.py +0 -2
  8. classiq/interface/_version.py +1 -1
  9. classiq/interface/backend/backend_preferences.py +22 -0
  10. classiq/interface/backend/quantum_backend_providers.py +2 -0
  11. classiq/interface/generator/expressions/expression_types.py +4 -1
  12. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +135 -0
  13. classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
  14. classiq/interface/generator/generated_circuit_data.py +13 -0
  15. classiq/interface/generator/hardware/hardware_data.py +3 -1
  16. classiq/interface/generator/transpiler_basis_gates.py +3 -1
  17. classiq/interface/hardware.py +1 -0
  18. classiq/interface/model/handle_binding.py +21 -0
  19. classiq/interface/server/routes.py +0 -2
  20. classiq/model_expansions/atomic_expression_functions_defs.py +35 -13
  21. classiq/model_expansions/closure.py +0 -9
  22. classiq/model_expansions/evaluators/parameter_types.py +6 -10
  23. classiq/model_expansions/interpreters/base_interpreter.py +4 -4
  24. classiq/model_expansions/interpreters/generative_interpreter.py +33 -5
  25. classiq/model_expansions/quantum_operations/__init__.py +0 -2
  26. classiq/model_expansions/quantum_operations/block_evaluator.py +16 -2
  27. classiq/model_expansions/quantum_operations/call_emitter.py +4 -1
  28. classiq/model_expansions/quantum_operations/emitter.py +26 -9
  29. classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -1
  30. classiq/model_expansions/quantum_operations/quantum_function_call.py +49 -0
  31. classiq/model_expansions/quantum_operations/repeat_block_evaluator.py +34 -0
  32. classiq/model_expansions/scope.py +34 -14
  33. classiq/model_expansions/scope_initialization.py +8 -4
  34. classiq/model_expansions/transformers/model_renamer.py +69 -63
  35. classiq/model_expansions/utils/sympy_utils.py +24 -0
  36. classiq/model_expansions/visitors/variable_references.py +1 -0
  37. classiq/qmod/builtins/functions/__init__.py +8 -0
  38. classiq/qmod/builtins/functions/allocation.py +36 -0
  39. classiq/qmod/builtins/functions/arithmetic.py +10 -5
  40. classiq/qmod/builtins/functions/mid_circuit_measurement.py +3 -0
  41. classiq/qmod/builtins/operations.py +2 -2
  42. classiq/qmod/model_state_container.py +9 -0
  43. classiq/qmod/symbolic.py +16 -3
  44. {classiq-0.71.0.dist-info → classiq-0.72.0.dist-info}/METADATA +1 -1
  45. {classiq-0.71.0.dist-info → classiq-0.72.0.dist-info}/RECORD +46 -51
  46. classiq/applications/finance/finance_model_constructor.py +0 -137
  47. classiq/applications/grover/__init__.py +0 -9
  48. classiq/applications/grover/grover_model_constructor.py +0 -167
  49. classiq/applications/libraries/__init__.py +0 -0
  50. classiq/applications/libraries/qmci_library.py +0 -22
  51. classiq/applications/qsvm/qsvm_model_constructor.py +0 -131
  52. classiq/model_expansions/quantum_operations/classicalif.py +0 -57
  53. classiq/model_expansions/quantum_operations/repeat.py +0 -62
  54. {classiq-0.71.0.dist-info → classiq-0.72.0.dist-info}/WHEEL +0 -0
classiq/__init__.py CHANGED
@@ -34,13 +34,10 @@ from classiq.applications.combinatorial_optimization import (
34
34
  execute_qaoa,
35
35
  pyo_model_to_hamiltonian,
36
36
  )
37
- from classiq.applications.finance import construct_finance_model
38
- from classiq.applications.grover import construct_grover_model
39
37
  from classiq.applications.hamiltonian.pauli_decomposition import (
40
38
  hamiltonian_to_matrix,
41
39
  matrix_to_hamiltonian,
42
40
  )
43
- from classiq.applications.qsvm import construct_qsvm_model
44
41
  from classiq.executor import (
45
42
  execute,
46
43
  execute_async,
@@ -65,11 +62,8 @@ from classiq.synthesis import (
65
62
  )
66
63
 
67
64
  _application_constructors_all = [
68
- "construct_qsvm_model",
69
65
  "construct_combinatorial_optimization_model",
70
66
  "construct_chemistry_model",
71
- "construct_finance_model",
72
- "construct_grover_model",
73
67
  "molecule_problem_to_qmod",
74
68
  ]
75
69
 
@@ -23,6 +23,7 @@ from classiq._internals.authentication import token_manager
23
23
  from classiq._internals.host_checker import HostChecker
24
24
 
25
25
  _FRONTEND_VARIANT: str = "classiq-sdk"
26
+ _SDK_ENV: str = "sdk-env"
26
27
  _INTERFACE_VARIANT: str = "classiq-interface-sdk"
27
28
  _USERAGENT_SEPARATOR: str = " "
28
29
 
@@ -74,12 +75,21 @@ def _get_user_agent_header() -> Headers:
74
75
  python_version = (
75
76
  f"python({_get_python_execution_environment()})/{platform.python_version()}"
76
77
  )
78
+
79
+ sdk_env_value = os.getenv("SDK_ENV", "Default")
77
80
  os_platform = f"{os.name}/{platform.platform()}"
78
81
  frontend_version = f"{_FRONTEND_VARIANT}/{_VERSION}"
79
82
  interface_version = f"{_INTERFACE_VARIANT}/{_VERSION}"
83
+ sdk_env = f"{_SDK_ENV}/{sdk_env_value}"
80
84
  return {
81
85
  "User-Agent": _USERAGENT_SEPARATOR.join(
82
- (python_version, os_platform, frontend_version, interface_version)
86
+ (
87
+ python_version,
88
+ os_platform,
89
+ frontend_version,
90
+ interface_version,
91
+ sdk_env,
92
+ )
83
93
  )
84
94
  }
85
95
 
@@ -1,30 +1,17 @@
1
- # flake8: noqa
2
-
3
- from typing import Optional, cast
4
1
  from collections.abc import Mapping
2
+ from typing import Optional, cast
5
3
 
6
4
  from classiq.interface.chemistry.fermionic_operator import (
7
5
  FermionicOperator,
8
6
  SummedFermionicOperator,
9
7
  )
10
- from classiq.interface.model.allocate import Allocate
11
- from classiq.interface.model.quantum_statement import QuantumStatement
12
- from classiq.qmod.builtins.structs import (
13
- MoleculeProblem as QmodMoleculeProblem,
14
- Molecule as QmodMolecule,
15
- ChemistryAtom as QmodChemistryAtom,
16
- Position as QmodPosition,
17
- )
18
8
  from classiq.interface.chemistry.ground_state_problem import (
19
9
  CHEMISTRY_PROBLEMS_TYPE,
20
10
  HamiltonianProblem,
21
11
  MoleculeProblem,
22
12
  )
23
13
  from classiq.interface.chemistry.molecule import Atom
24
- from classiq.qmod.builtins.enums import (
25
- Element,
26
- FermionMapping,
27
- )
14
+ from classiq.interface.exceptions import ClassiqError
28
15
  from classiq.interface.generator.expressions.expression import Expression
29
16
  from classiq.interface.generator.function_params import IOName
30
17
  from classiq.interface.generator.functions.classical_type import (
@@ -34,6 +21,7 @@ from classiq.interface.generator.functions.classical_type import (
34
21
  from classiq.interface.generator.functions.port_declaration import (
35
22
  PortDeclarationDirection,
36
23
  )
24
+ from classiq.interface.model.allocate import Allocate
37
25
  from classiq.interface.model.classical_parameter_declaration import (
38
26
  ClassicalParameterDeclaration,
39
27
  )
@@ -43,6 +31,7 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
43
31
  from classiq.interface.model.port_declaration import PortDeclaration
44
32
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
45
33
  from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
34
+ from classiq.interface.model.quantum_statement import QuantumStatement
46
35
 
47
36
  from classiq.applications.chemistry.ansatz_parameters import (
48
37
  AnsatzParameters,
@@ -53,8 +42,21 @@ from classiq.applications.chemistry.ansatz_parameters import (
53
42
  from classiq.applications.chemistry.chemistry_execution_parameters import (
54
43
  ChemistryExecutionParameters,
55
44
  )
56
- from classiq.interface.exceptions import ClassiqError
45
+ from classiq.qmod.builtins.enums import (
46
+ Element,
47
+ FermionMapping,
48
+ )
49
+ from classiq.qmod.builtins.structs import (
50
+ ChemistryAtom as QmodChemistryAtom,
51
+ Molecule as QmodMolecule,
52
+ MoleculeProblem as QmodMoleculeProblem,
53
+ Position as QmodPosition,
54
+ )
57
55
  from classiq.qmod.utilities import qmod_val_to_expr_str
56
+
57
+ # isort: split
58
+
59
+ # This import causes a circular import if done earlier. We use isort: split to avoid it
58
60
  from classiq.open_library.functions.hea import full_hea
59
61
 
60
62
  _LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
@@ -4,6 +4,7 @@ from itertools import filterfalse
4
4
  from typing import Optional, Union
5
5
 
6
6
  import pyomo.environ as pyo
7
+ import sympy
7
8
  from pyomo.core import ConcreteModel
8
9
  from pyomo.core.base import _GeneralVarData
9
10
  from pyomo.core.base.constraint import _GeneralConstraintData
@@ -179,8 +180,13 @@ class OptimizationModel:
179
180
  objective_map.sympy2pyomo |= penalty_map.sympy2pyomo
180
181
  for key, value in penalty_map.pyomo2sympy.items():
181
182
  objective_map.pyomo2sympy[key] = value
183
+ sympy_renaming = {
184
+ var: sympy.Symbol(str(var).replace(",", "_").replace("'", "_"))
185
+ for var in objective_expr.free_symbols
186
+ }
187
+ objective_expr = objective_expr.subs(sympy_renaming)
182
188
  sympy_mapping = {
183
- sympy_var: (
189
+ sympy_renaming[sympy_var]: (
184
190
  get_field_name(pyomo_var)
185
191
  if not is_index_var(pyomo_var)
186
192
  else (
@@ -190,4 +196,5 @@ class OptimizationModel:
190
196
  )
191
197
  for pyomo_var, sympy_var in objective_map.pyomo2sympy.items()
192
198
  }
193
- self.objective_not_encoded_sympy = sympy_mapping, objective_expr
199
+ compiled_expr = compile(str(objective_expr), "<string>", "eval")
200
+ self.objective_not_encoded_sympy = sympy_mapping, objective_expr, compiled_expr
@@ -7,6 +7,7 @@ from contextlib import contextmanager
7
7
  from enum import Enum
8
8
  from functools import reduce
9
9
  from operator import mul
10
+ from types import CodeType
10
11
  from typing import Any, Optional, TypeVar, Union
11
12
 
12
13
  import pydantic
@@ -362,6 +363,7 @@ def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]
362
363
  def evaluate_objective(
363
364
  var_mapping: dict[Any, Union[str, tuple[str, tuple[int, ...]]]],
364
365
  sympy_expr: sympy.Expr,
366
+ code_expr: CodeType,
365
367
  struct_obj: Any,
366
368
  ) -> Any:
367
369
  sympy_assignment = {
@@ -375,7 +377,10 @@ def evaluate_objective(
375
377
 
376
378
  # classical objective evaluation
377
379
  if not isinstance(struct_obj, QStruct):
378
- return float(sympy_expr.evalf(subs=sympy_assignment))
380
+ var_assignment = {
381
+ str(sympy_var): value for sympy_var, value in sympy_assignment.items()
382
+ }
383
+ return eval(code_expr, {}, var_assignment) # noqa: S307
379
384
 
380
385
  # quantum objective evaluation
381
386
  expr_str = str(sympy_expr).replace("'", "")
@@ -4,10 +4,7 @@ from classiq.interface.finance import (
4
4
  log_normal_model_input,
5
5
  )
6
6
 
7
- from .finance_model_constructor import construct_finance_model
8
-
9
7
  __all__ = [
10
- "construct_finance_model",
11
8
  "function_input",
12
9
  "gaussian_model_input",
13
10
  "log_normal_model_input",
@@ -2,9 +2,7 @@ from classiq.qmod.builtins.enums import QSVMFeatureMapEntanglement
2
2
 
3
3
  from ..qsvm import qsvm_data_generation
4
4
  from .qsvm import * # noqa: F403
5
- from .qsvm_model_constructor import construct_qsvm_model
6
5
 
7
6
  __all__ = [
8
7
  "QSVMFeatureMapEntanglement",
9
- "construct_qsvm_model",
10
8
  ]
@@ -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.71.0'
6
+ SEMVER_VERSION = '0.72.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -477,6 +477,27 @@ class IQCCBackendPreferences(BackendPreferences):
477
477
  slurm_account: str
478
478
 
479
479
 
480
+ class CINECABackendPreferences(BackendPreferences):
481
+ """
482
+ Represents the backend preferences specific to CINECA.
483
+
484
+ Attributes:
485
+ ssh_username: The username to use when connecting to the SSH server on the login node.
486
+ ssh_private_key_path: The path to the ssh private key on local machine.
487
+ """
488
+
489
+ backend_service_provider: ProviderTypeVendor.CINECA = pydantic.Field(
490
+ default=ProviderVendor.CINECA
491
+ )
492
+
493
+ ssh_username: str = pydantic.Field(
494
+ description="Username to use when connecting to the SSH server on the login node."
495
+ )
496
+ ssh_private_key_path: str = pydantic.Field(
497
+ description="Path of private key file on local machine to use when connecting to the SSH server on the login node."
498
+ )
499
+
500
+
480
501
  def is_exact_simulator(backend_preferences: BackendPreferences) -> bool:
481
502
  return backend_preferences.backend_name in EXACT_SIMULATORS
482
503
 
@@ -509,6 +530,7 @@ BackendPreferencesTypes = Union[
509
530
  IntelBackendPreferences,
510
531
  AQTBackendPreferences,
511
532
  IQCCBackendPreferences,
533
+ CINECABackendPreferences,
512
534
  ]
513
535
 
514
536
  __all__ = [
@@ -21,6 +21,7 @@ class ProviderVendor(StrEnum):
21
21
  INTEL = "Intel"
22
22
  AQT = "AQT"
23
23
  IQCC = "IQCC"
24
+ CINECA = "CINECA"
24
25
 
25
26
 
26
27
  class ProviderTypeVendor:
@@ -35,6 +36,7 @@ class ProviderTypeVendor:
35
36
  INTEL = Literal[ProviderVendor.INTEL]
36
37
  AQT = Literal[ProviderVendor.AQT]
37
38
  IQCC = Literal[ProviderVendor.IQCC]
39
+ CINECA = Literal[ProviderVendor.CINECA]
38
40
 
39
41
 
40
42
  class ClassiqSimulatorBackendNames(StrEnum):
@@ -4,6 +4,9 @@ from sympy import Expr
4
4
  from sympy.logic.boolalg import Boolean
5
5
 
6
6
  from classiq.interface.generator.expressions.handle_identifier import HandleIdentifier
7
+ from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
8
+ AnyClassicalValue,
9
+ )
7
10
  from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
8
11
  ClassicalProxy,
9
12
  )
@@ -28,5 +31,5 @@ Proxies = Union[
28
31
  QmodSizedProxy,
29
32
  ClassicalProxy,
30
33
  ]
31
- RuntimeExpression = Union[Expr, Boolean]
34
+ RuntimeExpression = Union[AnyClassicalValue, Expr, Boolean]
32
35
  ExpressionValue = Union[RuntimeConstant, Proxies, RuntimeExpression]
@@ -0,0 +1,135 @@
1
+ from typing import Any
2
+
3
+
4
+ class AnyClassicalValue:
5
+ def __init__(self, expr: str) -> None:
6
+ self._expr = expr
7
+
8
+ def __str__(self) -> str:
9
+ return self._expr
10
+
11
+ def __repr__(self) -> str:
12
+ return str(self)
13
+
14
+ def __getitem__(self, item: Any) -> "AnyClassicalValue":
15
+ if isinstance(item, slice):
16
+ subscript = ""
17
+ if item.start is not None:
18
+ subscript += str(item.start)
19
+ subscript += ":"
20
+ if item.stop is not None:
21
+ subscript += str(item.stop)
22
+ if item.step is not None:
23
+ subscript += f":{item.stop}"
24
+ item = subscript
25
+ return AnyClassicalValue(f"{self}[{item}]")
26
+
27
+ @staticmethod
28
+ def _binary_op(lhs: Any, rhs: Any, op: str) -> "AnyClassicalValue":
29
+ return AnyClassicalValue(f"{lhs} {op} {rhs}")
30
+
31
+ @staticmethod
32
+ def _unary_op(arg: Any, op: str) -> "AnyClassicalValue":
33
+ return AnyClassicalValue(f"{op}({arg})")
34
+
35
+ def __add__(self, other: Any) -> "AnyClassicalValue":
36
+ return AnyClassicalValue._binary_op(self, other, "+")
37
+
38
+ def __sub__(self, other: Any) -> "AnyClassicalValue":
39
+ return AnyClassicalValue._binary_op(self, other, "-")
40
+
41
+ def __mul__(self, other: Any) -> "AnyClassicalValue":
42
+ return AnyClassicalValue._binary_op(self, other, "*")
43
+
44
+ def __truediv__(self, other: Any) -> "AnyClassicalValue":
45
+ return AnyClassicalValue._binary_op(self, other, "/")
46
+
47
+ def __floordiv__(self, other: Any) -> "AnyClassicalValue":
48
+ return AnyClassicalValue._binary_op(self, other, "//")
49
+
50
+ def __mod__(self, other: Any) -> "AnyClassicalValue":
51
+ return AnyClassicalValue._binary_op(self, other, "%")
52
+
53
+ def __pow__(self, other: Any) -> "AnyClassicalValue":
54
+ return AnyClassicalValue._binary_op(self, other, "**")
55
+
56
+ def __lshift__(self, other: Any) -> "AnyClassicalValue":
57
+ return AnyClassicalValue._binary_op(self, other, "<<")
58
+
59
+ def __rshift__(self, other: Any) -> "AnyClassicalValue":
60
+ return AnyClassicalValue._binary_op(self, other, ">>")
61
+
62
+ def __and__(self, other: Any) -> "AnyClassicalValue":
63
+ return AnyClassicalValue._binary_op(self, other, "&")
64
+
65
+ def __xor__(self, other: Any) -> "AnyClassicalValue":
66
+ return AnyClassicalValue._binary_op(self, other, "^")
67
+
68
+ def __or__(self, other: Any) -> "AnyClassicalValue":
69
+ return AnyClassicalValue._binary_op(self, other, "|")
70
+
71
+ def __radd__(self, other: Any) -> "AnyClassicalValue":
72
+ return AnyClassicalValue._binary_op(other, self, "+")
73
+
74
+ def __rsub__(self, other: Any) -> "AnyClassicalValue":
75
+ return AnyClassicalValue._binary_op(other, self, "-")
76
+
77
+ def __rmul__(self, other: Any) -> "AnyClassicalValue":
78
+ return AnyClassicalValue._binary_op(other, self, "*")
79
+
80
+ def __rtruediv__(self, other: Any) -> "AnyClassicalValue":
81
+ return AnyClassicalValue._binary_op(other, self, "/")
82
+
83
+ def __rfloordiv__(self, other: Any) -> "AnyClassicalValue":
84
+ return AnyClassicalValue._binary_op(other, self, "//")
85
+
86
+ def __rmod__(self, other: Any) -> "AnyClassicalValue":
87
+ return AnyClassicalValue._binary_op(other, self, "%")
88
+
89
+ def __rpow__(self, other: Any) -> "AnyClassicalValue":
90
+ return AnyClassicalValue._binary_op(other, self, "**")
91
+
92
+ def __rlshift__(self, other: Any) -> "AnyClassicalValue":
93
+ return AnyClassicalValue._binary_op(other, self, "<<")
94
+
95
+ def __rrshift__(self, other: Any) -> "AnyClassicalValue":
96
+ return AnyClassicalValue._binary_op(other, self, ">>")
97
+
98
+ def __rand__(self, other: Any) -> "AnyClassicalValue":
99
+ return AnyClassicalValue._binary_op(other, self, "&")
100
+
101
+ def __rxor__(self, other: Any) -> "AnyClassicalValue":
102
+ return AnyClassicalValue._binary_op(other, self, "^")
103
+
104
+ def __ror__(self, other: Any) -> "AnyClassicalValue":
105
+ return AnyClassicalValue._binary_op(other, self, "|")
106
+
107
+ def __lt__(self, other: Any) -> "AnyClassicalValue":
108
+ return AnyClassicalValue._binary_op(self, other, "<")
109
+
110
+ def __le__(self, other: Any) -> "AnyClassicalValue":
111
+ return AnyClassicalValue._binary_op(self, other, "<=")
112
+
113
+ def __eq__(self, other: Any) -> "AnyClassicalValue": # type:ignore[override]
114
+ return AnyClassicalValue._binary_op(self, other, "==")
115
+
116
+ def __ne__(self, other: Any) -> "AnyClassicalValue": # type: ignore[override]
117
+ return AnyClassicalValue._binary_op(self, other, "!=")
118
+
119
+ def __gt__(self, other: Any) -> "AnyClassicalValue":
120
+ return AnyClassicalValue._binary_op(self, other, ">")
121
+
122
+ def __ge__(self, other: Any) -> "AnyClassicalValue":
123
+ return AnyClassicalValue._binary_op(self, other, ">=")
124
+
125
+ def __neg__(self) -> "AnyClassicalValue":
126
+ return AnyClassicalValue._unary_op(self, "-")
127
+
128
+ def __pos__(self) -> "AnyClassicalValue":
129
+ return AnyClassicalValue._unary_op(self, "+")
130
+
131
+ def __abs__(self) -> "AnyClassicalValue":
132
+ return AnyClassicalValue._unary_op(self, "abs")
133
+
134
+ def __invert__(self) -> "AnyClassicalValue":
135
+ return AnyClassicalValue._unary_op(self, "~")
@@ -2,6 +2,7 @@ CTRL_VAR_PREFIX = "ctrl__"
2
2
  CONTROL_OPERATOR_NAME = "control"
3
3
  INVERT_OPERATOR_NAME = "invert"
4
4
  REPEAT_OPERATOR_NAME = "iteration"
5
+ CLASSICAL_IF_OPERATOR_NAME = "classical_if"
5
6
  POWER_OPERATOR_NAME = "power"
6
7
  UNCOMPUTE_OPERATOR_NAME = "uncompute"
7
8
  WITHIN_APPLY_NAME = "within_apply"
@@ -233,6 +233,19 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
233
233
  return list()
234
234
  return self.generated_function.control_states
235
235
 
236
+ @property
237
+ def control_qubits(self) -> tuple[int, ...]:
238
+ control_states_names = {
239
+ control_state.name for control_state in self.control_states
240
+ }
241
+ return tuple(
242
+ qubit
243
+ for register in self.registers
244
+ for qubit in register.qubit_indexes_absolute
245
+ if register.role is RegisterRole.INPUT
246
+ and register.name in control_states_names
247
+ )
248
+
236
249
  def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
237
250
  if self.absolute_qubits is None:
238
251
  return self
@@ -110,10 +110,12 @@ class HardwareData(pydantic.BaseModel):
110
110
  for gate in specified_basis_gates
111
111
  if gate in TWO_QUBIT_GATES and gate not in ROUTING_TWO_QUBIT_BASIS_GATES
112
112
  ]
113
+
113
114
  if invalid_gates:
114
115
  raise ClassiqValueError(
115
116
  "Connectivity-aware synthesis with non-symmetric coupling map "
116
- "is currently supported for the following two-qubit gates only: cx, ecr, rzx."
117
+ "is currently supported for the following two-qubit gates only: "
118
+ "cx, ecr, rzx, ryy, rxx, rzz, cy, cp, cz, swap"
117
119
  )
118
120
 
119
121
  return self
@@ -63,7 +63,9 @@ THREE_QUBIT_GATES: BasisGates = frozenset(("ccx", "cswap"))
63
63
  DEFAULT_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | BASIC_TWO_QUBIT_GATES
64
64
  ALL_GATES: BasisGates = SINGLE_QUBIT_GATES | TWO_QUBIT_GATES | THREE_QUBIT_GATES
65
65
 
66
- ROUTING_TWO_QUBIT_BASIS_GATES: BasisGates = frozenset(("cx", "ecr", "rzx"))
66
+ ROUTING_TWO_QUBIT_BASIS_GATES: BasisGates = frozenset(
67
+ ("cx", "ecr", "rzx", "ryy", "rxx", "rzz", "cy", "cz", "cp", "swap")
68
+ )
67
69
  DEFAULT_ROUTING_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | frozenset(("cx",))
68
70
  # The Enum names are capitalized per recommendation in https://docs.python.org/3/library/enum.html#module-enum
69
71
  # The Enum values are lowered to keep consistency
@@ -33,6 +33,7 @@ class Provider(StrEnum):
33
33
  INTEL = "Intel"
34
34
  AQT = "AQT"
35
35
  IQCC = "IQCC"
36
+ CINECA = "CINECA"
36
37
 
37
38
  @property
38
39
  def id(self) -> "ProviderIDEnum":
@@ -64,6 +64,9 @@ class HandleBinding(ASTNode):
64
64
  def __contains__(self, other_handle: "HandleBinding") -> bool:
65
65
  return self.collapse() in other_handle.collapse().prefixes()
66
66
 
67
+ def is_constant(self) -> bool:
68
+ return True
69
+
67
70
 
68
71
  class NestedHandleBinding(HandleBinding):
69
72
  base_handle: "ConcreteHandleBinding"
@@ -105,6 +108,9 @@ class NestedHandleBinding(HandleBinding):
105
108
  )
106
109
  return self
107
110
 
111
+ def is_constant(self) -> bool:
112
+ return self.base_handle.is_constant()
113
+
108
114
 
109
115
  class SubscriptHandleBinding(NestedHandleBinding):
110
116
  index: Expression
@@ -178,6 +184,13 @@ class SubscriptHandleBinding(NestedHandleBinding):
178
184
  )
179
185
  return super().replace_prefix(prefix, replacement)
180
186
 
187
+ def is_constant(self) -> bool:
188
+ return (
189
+ super().is_constant()
190
+ and self.index.is_evaluated()
191
+ and self.index.is_constant()
192
+ )
193
+
181
194
 
182
195
  class SlicedHandleBinding(NestedHandleBinding):
183
196
  start: Expression
@@ -284,6 +297,14 @@ class SlicedHandleBinding(NestedHandleBinding):
284
297
  def _is_evaluated(self) -> bool:
285
298
  return self.start.is_evaluated() and self.end.is_evaluated()
286
299
 
300
+ def is_constant(self) -> bool:
301
+ return (
302
+ super().is_constant()
303
+ and self._is_evaluated()
304
+ and self.start.is_constant()
305
+ and self.end.is_constant()
306
+ )
307
+
287
308
 
288
309
  class FieldHandleBinding(NestedHandleBinding):
289
310
  field: str
@@ -43,8 +43,6 @@ TASKS_VISUAL_MODEL_SUFFIX = TASKS_SUFFIX + "/visual_model"
43
43
  TASKS_SOLVE_SUFFIX = "/tasks/solve"
44
44
 
45
45
  CHEMISTRY_QMOD_PATH = "/generate_model/chemistry/qmod"
46
- GROVER_QMOD_PATH = "/generate_model/grover/qmod"
47
- FINANCE_QMOD_PATH = "/generate_model/finance/qmod"
48
46
 
49
47
 
50
48
  TASK_TRAIN_SUFFIX = TASKS_SUFFIX + "/train"
@@ -1,8 +1,8 @@
1
1
  from collections.abc import Mapping
2
2
  from enum import Enum
3
- from typing import Any, Callable, Union
3
+ from typing import Any, Callable, Union, get_args
4
4
 
5
- from sympy import Eq, Expr, Number, Piecewise, Symbol
5
+ from sympy import Eq, Expr, Piecewise, Symbol
6
6
 
7
7
  from classiq.interface.exceptions import (
8
8
  ClassiqExpansionError,
@@ -12,6 +12,9 @@ from classiq.interface.generator.expressions.expression_types import (
12
12
  ExpressionValue,
13
13
  QmodStructInstance,
14
14
  )
15
+ from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
16
+ AnyClassicalValue,
17
+ )
15
18
  from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
16
19
  QmodQNumProxy,
17
20
  )
@@ -54,6 +57,10 @@ from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
54
57
  from classiq.model_expansions.sympy_conversion.sympy_to_python import (
55
58
  sympy_to_python,
56
59
  )
60
+ from classiq.model_expansions.utils.sympy_utils import (
61
+ is_constant_subscript,
62
+ unwrap_sympy_numeric,
63
+ )
57
64
  from classiq.qmod.model_state_container import QMODULE
58
65
 
59
66
 
@@ -151,9 +158,13 @@ def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInsta
151
158
 
152
159
 
153
160
  def get_field(
154
- proxy: Union[QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list],
161
+ proxy: Union[
162
+ QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list, AnyClassicalValue
163
+ ],
155
164
  field: str,
156
165
  ) -> ExpressionValue:
166
+ if isinstance(proxy, AnyClassicalValue):
167
+ return AnyClassicalValue(f"({proxy}).{field}")
157
168
  if isinstance(proxy, type) and issubclass(proxy, Enum):
158
169
  return getattr(proxy, field)
159
170
  if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
@@ -189,20 +200,25 @@ def get_type(struct_type: Symbol) -> TypeProxy:
189
200
  return TypeProxy(QMODULE.type_decls[struct_type.name])
190
201
 
191
202
 
192
- def _unwrap_sympy_numeric(n: Any) -> Any:
193
- if not isinstance(n, Number) or not n.is_constant():
194
- return n
195
- if n.is_Integer:
196
- return int(n)
197
- return float(n)
198
-
199
-
200
203
  def do_div(lhs: Any, rhs: Any) -> Any:
201
- lhs = _unwrap_sympy_numeric(lhs)
202
- rhs = _unwrap_sympy_numeric(rhs)
204
+ lhs = unwrap_sympy_numeric(lhs)
205
+ rhs = unwrap_sympy_numeric(rhs)
203
206
  return lhs / rhs
204
207
 
205
208
 
209
+ _EXPRESSION_TYPES = get_args(ExpressionValue)
210
+
211
+
212
+ def _is_qmod_value(val: Any) -> bool:
213
+ if not isinstance(val, slice):
214
+ return isinstance(val, _EXPRESSION_TYPES)
215
+ if val.start is not None and not isinstance(val.start, _EXPRESSION_TYPES):
216
+ return False
217
+ if val.stop is not None and not isinstance(val.stop, _EXPRESSION_TYPES):
218
+ return False
219
+ return val.step is None or isinstance(val.step, _EXPRESSION_TYPES)
220
+
221
+
206
222
  def do_subscript(value: Any, index: Any) -> Any:
207
223
  if not isinstance(value, list) or not isinstance(index, QmodQNumProxy):
208
224
  if isinstance(index, (QmodSizedProxy, QmodStructInstance)):
@@ -214,6 +230,12 @@ def do_subscript(value: Any, index: Any) -> Any:
214
230
  f"\t2. `l[n]`, where `l` is a list of classical real numbers and `n` "
215
231
  f"is a classical or quantum integer."
216
232
  )
233
+ if (
234
+ isinstance(value, list)
235
+ and not is_constant_subscript(index)
236
+ and _is_qmod_value(index)
237
+ ):
238
+ return AnyClassicalValue(str(value))[index]
217
239
  return value[index]
218
240
  if index.is_signed or index.fraction_digits > 0:
219
241
  raise ClassiqExpansionError(
@@ -8,7 +8,6 @@ from typing import Any, Optional
8
8
  from typing_extensions import Self
9
9
 
10
10
  from classiq.interface.exceptions import ClassiqInternalExpansionError
11
- from classiq.interface.model.port_declaration import PortDeclaration
12
11
  from classiq.interface.model.quantum_function_declaration import (
13
12
  NamedParamsQuantumFunctionDeclaration,
14
13
  PositionalArg,
@@ -35,14 +34,6 @@ class Closure:
35
34
  positional_arg_declarations: Sequence[PositionalArg] = tuple()
36
35
  captured_vars: CapturedVars = field(default_factory=CapturedVars)
37
36
 
38
- @property
39
- def port_declarations(self) -> dict[str, PortDeclaration]:
40
- return {
41
- param.name: param
42
- for param in self.positional_arg_declarations
43
- if isinstance(param, PortDeclaration)
44
- }
45
-
46
37
 
47
38
  @dataclass(frozen=True)
48
39
  class GenerativeClosure(Closure):