classiq 0.70.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 (98) 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/debug_info/debug_info.py +4 -0
  12. classiq/interface/generator/expressions/expression_constants.py +0 -3
  13. classiq/interface/generator/expressions/expression_types.py +8 -3
  14. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +135 -0
  15. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +4 -0
  16. classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +5 -1
  17. classiq/interface/generator/expressions/proxies/classical/utils.py +34 -0
  18. classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
  19. classiq/interface/generator/functions/classical_type.py +1 -1
  20. classiq/interface/generator/functions/type_name.py +16 -0
  21. classiq/interface/generator/functions/type_qualifier.py +7 -0
  22. classiq/interface/generator/generated_circuit_data.py +14 -1
  23. classiq/interface/generator/hardware/hardware_data.py +3 -1
  24. classiq/interface/generator/quantum_function_call.py +8 -1
  25. classiq/interface/generator/synthesis_execution_parameter.py +1 -0
  26. classiq/interface/generator/transpiler_basis_gates.py +3 -1
  27. classiq/interface/generator/types/compilation_metadata.py +1 -0
  28. classiq/interface/hardware.py +1 -0
  29. classiq/interface/ide/visual_model.py +1 -0
  30. classiq/interface/interface_version.py +1 -1
  31. classiq/interface/model/allocate.py +7 -0
  32. classiq/interface/model/block.py +12 -0
  33. classiq/interface/model/classical_if.py +4 -0
  34. classiq/interface/model/handle_binding.py +21 -0
  35. classiq/interface/model/inplace_binary_operation.py +4 -0
  36. classiq/interface/model/model.py +3 -1
  37. classiq/interface/model/phase_operation.py +4 -0
  38. classiq/interface/model/port_declaration.py +3 -0
  39. classiq/interface/model/power.py +4 -0
  40. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -0
  41. classiq/interface/model/quantum_function_call.py +4 -0
  42. classiq/interface/model/quantum_function_declaration.py +1 -1
  43. classiq/interface/model/quantum_statement.py +5 -0
  44. classiq/interface/model/quantum_type.py +22 -0
  45. classiq/interface/model/repeat.py +4 -0
  46. classiq/interface/model/statement_block.py +3 -0
  47. classiq/interface/model/variable_declaration_statement.py +5 -0
  48. classiq/interface/server/routes.py +0 -2
  49. classiq/model_expansions/atomic_expression_functions_defs.py +35 -13
  50. classiq/model_expansions/capturing/captured_vars.py +156 -34
  51. classiq/model_expansions/closure.py +0 -9
  52. classiq/model_expansions/evaluators/classical_type_inference.py +70 -0
  53. classiq/model_expansions/evaluators/parameter_types.py +20 -10
  54. classiq/model_expansions/expression_evaluator.py +0 -11
  55. classiq/model_expansions/function_builder.py +2 -8
  56. classiq/model_expansions/generative_functions.py +7 -30
  57. classiq/model_expansions/interpreters/base_interpreter.py +7 -8
  58. classiq/model_expansions/interpreters/generative_interpreter.py +33 -5
  59. classiq/model_expansions/quantum_operations/__init__.py +0 -2
  60. classiq/model_expansions/quantum_operations/block_evaluator.py +16 -2
  61. classiq/model_expansions/quantum_operations/call_emitter.py +49 -6
  62. classiq/model_expansions/quantum_operations/emitter.py +64 -6
  63. classiq/model_expansions/quantum_operations/expression_evaluator.py +4 -0
  64. classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -1
  65. classiq/model_expansions/quantum_operations/quantum_function_call.py +49 -0
  66. classiq/model_expansions/quantum_operations/repeat_block_evaluator.py +34 -0
  67. classiq/model_expansions/scope.py +33 -21
  68. classiq/model_expansions/scope_initialization.py +28 -32
  69. classiq/model_expansions/transformers/model_renamer.py +69 -63
  70. classiq/model_expansions/utils/sympy_utils.py +24 -0
  71. classiq/model_expansions/visitors/variable_references.py +1 -0
  72. classiq/qmod/__init__.py +3 -1
  73. classiq/qmod/builtins/functions/__init__.py +8 -0
  74. classiq/qmod/builtins/functions/allocation.py +36 -0
  75. classiq/qmod/builtins/functions/arithmetic.py +10 -5
  76. classiq/qmod/builtins/functions/mid_circuit_measurement.py +3 -0
  77. classiq/qmod/builtins/operations.py +2 -2
  78. classiq/qmod/declaration_inferrer.py +52 -24
  79. classiq/qmod/model_state_container.py +9 -0
  80. classiq/qmod/native/pretty_printer.py +25 -3
  81. classiq/qmod/pretty_print/pretty_printer.py +31 -14
  82. classiq/qmod/python_classical_type.py +12 -1
  83. classiq/qmod/qfunc.py +33 -8
  84. classiq/qmod/qmod_variable.py +188 -147
  85. classiq/qmod/quantum_function.py +3 -4
  86. classiq/qmod/semantics/validation/type_hints.py +19 -10
  87. classiq/qmod/symbolic.py +16 -3
  88. {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/METADATA +1 -1
  89. {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/RECORD +90 -91
  90. classiq/applications/finance/finance_model_constructor.py +0 -137
  91. classiq/applications/grover/__init__.py +0 -9
  92. classiq/applications/grover/grover_model_constructor.py +0 -167
  93. classiq/applications/libraries/__init__.py +0 -0
  94. classiq/applications/libraries/qmci_library.py +0 -22
  95. classiq/applications/qsvm/qsvm_model_constructor.py +0 -131
  96. classiq/model_expansions/quantum_operations/classicalif.py +0 -57
  97. classiq/model_expansions/quantum_operations/repeat.py +0 -62
  98. {classiq-0.70.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.70.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):
@@ -10,6 +10,7 @@ from classiq.interface.generator.generated_circuit_data import (
10
10
  OperationLevel,
11
11
  StatementType,
12
12
  )
13
+ from classiq.interface.model.block import Block
13
14
  from classiq.interface.model.statement_block import ConcreteQuantumStatement
14
15
 
15
16
  ParameterValue = Union[float, int, str, None]
@@ -84,6 +85,9 @@ def get_back_refs(
84
85
  ) -> list[ConcreteQuantumStatement]:
85
86
  back_refs: list[ConcreteQuantumStatement] = []
86
87
  while (node := debug_info.node) is not None:
88
+ # For backwards compatibility, we make sure that the back_ref is not a block
89
+ # Remove this check when we start saving blocks in the debug info collection.
90
+ assert not isinstance(node, Block)
87
91
  back_refs.insert(0, node)
88
92
  if node.back_ref is None:
89
93
  break
@@ -20,6 +20,3 @@ BOOLEAN_LITERALS = {"True", "False"}
20
20
  FORBIDDEN_LITERALS: set[str] = set(keyword.kwlist) - SUPPORTED_FUNC_NAMES
21
21
  CPARAM_EXECUTION_SUFFIX: Final[str] = "_param"
22
22
  RESERVED_EXPRESSIONS: frozenset[str] = frozenset({"i"})
23
- CPARAM_EXECUTION_SUFFIX_PATTERN = (
24
- rf"({CPARAM_EXECUTION_SUFFIX}|^({'|'.join(RESERVED_EXPRESSIONS)}))(_\d+)*$"
25
- )
@@ -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
  )
@@ -21,10 +24,12 @@ RuntimeConstant = Union[
21
24
  list,
22
25
  bool,
23
26
  QmodStructInstance,
24
- QmodSizedProxy,
25
27
  TypeProxy,
26
28
  HandleIdentifier,
29
+ ]
30
+ Proxies = Union[
31
+ QmodSizedProxy,
27
32
  ClassicalProxy,
28
33
  ]
29
- RuntimeExpression = Union[Expr, Boolean]
30
- ExpressionValue = Union[RuntimeConstant, RuntimeExpression]
34
+ RuntimeExpression = Union[AnyClassicalValue, Expr, Boolean]
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, "~")
@@ -38,6 +38,10 @@ class ClassicalArrayProxy(NonSymbolicExpr, ClassicalProxy):
38
38
  def type_name(self) -> str:
39
39
  return "Array"
40
40
 
41
+ @property
42
+ def length(self) -> int:
43
+ return self._length
44
+
41
45
  def __getitem__(self, key: Union[slice, int, Integer]) -> ClassicalProxy:
42
46
  return (
43
47
  self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
@@ -17,11 +17,15 @@ class ClassicalStructProxy(NonSymbolicExpr, ClassicalProxy):
17
17
  super().__init__(handle)
18
18
  self._decl = decl
19
19
 
20
+ @property
21
+ def struct_declaration(self) -> "StructDeclaration":
22
+ return self._decl
23
+
20
24
  @property
21
25
  def fields(self) -> Mapping[str, "ExpressionValue"]:
22
26
  return {
23
27
  field_name: field_type.get_classical_proxy(
24
- FieldHandleBinding(base_handle=self.handle, field_name=field_name)
28
+ FieldHandleBinding(base_handle=self.handle, field=field_name)
25
29
  )
26
30
  for field_name, field_type in self._decl.variables.items()
27
31
  }
@@ -0,0 +1,34 @@
1
+ from classiq.interface.exceptions import ClassiqInternalExpansionError
2
+ from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
3
+ ClassicalArrayProxy,
4
+ )
5
+ from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
6
+ ClassicalProxy,
7
+ )
8
+ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
9
+ ClassicalScalarProxy,
10
+ )
11
+ from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
12
+ ClassicalStructProxy,
13
+ )
14
+ from classiq.interface.generator.functions.classical_type import (
15
+ ClassicalArray,
16
+ ClassicalType,
17
+ )
18
+ from classiq.interface.generator.functions.type_name import TypeName
19
+
20
+
21
+ def get_proxy_type(proxy: ClassicalProxy) -> ClassicalType:
22
+ if isinstance(proxy, ClassicalScalarProxy):
23
+ classical_type = proxy._classical_type
24
+ elif isinstance(proxy, ClassicalArrayProxy):
25
+ classical_type = ClassicalArray(
26
+ element_type=proxy._element_type, size=proxy.length
27
+ )
28
+ elif isinstance(proxy, ClassicalStructProxy):
29
+ classical_type = TypeName(name=proxy._decl.name)
30
+ else:
31
+ raise ClassiqInternalExpansionError(
32
+ f"Unrecognized classical proxy {type(proxy).__name__}"
33
+ )
34
+ return classical_type
@@ -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"
@@ -98,7 +98,7 @@ class StructMetaType(ClassicalType):
98
98
  class ClassicalArray(ClassicalType):
99
99
  kind: Literal["array"]
100
100
  element_type: "ConcreteClassicalType"
101
- size: pydantic.PositiveInt
101
+ size: int
102
102
 
103
103
  @pydantic.model_validator(mode="before")
104
104
  @classmethod
@@ -1,9 +1,11 @@
1
1
  from collections.abc import Mapping
2
+ from itertools import chain
2
3
  from typing import TYPE_CHECKING, Any, Literal, Optional
3
4
 
4
5
  import pydantic
5
6
 
6
7
  from classiq.interface.exceptions import ClassiqExpansionError
8
+ from classiq.interface.generator.expressions.expression import Expression
7
9
  from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
8
10
  ClassicalProxy,
9
11
  )
@@ -97,6 +99,12 @@ class TypeName(ClassicalType, QuantumType):
97
99
  def has_classical_struct_decl(self) -> bool:
98
100
  return self._classical_struct_decl is not None
99
101
 
102
+ @property
103
+ def classical_struct_decl(self) -> "StructDeclaration":
104
+ if self._classical_struct_decl is None:
105
+ raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
106
+ return self._classical_struct_decl
107
+
100
108
  def set_classical_struct_decl(self, decl: "StructDeclaration") -> None:
101
109
  self._classical_struct_decl = decl
102
110
 
@@ -105,6 +113,14 @@ class TypeName(ClassicalType, QuantumType):
105
113
  raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
106
114
  return ClassicalStructProxy(handle, self._classical_struct_decl)
107
115
 
116
+ @property
117
+ def expressions(self) -> list[Expression]:
118
+ return list(
119
+ chain.from_iterable(
120
+ field_type.expressions for field_type in self.fields.values()
121
+ )
122
+ )
123
+
108
124
 
109
125
  class Enum(TypeName):
110
126
  pass
@@ -0,0 +1,7 @@
1
+ from classiq.interface.enum_utils import StrEnum
2
+
3
+
4
+ class TypeQualifier(StrEnum):
5
+ Const = "const"
6
+ QFree = "qfree"
7
+ Quantum = "quantum"
@@ -83,7 +83,7 @@ class GeneratedRegister(pydantic.BaseModel):
83
83
  @staticmethod
84
84
  def demangle_name(name: str) -> str:
85
85
  if is_captured_var_name(name):
86
- return demangle_capture_name(name)
86
+ name = demangle_capture_name(name)
87
87
  return demangle_name(name)
88
88
 
89
89
 
@@ -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
@@ -40,7 +40,10 @@ from classiq.interface.generator.slice_parsing_utils import (
40
40
  SLICING,
41
41
  parse_io_slicing,
42
42
  )
43
- from classiq.interface.generator.synthesis_execution_parameter import PydanticPowerType
43
+ from classiq.interface.generator.synthesis_execution_parameter import (
44
+ ClassicalArg,
45
+ PydanticPowerType,
46
+ )
44
47
  from classiq.interface.generator.user_defined_function_params import CustomFunction
45
48
  from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
46
49
  from classiq.interface.helpers.hashable_pydantic_base_model import (
@@ -148,6 +151,10 @@ class SynthesisQuantumFunctionCall(BaseModel):
148
151
  description="The name of the function instance. "
149
152
  "If not set, determined automatically.",
150
153
  )
154
+ caller_parameters: Optional[list[str]] = pydantic.Field(default=None)
155
+ parameter_assignments: Optional[dict[str, ClassicalArg]] = pydantic.Field(
156
+ default=None
157
+ )
151
158
  source_id: Optional[UUID] = pydantic.Field(default=None)
152
159
  arithmetic_id: Optional[str] = pydantic.Field(default=None)
153
160
  inverse_op_id: Optional[UUID] = pydantic.Field(default=None)
@@ -6,3 +6,4 @@ from classiq.interface.backend.pydantic_backend import PydanticExecutionParamete
6
6
 
7
7
  PydanticIntSynthesisExecutionParameter = Union[PydanticExecutionParameter, int]
8
8
  PydanticPowerType: TypeAlias = PydanticIntSynthesisExecutionParameter
9
+ ClassicalArg = Union[float, str]