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.
- classiq/__init__.py +0 -6
- classiq/_internals/client.py +11 -1
- classiq/applications/chemistry/chemistry_model_constructor.py +18 -16
- classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +6 -1
- classiq/applications/finance/__init__.py +0 -3
- classiq/applications/qsvm/__init__.py +0 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +22 -0
- classiq/interface/backend/quantum_backend_providers.py +2 -0
- classiq/interface/generator/expressions/expression_types.py +4 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +135 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
- classiq/interface/generator/generated_circuit_data.py +13 -0
- classiq/interface/generator/hardware/hardware_data.py +3 -1
- classiq/interface/generator/transpiler_basis_gates.py +3 -1
- classiq/interface/hardware.py +1 -0
- classiq/interface/model/handle_binding.py +21 -0
- classiq/interface/server/routes.py +0 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +35 -13
- classiq/model_expansions/closure.py +0 -9
- classiq/model_expansions/evaluators/parameter_types.py +6 -10
- classiq/model_expansions/interpreters/base_interpreter.py +4 -4
- classiq/model_expansions/interpreters/generative_interpreter.py +33 -5
- classiq/model_expansions/quantum_operations/__init__.py +0 -2
- classiq/model_expansions/quantum_operations/block_evaluator.py +16 -2
- classiq/model_expansions/quantum_operations/call_emitter.py +4 -1
- classiq/model_expansions/quantum_operations/emitter.py +26 -9
- classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_function_call.py +49 -0
- classiq/model_expansions/quantum_operations/repeat_block_evaluator.py +34 -0
- classiq/model_expansions/scope.py +34 -14
- classiq/model_expansions/scope_initialization.py +8 -4
- classiq/model_expansions/transformers/model_renamer.py +69 -63
- classiq/model_expansions/utils/sympy_utils.py +24 -0
- classiq/model_expansions/visitors/variable_references.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +8 -0
- classiq/qmod/builtins/functions/allocation.py +36 -0
- classiq/qmod/builtins/functions/arithmetic.py +10 -5
- classiq/qmod/builtins/functions/mid_circuit_measurement.py +3 -0
- classiq/qmod/builtins/operations.py +2 -2
- classiq/qmod/model_state_container.py +9 -0
- classiq/qmod/symbolic.py +16 -3
- {classiq-0.71.0.dist-info → classiq-0.72.0.dist-info}/METADATA +1 -1
- {classiq-0.71.0.dist-info → classiq-0.72.0.dist-info}/RECORD +46 -51
- classiq/applications/finance/finance_model_constructor.py +0 -137
- classiq/applications/grover/__init__.py +0 -9
- classiq/applications/grover/grover_model_constructor.py +0 -167
- classiq/applications/libraries/__init__.py +0 -0
- classiq/applications/libraries/qmci_library.py +0 -22
- classiq/applications/qsvm/qsvm_model_constructor.py +0 -131
- classiq/model_expansions/quantum_operations/classicalif.py +0 -57
- classiq/model_expansions/quantum_operations/repeat.py +0 -62
- {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
|
|
classiq/_internals/client.py
CHANGED
@@ -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
|
-
(
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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("'", "")
|
@@ -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
|
]
|
classiq/interface/_version.py
CHANGED
@@ -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:
|
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(
|
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
|
classiq/interface/hardware.py
CHANGED
@@ -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,
|
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[
|
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 =
|
202
|
-
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):
|