classiq 0.86.1__py3-none-any.whl → 0.87.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 +2 -0
- classiq/applications/chemistry/hartree_fock.py +5 -1
- classiq/applications/chemistry/op_utils.py +2 -2
- classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
- classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
- classiq/applications/combinatorial_helpers/memory.py +4 -4
- classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
- classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
- classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
- classiq/applications/hamiltonian/pauli_decomposition.py +33 -1
- classiq/evaluators/argument_types.py +15 -6
- classiq/evaluators/parameter_types.py +43 -39
- classiq/evaluators/qmod_annotated_expression.py +88 -11
- classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +54 -11
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +40 -25
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +29 -59
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +12 -5
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +21 -14
- classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +9 -5
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +20 -1
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
- classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
- classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +2 -3
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +48 -21
- classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
- classiq/evaluators/qmod_node_evaluators/utils.py +27 -5
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
- classiq/evaluators/qmod_type_inference/quantum_type_inference.py +292 -0
- classiq/evaluators/quantum_type_utils.py +0 -131
- classiq/execution/execution_session.py +1 -1
- classiq/execution/qnn.py +4 -1
- classiq/execution/user_budgets.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +10 -30
- classiq/interface/backend/quantum_backend_providers.py +63 -52
- classiq/interface/generator/arith/binary_ops.py +107 -115
- classiq/interface/generator/arith/extremum_operations.py +33 -45
- classiq/interface/generator/arith/number_utils.py +4 -1
- classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
- classiq/interface/generator/compiler_keywords.py +2 -0
- classiq/interface/generator/function_param_list.py +133 -5
- classiq/interface/generator/functions/classical_type.py +59 -2
- classiq/interface/generator/functions/qmod_python_interface.py +15 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/model/preferences/preferences.py +1 -17
- classiq/interface/generator/quantum_program.py +1 -13
- classiq/interface/helpers/model_normalizer.py +2 -2
- classiq/interface/helpers/text_utils.py +7 -2
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/classical_if.py +40 -0
- classiq/interface/model/handle_binding.py +28 -16
- classiq/interface/model/quantum_type.py +61 -2
- classiq/interface/pretty_print/expression_to_qmod.py +24 -11
- classiq/interface/pyomo_extension/__init__.py +0 -4
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
- classiq/model_expansions/arithmetic.py +43 -1
- classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
- classiq/model_expansions/capturing/captured_vars.py +2 -5
- classiq/model_expansions/quantum_operations/allocate.py +22 -15
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
- classiq/model_expansions/quantum_operations/bind.py +15 -7
- classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
- classiq/open_library/functions/__init__.py +3 -0
- classiq/open_library/functions/lcu.py +117 -0
- classiq/qmod/builtins/enums.py +2 -2
- classiq/qmod/builtins/structs.py +33 -18
- classiq/qmod/pretty_print/expression_to_python.py +7 -9
- {classiq-0.86.1.dist-info → classiq-0.87.0.dist-info}/METADATA +3 -3
- {classiq-0.86.1.dist-info → classiq-0.87.0.dist-info}/RECORD +83 -89
- classiq/interface/generator/amplitude_estimation.py +0 -34
- classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
- classiq/interface/generator/grover_diffuser.py +0 -93
- classiq/interface/generator/grover_operator.py +0 -106
- classiq/interface/generator/oracles/__init__.py +0 -3
- classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
- classiq/interface/generator/oracles/custom_oracle.py +0 -65
- classiq/interface/generator/oracles/oracle_abc.py +0 -76
- classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
- classiq/interface/generator/qpe.py +0 -169
- classiq/interface/grover/grover_modelling_params.py +0 -13
- classiq/model_expansions/transformers/var_splitter.py +0 -224
- /classiq/{interface/grover → evaluators/qmod_type_inference}/__init__.py +0 -0
- {classiq-0.86.1.dist-info → classiq-0.87.0.dist-info}/WHEEL +0 -0
@@ -1,93 +0,0 @@
|
|
1
|
-
from typing import Any, Union
|
2
|
-
|
3
|
-
import pydantic
|
4
|
-
from pydantic_core.core_schema import ValidationInfo
|
5
|
-
|
6
|
-
from classiq.interface.exceptions import ClassiqValueError
|
7
|
-
from classiq.interface.generator.arith.register_user_input import RegisterUserInput
|
8
|
-
from classiq.interface.generator.function_params import (
|
9
|
-
ArithmeticIODict,
|
10
|
-
FunctionParams,
|
11
|
-
parse_function_params_values,
|
12
|
-
)
|
13
|
-
from classiq.interface.generator.state_preparation import StatePreparation
|
14
|
-
from classiq.interface.generator.user_defined_function_params import CustomFunction
|
15
|
-
|
16
|
-
GroverStatePreparation = Union[StatePreparation, CustomFunction]
|
17
|
-
|
18
|
-
|
19
|
-
class GroverDiffuser(FunctionParams):
|
20
|
-
variables: list[RegisterUserInput]
|
21
|
-
state_preparation: str = pydantic.Field(
|
22
|
-
default="", description="State preparation function"
|
23
|
-
)
|
24
|
-
state_preparation_params: GroverStatePreparation = pydantic.Field(
|
25
|
-
description="State preparation function parameters",
|
26
|
-
default_factory=CustomFunction,
|
27
|
-
)
|
28
|
-
|
29
|
-
def _create_ios(self) -> None:
|
30
|
-
self._inputs = {reg.name: reg for reg in self.variables}
|
31
|
-
self._outputs = {reg.name: reg for reg in self.variables}
|
32
|
-
|
33
|
-
@pydantic.model_validator(mode="before")
|
34
|
-
@classmethod
|
35
|
-
def _validate_state_preparation_name(cls, values: Any) -> dict[str, Any]:
|
36
|
-
if (
|
37
|
-
isinstance(values, dict)
|
38
|
-
and isinstance(values.get("state_preparation_params"), CustomFunction)
|
39
|
-
and not values.get("state_preparation")
|
40
|
-
):
|
41
|
-
raise ClassiqValueError(
|
42
|
-
"Must receive the function name from the `state_preparation` field for user defined functions"
|
43
|
-
)
|
44
|
-
return values
|
45
|
-
|
46
|
-
@pydantic.model_validator(mode="before")
|
47
|
-
@classmethod
|
48
|
-
def _parse_state_preparation(cls, values: Any) -> dict[str, Any]:
|
49
|
-
if isinstance(values, dict):
|
50
|
-
parse_function_params_values(
|
51
|
-
values=values,
|
52
|
-
params_key="state_preparation_params",
|
53
|
-
discriminator_key="state_preparation",
|
54
|
-
param_classes={StatePreparation, CustomFunction},
|
55
|
-
default_parser_class=CustomFunction,
|
56
|
-
)
|
57
|
-
return values
|
58
|
-
|
59
|
-
@pydantic.field_validator("variables")
|
60
|
-
@classmethod
|
61
|
-
def _validate_variables(
|
62
|
-
cls, variables: list[RegisterUserInput]
|
63
|
-
) -> list[RegisterUserInput]:
|
64
|
-
names = {reg.name for reg in variables}
|
65
|
-
assert len(variables) == len(names), "Repeating names not allowed"
|
66
|
-
return variables
|
67
|
-
|
68
|
-
@pydantic.field_validator("state_preparation_params")
|
69
|
-
@classmethod
|
70
|
-
def _validate_state_preparation(
|
71
|
-
cls, state_preparation_params: GroverStatePreparation, info: ValidationInfo
|
72
|
-
) -> GroverStatePreparation:
|
73
|
-
variables = info.data.get("variables", list())
|
74
|
-
sp_inputs = state_preparation_params.inputs_full(strict_zero_ios=False)
|
75
|
-
sp_outputs = state_preparation_params.outputs
|
76
|
-
if len(sp_inputs) == 1 and len(sp_outputs) == 1:
|
77
|
-
var_size = sum(reg.size for reg in variables)
|
78
|
-
assert (
|
79
|
-
state_preparation_params.num_input_qubits(strict_zero_ios=False)
|
80
|
-
== var_size
|
81
|
-
)
|
82
|
-
assert state_preparation_params.num_output_qubits == var_size
|
83
|
-
else:
|
84
|
-
variable_names_and_sizes = cls._names_and_sizes(
|
85
|
-
{var.name: var for var in variables}
|
86
|
-
)
|
87
|
-
assert cls._names_and_sizes(sp_inputs) == variable_names_and_sizes
|
88
|
-
assert cls._names_and_sizes(sp_outputs) == variable_names_and_sizes
|
89
|
-
return state_preparation_params
|
90
|
-
|
91
|
-
@staticmethod
|
92
|
-
def _names_and_sizes(transputs: ArithmeticIODict) -> set[tuple[str, int]]:
|
93
|
-
return {(name, reg.size) for name, reg in transputs.items()}
|
@@ -1,106 +0,0 @@
|
|
1
|
-
from typing import Any, Optional
|
2
|
-
|
3
|
-
import pydantic
|
4
|
-
from pydantic_core.core_schema import ValidationInfo
|
5
|
-
|
6
|
-
from classiq.interface.exceptions import ClassiqValueError
|
7
|
-
from classiq.interface.generator.function_params import (
|
8
|
-
FunctionParams,
|
9
|
-
FunctionParamsDiscriminator,
|
10
|
-
parse_function_params,
|
11
|
-
)
|
12
|
-
from classiq.interface.generator.grover_diffuser import (
|
13
|
-
GroverDiffuser,
|
14
|
-
GroverStatePreparation,
|
15
|
-
)
|
16
|
-
from classiq.interface.generator.oracles import ArithmeticOracle, OracleABC
|
17
|
-
from classiq.interface.generator.oracles.oracle_function_param_list import (
|
18
|
-
oracle_function_param_library,
|
19
|
-
)
|
20
|
-
from classiq.interface.generator.range_types import NonNegativeFloatRange
|
21
|
-
from classiq.interface.generator.state_preparation import Metrics, StatePreparation
|
22
|
-
|
23
|
-
_DEFAULT_ORACLE_DISCRIMINATOR: FunctionParamsDiscriminator = (
|
24
|
-
ArithmeticOracle.discriminator()
|
25
|
-
)
|
26
|
-
|
27
|
-
|
28
|
-
class GroverOperator(FunctionParams):
|
29
|
-
oracle: str = pydantic.Field(
|
30
|
-
default=_DEFAULT_ORACLE_DISCRIMINATOR,
|
31
|
-
description="Oracle function",
|
32
|
-
validate_default=True,
|
33
|
-
)
|
34
|
-
oracle_params: OracleABC = pydantic.Field(description="Oracle function parameters")
|
35
|
-
state_preparation: str = pydantic.Field(
|
36
|
-
default="",
|
37
|
-
description="State preparation function",
|
38
|
-
validate_default=True,
|
39
|
-
)
|
40
|
-
state_preparation_params: GroverStatePreparation = pydantic.Field(
|
41
|
-
default=None,
|
42
|
-
description="State preparation function parameters",
|
43
|
-
validate_default=True,
|
44
|
-
)
|
45
|
-
|
46
|
-
def _create_ios(self) -> None:
|
47
|
-
self._inputs = {**self.oracle_params.inputs}
|
48
|
-
self._outputs = {**self.oracle_params.outputs}
|
49
|
-
|
50
|
-
@pydantic.model_validator(mode="before")
|
51
|
-
@classmethod
|
52
|
-
def _parse_oracle(cls, values: Any) -> dict[str, Any]:
|
53
|
-
if isinstance(values, dict):
|
54
|
-
oracle_params = values.get("oracle_params")
|
55
|
-
if isinstance(oracle_params, dict):
|
56
|
-
values["oracle_params"] = parse_function_params(
|
57
|
-
params=oracle_params,
|
58
|
-
discriminator=values.get("oracle", _DEFAULT_ORACLE_DISCRIMINATOR),
|
59
|
-
param_classes=oracle_function_param_library.param_list,
|
60
|
-
no_discriminator_error=ClassiqValueError("Invalid oracle name"),
|
61
|
-
bad_function_error=ClassiqValueError("Invalid oracle params"),
|
62
|
-
)
|
63
|
-
elif isinstance(oracle_params, FunctionParams):
|
64
|
-
values["oracle"] = oracle_params.discriminator()
|
65
|
-
else:
|
66
|
-
raise ClassiqValueError("Invalid oracle params")
|
67
|
-
return values
|
68
|
-
|
69
|
-
@pydantic.field_validator("state_preparation_params", mode="before")
|
70
|
-
@classmethod
|
71
|
-
def _validate_state_preparation(
|
72
|
-
cls,
|
73
|
-
state_preparation_params: Optional[GroverStatePreparation],
|
74
|
-
info: ValidationInfo,
|
75
|
-
) -> GroverStatePreparation:
|
76
|
-
oracle = info.data.get("oracle_params")
|
77
|
-
assert oracle is not None, "Must receive an oracle"
|
78
|
-
state_preparation_params = (
|
79
|
-
state_preparation_params
|
80
|
-
or cls._default_state_preparation_params(
|
81
|
-
num_qubits=oracle.num_input_qubits(strict_zero_ios=True)
|
82
|
-
)
|
83
|
-
)
|
84
|
-
assert GroverDiffuser(
|
85
|
-
state_preparation_params=state_preparation_params,
|
86
|
-
state_preparation=info.data.get("state_preparation", ""),
|
87
|
-
variables=oracle.variables(),
|
88
|
-
), "Cannot construct a GroverDiffuser"
|
89
|
-
return state_preparation_params
|
90
|
-
|
91
|
-
@staticmethod
|
92
|
-
def _default_state_preparation_params(num_qubits: int) -> StatePreparation:
|
93
|
-
num_states: int = 2**num_qubits
|
94
|
-
return StatePreparation(
|
95
|
-
probabilities=[1.0 / float(num_states)] * num_states,
|
96
|
-
error_metric={
|
97
|
-
Metrics.L2: NonNegativeFloatRange(lower_bound=0.0, upper_bound=0.0)
|
98
|
-
},
|
99
|
-
)
|
100
|
-
|
101
|
-
def get_diffuser(self) -> GroverDiffuser:
|
102
|
-
return GroverDiffuser(
|
103
|
-
variables=self.oracle_params.variables(),
|
104
|
-
state_preparation=self.state_preparation,
|
105
|
-
state_preparation_params=self.state_preparation_params,
|
106
|
-
)
|
@@ -1,82 +0,0 @@
|
|
1
|
-
import ast
|
2
|
-
import re
|
3
|
-
|
4
|
-
import numexpr # type: ignore[import]
|
5
|
-
|
6
|
-
from classiq.interface.exceptions import ClassiqArithmeticError, ClassiqValueError
|
7
|
-
from classiq.interface.generator.arith import number_utils
|
8
|
-
from classiq.interface.generator.arith.arithmetic import Arithmetic
|
9
|
-
from classiq.interface.generator.arith.arithmetic_expression_abc import (
|
10
|
-
ArithmeticExpressionABC,
|
11
|
-
)
|
12
|
-
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
13
|
-
from classiq.interface.generator.oracles.oracle_abc import (
|
14
|
-
ArithmeticIODict,
|
15
|
-
OracleABC,
|
16
|
-
VariableBinResultMap,
|
17
|
-
VariableTypedResultMap,
|
18
|
-
)
|
19
|
-
|
20
|
-
|
21
|
-
class ArithmeticOracle(OracleABC[float], ArithmeticExpressionABC):
|
22
|
-
@staticmethod
|
23
|
-
def _validate_ast_obj(ast_obj: ast.AST) -> None:
|
24
|
-
if not isinstance(ast_obj, ast.Expression):
|
25
|
-
raise ClassiqValueError("Must be an expression")
|
26
|
-
if not isinstance(ast_obj.body, (ast.Compare, ast.BoolOp)):
|
27
|
-
raise ClassiqValueError("Must be a comparison expression")
|
28
|
-
|
29
|
-
def get_arithmetic_expression_params(self) -> Arithmetic:
|
30
|
-
return Arithmetic(
|
31
|
-
machine_precision=self.machine_precision,
|
32
|
-
expression=self.expression,
|
33
|
-
definitions=self.definitions,
|
34
|
-
uncomputation_method=self.uncomputation_method,
|
35
|
-
qubit_count=self.qubit_count,
|
36
|
-
target=RegisterArithmeticInfo(size=1),
|
37
|
-
inputs_to_save=set(self.definitions.keys()),
|
38
|
-
)
|
39
|
-
|
40
|
-
def _get_register_transputs(self) -> ArithmeticIODict:
|
41
|
-
return {
|
42
|
-
name: register
|
43
|
-
for name, register in self.definitions.items()
|
44
|
-
if name in self._get_literal_set()
|
45
|
-
and isinstance(register, RegisterArithmeticInfo)
|
46
|
-
}
|
47
|
-
|
48
|
-
def is_good_result(self, problem_result: VariableTypedResultMap[float]) -> bool:
|
49
|
-
expression = self._simplify_negations_of_boolean_variables(
|
50
|
-
expression=self.expression, input_definitions=self.inputs
|
51
|
-
)
|
52
|
-
for var_name, value in problem_result.items():
|
53
|
-
expression = re.sub(r"\b" + var_name + r"\b", str(value), expression)
|
54
|
-
try:
|
55
|
-
return bool(numexpr.evaluate(expression).item())
|
56
|
-
except TypeError:
|
57
|
-
raise ClassiqArithmeticError(
|
58
|
-
f"Cannot evaluate expression {expression}"
|
59
|
-
) from None
|
60
|
-
|
61
|
-
@staticmethod
|
62
|
-
def _simplify_negations_of_boolean_variables(
|
63
|
-
expression: str, input_definitions: dict[str, RegisterArithmeticInfo]
|
64
|
-
) -> str:
|
65
|
-
for var_name in input_definitions:
|
66
|
-
if getattr(input_definitions[var_name], "size", 0) == 1:
|
67
|
-
expression = re.sub(
|
68
|
-
rf"~\s*{var_name}\b", f"(1 - {var_name})", expression
|
69
|
-
)
|
70
|
-
return expression
|
71
|
-
|
72
|
-
def binary_result_to_typed_result(
|
73
|
-
self, bin_result: VariableBinResultMap
|
74
|
-
) -> VariableTypedResultMap[float]:
|
75
|
-
typed_result: VariableTypedResultMap[float] = {}
|
76
|
-
for var_name, var_string in bin_result.items():
|
77
|
-
var = self.inputs[var_name]
|
78
|
-
var_value = number_utils.binary_to_float_or_int(
|
79
|
-
var_string, var.fraction_places, var.is_signed
|
80
|
-
)
|
81
|
-
typed_result[var_name] = var_value
|
82
|
-
return typed_result
|
@@ -1,65 +0,0 @@
|
|
1
|
-
from typing import Any
|
2
|
-
|
3
|
-
import pydantic
|
4
|
-
|
5
|
-
from classiq.interface.exceptions import ClassiqValueError
|
6
|
-
from classiq.interface.generator.function_params import parse_function_params_values
|
7
|
-
from classiq.interface.generator.oracles.oracle_abc import (
|
8
|
-
ArithmeticIODict,
|
9
|
-
OracleABC,
|
10
|
-
VariableBinResultMap,
|
11
|
-
VariableTypedResultMap,
|
12
|
-
)
|
13
|
-
from classiq.interface.generator.user_defined_function_params import CustomFunction
|
14
|
-
|
15
|
-
QubitState = str
|
16
|
-
|
17
|
-
|
18
|
-
class CustomOracle(OracleABC[QubitState]):
|
19
|
-
custom_oracle: str = pydantic.Field(description="Oracle function")
|
20
|
-
custom_oracle_params: CustomFunction = pydantic.Field(
|
21
|
-
description="Oracle function parameters",
|
22
|
-
default_factory=CustomFunction,
|
23
|
-
)
|
24
|
-
|
25
|
-
@pydantic.model_validator(mode="before")
|
26
|
-
@classmethod
|
27
|
-
def _parse_oracle(cls, values: Any) -> dict[str, Any]:
|
28
|
-
if isinstance(values, dict):
|
29
|
-
parse_function_params_values(
|
30
|
-
values=values,
|
31
|
-
params_key="custom_oracle_params",
|
32
|
-
discriminator_key="custom_oracle",
|
33
|
-
param_classes={CustomFunction},
|
34
|
-
default_parser_class=CustomFunction,
|
35
|
-
)
|
36
|
-
return values
|
37
|
-
|
38
|
-
@pydantic.field_validator("custom_oracle_params")
|
39
|
-
@classmethod
|
40
|
-
def _validate_names_match_oracle(
|
41
|
-
cls, custom_oracle_params: CustomFunction
|
42
|
-
) -> CustomFunction:
|
43
|
-
if set(custom_oracle_params.input_decls.keys()) != set(
|
44
|
-
custom_oracle_params.output_decls.keys()
|
45
|
-
):
|
46
|
-
raise ClassiqValueError("Oracle IO names must be identical")
|
47
|
-
if any(
|
48
|
-
custom_oracle_params.output_decls[name].size != input_decl.size
|
49
|
-
for name, input_decl in custom_oracle_params.input_decls.items()
|
50
|
-
):
|
51
|
-
raise ClassiqValueError("Oracle IO sizes must be identical")
|
52
|
-
return custom_oracle_params
|
53
|
-
|
54
|
-
def _get_register_transputs(self) -> ArithmeticIODict:
|
55
|
-
return {**self.custom_oracle_params.input_decls}
|
56
|
-
|
57
|
-
def binary_result_to_typed_result(
|
58
|
-
self, bin_result: VariableBinResultMap
|
59
|
-
) -> VariableTypedResultMap[QubitState]:
|
60
|
-
return bin_result
|
61
|
-
|
62
|
-
def is_good_result(
|
63
|
-
self, problem_result: VariableTypedResultMap[QubitState]
|
64
|
-
) -> bool:
|
65
|
-
return True
|
@@ -1,76 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
from collections.abc import Sequence
|
3
|
-
from typing import Generic, Optional, TypeVar
|
4
|
-
|
5
|
-
import numpy as np
|
6
|
-
|
7
|
-
from classiq.interface.exceptions import ClassiqOracleError
|
8
|
-
from classiq.interface.executor.result import State
|
9
|
-
from classiq.interface.generator.arith.register_user_input import RegisterUserInput
|
10
|
-
from classiq.interface.generator.function_params import ArithmeticIODict, FunctionParams
|
11
|
-
from classiq.interface.generator.generated_circuit_data import IOQubitMapping
|
12
|
-
|
13
|
-
ProblemResultType = TypeVar("ProblemResultType")
|
14
|
-
|
15
|
-
VariableBinResultMap = dict[str, State]
|
16
|
-
VariableTypedResultMap = dict[str, ProblemResultType]
|
17
|
-
|
18
|
-
|
19
|
-
class OracleABC(abc.ABC, FunctionParams, Generic[ProblemResultType]):
|
20
|
-
def get_power_order(self) -> Optional[int]:
|
21
|
-
return 2
|
22
|
-
|
23
|
-
@abc.abstractmethod
|
24
|
-
def _get_register_transputs(self) -> ArithmeticIODict:
|
25
|
-
pass
|
26
|
-
|
27
|
-
def _create_ios(self) -> None:
|
28
|
-
self._inputs = self._get_register_transputs()
|
29
|
-
self._outputs = {**self._inputs}
|
30
|
-
|
31
|
-
def is_good_state(self, state: str, indices: IOQubitMapping) -> bool:
|
32
|
-
bin_result = self.split_state_by_variables(state, indices)
|
33
|
-
problem_result = self.binary_result_to_typed_result(bin_result)
|
34
|
-
return self.is_good_result(problem_result)
|
35
|
-
|
36
|
-
def split_state_by_variables(
|
37
|
-
self, state: str, indices: IOQubitMapping
|
38
|
-
) -> VariableBinResultMap:
|
39
|
-
self._check_indices(indices)
|
40
|
-
|
41
|
-
input_values: VariableBinResultMap = {}
|
42
|
-
state_as_array = np.array(list(state))
|
43
|
-
for var_name, var_indices in indices.items():
|
44
|
-
var_string = "".join(
|
45
|
-
state_as_array[sorted(_reverse_endianness(var_indices, len(state)))]
|
46
|
-
)
|
47
|
-
input_values[var_name] = var_string
|
48
|
-
return input_values
|
49
|
-
|
50
|
-
@abc.abstractmethod
|
51
|
-
def binary_result_to_typed_result(
|
52
|
-
self, bin_result: VariableBinResultMap
|
53
|
-
) -> VariableTypedResultMap[ProblemResultType]:
|
54
|
-
pass
|
55
|
-
|
56
|
-
@abc.abstractmethod
|
57
|
-
def is_good_result(
|
58
|
-
self, problem_result: VariableTypedResultMap[ProblemResultType]
|
59
|
-
) -> bool:
|
60
|
-
pass
|
61
|
-
|
62
|
-
def variables(self) -> list[RegisterUserInput]:
|
63
|
-
return [
|
64
|
-
RegisterUserInput.from_arithmetic_info(info=info, name=name)
|
65
|
-
for name, info in self._inputs.items()
|
66
|
-
]
|
67
|
-
|
68
|
-
def _check_indices(self, indices: IOQubitMapping) -> None:
|
69
|
-
if set(indices.keys()) != {reg.name for reg in self.variables()}:
|
70
|
-
raise ClassiqOracleError(
|
71
|
-
"Argument name mismatch between indices and registers"
|
72
|
-
)
|
73
|
-
|
74
|
-
|
75
|
-
def _reverse_endianness(indices: Sequence[int], state_length: int) -> list[int]:
|
76
|
-
return [state_length - 1 - index for index in indices]
|
@@ -1,6 +0,0 @@
|
|
1
|
-
from classiq.interface.generator.function_param_library import FunctionParamLibrary
|
2
|
-
from classiq.interface.generator.oracles import ArithmeticOracle, CustomOracle
|
3
|
-
|
4
|
-
oracle_function_param_library: FunctionParamLibrary = FunctionParamLibrary(
|
5
|
-
param_list=[ArithmeticOracle, CustomOracle]
|
6
|
-
)
|
@@ -1,165 +0,0 @@
|
|
1
|
-
import math
|
2
|
-
from collections.abc import Sequence
|
3
|
-
from typing import Any, Generic, TypeVar
|
4
|
-
|
5
|
-
import pydantic
|
6
|
-
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
7
|
-
from pydantic_core.core_schema import ValidationInfo
|
8
|
-
|
9
|
-
from classiq.interface.exceptions import ClassiqError
|
10
|
-
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
11
|
-
from classiq.interface.generator.function_params import FunctionParams
|
12
|
-
from classiq.interface.helpers.hashable_pydantic_base_model import (
|
13
|
-
HashablePydanticBaseModel,
|
14
|
-
)
|
15
|
-
|
16
|
-
STATE_NAME: str = "state"
|
17
|
-
TARGET_NAME: str = "target"
|
18
|
-
_REL_TOLERANCE: float = 0.01
|
19
|
-
|
20
|
-
Breakpoint = TypeVar("Breakpoint")
|
21
|
-
|
22
|
-
|
23
|
-
class AffineMap(HashablePydanticBaseModel):
|
24
|
-
slope: float = Field(default=1.0)
|
25
|
-
offset: float = Field(default=0.0)
|
26
|
-
|
27
|
-
def evaluate(self, x: float) -> float:
|
28
|
-
return self.offset + self.slope * x
|
29
|
-
|
30
|
-
def image_bounds(self, domain_bounds: tuple[float, float]) -> tuple[float, float]:
|
31
|
-
return self.evaluate(domain_bounds[0]), self.evaluate(domain_bounds[1])
|
32
|
-
|
33
|
-
model_config = ConfigDict(frozen=True)
|
34
|
-
|
35
|
-
|
36
|
-
class PiecewiseLinearAmplitudeLoadingABC(
|
37
|
-
FunctionParams, BaseModel, Generic[Breakpoint]
|
38
|
-
):
|
39
|
-
num_qubits: int = Field()
|
40
|
-
breakpoints: Sequence[int] = Field()
|
41
|
-
affine_maps: Sequence[AffineMap] = Field()
|
42
|
-
|
43
|
-
def _create_ios(self) -> None:
|
44
|
-
self._inputs = {
|
45
|
-
STATE_NAME: RegisterArithmeticInfo(size=self.num_qubits),
|
46
|
-
TARGET_NAME: RegisterArithmeticInfo(size=1),
|
47
|
-
}
|
48
|
-
self._outputs = {**self._inputs}
|
49
|
-
|
50
|
-
@property
|
51
|
-
def _max_index(self) -> int:
|
52
|
-
return 2**self.num_qubits - 1
|
53
|
-
|
54
|
-
def _get_image_bounds(self) -> tuple[float, float]:
|
55
|
-
piece_bounds: Sequence[tuple[float, float]] = [
|
56
|
-
affine_map.image_bounds((self.breakpoints[idx], self.breakpoints[idx + 1]))
|
57
|
-
for idx, affine_map in enumerate(self.affine_maps)
|
58
|
-
]
|
59
|
-
bottom = min(min(piece) for piece in piece_bounds)
|
60
|
-
top = max(max(piece) for piece in piece_bounds)
|
61
|
-
return bottom, top
|
62
|
-
|
63
|
-
@field_validator("breakpoints", mode="before")
|
64
|
-
@classmethod
|
65
|
-
def _validate_breakpoints(cls, breakpoints: Sequence[int]) -> Sequence[int]:
|
66
|
-
return cls.validate_breakpoints(breakpoints)
|
67
|
-
|
68
|
-
@classmethod
|
69
|
-
def validate_breakpoints(cls, breakpoints: Sequence[int]) -> Sequence[int]:
|
70
|
-
assert len(breakpoints) == len(
|
71
|
-
set(breakpoints)
|
72
|
-
), "Repeated breakpoints encountered"
|
73
|
-
assert list(breakpoints) == sorted(breakpoints), "Breakpoints not sorted"
|
74
|
-
return list(map(int, breakpoints))
|
75
|
-
|
76
|
-
@pydantic.model_validator(mode="before")
|
77
|
-
@classmethod
|
78
|
-
def _validate_lengths(cls, values: Any) -> dict[str, Any]:
|
79
|
-
breakpoints = values.get("breakpoints", list())
|
80
|
-
affine_maps = values.get("affine_maps", list())
|
81
|
-
num_qubits = values.get("num_qubits", int)
|
82
|
-
if isinstance(values, dict):
|
83
|
-
breakpoints = values.get("breakpoints", list())
|
84
|
-
affine_maps = values.get("affine_maps", list())
|
85
|
-
num_qubits = values.get("num_qubits", int)
|
86
|
-
elif isinstance(values, PiecewiseLinearAmplitudeLoadingABC):
|
87
|
-
breakpoints = values.breakpoints
|
88
|
-
affine_maps = values.affine_maps
|
89
|
-
num_qubits = values.num_qubits
|
90
|
-
values = values.__dict__
|
91
|
-
|
92
|
-
assert len(breakpoints) - 1 == len(
|
93
|
-
affine_maps
|
94
|
-
), "Size mismatch between the number of slopes and breakpoints. The number of breakpoints should be the number of slopes + 1"
|
95
|
-
assert (
|
96
|
-
len(breakpoints) <= num_qubits**2
|
97
|
-
), "Number of breakpoints must be equal to or smaller than num_qubits**2"
|
98
|
-
return values
|
99
|
-
|
100
|
-
|
101
|
-
class PiecewiseLinearRotationAmplitudeLoading(PiecewiseLinearAmplitudeLoadingABC[int]):
|
102
|
-
pass
|
103
|
-
|
104
|
-
@field_validator("breakpoints")
|
105
|
-
@classmethod
|
106
|
-
def _validate_breakpoints_field(
|
107
|
-
cls, breakpoints: Sequence[int], info: ValidationInfo
|
108
|
-
) -> Sequence[int]:
|
109
|
-
num_qubits = info.data.get("num_qubits")
|
110
|
-
assert isinstance(num_qubits, int), "Must have an integer number of qubits"
|
111
|
-
assert min(breakpoints) == 0, "First breakpoint must be 0"
|
112
|
-
assert (
|
113
|
-
max(breakpoints) == 2**num_qubits - 1
|
114
|
-
), f"Last breakpoint must be {2**num_qubits - 1}"
|
115
|
-
return PiecewiseLinearAmplitudeLoadingABC.validate_breakpoints(
|
116
|
-
breakpoints=breakpoints
|
117
|
-
)
|
118
|
-
|
119
|
-
|
120
|
-
class PiecewiseLinearAmplitudeLoading(PiecewiseLinearAmplitudeLoadingABC[float]):
|
121
|
-
rescaling_factor: float = Field(default=0.25 * math.pi)
|
122
|
-
|
123
|
-
def rescaled(self) -> PiecewiseLinearRotationAmplitudeLoading:
|
124
|
-
c, d = self._get_image_bounds()
|
125
|
-
if math.isclose(c, d):
|
126
|
-
raise ClassiqError("Cannot rescale flat linear maps")
|
127
|
-
|
128
|
-
a, b = self.breakpoints[0], self.breakpoints[-1]
|
129
|
-
|
130
|
-
normalized_breakpoints: list[int] = [
|
131
|
-
round(self._max_index * (point - a) / (b - a)) for point in self.breakpoints
|
132
|
-
]
|
133
|
-
|
134
|
-
normalized_affine_maps: list[AffineMap] = list()
|
135
|
-
for affine_map in self.affine_maps:
|
136
|
-
normalized_slope = (
|
137
|
-
2 * affine_map.slope * self.rescaling_factor * (b - a)
|
138
|
-
) / (self._max_index * (d - c))
|
139
|
-
normalized_offset = (
|
140
|
-
(2 * self.rescaling_factor * (affine_map.evaluate(a) - c)) / (d - c)
|
141
|
-
- self.rescaling_factor
|
142
|
-
+ math.pi / 4
|
143
|
-
)
|
144
|
-
normalized_affine_maps.append(
|
145
|
-
AffineMap(slope=normalized_slope, offset=normalized_offset)
|
146
|
-
)
|
147
|
-
return PiecewiseLinearRotationAmplitudeLoading(
|
148
|
-
num_qubits=self.num_qubits,
|
149
|
-
breakpoints=normalized_breakpoints,
|
150
|
-
affine_maps=normalized_affine_maps,
|
151
|
-
)
|
152
|
-
|
153
|
-
@staticmethod
|
154
|
-
def _descaled_value(
|
155
|
-
*, scaled_expectation_value: float, rescaling_factor: float
|
156
|
-
) -> float:
|
157
|
-
return 0.5 * ((scaled_expectation_value - 0.5) / rescaling_factor + 1)
|
158
|
-
|
159
|
-
def compute_expectation_value(self, scaled_expectation_value: float) -> float:
|
160
|
-
bounds = self._get_image_bounds()
|
161
|
-
image_bottom, image_top = min(bounds), max(bounds)
|
162
|
-
return image_bottom + (image_top - image_bottom) * self._descaled_value(
|
163
|
-
rescaling_factor=self.rescaling_factor,
|
164
|
-
scaled_expectation_value=scaled_expectation_value,
|
165
|
-
)
|