classiq 0.51.1__py3-none-any.whl → 0.52.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/_internals/api_wrapper.py +41 -15
- classiq/_internals/authentication/auth0.py +20 -4
- classiq/_internals/authentication/password_manager.py +16 -4
- classiq/_internals/client.py +2 -2
- classiq/_internals/host_checker.py +5 -3
- classiq/_internals/jobs.py +3 -3
- classiq/analyzer/analyzer_utilities.py +1 -1
- classiq/applications/chemistry/ground_state_problem.py +1 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/qlayer.py +2 -2
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +2 -2
- classiq/execution/iqcc.py +63 -0
- classiq/execution/jobs.py +2 -2
- classiq/executor.py +2 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +19 -9
- classiq/interface/analyzer/cytoscape_graph.py +10 -3
- classiq/interface/analyzer/result.py +6 -5
- classiq/interface/applications/qsvm.py +13 -12
- classiq/interface/backend/backend_preferences.py +78 -105
- classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
- classiq/interface/backend/pydantic_backend.py +24 -12
- classiq/interface/backend/quantum_backend_providers.py +2 -0
- classiq/interface/chemistry/fermionic_operator.py +7 -7
- classiq/interface/chemistry/ground_state_problem.py +23 -18
- classiq/interface/chemistry/molecule.py +10 -5
- classiq/interface/chemistry/operator.py +71 -44
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
- classiq/interface/debug_info/debug_info.py +3 -4
- classiq/interface/execution/iqcc.py +21 -0
- classiq/interface/execution/jobs.py +10 -10
- classiq/interface/executor/aws_execution_cost.py +37 -20
- classiq/interface/executor/execution_preferences.py +1 -2
- classiq/interface/executor/execution_request.py +2 -2
- classiq/interface/executor/execution_result.py +4 -2
- classiq/interface/executor/iqae_result.py +1 -1
- classiq/interface/executor/optimizer_preferences.py +14 -10
- classiq/interface/executor/quantum_code.py +21 -16
- classiq/interface/executor/register_initialization.py +10 -10
- classiq/interface/executor/result.py +19 -16
- classiq/interface/executor/vqe_result.py +1 -1
- classiq/interface/finance/function_input.py +27 -18
- classiq/interface/finance/log_normal_model_input.py +2 -2
- classiq/interface/finance/model_input.py +3 -2
- classiq/interface/generator/amplitude_loading.py +8 -6
- classiq/interface/generator/arith/argument_utils.py +24 -0
- classiq/interface/generator/arith/arithmetic.py +5 -3
- classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
- classiq/interface/generator/arith/arithmetic_operations.py +6 -3
- classiq/interface/generator/arith/binary_ops.py +88 -63
- classiq/interface/generator/arith/extremum_operations.py +22 -13
- classiq/interface/generator/arith/logical_ops.py +6 -4
- classiq/interface/generator/arith/number_utils.py +3 -3
- classiq/interface/generator/arith/register_user_input.py +32 -17
- classiq/interface/generator/arith/unary_ops.py +5 -4
- classiq/interface/generator/chemistry_function_params.py +2 -1
- classiq/interface/generator/circuit_code/circuit_code.py +2 -1
- classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
- classiq/interface/generator/complex_type.py +14 -18
- classiq/interface/generator/control_state.py +32 -26
- classiq/interface/generator/expressions/expression.py +6 -5
- classiq/interface/generator/function_params.py +22 -39
- classiq/interface/generator/functions/classical_function_declaration.py +1 -1
- classiq/interface/generator/functions/classical_type.py +32 -23
- classiq/interface/generator/functions/concrete_types.py +8 -7
- classiq/interface/generator/functions/function_declaration.py +4 -5
- classiq/interface/generator/functions/type_name.py +5 -4
- classiq/interface/generator/generated_circuit_data.py +9 -6
- classiq/interface/generator/grover_diffuser.py +26 -18
- classiq/interface/generator/grover_operator.py +32 -22
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
- classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
- classiq/interface/generator/hardware/hardware_data.py +27 -26
- classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
- classiq/interface/generator/hartree_fock.py +2 -1
- classiq/interface/generator/identity.py +7 -2
- classiq/interface/generator/linear_pauli_rotations.py +27 -14
- classiq/interface/generator/mcu.py +15 -12
- classiq/interface/generator/mcx.py +18 -10
- classiq/interface/generator/model/constraints.py +4 -2
- classiq/interface/generator/model/model.py +2 -1
- classiq/interface/generator/model/preferences/preferences.py +30 -32
- classiq/interface/generator/oracles/custom_oracle.py +13 -10
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
- classiq/interface/generator/qpe.py +38 -26
- classiq/interface/generator/qsvm.py +4 -4
- classiq/interface/generator/quantum_function_call.py +57 -44
- classiq/interface/generator/quantum_program.py +8 -6
- classiq/interface/generator/range_types.py +10 -11
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
- classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
- classiq/interface/generator/standard_gates/u_gate.py +7 -10
- classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
- classiq/interface/generator/state_preparation/distributions.py +12 -12
- classiq/interface/generator/state_preparation/state_preparation.py +22 -16
- classiq/interface/generator/types/enum_declaration.py +2 -1
- classiq/interface/generator/ucc.py +2 -1
- classiq/interface/generator/unitary_gate.py +2 -1
- classiq/interface/generator/user_defined_function_params.py +3 -0
- classiq/interface/generator/visitor.py +1 -1
- classiq/interface/hardware.py +18 -3
- classiq/interface/helpers/custom_pydantic_types.py +38 -47
- classiq/interface/helpers/pydantic_model_helpers.py +3 -2
- classiq/interface/helpers/versioned_model.py +1 -4
- classiq/interface/ide/ide_data.py +5 -5
- classiq/interface/ide/visual_model.py +5 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/jobs.py +12 -22
- classiq/interface/model/bind_operation.py +2 -1
- classiq/interface/model/classical_parameter_declaration.py +10 -4
- classiq/interface/model/handle_binding.py +20 -24
- classiq/interface/model/inplace_binary_operation.py +16 -9
- classiq/interface/model/model.py +21 -11
- classiq/interface/model/port_declaration.py +10 -7
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
- classiq/interface/model/quantum_function_declaration.py +22 -11
- classiq/interface/model/quantum_statement.py +6 -7
- classiq/interface/model/quantum_type.py +22 -19
- classiq/interface/model/statement_block.py +9 -9
- classiq/interface/server/global_versions.py +4 -5
- classiq/interface/server/routes.py +8 -0
- classiq/model_expansions/evaluators/parameter_types.py +3 -3
- classiq/model_expansions/expression_renamer.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +11 -12
- classiq/model_expansions/quantum_operations/emitter.py +22 -0
- classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +38 -9
- classiq/model_expansions/quantum_operations/invert.py +1 -1
- classiq/model_expansions/quantum_operations/phase.py +4 -5
- classiq/model_expansions/quantum_operations/power.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
- classiq/model_expansions/quantum_operations/within_apply.py +1 -1
- classiq/qmod/builtins/__init__.py +1 -3
- classiq/qmod/builtins/functions/__init__.py +4 -0
- classiq/qmod/builtins/functions/arithmetic.py +10 -0
- classiq/qmod/create_model_function.py +4 -4
- classiq/qmod/quantum_expandable.py +22 -9
- classiq/qmod/quantum_function.py +1 -1
- classiq/qmod/semantics/static_semantics_visitor.py +3 -1
- classiq/qmod/type_attribute_remover.py +1 -1
- classiq/qmod/write_qmod.py +2 -4
- classiq/synthesis.py +11 -13
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/RECORD +149 -147
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -14,7 +14,9 @@ from typing import (
|
|
14
14
|
)
|
15
15
|
|
16
16
|
import pydantic
|
17
|
-
from pydantic
|
17
|
+
from pydantic import BaseModel
|
18
|
+
from pydantic_core.core_schema import ValidationInfo
|
19
|
+
from typing_extensions import Self
|
18
20
|
|
19
21
|
from classiq.interface.enum_utils import StrEnum
|
20
22
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -54,21 +56,24 @@ class ArgToInplace(StrEnum):
|
|
54
56
|
|
55
57
|
|
56
58
|
class BinaryOpParams(
|
57
|
-
ArithmeticOperationParams,
|
59
|
+
ArithmeticOperationParams, BaseModel, Generic[LeftDataT, RightDataT]
|
58
60
|
):
|
59
61
|
left_arg: LeftDataT
|
60
62
|
right_arg: RightDataT
|
61
63
|
left_arg_name: ClassVar[str] = DEFAULT_LEFT_ARG_NAME
|
62
64
|
right_arg_name: ClassVar[str] = DEFAULT_RIGHT_ARG_NAME
|
63
65
|
|
64
|
-
@pydantic.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
@pydantic.model_validator(mode="before")
|
67
|
+
@classmethod
|
68
|
+
def _clone_repeated_arg(cls, values: Any) -> Dict[str, Any]:
|
69
|
+
if isinstance(values, dict):
|
70
|
+
left_arg = values.get("left_arg")
|
71
|
+
right_arg = values.get("right_arg")
|
72
|
+
|
73
|
+
if left_arg is right_arg and isinstance(left_arg, pydantic.BaseModel):
|
74
|
+
# In case both arguments refer to the same object, copy it.
|
75
|
+
# This prevents changes performed on one argument to affect the other.
|
76
|
+
values["right_arg"] = left_arg.model_copy(deep=True)
|
72
77
|
return values
|
73
78
|
|
74
79
|
def garbage_output_size(self) -> pydantic.NonNegativeInt:
|
@@ -106,19 +111,21 @@ class InplacableBinaryOpParams(
|
|
106
111
|
):
|
107
112
|
inplace_arg: Optional[ArgToInplace] = None
|
108
113
|
|
109
|
-
@pydantic.
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
114
|
+
@pydantic.model_validator(mode="before")
|
115
|
+
@classmethod
|
116
|
+
def _validate_inplace_arg(cls, values: Any) -> Dict[str, Any]:
|
117
|
+
if isinstance(values, dict):
|
118
|
+
left_arg = values.get("left_arg")
|
119
|
+
right_arg = values.get("right_arg")
|
120
|
+
inplace_arg: Optional[ArgToInplace] = values.get("inplace_arg")
|
121
|
+
if inplace_arg == ArgToInplace.RIGHT and isinstance(right_arg, Numeric):
|
122
|
+
raise ClassiqValueError(
|
123
|
+
_NumericArgumentInplaceErrorMessage.format(right_arg)
|
124
|
+
)
|
125
|
+
elif inplace_arg == ArgToInplace.LEFT and isinstance(left_arg, Numeric):
|
126
|
+
raise ClassiqValueError(
|
127
|
+
_NumericArgumentInplaceErrorMessage.format(left_arg)
|
128
|
+
)
|
122
129
|
return values
|
123
130
|
|
124
131
|
def _create_ios(self) -> None:
|
@@ -192,28 +199,28 @@ class InplacableBinaryOpParams(
|
|
192
199
|
yield ArgToInplace.LEFT
|
193
200
|
|
194
201
|
def get_params_inplace_options(self) -> Iterable["InplacableBinaryOpParams"]:
|
195
|
-
params_kwargs = self.
|
202
|
+
params_kwargs = self.model_copy().__dict__
|
196
203
|
for inplace_arg in self._get_binary_op_inplace_options():
|
197
204
|
params_kwargs["inplace_arg"] = inplace_arg
|
198
205
|
yield self.__class__(**params_kwargs)
|
199
206
|
|
200
207
|
|
201
208
|
class BinaryOpWithIntInputs(BinaryOpParams[RegisterOrInt, RegisterOrInt]):
|
202
|
-
@pydantic.
|
203
|
-
def validate_int_registers(
|
204
|
-
left_arg =
|
209
|
+
@pydantic.model_validator(mode="after")
|
210
|
+
def validate_int_registers(self) -> Self:
|
211
|
+
left_arg = self.left_arg
|
205
212
|
is_left_arg_float_register = (
|
206
213
|
isinstance(left_arg, RegisterArithmeticInfo)
|
207
214
|
and left_arg.fraction_places > 0
|
208
215
|
)
|
209
|
-
right_arg =
|
216
|
+
right_arg = self.right_arg
|
210
217
|
is_right_arg_float_register = (
|
211
218
|
isinstance(right_arg, RegisterArithmeticInfo)
|
212
219
|
and right_arg.fraction_places > 0
|
213
220
|
)
|
214
221
|
if is_left_arg_float_register or is_right_arg_float_register:
|
215
222
|
raise ClassiqValueError(BOOLEAN_OP_WITH_FRACTIONS_ERROR)
|
216
|
-
return
|
223
|
+
return self
|
217
224
|
|
218
225
|
@staticmethod
|
219
226
|
def _is_signed(arg: Union[int, RegisterArithmeticInfo]) -> bool:
|
@@ -344,11 +351,18 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
|
|
344
351
|
argument_utils.fraction_places(self.effective_right_arg),
|
345
352
|
)
|
346
353
|
|
354
|
+
size = self.output_size or self._get_output_size(bounds, fraction_places)
|
355
|
+
is_signed = self._include_sign and min(bounds) < 0
|
347
356
|
return RegisterArithmeticInfo(
|
348
|
-
size=
|
357
|
+
size=size,
|
349
358
|
fraction_places=fraction_places,
|
350
|
-
is_signed=
|
351
|
-
bounds=self._legal_bounds(
|
359
|
+
is_signed=is_signed,
|
360
|
+
bounds=self._legal_bounds(
|
361
|
+
bounds,
|
362
|
+
RegisterArithmeticInfo.get_maximal_bounds(
|
363
|
+
size=size, is_signed=is_signed, fraction_places=fraction_places
|
364
|
+
),
|
365
|
+
),
|
352
366
|
)
|
353
367
|
|
354
368
|
def _get_output_size(
|
@@ -492,12 +506,20 @@ class Multiplier(BinaryOpWithFloatInputs):
|
|
492
506
|
)
|
493
507
|
bounds = number_utils.bounds_cut(bounds, max_bounds)
|
494
508
|
|
509
|
+
size = self.output_size or self._get_output_size(
|
510
|
+
bounds, fraction_places, left_arg, right_arg
|
511
|
+
)
|
512
|
+
is_signed = self._include_sign and min(bounds) < 0
|
495
513
|
return RegisterArithmeticInfo(
|
496
|
-
size=
|
497
|
-
or self._get_output_size(bounds, fraction_places, left_arg, right_arg),
|
514
|
+
size=size,
|
498
515
|
fraction_places=fraction_places,
|
499
|
-
is_signed=
|
500
|
-
bounds=self._legal_bounds(
|
516
|
+
is_signed=is_signed,
|
517
|
+
bounds=self._legal_bounds(
|
518
|
+
bounds,
|
519
|
+
RegisterArithmeticInfo.get_maximal_bounds(
|
520
|
+
size=size, is_signed=is_signed, fraction_places=fraction_places
|
521
|
+
),
|
522
|
+
),
|
501
523
|
)
|
502
524
|
|
503
525
|
@staticmethod
|
@@ -562,7 +584,8 @@ class LessEqual(Comparator):
|
|
562
584
|
class Power(BinaryOpParams[RegisterArithmeticInfo, pydantic.PositiveInt]):
|
563
585
|
output_name = "powered"
|
564
586
|
|
565
|
-
@pydantic.
|
587
|
+
@pydantic.field_validator("right_arg", mode="before")
|
588
|
+
@classmethod
|
566
589
|
def _validate_legal_power(cls, right_arg: Any) -> pydantic.PositiveInt:
|
567
590
|
if not float(right_arg).is_integer():
|
568
591
|
raise ClassiqValueError("Power must be an integer")
|
@@ -674,19 +697,19 @@ class LShift(EffectiveUnaryOpParams[pydantic.NonNegativeInt]):
|
|
674
697
|
output_name = "left_shifted"
|
675
698
|
inplace_arg: Optional[ArgToInplace] = ArgToInplace.LEFT
|
676
699
|
|
677
|
-
@pydantic.
|
678
|
-
def _validate_legal_modulo(
|
679
|
-
output_size =
|
700
|
+
@pydantic.model_validator(mode="after")
|
701
|
+
def _validate_legal_modulo(self) -> Self:
|
702
|
+
output_size = self.output_size
|
680
703
|
if output_size is None:
|
681
|
-
return
|
682
|
-
arg =
|
683
|
-
shift =
|
704
|
+
return self
|
705
|
+
arg = self.left_arg
|
706
|
+
shift = self.right_arg
|
684
707
|
if not isinstance(arg, RegisterArithmeticInfo):
|
685
708
|
raise ClassiqValueError("left arg must be a RegisterArithmeticInfo")
|
686
709
|
if not isinstance(shift, int):
|
687
710
|
raise ClassiqValueError("Shift must be an integer")
|
688
711
|
assert arg.fraction_places - shift <= 0, _FLOATING_POINT_MODULO_ERROR_MESSAGE
|
689
|
-
return
|
712
|
+
return self
|
690
713
|
|
691
714
|
def garbage_output_size(self) -> pydantic.NonNegativeInt:
|
692
715
|
if self.inplace_arg is None or self.output_size is None:
|
@@ -715,21 +738,21 @@ class RShift(EffectiveUnaryOpParams[pydantic.NonNegativeInt]):
|
|
715
738
|
def _shifted_fraction_places(*, arg: RegisterArithmeticInfo, shift: int) -> int:
|
716
739
|
return arg.fraction_places * int(arg.is_signed or shift < arg.size)
|
717
740
|
|
718
|
-
@pydantic.
|
719
|
-
def _validate_legal_modulo(
|
720
|
-
output_size =
|
741
|
+
@pydantic.model_validator(mode="after")
|
742
|
+
def _validate_legal_modulo(self) -> Self:
|
743
|
+
output_size = self.output_size
|
721
744
|
if output_size is None:
|
722
|
-
return
|
723
|
-
arg =
|
724
|
-
shift =
|
745
|
+
return self
|
746
|
+
arg = self.left_arg
|
747
|
+
shift = self.right_arg
|
725
748
|
if not isinstance(arg, RegisterArithmeticInfo):
|
726
749
|
raise ClassiqValueError("left arg must be a RegisterArithmeticInfo")
|
727
750
|
if not isinstance(shift, int):
|
728
751
|
raise ClassiqValueError("Shift must be an integer")
|
729
752
|
assert (
|
730
|
-
|
753
|
+
self._shifted_fraction_places(arg=arg, shift=shift) == 0
|
731
754
|
), _FLOATING_POINT_MODULO_ERROR_MESSAGE
|
732
|
-
return
|
755
|
+
return self
|
733
756
|
|
734
757
|
def garbage_output_size(self) -> pydantic.NonNegativeInt:
|
735
758
|
if self.inplace_arg is None:
|
@@ -759,16 +782,16 @@ class CyclicShift(EffectiveUnaryOpParams[int]):
|
|
759
782
|
output_name = "cyclic_shifted"
|
760
783
|
inplace_arg: Optional[ArgToInplace] = ArgToInplace.LEFT
|
761
784
|
|
762
|
-
@pydantic.
|
763
|
-
def _validate_legal_modulo(
|
764
|
-
output_size =
|
785
|
+
@pydantic.model_validator(mode="after")
|
786
|
+
def _validate_legal_modulo(self) -> Self:
|
787
|
+
output_size = self.output_size
|
765
788
|
if output_size is None:
|
766
|
-
return
|
767
|
-
arg =
|
789
|
+
return self
|
790
|
+
arg = self.left_arg
|
768
791
|
if not isinstance(arg, RegisterArithmeticInfo):
|
769
792
|
raise ClassiqValueError("left arg must be a RegisterArithmeticInfo")
|
770
793
|
assert arg.fraction_places == 0, _FLOATING_POINT_MODULO_ERROR_MESSAGE
|
771
|
-
return
|
794
|
+
return self
|
772
795
|
|
773
796
|
def garbage_output_size(self) -> pydantic.NonNegativeInt:
|
774
797
|
if self.inplace_arg is None:
|
@@ -787,24 +810,26 @@ class Modulo(EffectiveUnaryOpParams[int]):
|
|
787
810
|
output_name = "modulus"
|
788
811
|
inplace_arg: Optional[ArgToInplace] = ArgToInplace.LEFT
|
789
812
|
|
790
|
-
@pydantic.
|
813
|
+
@pydantic.field_validator("left_arg", mode="before")
|
814
|
+
@classmethod
|
791
815
|
def _validate_left_arg_is_integer(
|
792
816
|
cls, left_arg: RegisterArithmeticInfo
|
793
817
|
) -> RegisterArithmeticInfo:
|
794
818
|
assert left_arg.fraction_places == 0, _FLOATING_POINT_MODULO_ERROR_MESSAGE
|
795
819
|
return left_arg
|
796
820
|
|
797
|
-
@pydantic.
|
821
|
+
@pydantic.field_validator("right_arg", mode="before")
|
822
|
+
@classmethod
|
798
823
|
def _validate_right_arg_is_a_power_of_two(
|
799
|
-
cls, right_arg: int,
|
824
|
+
cls, right_arg: int, info: ValidationInfo
|
800
825
|
) -> int:
|
801
826
|
repr_qubits_float = math.log2(right_arg)
|
802
827
|
repr_qubits = round(repr_qubits_float)
|
803
828
|
assert abs(repr_qubits - repr_qubits_float) < 10**-8, NOT_POWER_OF_TWO_ERROR_MSG
|
804
|
-
output_size =
|
829
|
+
output_size = info.data.get("output_size")
|
805
830
|
if output_size is not None:
|
806
831
|
repr_qubits = min(repr_qubits, output_size)
|
807
|
-
|
832
|
+
info.data["output_size"] = None
|
808
833
|
return 2 ** (repr_qubits)
|
809
834
|
|
810
835
|
def _get_result_register(self) -> RegisterArithmeticInfo:
|
@@ -24,16 +24,18 @@ class Extremum(ArithmeticOperationParams):
|
|
24
24
|
left_arg: RegisterOrConst
|
25
25
|
right_arg: RegisterOrConst
|
26
26
|
|
27
|
-
@pydantic.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
@pydantic.model_validator(mode="before")
|
28
|
+
@classmethod
|
29
|
+
def _validate_one_is_register(cls, values: Any) -> Dict[str, Any]:
|
30
|
+
if isinstance(values, dict):
|
31
|
+
left_arg = values.get("left_arg")
|
32
|
+
right_arg = values.get("right_arg")
|
33
|
+
if isinstance(left_arg, Numeric) and isinstance(right_arg, Numeric):
|
34
|
+
raise ClassiqValueError("One argument must be a register")
|
35
|
+
if left_arg is right_arg and isinstance(left_arg, pydantic.BaseModel):
|
36
|
+
# In case both arguments refer to the same object, copy it.
|
37
|
+
# This prevents changes performed on one argument from affecting the other.
|
38
|
+
values["right_arg"] = left_arg.model_copy(deep=True)
|
37
39
|
return values
|
38
40
|
|
39
41
|
def _create_ios(self) -> None:
|
@@ -116,11 +118,18 @@ class Extremum(ArithmeticOperationParams):
|
|
116
118
|
size=self.output_size, is_signed=False, fraction_places=0
|
117
119
|
)
|
118
120
|
bounds = number_utils.bounds_cut(bounds, max_bounds)
|
121
|
+
size = self.output_size or required_size
|
122
|
+
is_signed = self._include_sign and min(bounds) < 0
|
119
123
|
return RegisterArithmeticInfo(
|
120
|
-
size=
|
124
|
+
size=size,
|
121
125
|
fraction_places=fraction_places,
|
122
|
-
is_signed=
|
123
|
-
bounds=self._legal_bounds(
|
126
|
+
is_signed=is_signed,
|
127
|
+
bounds=self._legal_bounds(
|
128
|
+
bounds,
|
129
|
+
RegisterArithmeticInfo.get_maximal_bounds(
|
130
|
+
size=size, is_signed=is_signed, fraction_places=fraction_places
|
131
|
+
),
|
132
|
+
),
|
124
133
|
)
|
125
134
|
|
126
135
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import Iterable, List, Optional
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from pydantic import ConfigDict
|
4
5
|
|
5
6
|
from classiq.interface.exceptions import ClassiqValueError
|
6
7
|
from classiq.interface.generator.arith.argument_utils import RegisterOrConst
|
@@ -23,13 +24,15 @@ class LogicalOps(ArithmeticOperationParams):
|
|
23
24
|
def update_should_invert_node_list(self, invert_args: List[str]) -> None:
|
24
25
|
self._should_invert_node_list.extend(invert_args)
|
25
26
|
|
26
|
-
@pydantic.
|
27
|
+
@pydantic.field_validator("output_size")
|
28
|
+
@classmethod
|
27
29
|
def _validate_output_size(cls, output_size: Optional[int]) -> int:
|
28
30
|
if output_size is not None and output_size != 1:
|
29
31
|
raise ClassiqValueError("logical operation output size must be 1")
|
30
32
|
return 1
|
31
33
|
|
32
|
-
@pydantic.
|
34
|
+
@pydantic.field_validator("args")
|
35
|
+
@classmethod
|
33
36
|
def _validate_inputs_sizes(
|
34
37
|
cls, arguments: List[RegisterOrConst]
|
35
38
|
) -> List[RegisterOrConst]:
|
@@ -64,8 +67,7 @@ class LogicalOps(ArithmeticOperationParams):
|
|
64
67
|
def get_params_inplace_options(self) -> Iterable["LogicalOps"]:
|
65
68
|
return ()
|
66
69
|
|
67
|
-
|
68
|
-
arbitrary_types_allowed = True
|
70
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
69
71
|
|
70
72
|
|
71
73
|
class LogicalAnd(LogicalOps):
|
@@ -12,7 +12,7 @@ def signed_int_to_unsigned(number: int) -> int:
|
|
12
12
|
return number + 2 ** (number.bit_length() + 1 * not_power2)
|
13
13
|
|
14
14
|
|
15
|
-
def
|
15
|
+
def binary_to_int(bin_rep: str, is_signed: bool = False) -> int:
|
16
16
|
negative_offset: int = -(2 ** len(bin_rep)) * (bin_rep[0] == "1") * is_signed
|
17
17
|
return int(bin_rep, 2) + negative_offset
|
18
18
|
|
@@ -20,14 +20,14 @@ def _binary_to_int(bin_rep: str, is_signed: bool) -> int:
|
|
20
20
|
def binary_to_float(
|
21
21
|
bin_rep: str, fraction_part_size: int = 0, is_signed: bool = False
|
22
22
|
) -> float:
|
23
|
-
return
|
23
|
+
return binary_to_int(bin_rep, is_signed) / 2**fraction_part_size
|
24
24
|
|
25
25
|
|
26
26
|
def binary_to_float_or_int(
|
27
27
|
bin_rep: str, fraction_part_size: int = 0, is_signed: bool = False
|
28
28
|
) -> Union[float, int]:
|
29
29
|
if fraction_part_size == 0:
|
30
|
-
return
|
30
|
+
return binary_to_int(bin_rep, is_signed)
|
31
31
|
return binary_to_float(bin_rep, fraction_part_size, is_signed)
|
32
32
|
|
33
33
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
from typing import Any, Dict, Optional, Tuple
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from pydantic import ConfigDict
|
5
|
+
from pydantic_core.core_schema import ValidationInfo
|
4
6
|
|
5
7
|
from classiq.interface.exceptions import ClassiqValueError
|
6
8
|
from classiq.interface.generator.arith import number_utils
|
@@ -11,16 +13,28 @@ from classiq.interface.helpers.hashable_pydantic_base_model import (
|
|
11
13
|
|
12
14
|
|
13
15
|
class RegisterArithmeticInfo(HashablePydanticBaseModel):
|
14
|
-
size: pydantic.PositiveInt
|
16
|
+
size: pydantic.PositiveInt = pydantic.Field(default=1)
|
15
17
|
is_signed: bool = pydantic.Field(default=False)
|
16
18
|
fraction_places: pydantic.NonNegativeInt = pydantic.Field(default=0)
|
17
19
|
bypass_bounds_validation: bool = pydantic.Field(default=False)
|
18
|
-
bounds: PydanticFloatTuple = pydantic.Field(
|
20
|
+
bounds: PydanticFloatTuple = pydantic.Field(
|
21
|
+
default=None,
|
22
|
+
validate_default=True,
|
23
|
+
)
|
19
24
|
|
20
|
-
@pydantic.
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
@pydantic.model_validator(mode="before")
|
26
|
+
@classmethod
|
27
|
+
def _remove_name(cls, values: Any, info: ValidationInfo) -> Dict[str, Any]:
|
28
|
+
if isinstance(values, dict):
|
29
|
+
values = values.copy()
|
30
|
+
elif hasattr(values, "__dict__"):
|
31
|
+
values = values.__dict__.copy()
|
32
|
+
elif values is None and info.data:
|
33
|
+
values = info.data.copy()
|
34
|
+
else:
|
35
|
+
raise ValueError("Unsupported type for removing 'name'.")
|
36
|
+
|
37
|
+
values.pop("name", None)
|
24
38
|
return values
|
25
39
|
|
26
40
|
@staticmethod
|
@@ -32,13 +46,14 @@ class RegisterArithmeticInfo(HashablePydanticBaseModel):
|
|
32
46
|
fraction_factor = float(2**-fraction_places)
|
33
47
|
return (lb * fraction_factor, ub * fraction_factor)
|
34
48
|
|
35
|
-
@pydantic.
|
49
|
+
@pydantic.field_validator("bounds", mode="before")
|
50
|
+
@classmethod
|
36
51
|
def _validate_bounds(
|
37
|
-
cls, bounds: Optional[PydanticFloatTuple],
|
52
|
+
cls, bounds: Optional[PydanticFloatTuple], info: ValidationInfo
|
38
53
|
) -> PydanticFloatTuple:
|
39
|
-
size =
|
40
|
-
is_signed =
|
41
|
-
fraction_places =
|
54
|
+
size = info.data.get("size")
|
55
|
+
is_signed = info.data.get("is_signed", False)
|
56
|
+
fraction_places = info.data.get("fraction_places", 0)
|
42
57
|
if not isinstance(size, int):
|
43
58
|
raise ClassiqValueError("RegisterArithmeticInfo must have an integer size")
|
44
59
|
|
@@ -52,7 +67,7 @@ class RegisterArithmeticInfo(HashablePydanticBaseModel):
|
|
52
67
|
number_utils.limit_fraction_places(min(bounds), fraction_places),
|
53
68
|
number_utils.limit_fraction_places(max(bounds), fraction_places),
|
54
69
|
)
|
55
|
-
if not
|
70
|
+
if not info.data.get("bypass_bounds_validation", False):
|
56
71
|
assert min(trimmed_bounds) >= min(maximal_bounds), "Illegal bound min"
|
57
72
|
assert max(trimmed_bounds) <= max(maximal_bounds), "Illegal bound max"
|
58
73
|
return trimmed_bounds
|
@@ -79,8 +94,7 @@ class RegisterArithmeticInfo(HashablePydanticBaseModel):
|
|
79
94
|
def integer_part_size(self) -> pydantic.NonNegativeInt:
|
80
95
|
return self.size - self.fraction_places
|
81
96
|
|
82
|
-
|
83
|
-
frozen = True
|
97
|
+
model_config = ConfigDict(frozen=True)
|
84
98
|
|
85
99
|
|
86
100
|
class RegisterUserInput(RegisterArithmeticInfo):
|
@@ -90,12 +104,13 @@ class RegisterUserInput(RegisterArithmeticInfo):
|
|
90
104
|
super().__init__(**data)
|
91
105
|
self._fields_to_skip_in_hash = frozenset({"name"})
|
92
106
|
|
93
|
-
@pydantic.
|
94
|
-
|
107
|
+
@pydantic.model_validator(mode="before")
|
108
|
+
@classmethod
|
109
|
+
def _remove_name(cls, values: Any, info: ValidationInfo) -> Dict[str, Any]:
|
95
110
|
return values
|
96
111
|
|
97
112
|
def revalued(self, **kwargs: Any) -> "RegisterUserInput":
|
98
|
-
return self.
|
113
|
+
return self.model_copy(update=kwargs)
|
99
114
|
|
100
115
|
@classmethod
|
101
116
|
def from_arithmetic_info(
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Final, Iterable, Optional
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
from pydantic import ConfigDict
|
4
5
|
|
5
6
|
from classiq.interface.exceptions import ClassiqValueError
|
6
7
|
from classiq.interface.generator.arith import argument_utils, number_utils
|
@@ -52,12 +53,11 @@ class UnaryOpParams(ArithmeticOperationParams):
|
|
52
53
|
return self.inplace
|
53
54
|
|
54
55
|
def get_params_inplace_options(self) -> Iterable["UnaryOpParams"]:
|
55
|
-
params_kwargs = self.
|
56
|
+
params_kwargs = self.model_copy().model_dump()
|
56
57
|
params_kwargs["inplace"] = True
|
57
58
|
yield self.__class__(**params_kwargs)
|
58
59
|
|
59
|
-
|
60
|
-
arbitrary_types_allowed = True
|
60
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
61
61
|
|
62
62
|
|
63
63
|
class BitwiseInvert(UnaryOpParams):
|
@@ -119,7 +119,8 @@ class Negation(UnaryOpParams):
|
|
119
119
|
class Sign(UnaryOpParams):
|
120
120
|
output_name = "sign"
|
121
121
|
|
122
|
-
@pydantic.
|
122
|
+
@pydantic.field_validator("output_size")
|
123
|
+
@classmethod
|
123
124
|
def _validate_output_size(
|
124
125
|
cls, output_size: Optional[pydantic.PositiveInt]
|
125
126
|
) -> pydantic.PositiveInt:
|
@@ -16,7 +16,8 @@ from classiq.interface.generator.function_params import (
|
|
16
16
|
class ChemistryFunctionParams(FunctionParams):
|
17
17
|
gs_problem: CHEMISTRY_PROBLEMS_TYPE
|
18
18
|
|
19
|
-
@pydantic.
|
19
|
+
@pydantic.field_validator("gs_problem")
|
20
|
+
@classmethod
|
20
21
|
def validate_gs_problem_contains_num_qubits(
|
21
22
|
cls, gs_problem: CHEMISTRY_PROBLEMS_TYPE
|
22
23
|
) -> CHEMISTRY_PROBLEMS_TYPE:
|
@@ -18,7 +18,8 @@ class CircuitCodeInterface(pydantic.BaseModel):
|
|
18
18
|
outputs: Dict[QuantumFormat, Code]
|
19
19
|
qasm_version: QasmVersion
|
20
20
|
|
21
|
-
@pydantic.
|
21
|
+
@pydantic.field_validator("outputs")
|
22
|
+
@classmethod
|
22
23
|
def reformat_long_string_output_formats(
|
23
24
|
cls, outputs: Dict[QuantumFormat, str]
|
24
25
|
) -> Dict[QuantumFormat, LongStr]:
|
@@ -8,8 +8,8 @@ from classiq.interface.generator.function_params import (
|
|
8
8
|
DEFAULT_INPUT_NAME,
|
9
9
|
DEFAULT_OUTPUT_NAME,
|
10
10
|
FunctionParams,
|
11
|
+
FunctionParamsNumericParameter,
|
11
12
|
)
|
12
|
-
from classiq.interface.generator.parameters import ParameterFloatType
|
13
13
|
|
14
14
|
|
15
15
|
class CommutingPauliExponentiation(FunctionParams):
|
@@ -20,17 +20,18 @@ class CommutingPauliExponentiation(FunctionParams):
|
|
20
20
|
pauli_operator: PauliOperator = pydantic.Field(
|
21
21
|
description="A weighted sum of Pauli strings."
|
22
22
|
)
|
23
|
-
evolution_coefficient:
|
23
|
+
evolution_coefficient: FunctionParamsNumericParameter = pydantic.Field(
|
24
24
|
default=1.0,
|
25
25
|
description="A global coefficient multiplying the operator.",
|
26
|
-
is_exec_param=True,
|
27
26
|
)
|
28
27
|
|
29
|
-
@pydantic.
|
28
|
+
@pydantic.field_validator("pauli_operator")
|
29
|
+
@classmethod
|
30
30
|
def _validate_is_hermitian(cls, pauli_operator: PauliOperator) -> PauliOperator:
|
31
31
|
return operator.validate_operator_is_hermitian(pauli_operator)
|
32
32
|
|
33
|
-
@pydantic.
|
33
|
+
@pydantic.field_validator("pauli_operator")
|
34
|
+
@classmethod
|
34
35
|
def _validate_paulis_commute(cls, pauli_operator: PauliOperator) -> PauliOperator:
|
35
36
|
if not pauli_operator.is_commutative:
|
36
37
|
raise ClassiqValueError("Pauli strings are not commutative")
|
@@ -1,23 +1,19 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Union
|
2
2
|
|
3
|
-
from
|
3
|
+
from pydantic import PlainSerializer, PlainValidator
|
4
|
+
from pydantic.json_schema import WithJsonSchema
|
5
|
+
from typing_extensions import Annotated
|
4
6
|
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
yield cls.validate
|
8
|
+
def validate_complex(v: Union[complex, str]) -> complex:
|
9
|
+
if isinstance(v, str):
|
10
|
+
v = "".join(v.split())
|
11
|
+
return complex(v)
|
11
12
|
|
12
|
-
@classmethod
|
13
|
-
def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
|
14
|
-
field_schema.update(
|
15
|
-
pattern=r"[+-]?\d+\.?\d* *[+-] *\d+\.?\d*j",
|
16
|
-
)
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
Complex = Annotated[
|
15
|
+
complex,
|
16
|
+
PlainValidator(validate_complex),
|
17
|
+
PlainSerializer(lambda x: str(x)),
|
18
|
+
WithJsonSchema({"type": "string", "pattern": r"[+-]?\d+\.?\d* *[+-] *\d+\.?\d*j"}),
|
19
|
+
]
|