classiq 0.42.2__py3-none-any.whl → 0.43.1__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 (113) hide show
  1. classiq/__init__.py +2 -6
  2. classiq/_internals/api_wrapper.py +6 -12
  3. classiq/_internals/authentication/token_manager.py +5 -2
  4. classiq/_internals/jobs.py +5 -10
  5. classiq/analyzer/rb.py +3 -3
  6. classiq/applications/chemistry/chemistry_model_constructor.py +12 -8
  7. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -2
  8. classiq/applications/finance/finance_model_constructor.py +16 -13
  9. classiq/applications/qsvm/__init__.py +1 -3
  10. classiq/applications/qsvm/qsvm_model_constructor.py +7 -6
  11. classiq/exceptions.py +9 -4
  12. classiq/execution/execution_session.py +5 -2
  13. classiq/execution/qnn.py +1 -1
  14. classiq/executor.py +0 -2
  15. classiq/interface/_version.py +1 -1
  16. classiq/interface/chemistry/operator.py +19 -5
  17. classiq/interface/executor/constants.py +1 -0
  18. classiq/interface/finance/function_input.py +16 -10
  19. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -2
  20. classiq/interface/generator/application_apis/qsvm_declarations.py +4 -2
  21. classiq/interface/generator/arith/argument_utils.py +20 -3
  22. classiq/interface/generator/arith/arithmetic_expression_validator.py +3 -26
  23. classiq/interface/generator/arith/binary_ops.py +8 -14
  24. classiq/interface/generator/arith/extremum_operations.py +30 -0
  25. classiq/interface/generator/arith/number_utils.py +1 -1
  26. classiq/interface/generator/arith/unary_ops.py +1 -3
  27. classiq/interface/generator/compiler_keywords.py +1 -1
  28. classiq/interface/generator/expressions/atomic_expression_functions.py +13 -3
  29. classiq/interface/generator/expressions/enums/__init__.py +0 -20
  30. classiq/interface/generator/expressions/enums/finance_functions.py +11 -18
  31. classiq/interface/generator/expressions/non_symbolic_expr.py +119 -0
  32. classiq/interface/generator/expressions/qmod_qarray_proxy.py +52 -37
  33. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +16 -11
  34. classiq/interface/generator/expressions/qmod_sized_proxy.py +5 -5
  35. classiq/interface/generator/function_param_list_without_self_reference.py +0 -10
  36. classiq/interface/generator/function_params.py +0 -4
  37. classiq/interface/generator/functions/__init__.py +0 -20
  38. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +2 -2
  39. classiq/interface/generator/functions/builtins/open_lib_functions.py +530 -1
  40. classiq/interface/generator/functions/classical_type.py +22 -69
  41. classiq/interface/generator/functions/port_declaration.py +0 -11
  42. classiq/interface/generator/model/__init__.py +0 -1
  43. classiq/interface/generator/model/model.py +9 -185
  44. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +3 -1
  45. classiq/interface/generator/types/builtin_enum_declarations.py +69 -0
  46. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +2 -2
  47. classiq/interface/generator/types/enum_declaration.py +57 -0
  48. classiq/interface/jobs.py +36 -65
  49. classiq/interface/model/bind_operation.py +3 -0
  50. classiq/interface/model/classical_parameter_declaration.py +3 -0
  51. classiq/interface/model/handle_binding.py +7 -0
  52. classiq/interface/model/inplace_binary_operation.py +13 -15
  53. classiq/interface/model/model.py +8 -20
  54. classiq/interface/model/native_function_definition.py +0 -17
  55. classiq/interface/model/quantum_function_call.py +63 -182
  56. classiq/interface/model/quantum_type.py +71 -10
  57. classiq/interface/server/routes.py +0 -6
  58. classiq/qmod/__init__.py +3 -3
  59. classiq/qmod/builtins/__init__.py +10 -1
  60. classiq/qmod/builtins/classical_execution_primitives.py +4 -2
  61. classiq/qmod/builtins/enums.py +177 -0
  62. classiq/qmod/builtins/functions.py +1 -2
  63. classiq/qmod/builtins/operations.py +2 -4
  64. classiq/qmod/builtins/structs.py +16 -17
  65. classiq/qmod/declaration_inferrer.py +23 -20
  66. classiq/qmod/model_state_container.py +2 -0
  67. classiq/qmod/native/pretty_printer.py +31 -13
  68. classiq/qmod/pretty_print/pretty_printer.py +52 -27
  69. classiq/qmod/qmod_constant.py +7 -3
  70. classiq/qmod/qmod_parameter.py +2 -1
  71. classiq/qmod/qmod_struct.py +9 -33
  72. classiq/qmod/qmod_variable.py +55 -22
  73. classiq/qmod/quantum_callable.py +6 -1
  74. classiq/qmod/quantum_expandable.py +29 -11
  75. classiq/qmod/quantum_function.py +8 -4
  76. classiq/qmod/semantics/annotation.py +38 -0
  77. classiq/qmod/semantics/error_manager.py +49 -0
  78. classiq/qmod/semantics/static_semantics_visitor.py +308 -0
  79. classiq/qmod/semantics/validation/func_call_validation.py +149 -0
  80. classiq/qmod/semantics/validation/types_validation.py +21 -0
  81. classiq/qmod/symbolic.py +6 -6
  82. classiq/qmod/symbolic_expr.py +26 -11
  83. classiq/qmod/utilities.py +23 -1
  84. {classiq-0.42.2.dist-info → classiq-0.43.1.dist-info}/METADATA +2 -2
  85. {classiq-0.42.2.dist-info → classiq-0.43.1.dist-info}/RECORD +88 -103
  86. classiq/_internals/_qfunc_ext.py +0 -6
  87. classiq/applications/libraries/ampltitude_estimation_library.py +0 -11
  88. classiq/interface/generator/credit_risk_example/linear_gci.py +0 -122
  89. classiq/interface/generator/credit_risk_example/weighted_adder.py +0 -69
  90. classiq/interface/generator/expressions/enums/chemistry.py +0 -28
  91. classiq/interface/generator/expressions/enums/classical_enum.py +0 -20
  92. classiq/interface/generator/expressions/enums/ladder_operator.py +0 -6
  93. classiq/interface/generator/expressions/enums/optimizers.py +0 -9
  94. classiq/interface/generator/expressions/enums/pauli.py +0 -8
  95. classiq/interface/generator/expressions/enums/qsvm_feature_map_entanglement.py +0 -9
  96. classiq/interface/generator/functions/foreign_function_definition.py +0 -114
  97. classiq/interface/generator/functions/function_implementation.py +0 -107
  98. classiq/interface/generator/functions/native_function_definition.py +0 -155
  99. classiq/interface/generator/functions/quantum_function_declaration.py +0 -69
  100. classiq/interface/generator/functions/register.py +0 -44
  101. classiq/interface/generator/functions/register_mapping_data.py +0 -106
  102. classiq/interface/generator/inequality_mixer.py +0 -51
  103. classiq/interface/generator/model/classical_main_validator.py +0 -106
  104. classiq/interface/generator/range_mixer.py +0 -56
  105. classiq/interface/generator/state_propagator.py +0 -74
  106. classiq/interface/model/resolvers/function_call_resolver.py +0 -64
  107. classiq/interface/model/validations/__init__.py +0 -0
  108. classiq/interface/model/validations/handle_validation_base.py +0 -55
  109. classiq/interface/model/validations/handles_validator.py +0 -153
  110. classiq/interface/model/validations/port_to_wire_name_generator.py +0 -12
  111. /classiq/{interface/generator/credit_risk_example → qmod/semantics}/__init__.py +0 -0
  112. /classiq/{interface/model/resolvers → qmod/semantics/validation}/__init__.py +0 -0
  113. {classiq-0.42.2.dist-info → classiq-0.43.1.dist-info}/WHEEL +0 -0
@@ -1,69 +0,0 @@
1
- from typing import Dict, Set
2
-
3
- import pydantic
4
- from pydantic import BaseModel
5
-
6
- from classiq.interface.generator.arith.register_user_input import RegisterUserInput
7
- from classiq.interface.generator.function_params import (
8
- ArithmeticIODict,
9
- IOName,
10
- PortDirection,
11
- )
12
- from classiq.interface.generator.functions.port_declaration import (
13
- SynthesisPortDeclaration,
14
- )
15
- from classiq.interface.helpers.validation_helpers import validate_nameables_mapping
16
-
17
-
18
- class SynthesisQuantumFunctionDeclaration(BaseModel):
19
- """
20
- Facilitates the creation of a common quantum function interface object.
21
- """
22
-
23
- name: str = pydantic.Field(description="The name of the function")
24
-
25
- port_declarations: Dict[IOName, SynthesisPortDeclaration] = pydantic.Field(
26
- description="The input and output ports of the function.",
27
- default_factory=dict,
28
- )
29
-
30
- @property
31
- def input_set(self) -> Set[IOName]:
32
- return set(self.inputs.keys())
33
-
34
- @property
35
- def output_set(self) -> Set[IOName]:
36
- return set(self.outputs.keys())
37
-
38
- @property
39
- def inputs(self) -> ArithmeticIODict:
40
- return _ports_to_registers(self.port_declarations, PortDirection.Input)
41
-
42
- @property
43
- def outputs(self) -> ArithmeticIODict:
44
- return _ports_to_registers(self.port_declarations, PortDirection.Output)
45
-
46
- @pydantic.validator("port_declarations")
47
- def _validate_port_declarations_names(
48
- cls, port_declarations: Dict[IOName, SynthesisPortDeclaration]
49
- ) -> Dict[IOName, SynthesisPortDeclaration]:
50
- validate_nameables_mapping(port_declarations, "Port")
51
- return port_declarations
52
-
53
- class Config:
54
- extra = pydantic.Extra.forbid
55
-
56
-
57
- def _ports_to_registers(
58
- port_declarations: Dict[IOName, SynthesisPortDeclaration], direction: PortDirection
59
- ) -> ArithmeticIODict:
60
- return {
61
- name: RegisterUserInput(
62
- name=name,
63
- size=port_decl.size,
64
- is_signed=port_decl.is_signed,
65
- fraction_places=port_decl.fraction_places,
66
- )
67
- for name, port_decl in port_declarations.items()
68
- if port_decl.direction.includes_port_direction(direction)
69
- }
@@ -1,44 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from operator import attrgetter
4
- from typing import Iterable, Tuple
5
-
6
- import pydantic
7
- from pydantic import BaseModel
8
-
9
- from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
10
-
11
- from classiq.exceptions import ClassiqValueError
12
-
13
- QubitsType = Tuple[pydantic.NonNegativeInt, ...]
14
-
15
-
16
- class Register(BaseModel):
17
- """
18
- A user-defined custom register.
19
- """
20
-
21
- name: PydanticNonEmptyString = pydantic.Field(
22
- description="The name of the custom register",
23
- )
24
-
25
- qubits: QubitsType = pydantic.Field(
26
- description="A tuple of qubits as integers as indexed within a custom function code",
27
- )
28
-
29
- @property
30
- def width(self) -> pydantic.PositiveInt:
31
- """The number of qubits of the custom register"""
32
- return len(self.qubits)
33
-
34
- @pydantic.validator("qubits")
35
- def validate_qubits(cls, qubits: QubitsType) -> QubitsType:
36
- if len(qubits) == 0:
37
- raise ClassiqValueError("qubits field must be non-empty.")
38
- if len(set(qubits)) != len(qubits):
39
- raise ClassiqValueError("All qubits of a register must be distinct.")
40
- return qubits
41
-
42
-
43
- def get_register_names(reg_list: Iterable[Register]) -> Iterable[str]:
44
- return map(attrgetter("name"), reg_list)
@@ -1,106 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import itertools
4
- from typing import Any, Dict, Iterable, List, Tuple
5
-
6
- import pydantic
7
-
8
- from classiq.interface.generator.functions.register import Register, get_register_names
9
- from classiq.interface.generator.register_role import RegisterRole as Role
10
- from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
11
-
12
- from classiq.exceptions import ClassiqValueError
13
-
14
- REGISTER_NOT_FOUND_ERROR = "Register name not found"
15
-
16
-
17
- class RegisterMappingData(pydantic.BaseModel):
18
- input_registers: List[Register] = pydantic.Field(default_factory=list)
19
- output_registers: List[Register] = pydantic.Field(default_factory=list)
20
- zero_input_registers: List[Register] = pydantic.Field(default_factory=list)
21
-
22
- @pydantic.root_validator()
23
- def validate_mapping(cls, values: Dict[str, Any]) -> Dict[str, Any]:
24
- input_registers = values.get("input_registers", list())
25
- output_registers = values.get("output_registers", list())
26
- zero_input_registers = values.get("zero_input_registers", list())
27
-
28
- input_qubits = cls._get_qubit_range(input_registers)
29
- output_qubits = cls._get_qubit_range(output_registers)
30
- zero_input_qubits = cls._get_qubit_range(zero_input_registers)
31
-
32
- all_input_qubits = sorted(input_qubits + zero_input_qubits)
33
- if not cls._validate_no_overlap(all_input_qubits):
34
- raise ClassiqValueError("overlapping input qubits are not allowed")
35
- if not cls._validate_no_overlap(output_qubits):
36
- raise ClassiqValueError("overlapping output qubits are not allowed")
37
-
38
- if not output_qubits == all_input_qubits:
39
- raise ClassiqValueError(
40
- "output registers should be included within the input / zero input registers"
41
- )
42
-
43
- return values
44
-
45
- @pydantic.validator("input_registers", "output_registers")
46
- def validate_input_registers_are_distinct(
47
- cls, field_value: List[Register]
48
- ) -> List[Register]:
49
- if len(field_value) != len({io_register.name for io_register in field_value}):
50
- raise ClassiqValueError(
51
- "The names of PortDirection registers must be distinct."
52
- )
53
- return field_value
54
-
55
- @staticmethod
56
- def _validate_no_overlap(reg_list: List[int]) -> bool:
57
- return len(reg_list) == len(set(reg_list))
58
-
59
- @staticmethod
60
- def _get_qubit_range(registers: Iterable[Register]) -> List[int]:
61
- return sorted(itertools.chain.from_iterable(reg.qubits for reg in registers))
62
-
63
- @property
64
- def input_names(self) -> Iterable[str]:
65
- return get_register_names(self.input_registers)
66
-
67
- @property
68
- def output_names(self) -> Iterable[str]:
69
- return get_register_names(self.output_registers)
70
-
71
- def validate_equal_mappings(self, other: RegisterMappingData) -> None:
72
- if any(
73
- [
74
- self.input_registers != other.input_registers,
75
- self.output_registers != other.output_registers,
76
- self.zero_input_registers != other.zero_input_registers,
77
- ]
78
- ):
79
- raise ClassiqValueError(
80
- "Interface should be identical in all implementations"
81
- )
82
-
83
- def get_input_register(self, name: PydanticNonEmptyString) -> Register:
84
- for reg in self.input_registers:
85
- if reg.name == name:
86
- return reg
87
- raise ClassiqValueError(REGISTER_NOT_FOUND_ERROR)
88
-
89
- def get_output_register(self, name: PydanticNonEmptyString) -> Register:
90
- for reg in self.output_registers:
91
- if reg.name == name:
92
- return reg
93
- raise ClassiqValueError(REGISTER_NOT_FOUND_ERROR)
94
-
95
- @staticmethod
96
- def from_registers_dict(
97
- regs_dict: Dict[Role, Tuple[Register, ...]]
98
- ) -> RegisterMappingData:
99
- return RegisterMappingData(
100
- input_registers=list(regs_dict[Role.INPUT]),
101
- output_registers=list(regs_dict[Role.OUTPUT]),
102
- zero_input_registers=list(regs_dict[Role.ZERO_INPUT]),
103
- )
104
-
105
- class Config:
106
- extra = "forbid"
@@ -1,51 +0,0 @@
1
- import pydantic
2
-
3
- from classiq.interface.generator import function_params
4
- from classiq.interface.generator.arith.argument_utils import RegisterOrConst
5
- from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
6
- from classiq.interface.generator.parameters import ParameterFloatType
7
-
8
- DATA_REG_INPUT_NAME: str = "data_reg_input"
9
- BOUND_REG_INPUT_NAME: str = "bound_reg_input"
10
-
11
- DATA_REG_OUTPUT_NAME: str = "data_reg_output"
12
- BOUND_REG_OUTPUT_NAME: str = "bound_reg_output"
13
-
14
-
15
- class InequalityMixer(function_params.FunctionParams):
16
- """
17
- Mixing a fixed point number variable below a given upper bound or above a given
18
- lower bound. i.e. after applying this function the variable will hold a
19
- superposition position of all the valid values.
20
- """
21
-
22
- data_reg_input: RegisterArithmeticInfo = pydantic.Field(
23
- description="The input variable to mix."
24
- )
25
-
26
- bound_reg_input: RegisterOrConst = pydantic.Field(
27
- description="Fixed number or variable that define the upper or lower bound for"
28
- " the mixing operation. In case of a fixed number bound, the value"
29
- " must be positive."
30
- )
31
-
32
- mixer_parameter: ParameterFloatType = pydantic.Field(
33
- description="The parameter used for rotation gates in the mixer.",
34
- is_exec_param=True,
35
- )
36
-
37
- is_less_inequality: bool = pydantic.Field(
38
- default=True,
39
- description="Whether to mix below or above a certain bound."
40
- "Less inequality mixes between 0 and the given bound."
41
- "Greater inequality mixes between the bound and the maximal number allowed by"
42
- " the number of qubits (i.e 2^n - 1).",
43
- )
44
-
45
- def _create_ios(self) -> None:
46
- self._inputs = {DATA_REG_INPUT_NAME: self.data_reg_input}
47
- self._outputs = {DATA_REG_OUTPUT_NAME: self.data_reg_input}
48
-
49
- if isinstance(self.bound_reg_input, RegisterArithmeticInfo):
50
- self._inputs[BOUND_REG_INPUT_NAME] = self.bound_reg_input
51
- self._outputs[BOUND_REG_OUTPUT_NAME] = self.bound_reg_input
@@ -1,106 +0,0 @@
1
- import ast
2
- from typing import Dict, List
3
-
4
- from classiq.executor import DEFAULT_RESULT_NAME
5
-
6
- STANDARD_CMAIN_BODY_LENGTH = 2 # assignment of sample call, save statement
7
-
8
-
9
- class NonStandardClassicalCodeError(Exception):
10
- pass
11
-
12
-
13
- # `is_standard_cmain` and `extract_sample_params` could easily be merged to one function, as they
14
- # are doing similar tasks, but we decided to separate them for the sake of a better interface
15
- def is_standard_cmain(model_classical_execution_code: str) -> bool:
16
- try:
17
- classical_body = _get_classical_body(model_classical_execution_code)
18
- if len(classical_body) != STANDARD_CMAIN_BODY_LENGTH:
19
- return False
20
-
21
- _assert_sample_call(classical_body)
22
- _assert_save_statement(classical_body)
23
-
24
- return True
25
- except NonStandardClassicalCodeError:
26
- return False
27
-
28
-
29
- def extract_sample_params(model_classical_execution_code: str) -> Dict[str, float]:
30
- classical_main = _get_classical_body(model_classical_execution_code)
31
-
32
- qmain_params: Dict[str, float] = {}
33
- sample_call = _get_sample_call(classical_main)
34
- if len(sample_call.args) == 1 and isinstance(sample_call.args[0], ast.Dict):
35
- ast_dict = sample_call.args[0]
36
- qmain_params = dict(
37
- zip(
38
- [k.value for k in ast_dict.keys if isinstance(k, ast.Constant)],
39
- [v.value for v in ast_dict.values if isinstance(v, ast.Constant)],
40
- )
41
- )
42
-
43
- return qmain_params
44
-
45
-
46
- def has_classical_exec(model_classical_execution_code: str) -> bool:
47
- return model_classical_execution_code != ""
48
-
49
-
50
- def _get_classical_body(model_classical_execution_code: str) -> List[ast.stmt]:
51
- if not has_classical_exec(model_classical_execution_code):
52
- raise NonStandardClassicalCodeError
53
- return ast.parse(model_classical_execution_code).body
54
-
55
-
56
- def _assert_sample_call(classical_body: List[ast.stmt]) -> None:
57
- _get_sample_call(classical_body)
58
-
59
-
60
- def _get_sample_call(
61
- classical_body: List[ast.stmt],
62
- ) -> ast.Call:
63
- classical_call = classical_body[0]
64
- if not isinstance(classical_call, ast.Assign):
65
- raise NonStandardClassicalCodeError
66
-
67
- if len(classical_call.targets) != 1:
68
- raise NonStandardClassicalCodeError
69
- target = classical_call.targets[0]
70
- if not isinstance(target, ast.Name) or target.id != DEFAULT_RESULT_NAME:
71
- raise NonStandardClassicalCodeError
72
-
73
- invoked_expression = classical_call.value
74
- if not isinstance(invoked_expression, ast.Call):
75
- raise NonStandardClassicalCodeError
76
- if (
77
- not isinstance(invoked_expression.func, ast.Name)
78
- or invoked_expression.func.id != "sample"
79
- ):
80
- raise NonStandardClassicalCodeError
81
-
82
- return invoked_expression
83
-
84
-
85
- def _assert_save_statement(classical_body: List[ast.stmt]) -> None:
86
- save_statement = classical_body[1]
87
- if not isinstance(save_statement, ast.Expr) or not isinstance(
88
- save_statement.value, ast.Call
89
- ):
90
- raise NonStandardClassicalCodeError
91
-
92
- call = save_statement.value
93
- if not isinstance(call.func, ast.Name) or call.func.id != "save":
94
- raise NonStandardClassicalCodeError
95
-
96
- if not len(call.args) == 1:
97
- raise NonStandardClassicalCodeError
98
-
99
- if (
100
- not isinstance(call.args[0], ast.Dict)
101
- or not isinstance(call.args[0].keys[0], ast.Constant)
102
- or call.args[0].keys[0].value != DEFAULT_RESULT_NAME
103
- or not isinstance(call.args[0].values[0], ast.Name)
104
- or call.args[0].values[0].id != DEFAULT_RESULT_NAME
105
- ):
106
- raise NonStandardClassicalCodeError
@@ -1,56 +0,0 @@
1
- import pydantic
2
-
3
- from classiq.interface.generator.arith.argument_utils import RegisterOrConst
4
- from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
5
- from classiq.interface.generator.function_params import FunctionParams
6
- from classiq.interface.generator.parameters import ParameterFloatType
7
-
8
- DATA_REG_INPUT_NAME: str = "data_reg_input"
9
- LOWER_BOUND_REG_INPUT_NAME: str = "lower_bound_reg_input"
10
- UPPER_BOUND_REG_INPUT_NAME: str = "upper_bound_reg_input"
11
-
12
-
13
- DATA_REG_OUTPUT_NAME: str = "data_reg_output"
14
- LOWER_BOUND_REG_OUTPUT_NAME: str = "lower_bound_reg_output"
15
- UPPER_BOUND_REG_OUTPUT_NAME: str = "upper_bound_reg_output"
16
-
17
-
18
- class RangeMixer(FunctionParams):
19
- """
20
- Mixing a fixed point number variable between a given lower and upper bounds.
21
- I.e. after applying this function the variable will hold a
22
- superposition of all the valid values.
23
- """
24
-
25
- data_reg_input: RegisterArithmeticInfo = pydantic.Field(
26
- description="The input variable to mix."
27
- )
28
-
29
- lower_bound_reg_input: RegisterOrConst = pydantic.Field(
30
- description="Fixed number or variable that define the lower bound for"
31
- " the mixing operation. In case of a fixed number bound, the value"
32
- " must be positive."
33
- )
34
-
35
- upper_bound_reg_input: RegisterOrConst = pydantic.Field(
36
- description="Fixed number or variable that define the upper bound for"
37
- " the mixing operation. In case of a fixed number bound, the value"
38
- " must be positive."
39
- )
40
-
41
- mixer_parameter: ParameterFloatType = pydantic.Field(
42
- description="The parameter used for rotation gates in the mixer.",
43
- is_exec_param=True,
44
- )
45
-
46
- def _create_ios(self) -> None:
47
- self._inputs = {DATA_REG_INPUT_NAME: self.data_reg_input}
48
- self._outputs = {DATA_REG_OUTPUT_NAME: self.data_reg_input}
49
-
50
- if isinstance(self.lower_bound_reg_input, RegisterArithmeticInfo):
51
- self._inputs[LOWER_BOUND_REG_INPUT_NAME] = self.lower_bound_reg_input
52
- self._outputs[LOWER_BOUND_REG_OUTPUT_NAME] = self.lower_bound_reg_input
53
-
54
- if isinstance(self.upper_bound_reg_input, RegisterArithmeticInfo):
55
- self._inputs[UPPER_BOUND_REG_INPUT_NAME] = self.upper_bound_reg_input
56
- self._outputs[UPPER_BOUND_REG_OUTPUT_NAME] = self.upper_bound_reg_input
@@ -1,74 +0,0 @@
1
- from typing import Any, Dict, List
2
-
3
- import numpy as np
4
- import pydantic
5
-
6
- from classiq.interface.generator import function_params
7
- from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
8
- from classiq.interface.generator.complex_type import Complex
9
- from classiq.interface.generator.function_params import (
10
- DEFAULT_INPUT_NAME,
11
- DEFAULT_OUTPUT_NAME,
12
- )
13
-
14
- from classiq.exceptions import ClassiqValueError
15
-
16
-
17
- class StatePropagator(function_params.FunctionParams):
18
- """
19
- Creates a quantum circuit that propagates the start state vector to the end state vector,
20
- both are assumed to be pure states.
21
- The default start state vector is |000...0>.
22
- """
23
-
24
- end_state_vector: List[Complex] = pydantic.Field(
25
- description="The desired state vector at the end of the operator."
26
- " Must be of size 2**num_qubits. Does not have to be "
27
- "normalized"
28
- )
29
-
30
- start_state_vector: List[Complex] = pydantic.Field(
31
- default_factory=list,
32
- description="The state vector at the input of the operator."
33
- " Must be of size 2**num_qubits. Does not have to be"
34
- " normalized",
35
- )
36
-
37
- @pydantic.validator("start_state_vector", always=True)
38
- def validate_start_state(
39
- cls, start_state_vector: List[Complex], values: Dict[str, Any]
40
- ) -> List[Complex]:
41
- end_state_vector = values.get("end_state_vector")
42
- if end_state_vector is None:
43
- raise ClassiqValueError(
44
- "Cannot validate start_start_vector without end_state_vector"
45
- )
46
-
47
- num_qubits = cls._num_qubits(end_state_vector)
48
- if len(start_state_vector) == 0:
49
- default_start_state_vector = [Complex(0.0) for _ in range(2**num_qubits)]
50
- default_start_state_vector[0] = Complex(1.0)
51
- start_state_vector = default_start_state_vector
52
-
53
- if len(start_state_vector) != len(end_state_vector):
54
- raise ClassiqValueError(
55
- "Start and end state vectors are of non-equal length"
56
- )
57
-
58
- return start_state_vector
59
-
60
- @staticmethod
61
- def _num_qubits(vector: List[Complex]) -> int:
62
- return int(np.log2(len(vector)))
63
-
64
- def _create_ios(self) -> None:
65
- self._inputs = {
66
- DEFAULT_INPUT_NAME: RegisterArithmeticInfo(
67
- size=self._num_qubits(self.start_state_vector)
68
- )
69
- }
70
- self._outputs = {
71
- DEFAULT_OUTPUT_NAME: RegisterArithmeticInfo(
72
- size=self._num_qubits(self.end_state_vector)
73
- )
74
- }
@@ -1,64 +0,0 @@
1
- import itertools
2
- from typing import Any, Mapping
3
-
4
- from classiq.interface.generator.visitor import Visitor
5
- from classiq.interface.model.control import Control
6
- from classiq.interface.model.invert import Invert
7
- from classiq.interface.model.native_function_definition import NativeFunctionDefinition
8
- from classiq.interface.model.quantum_function_call import QuantumFunctionCall
9
- from classiq.interface.model.quantum_function_declaration import (
10
- QuantumFunctionDeclaration,
11
- )
12
- from classiq.interface.model.repeat import Repeat
13
- from classiq.interface.model.within_apply_operation import WithinApply
14
-
15
-
16
- class FunctionCallResolver(Visitor):
17
- def __init__(
18
- self,
19
- quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
20
- ) -> None:
21
- self._quantum_function_dict = quantum_function_dict
22
-
23
- def visit_Invert(self, invert: Invert) -> None:
24
- for fc in invert.body:
25
- self.visit(fc)
26
-
27
- def visit_Repeat(self, repeat: Repeat) -> None:
28
- for fc in repeat.body:
29
- self.visit(fc)
30
-
31
- def visit_Control(self, control: Control) -> None:
32
- for fc in control.body:
33
- self.visit(fc)
34
-
35
- def visit_WithinApply(self, within_apply: WithinApply) -> None:
36
- for fc in itertools.chain(within_apply.compute, within_apply.action):
37
- self.visit(fc)
38
-
39
- def visit_QuantumFunctionCall(self, fc: QuantumFunctionCall) -> None:
40
- fc.resolve_function_decl(self._quantum_function_dict, check_operands=True)
41
- self.visit_BaseModel(fc)
42
-
43
- def visit_NativeFunctionDefinition(
44
- self, func_def: NativeFunctionDefinition
45
- ) -> None:
46
- curr_dict = self._quantum_function_dict
47
- self._quantum_function_dict = {
48
- **self._quantum_function_dict,
49
- **func_def.operand_declarations,
50
- }
51
- self.visit_BaseModel(func_def)
52
- self._quantum_function_dict = curr_dict
53
-
54
-
55
- def resolve_function_calls(
56
- root: Any,
57
- quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
58
- ) -> None:
59
- FunctionCallResolver(
60
- {
61
- **QuantumFunctionDeclaration.BUILTIN_FUNCTION_DECLARATIONS,
62
- **quantum_function_dict,
63
- },
64
- ).visit(root)
File without changes
@@ -1,55 +0,0 @@
1
- import abc
2
- from typing import Dict, Mapping, Type
3
-
4
- from classiq.interface.generator.functions.port_declaration import (
5
- PortDeclarationDirection,
6
- )
7
- from classiq.interface.model.port_declaration import PortDeclaration
8
- from classiq.interface.model.validation_handle import HandleState, ValidationHandle
9
-
10
- EXPECTED_TERMINAL_STATES: Dict[PortDeclarationDirection, HandleState] = {
11
- PortDeclarationDirection.Output: HandleState.INITIALIZED,
12
- PortDeclarationDirection.Inout: HandleState.INITIALIZED,
13
- }
14
-
15
-
16
- class HandleValidationBase(abc.ABC):
17
- def __init__(
18
- self,
19
- port_declarations: Mapping[str, PortDeclaration],
20
- ) -> None:
21
- self._port_declarations = port_declarations.values()
22
-
23
- def report_errored_handles(self, exception_type: Type[Exception]) -> None:
24
- self._validate_terminal_handle_state()
25
-
26
- errored_handles = {
27
- name: state.errors
28
- for name, state in self._validation_handles_state.items()
29
- if state.state is HandleState.ERRORED
30
- }
31
- if errored_handles:
32
- raise exception_type(
33
- "\n".join(
34
- f"Handle {handle_name!r} was errored with {'. '.join(errors)!r}"
35
- for handle_name, errors in errored_handles.items()
36
- )
37
- )
38
-
39
- def _validate_terminal_handle_state(self) -> None:
40
- for port_decl in self._port_declarations:
41
- handle_state = self._validation_handles_state[port_decl.name]
42
- expected_terminal_state = EXPECTED_TERMINAL_STATES.get(port_decl.direction)
43
- if (
44
- expected_terminal_state is not None
45
- and handle_state.state is not expected_terminal_state
46
- and handle_state.state is not HandleState.ERRORED
47
- ):
48
- handle_state.append_error(
49
- f"At the end of the function, in port {port_decl.name} is expected to be {expected_terminal_state} but it isn't"
50
- )
51
-
52
- @property
53
- @abc.abstractmethod
54
- def _validation_handles_state(self) -> Mapping[str, ValidationHandle]:
55
- raise NotImplementedError