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.
Files changed (96) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/applications/chemistry/hartree_fock.py +5 -1
  3. classiq/applications/chemistry/op_utils.py +2 -2
  4. classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
  5. classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
  6. classiq/applications/combinatorial_helpers/memory.py +4 -4
  7. classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
  8. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
  9. classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
  10. classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
  11. classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
  12. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
  13. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
  14. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
  15. classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
  16. classiq/applications/hamiltonian/pauli_decomposition.py +33 -1
  17. classiq/evaluators/argument_types.py +15 -6
  18. classiq/evaluators/parameter_types.py +43 -39
  19. classiq/evaluators/qmod_annotated_expression.py +88 -11
  20. classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
  21. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +54 -11
  22. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +40 -25
  23. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +29 -59
  24. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +12 -5
  25. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
  26. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +21 -14
  27. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +9 -5
  28. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +20 -1
  29. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
  30. classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
  31. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
  32. classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
  33. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +2 -3
  34. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +48 -21
  35. classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
  36. classiq/evaluators/qmod_node_evaluators/utils.py +27 -5
  37. classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
  38. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +292 -0
  39. classiq/evaluators/quantum_type_utils.py +0 -131
  40. classiq/execution/execution_session.py +1 -1
  41. classiq/execution/qnn.py +4 -1
  42. classiq/execution/user_budgets.py +1 -1
  43. classiq/interface/_version.py +1 -1
  44. classiq/interface/backend/backend_preferences.py +10 -30
  45. classiq/interface/backend/quantum_backend_providers.py +63 -52
  46. classiq/interface/generator/arith/binary_ops.py +107 -115
  47. classiq/interface/generator/arith/extremum_operations.py +33 -45
  48. classiq/interface/generator/arith/number_utils.py +4 -1
  49. classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
  50. classiq/interface/generator/compiler_keywords.py +2 -0
  51. classiq/interface/generator/function_param_list.py +133 -5
  52. classiq/interface/generator/functions/classical_type.py +59 -2
  53. classiq/interface/generator/functions/qmod_python_interface.py +15 -0
  54. classiq/interface/generator/functions/type_name.py +6 -0
  55. classiq/interface/generator/model/preferences/preferences.py +1 -17
  56. classiq/interface/generator/quantum_program.py +1 -13
  57. classiq/interface/helpers/model_normalizer.py +2 -2
  58. classiq/interface/helpers/text_utils.py +7 -2
  59. classiq/interface/interface_version.py +1 -1
  60. classiq/interface/model/classical_if.py +40 -0
  61. classiq/interface/model/handle_binding.py +28 -16
  62. classiq/interface/model/quantum_type.py +61 -2
  63. classiq/interface/pretty_print/expression_to_qmod.py +24 -11
  64. classiq/interface/pyomo_extension/__init__.py +0 -4
  65. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
  66. classiq/model_expansions/arithmetic.py +43 -1
  67. classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
  68. classiq/model_expansions/capturing/captured_vars.py +2 -5
  69. classiq/model_expansions/quantum_operations/allocate.py +22 -15
  70. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
  71. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
  72. classiq/model_expansions/quantum_operations/bind.py +15 -7
  73. classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
  74. classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
  75. classiq/open_library/functions/__init__.py +3 -0
  76. classiq/open_library/functions/lcu.py +117 -0
  77. classiq/qmod/builtins/enums.py +2 -2
  78. classiq/qmod/builtins/structs.py +33 -18
  79. classiq/qmod/pretty_print/expression_to_python.py +7 -9
  80. {classiq-0.86.1.dist-info → classiq-0.87.0.dist-info}/METADATA +3 -3
  81. {classiq-0.86.1.dist-info → classiq-0.87.0.dist-info}/RECORD +83 -89
  82. classiq/interface/generator/amplitude_estimation.py +0 -34
  83. classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
  84. classiq/interface/generator/grover_diffuser.py +0 -93
  85. classiq/interface/generator/grover_operator.py +0 -106
  86. classiq/interface/generator/oracles/__init__.py +0 -3
  87. classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
  88. classiq/interface/generator/oracles/custom_oracle.py +0 -65
  89. classiq/interface/generator/oracles/oracle_abc.py +0 -76
  90. classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
  91. classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
  92. classiq/interface/generator/qpe.py +0 -169
  93. classiq/interface/grover/grover_modelling_params.py +0 -13
  94. classiq/model_expansions/transformers/var_splitter.py +0 -224
  95. /classiq/{interface/grover → evaluators/qmod_type_inference}/__init__.py +0 -0
  96. {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,3 +0,0 @@
1
- from .arithmetic_oracle import ArithmeticOracle
2
- from .custom_oracle import CustomOracle
3
- from .oracle_abc import OracleABC
@@ -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
- )