classiq 0.37.0__py3-none-any.whl → 0.38.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 -2
- classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
- classiq/_analyzer_extras/interactive_hardware.py +3 -3
- classiq/_internals/api_wrapper.py +24 -16
- classiq/_internals/async_utils.py +1 -74
- classiq/_internals/authentication/device.py +9 -4
- classiq/_internals/authentication/password_manager.py +25 -10
- classiq/_internals/authentication/token_manager.py +2 -2
- classiq/_internals/client.py +13 -5
- classiq/_internals/jobs.py +10 -7
- classiq/analyzer/analyzer.py +26 -28
- classiq/analyzer/analyzer_utilities.py +5 -5
- classiq/analyzer/rb.py +4 -5
- classiq/analyzer/show_interactive_hack.py +6 -6
- classiq/applications/benchmarking/mirror_benchmarking.py +9 -6
- classiq/applications/combinatorial_optimization/__init__.py +5 -0
- classiq/applications/qnn/circuit_utils.py +2 -2
- classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
- classiq/applications/qnn/types.py +2 -2
- classiq/applications/qsvm/qsvm.py +4 -7
- classiq/applications/qsvm/qsvm_data_generation.py +2 -5
- classiq/applications_model_constructors/__init__.py +9 -1
- classiq/applications_model_constructors/chemistry_model_constructor.py +9 -16
- classiq/applications_model_constructors/combinatorial_helpers/__init__.py +0 -0
- classiq/applications_model_constructors/combinatorial_helpers/allowed_constraints.py +20 -0
- classiq/applications_model_constructors/combinatorial_helpers/arithmetic/__init__.py +0 -0
- classiq/applications_model_constructors/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
- classiq/applications_model_constructors/combinatorial_helpers/arithmetic/isolation.py +42 -0
- classiq/applications_model_constructors/combinatorial_helpers/combinatorial_problem_utils.py +130 -0
- classiq/applications_model_constructors/combinatorial_helpers/encoding_mapping.py +107 -0
- classiq/applications_model_constructors/combinatorial_helpers/encoding_utils.py +122 -0
- classiq/applications_model_constructors/combinatorial_helpers/memory.py +79 -0
- classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +34 -0
- classiq/applications_model_constructors/combinatorial_helpers/optimization_model.py +166 -0
- classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
- classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
- classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_utils.py +65 -0
- classiq/applications_model_constructors/combinatorial_helpers/py.typed +0 -0
- classiq/applications_model_constructors/combinatorial_helpers/pyomo_utils.py +243 -0
- classiq/applications_model_constructors/combinatorial_helpers/sympy_utils.py +22 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/__init__.py +0 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/encoding.py +194 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/fixed_variables.py +144 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/ising_converter.py +124 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/penalty.py +32 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/penalty_support.py +41 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/sign_seperation.py +75 -0
- classiq/applications_model_constructors/combinatorial_helpers/transformations/slack_variables.py +90 -0
- classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +48 -91
- classiq/applications_model_constructors/finance_model_constructor.py +4 -17
- classiq/applications_model_constructors/grover_model_constructor.py +20 -91
- classiq/applications_model_constructors/libraries/qmci_library.py +17 -19
- classiq/builtin_functions/standard_gates.py +1 -1
- classiq/exceptions.py +43 -1
- classiq/executor.py +10 -9
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +6 -3
- classiq/interface/analyzer/result.py +12 -4
- classiq/interface/applications/qsvm.py +13 -1
- classiq/interface/backend/backend_preferences.py +4 -2
- classiq/interface/backend/pydantic_backend.py +3 -1
- classiq/interface/backend/quantum_backend_providers.py +1 -0
- classiq/interface/chemistry/fermionic_operator.py +15 -13
- classiq/interface/chemistry/ground_state_problem.py +18 -3
- classiq/interface/chemistry/molecule.py +8 -6
- classiq/interface/chemistry/operator.py +20 -14
- classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
- classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
- classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
- classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
- classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
- classiq/interface/combinatorial_optimization/examples/mht.py +3 -3
- classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
- classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
- classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
- classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
- classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
- classiq/interface/executor/aws_execution_cost.py +4 -3
- classiq/interface/executor/estimation.py +2 -2
- classiq/interface/executor/execution_preferences.py +5 -34
- classiq/interface/executor/execution_request.py +19 -17
- classiq/interface/executor/optimizer_preferences.py +22 -13
- classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
- classiq/interface/executor/quantum_instruction_set.py +2 -1
- classiq/interface/executor/register_initialization.py +1 -3
- classiq/interface/executor/result.py +41 -10
- classiq/interface/executor/vqe_result.py +1 -1
- classiq/interface/finance/function_input.py +17 -4
- classiq/interface/finance/gaussian_model_input.py +3 -1
- classiq/interface/finance/log_normal_model_input.py +3 -1
- classiq/interface/finance/model_input.py +2 -0
- classiq/interface/generator/amplitude_loading.py +6 -3
- classiq/interface/generator/application_apis/__init__.py +1 -0
- classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
- classiq/interface/generator/arith/argument_utils.py +14 -4
- classiq/interface/generator/arith/arithmetic.py +3 -1
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
- classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
- classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
- classiq/interface/generator/arith/arithmetic_operations.py +5 -10
- classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
- classiq/interface/generator/arith/binary_ops.py +202 -54
- classiq/interface/generator/arith/extremum_operations.py +5 -3
- classiq/interface/generator/arith/logical_ops.py +4 -2
- classiq/interface/generator/arith/machine_precision.py +3 -0
- classiq/interface/generator/arith/number_utils.py +34 -44
- classiq/interface/generator/arith/register_user_input.py +21 -1
- classiq/interface/generator/arith/unary_ops.py +16 -25
- classiq/interface/generator/chemistry_function_params.py +4 -4
- classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/complex_type.py +3 -10
- classiq/interface/generator/control_state.py +5 -3
- classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
- classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
- classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
- classiq/interface/generator/expressions/evaluated_expression.py +18 -4
- classiq/interface/generator/expressions/expression.py +1 -1
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
- classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
- classiq/interface/generator/finance.py +1 -1
- classiq/interface/generator/function_params.py +7 -6
- classiq/interface/generator/functions/__init__.py +1 -1
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +505 -138
- classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +25 -99
- classiq/interface/generator/functions/foreign_function_definition.py +12 -4
- classiq/interface/generator/functions/function_implementation.py +8 -4
- classiq/interface/generator/functions/native_function_definition.py +4 -2
- classiq/interface/generator/functions/register.py +4 -2
- classiq/interface/generator/functions/register_mapping_data.py +14 -10
- classiq/interface/generator/generated_circuit_data.py +2 -2
- classiq/interface/generator/grover_operator.py +5 -3
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
- classiq/interface/generator/hardware/hardware_data.py +6 -4
- classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
- classiq/interface/generator/hartree_fock.py +3 -1
- classiq/interface/generator/linear_pauli_rotations.py +3 -1
- classiq/interface/generator/mcu.py +5 -3
- classiq/interface/generator/mcx.py +7 -5
- classiq/interface/generator/model/constraints.py +2 -1
- classiq/interface/generator/model/model.py +11 -19
- classiq/interface/generator/model/preferences/preferences.py +4 -3
- classiq/interface/generator/oracles/custom_oracle.py +4 -2
- classiq/interface/generator/oracles/oracle_abc.py +2 -2
- classiq/interface/generator/qpe.py +6 -4
- classiq/interface/generator/qsvm.py +5 -8
- classiq/interface/generator/quantum_function_call.py +21 -16
- classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
- classiq/interface/generator/range_types.py +3 -1
- classiq/interface/generator/slice_parsing_utils.py +8 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
- classiq/interface/generator/state_preparation/metrics.py +2 -1
- classiq/interface/generator/state_preparation/state_preparation.py +7 -5
- classiq/interface/generator/state_propagator.py +16 -5
- classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
- classiq/interface/generator/types/struct_declaration.py +8 -3
- classiq/interface/generator/ucc.py +6 -4
- classiq/interface/generator/unitary_gate.py +7 -3
- classiq/interface/generator/validations/flow_graph.py +6 -4
- classiq/interface/generator/validations/validator_functions.py +6 -4
- classiq/interface/hardware.py +2 -2
- classiq/interface/helpers/custom_encoders.py +3 -0
- classiq/interface/helpers/pydantic_model_helpers.py +0 -6
- classiq/interface/helpers/validation_helpers.py +1 -1
- classiq/interface/helpers/versioned_model.py +4 -1
- classiq/interface/ide/show.py +2 -2
- classiq/interface/jobs.py +72 -3
- classiq/interface/model/bind_operation.py +18 -11
- classiq/interface/model/call_synthesis_data.py +68 -0
- classiq/interface/model/inplace_binary_operation.py +2 -2
- classiq/interface/model/model.py +27 -21
- classiq/interface/model/native_function_definition.py +3 -5
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
- classiq/interface/model/quantum_expressions/control_state.py +2 -2
- classiq/interface/model/quantum_function_call.py +25 -139
- classiq/interface/model/quantum_function_declaration.py +8 -0
- classiq/interface/model/quantum_if_operation.py +2 -3
- classiq/interface/model/quantum_lambda_function.py +64 -0
- classiq/interface/model/quantum_type.py +57 -56
- classiq/interface/model/quantum_variable_declaration.py +1 -1
- classiq/interface/model/statement_block.py +32 -0
- classiq/interface/model/validations/handles_validator.py +14 -12
- classiq/interface/model/within_apply_operation.py +11 -0
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
- classiq/interface/server/routes.py +5 -0
- classiq/model/function_handler.py +5 -9
- classiq/model/model.py +2 -19
- classiq/qmod/__init__.py +13 -6
- classiq/qmod/builtins/classical_execution_primitives.py +27 -36
- classiq/qmod/builtins/classical_functions.py +24 -14
- classiq/qmod/builtins/functions.py +162 -145
- classiq/qmod/builtins/operations.py +24 -35
- classiq/qmod/builtins/structs.py +15 -15
- classiq/qmod/cfunc.py +42 -0
- classiq/qmod/classical_function.py +6 -14
- classiq/qmod/declaration_inferrer.py +12 -21
- classiq/qmod/expression_query.py +23 -0
- classiq/qmod/model_state_container.py +2 -0
- classiq/qmod/native/__init__.py +0 -0
- classiq/qmod/native/expression_to_qmod.py +189 -0
- classiq/qmod/native/pretty_printer.py +311 -0
- classiq/qmod/qfunc.py +27 -0
- classiq/qmod/qmod_constant.py +76 -0
- classiq/qmod/qmod_parameter.py +34 -12
- classiq/qmod/qmod_struct.py +3 -3
- classiq/qmod/qmod_variable.py +102 -18
- classiq/qmod/quantum_expandable.py +16 -16
- classiq/qmod/quantum_function.py +37 -8
- classiq/qmod/symbolic.py +47 -4
- classiq/qmod/symbolic_expr.py +9 -0
- classiq/qmod/utilities.py +13 -0
- classiq/qmod/write_qmod.py +39 -0
- classiq/quantum_functions/__init__.py +2 -2
- classiq/quantum_functions/annotation_parser.py +9 -11
- classiq/quantum_functions/function_parser.py +1 -1
- classiq/quantum_functions/quantum_function.py +3 -3
- classiq/quantum_register.py +17 -9
- {classiq-0.37.0.dist-info → classiq-0.38.0.dist-info}/METADATA +2 -1
- {classiq-0.37.0.dist-info → classiq-0.38.0.dist-info}/RECORD +222 -186
- {classiq-0.37.0.dist-info → classiq-0.38.0.dist-info}/WHEEL +1 -1
- classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
- classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
- classiq/interface/generator/types/combinatorial_problem.py +0 -26
- classiq/interface/model/numeric_reinterpretation.py +0 -25
- classiq/interface/model/operator_synthesis_data.py +0 -48
- classiq/model/function_handler.pyi +0 -152
@@ -0,0 +1,311 @@
|
|
1
|
+
from typing import Dict, List
|
2
|
+
|
3
|
+
from classiq.interface.generator.constant import Constant
|
4
|
+
from classiq.interface.generator.expressions.expression import Expression
|
5
|
+
from classiq.interface.generator.functions.classical_type import (
|
6
|
+
ClassicalArray,
|
7
|
+
ConcreteClassicalType,
|
8
|
+
)
|
9
|
+
from classiq.interface.generator.functions.port_declaration import (
|
10
|
+
PortDeclarationDirection,
|
11
|
+
)
|
12
|
+
from classiq.interface.generator.visitor import NodeType, Visitor
|
13
|
+
from classiq.interface.model.bind_operation import BindOperation
|
14
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
15
|
+
ClassicalParameterDeclaration,
|
16
|
+
)
|
17
|
+
from classiq.interface.model.handle_binding import (
|
18
|
+
HandleBinding,
|
19
|
+
SlicedHandleBinding,
|
20
|
+
SubscriptHandleBinding,
|
21
|
+
)
|
22
|
+
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
23
|
+
from classiq.interface.model.model import Model
|
24
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
25
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
26
|
+
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
27
|
+
AmplitudeLoadingOperation,
|
28
|
+
)
|
29
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
30
|
+
ArithmeticOperation,
|
31
|
+
)
|
32
|
+
from classiq.interface.model.quantum_function_call import (
|
33
|
+
OperandIdentifier,
|
34
|
+
QuantumFunctionCall,
|
35
|
+
)
|
36
|
+
from classiq.interface.model.quantum_function_declaration import (
|
37
|
+
QuantumFunctionDeclaration,
|
38
|
+
QuantumOperandDeclaration,
|
39
|
+
)
|
40
|
+
from classiq.interface.model.quantum_if_operation import QuantumIfOperation
|
41
|
+
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
42
|
+
from classiq.interface.model.quantum_type import (
|
43
|
+
QuantumBit,
|
44
|
+
QuantumBitvector,
|
45
|
+
QuantumNumeric,
|
46
|
+
)
|
47
|
+
from classiq.interface.model.quantum_variable_declaration import (
|
48
|
+
QuantumVariableDeclaration,
|
49
|
+
)
|
50
|
+
from classiq.interface.model.statement_block import StatementBlock
|
51
|
+
from classiq.interface.model.variable_declaration_statement import (
|
52
|
+
VariableDeclarationStatement,
|
53
|
+
)
|
54
|
+
from classiq.interface.model.within_apply_operation import WithinApplyOperation
|
55
|
+
|
56
|
+
from classiq import Bool, ClassicalList, Integer, Pauli, Real, Struct, StructDeclaration
|
57
|
+
from classiq.qmod.native.expression_to_qmod import transform_expression
|
58
|
+
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
59
|
+
|
60
|
+
|
61
|
+
class DSLPrettyPrinter(Visitor):
|
62
|
+
def __init__(self, decimal_precision: int = DEFAULT_DECIMAL_PRECISION) -> None:
|
63
|
+
self._level = 0
|
64
|
+
self._decimal_precision = decimal_precision
|
65
|
+
|
66
|
+
def visit(self, node: NodeType) -> str:
|
67
|
+
res = super().visit(node)
|
68
|
+
if not isinstance(res, str):
|
69
|
+
raise AssertionError(f"Pretty printing for {type(node)} is not supported ")
|
70
|
+
return res
|
71
|
+
|
72
|
+
def visit_Model(self, model: Model) -> str:
|
73
|
+
struct_decls = [self.visit(struct_decl) for struct_decl in model.types]
|
74
|
+
func_defs = [self.visit(func_def) for func_def in model.functions]
|
75
|
+
constants = [self.visit(constant) for constant in model.constants]
|
76
|
+
classical_code = (
|
77
|
+
f"cscope ```\n{model.classical_execution_code}\n```"
|
78
|
+
if model.classical_execution_code
|
79
|
+
else ""
|
80
|
+
)
|
81
|
+
return "\n".join([*constants, *struct_decls, *func_defs, classical_code])
|
82
|
+
|
83
|
+
def visit_Constant(self, constant: Constant) -> str:
|
84
|
+
return f"{self._indent}{self.visit(constant.name)}: {self.visit(constant.const_type)} = {self.visit(constant.value)};\n"
|
85
|
+
|
86
|
+
def _visit_arg_decls(self, func_def: QuantumFunctionDeclaration) -> str:
|
87
|
+
gen_time_args = ", ".join(
|
88
|
+
self.visit(arg_decl)
|
89
|
+
for arg_decl in func_def.get_positional_arg_decls()
|
90
|
+
if not isinstance(arg_decl, PortDeclaration)
|
91
|
+
)
|
92
|
+
quantum_args = ", ".join(
|
93
|
+
self.visit(arg_decl)
|
94
|
+
for arg_decl in func_def.get_positional_arg_decls()
|
95
|
+
if isinstance(arg_decl, PortDeclaration)
|
96
|
+
)
|
97
|
+
gen_time_arg_list = f"<{gen_time_args}>" if gen_time_args else ""
|
98
|
+
return f"{gen_time_arg_list}({quantum_args})"
|
99
|
+
|
100
|
+
def visit_QuantumFunctionDeclaration(
|
101
|
+
self, func_decl: QuantumFunctionDeclaration
|
102
|
+
) -> str:
|
103
|
+
return f"qfunc {func_decl.name}{self._visit_arg_decls(func_decl)}"
|
104
|
+
|
105
|
+
def visit_StructDeclaration(self, struct_decl: StructDeclaration) -> str:
|
106
|
+
return f"struct {struct_decl.name} {{\n{self._visit_variables(struct_decl.variables)}}}\n"
|
107
|
+
|
108
|
+
def _visit_variables(self, variables: Dict[str, ConcreteClassicalType]) -> str:
|
109
|
+
self._level += 1
|
110
|
+
variables_str = "".join(
|
111
|
+
f"{self._indent}{self.visit(field_name)}: {self.visit(var_decl)};\n"
|
112
|
+
for field_name, var_decl in variables.items()
|
113
|
+
)
|
114
|
+
self._level -= 1
|
115
|
+
return variables_str
|
116
|
+
|
117
|
+
def visit_QuantumVariableDeclaration(
|
118
|
+
self, var_decl: QuantumVariableDeclaration
|
119
|
+
) -> str:
|
120
|
+
return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
|
121
|
+
|
122
|
+
def visit_PortDeclaration(self, port_decl: PortDeclaration) -> str:
|
123
|
+
dir_str = (
|
124
|
+
f"{port_decl.direction} "
|
125
|
+
if port_decl.direction != PortDeclarationDirection.Inout
|
126
|
+
else ""
|
127
|
+
)
|
128
|
+
return f"{dir_str}{self.visit_QuantumVariableDeclaration(port_decl)}"
|
129
|
+
|
130
|
+
def visit_QuantumBit(self, qtype: QuantumBit) -> str:
|
131
|
+
return "qbit"
|
132
|
+
|
133
|
+
def visit_QuantumBitvector(self, qtype: QuantumBitvector) -> str:
|
134
|
+
if qtype.length is not None:
|
135
|
+
if qtype.length.is_evaluated() and qtype.length.to_int_value() == 1:
|
136
|
+
return "qbit"
|
137
|
+
return f"qbit[{self.visit(qtype.length)}]"
|
138
|
+
return "qbit[]"
|
139
|
+
|
140
|
+
def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
|
141
|
+
params = ""
|
142
|
+
if qtype.size is not None:
|
143
|
+
assert qtype.is_signed is not None
|
144
|
+
assert qtype.fraction_digits is not None
|
145
|
+
|
146
|
+
params = "<{}>".format(
|
147
|
+
", ".join(
|
148
|
+
self.visit(param)
|
149
|
+
for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
|
150
|
+
)
|
151
|
+
)
|
152
|
+
|
153
|
+
return f"qnum{params}"
|
154
|
+
|
155
|
+
def visit_ClassicalParameterDeclaration(
|
156
|
+
self, cparam: ClassicalParameterDeclaration
|
157
|
+
) -> str:
|
158
|
+
return f"{cparam.name}: {self.visit(cparam.classical_type)}"
|
159
|
+
|
160
|
+
def visit_Integer(self, ctint: Integer) -> str:
|
161
|
+
return "int"
|
162
|
+
|
163
|
+
def visit_Real(self, ctint: Real) -> str:
|
164
|
+
return "real"
|
165
|
+
|
166
|
+
def visit_Bool(self, ctbool: Bool) -> str:
|
167
|
+
return "bool"
|
168
|
+
|
169
|
+
def visit_Pauli(self, ctbool: Pauli) -> str:
|
170
|
+
return "Pauli"
|
171
|
+
|
172
|
+
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
173
|
+
return f"{self.visit(ctlist.element_type)}[]"
|
174
|
+
|
175
|
+
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
176
|
+
return f"{self.visit(ctarray.element_type)}[{ctarray.size}]"
|
177
|
+
|
178
|
+
def visit_Struct(self, struct: Struct) -> str:
|
179
|
+
return struct.name
|
180
|
+
|
181
|
+
def visit_VariableDeclarationStatement(
|
182
|
+
self, local_decl: VariableDeclarationStatement
|
183
|
+
) -> str:
|
184
|
+
return f"{self._indent}{self.visit_QuantumVariableDeclaration(local_decl)};\n"
|
185
|
+
|
186
|
+
def visit_QuantumOperandDeclaration(
|
187
|
+
self, op_decl: QuantumOperandDeclaration
|
188
|
+
) -> str:
|
189
|
+
return f"{op_decl.name}: qfunc{[] if op_decl.is_list else ''} {self._visit_arg_decls(op_decl)}"
|
190
|
+
|
191
|
+
def visit_NativeFunctionDefinition(self, func_def: NativeFunctionDefinition) -> str:
|
192
|
+
self._level += 1
|
193
|
+
body = "".join(self.visit(qvar_decl) for qvar_decl in func_def.body)
|
194
|
+
self._level -= 1
|
195
|
+
return f"{self.visit_QuantumFunctionDeclaration(func_def)} {{\n{body}}}\n"
|
196
|
+
|
197
|
+
def visit_QuantumFunctionCall(self, func_call: QuantumFunctionCall) -> str:
|
198
|
+
gen_time_args = ", ".join(
|
199
|
+
self.visit(arg_decl)
|
200
|
+
for arg_decl in func_call.get_positional_args()
|
201
|
+
if not isinstance(arg_decl, HandleBinding)
|
202
|
+
)
|
203
|
+
gen_time_arg_list = f"<{gen_time_args}>" if gen_time_args else ""
|
204
|
+
quantum_args = ", ".join(
|
205
|
+
self.visit(arg_decl)
|
206
|
+
for arg_decl in func_call.get_positional_args()
|
207
|
+
if isinstance(arg_decl, HandleBinding)
|
208
|
+
)
|
209
|
+
return f"{self._indent}{func_call.func_name}{f'[{self.visit(func_call.function.index)}]' if isinstance(func_call.function, OperandIdentifier) else ''}{gen_time_arg_list}({quantum_args});\n"
|
210
|
+
|
211
|
+
def visit_QuantumIfOperation(self, op: QuantumIfOperation) -> str:
|
212
|
+
quantum_if = f"{self._indent}quantum_if ({self.visit(op.expression)}) {{\n"
|
213
|
+
operand = op.then
|
214
|
+
if not isinstance(operand, QuantumLambdaFunction):
|
215
|
+
raise AssertionError(
|
216
|
+
"Expected quantum_if to be implemented using a lambda function"
|
217
|
+
)
|
218
|
+
quantum_if += self._visit_body(operand.body)
|
219
|
+
quantum_if += f"{self._indent}}}\n"
|
220
|
+
return quantum_if
|
221
|
+
|
222
|
+
def visit_WithinApplyOperation(self, op: WithinApplyOperation) -> str:
|
223
|
+
action = op.action
|
224
|
+
compute = op.compute
|
225
|
+
if not isinstance(action, QuantumLambdaFunction) or not isinstance(
|
226
|
+
compute, QuantumLambdaFunction
|
227
|
+
):
|
228
|
+
raise AssertionError(
|
229
|
+
"Expected within-apply to be implemented using a lambda functions"
|
230
|
+
)
|
231
|
+
within_apply_code = f"{self._indent}within {{\n"
|
232
|
+
within_apply_code += self._visit_body(compute.body)
|
233
|
+
within_apply_code += f"{self._indent}}} apply {{\n"
|
234
|
+
within_apply_code += self._visit_body(action.body)
|
235
|
+
within_apply_code += f"{self._indent}}}\n"
|
236
|
+
return within_apply_code
|
237
|
+
|
238
|
+
def _visit_body(self, body: StatementBlock) -> str:
|
239
|
+
code = ""
|
240
|
+
self._level += 1
|
241
|
+
for statement in body:
|
242
|
+
code += self.visit(statement)
|
243
|
+
self._level -= 1
|
244
|
+
return code
|
245
|
+
|
246
|
+
def visit_InplaceBinaryOperation(self, op: InplaceBinaryOperation) -> str:
|
247
|
+
return (
|
248
|
+
f"{self._indent}{op.operation.value}({op.value.name}, {op.target.name});\n"
|
249
|
+
)
|
250
|
+
|
251
|
+
def _visit_pack_expr(self, vars: List[HandleBinding]) -> str:
|
252
|
+
if len(vars) == 1:
|
253
|
+
return self.visit(vars[0])
|
254
|
+
|
255
|
+
var_list_str = ", ".join(self.visit(var) for var in vars)
|
256
|
+
return f"{{{var_list_str}}}"
|
257
|
+
|
258
|
+
def visit_Expression(self, expr: Expression) -> str:
|
259
|
+
return transform_expression(
|
260
|
+
expr.expr, level=self._level, decimal_precision=self._decimal_precision
|
261
|
+
)
|
262
|
+
|
263
|
+
def visit_QuantumLambdaFunction(self, qlambda: QuantumLambdaFunction) -> str:
|
264
|
+
assert qlambda.func_decl is not None
|
265
|
+
gen_time_args = ", ".join(
|
266
|
+
qlambda.rename_params.get(arg_decl.name, arg_decl.name)
|
267
|
+
for arg_decl in qlambda.func_decl.get_positional_arg_decls()
|
268
|
+
if not isinstance(arg_decl, PortDeclaration)
|
269
|
+
)
|
270
|
+
quantum_args = ", ".join(
|
271
|
+
arg_decl.name
|
272
|
+
for arg_decl in qlambda.func_decl.get_positional_arg_decls()
|
273
|
+
if isinstance(arg_decl, PortDeclaration)
|
274
|
+
)
|
275
|
+
gen_time_arg_list = f"<{gen_time_args}>" if gen_time_args else ""
|
276
|
+
body = self._visit_body(qlambda.body)
|
277
|
+
return f"lambda{gen_time_arg_list}({quantum_args}) {{\n{body}{self._indent}}}"
|
278
|
+
|
279
|
+
def visit_HandleBinding(self, var_ref: HandleBinding) -> str:
|
280
|
+
return var_ref.name
|
281
|
+
|
282
|
+
def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
|
283
|
+
return str(var_ref)
|
284
|
+
|
285
|
+
def visit_SubscriptHandleBinding(self, var_ref: SubscriptHandleBinding) -> str:
|
286
|
+
return str(var_ref)
|
287
|
+
|
288
|
+
def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
|
289
|
+
op = "^=" if arith_op.inplace_result else "="
|
290
|
+
return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)};\n"
|
291
|
+
|
292
|
+
def visit_AmplitudeLoadingOperation(
|
293
|
+
self, amplitude_loading_op: AmplitudeLoadingOperation
|
294
|
+
) -> str:
|
295
|
+
return f"{self._indent}{self.visit(amplitude_loading_op.result_var)} *= {self.visit(amplitude_loading_op.expression)};\n"
|
296
|
+
|
297
|
+
def _print_bind_handles(self, handles: List[HandleBinding]) -> str:
|
298
|
+
if len(handles) == 1:
|
299
|
+
return self.visit(handles[0])
|
300
|
+
|
301
|
+
return "{" + ", ".join(self.visit(handle) for handle in handles) + "}"
|
302
|
+
|
303
|
+
def visit_BindOperation(self, bind_op: BindOperation) -> str:
|
304
|
+
return f"{self._indent}{self._print_bind_handles(bind_op.in_handles)} -> {self._print_bind_handles(bind_op.out_handles)};\n"
|
305
|
+
|
306
|
+
def visit_list(self, node: list) -> str:
|
307
|
+
return "[" + ", ".join(self.visit(elem) for elem in node) + "]"
|
308
|
+
|
309
|
+
@property
|
310
|
+
def _indent(self) -> str:
|
311
|
+
return " " * self._level
|
classiq/qmod/qfunc.py
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
from typing import Callable, Optional, Union, overload
|
2
|
+
|
3
|
+
from classiq.qmod.quantum_callable import QCallable
|
4
|
+
from classiq.qmod.quantum_function import ExternalQFunc, QFunc
|
5
|
+
|
6
|
+
|
7
|
+
@overload
|
8
|
+
def qfunc(func: Callable, *, external: bool = False) -> QFunc: ...
|
9
|
+
|
10
|
+
|
11
|
+
@overload
|
12
|
+
def qfunc(func: None = None, *, external: bool) -> Callable[[Callable], QCallable]: ...
|
13
|
+
|
14
|
+
|
15
|
+
def qfunc(
|
16
|
+
func: Optional[Callable] = None, *, external: bool = False
|
17
|
+
) -> Union[Callable[[Callable], QCallable], QCallable]:
|
18
|
+
def wrapper(func: Callable) -> QCallable:
|
19
|
+
if external:
|
20
|
+
return ExternalQFunc(func)
|
21
|
+
|
22
|
+
return QFunc(func)
|
23
|
+
|
24
|
+
if func is not None:
|
25
|
+
return wrapper(func)
|
26
|
+
|
27
|
+
return wrapper
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import inspect
|
2
|
+
from typing import Any, Optional
|
3
|
+
|
4
|
+
from classiq.interface.generator.constant import Constant
|
5
|
+
from classiq.interface.generator.expressions.expression import Expression
|
6
|
+
from classiq.interface.generator.functions.classical_type import QStructBase
|
7
|
+
|
8
|
+
from classiq.exceptions import ClassiqError
|
9
|
+
from classiq.qmod.declaration_inferrer import python_type_to_qmod
|
10
|
+
from classiq.qmod.model_state_container import ModelStateContainer
|
11
|
+
from classiq.qmod.qmod_parameter import QParam, QParamStruct
|
12
|
+
|
13
|
+
|
14
|
+
class QConstant:
|
15
|
+
CURRENT_QMODULE: Optional[ModelStateContainer] = None
|
16
|
+
|
17
|
+
def __init__(self, name: str, py_type: type, value: Any) -> None:
|
18
|
+
self.name = name
|
19
|
+
self._py_type = py_type
|
20
|
+
self._value = value
|
21
|
+
|
22
|
+
@staticmethod
|
23
|
+
def set_current_model(qmodule: ModelStateContainer) -> None:
|
24
|
+
QConstant.CURRENT_QMODULE = qmodule
|
25
|
+
|
26
|
+
def add_to_model(self) -> None:
|
27
|
+
if QConstant.CURRENT_QMODULE is None:
|
28
|
+
raise ClassiqError(
|
29
|
+
"Error trying to add a constant to a model without a current QModule."
|
30
|
+
)
|
31
|
+
|
32
|
+
expr = str(self._value)
|
33
|
+
if (
|
34
|
+
self.name in QConstant.CURRENT_QMODULE.constants
|
35
|
+
and expr != QConstant.CURRENT_QMODULE.constants[self.name].value.expr
|
36
|
+
):
|
37
|
+
raise ClassiqError(f"Constant {self.name} is already defined in the model")
|
38
|
+
|
39
|
+
if isinstance(self._value, QConstant):
|
40
|
+
QConstant.CURRENT_QMODULE.constants[self.name] = Constant(
|
41
|
+
name=self.name,
|
42
|
+
const_type=QConstant.CURRENT_QMODULE.constants[
|
43
|
+
self._value.name
|
44
|
+
].const_type,
|
45
|
+
value=Expression(expr=self._value.name),
|
46
|
+
)
|
47
|
+
else:
|
48
|
+
qmod_type = python_type_to_qmod(
|
49
|
+
self._py_type, qmodule=QConstant.CURRENT_QMODULE
|
50
|
+
)
|
51
|
+
if qmod_type is None:
|
52
|
+
raise ClassiqError("Invalid QMOD type")
|
53
|
+
|
54
|
+
QConstant.CURRENT_QMODULE.constants[self.name] = Constant(
|
55
|
+
name=self.name,
|
56
|
+
const_type=qmod_type,
|
57
|
+
value=Expression(expr=expr),
|
58
|
+
)
|
59
|
+
|
60
|
+
def __getattr__(self, name: str) -> QParam:
|
61
|
+
self.add_to_model()
|
62
|
+
|
63
|
+
py_type = type(self._value)
|
64
|
+
if (
|
65
|
+
QConstant.CURRENT_QMODULE is None
|
66
|
+
or not inspect.isclass(py_type)
|
67
|
+
or not issubclass(py_type, QStructBase)
|
68
|
+
):
|
69
|
+
return self.__getattribute__(name)
|
70
|
+
|
71
|
+
return QParamStruct.get_field(
|
72
|
+
QConstant.CURRENT_QMODULE, self.name, py_type.__name__, name
|
73
|
+
)
|
74
|
+
|
75
|
+
def __str__(self) -> str:
|
76
|
+
return self.name
|
classiq/qmod/qmod_parameter.py
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
import sys
|
2
|
-
from typing import
|
3
|
-
|
2
|
+
from typing import ( # type: ignore[attr-defined]
|
3
|
+
TYPE_CHECKING,
|
4
|
+
Any,
|
5
|
+
Generic,
|
6
|
+
TypeVar,
|
7
|
+
Union,
|
8
|
+
_GenericAlias,
|
9
|
+
)
|
4
10
|
|
5
11
|
from typing_extensions import ParamSpec
|
6
12
|
|
@@ -19,8 +25,15 @@ from classiq.qmod.symbolic_expr import Symbolic, SymbolicExpr
|
|
19
25
|
_T = TypeVar("_T")
|
20
26
|
|
21
27
|
|
22
|
-
|
23
|
-
|
28
|
+
if TYPE_CHECKING:
|
29
|
+
|
30
|
+
class QParam(SymbolicExpr, Generic[_T]):
|
31
|
+
pass
|
32
|
+
|
33
|
+
else:
|
34
|
+
|
35
|
+
class QParam(Symbolic, Generic[_T]):
|
36
|
+
pass
|
24
37
|
|
25
38
|
|
26
39
|
class QParamScalar(QParam, SymbolicExpr):
|
@@ -46,7 +59,7 @@ class QParamList(QParam):
|
|
46
59
|
)
|
47
60
|
|
48
61
|
def __len__(self) -> int:
|
49
|
-
raise
|
62
|
+
raise ClassiqValueError(
|
50
63
|
"len(<expr>) is not supported for QMod lists - use <expr>.len() instead"
|
51
64
|
)
|
52
65
|
|
@@ -63,22 +76,31 @@ class QParamStruct(QParam):
|
|
63
76
|
self._struct_type = struct_type
|
64
77
|
|
65
78
|
def __getattr__(self, field_name: str) -> QParam:
|
79
|
+
return QParamStruct.get_field(
|
80
|
+
self._qmodule, str(self), self._struct_type.name, field_name
|
81
|
+
)
|
82
|
+
|
83
|
+
@staticmethod
|
84
|
+
def get_field(
|
85
|
+
qmodule: ModelStateContainer,
|
86
|
+
variable_name: str,
|
87
|
+
struct_name: str,
|
88
|
+
field_name: str,
|
89
|
+
) -> QParam:
|
66
90
|
struct_decl = StructDeclaration.BUILTIN_STRUCT_DECLARATIONS.get(
|
67
|
-
|
91
|
+
struct_name, qmodule.type_decls.get(struct_name)
|
68
92
|
)
|
69
|
-
if struct_decl is None:
|
70
|
-
struct_decl = self._qmodule.type_decls.get(self._struct_type.name)
|
71
93
|
assert struct_decl is not None
|
72
94
|
field_type = struct_decl.variables.get(field_name)
|
73
95
|
if field_type is None:
|
74
96
|
raise ClassiqValueError(
|
75
|
-
f"Struct {
|
97
|
+
f"Struct {struct_name!r} doesn't have field {field_name!r}"
|
76
98
|
)
|
77
99
|
|
78
100
|
return create_param(
|
79
|
-
f"get_field({
|
101
|
+
f"get_field({variable_name},{field_name!r})",
|
80
102
|
field_type,
|
81
|
-
qmodule=
|
103
|
+
qmodule=qmodule,
|
82
104
|
)
|
83
105
|
|
84
106
|
|
@@ -100,7 +122,7 @@ class Array(ArrayBase[_P]):
|
|
100
122
|
def create_param(
|
101
123
|
expr_str: str, ctype: ClassicalType, qmodule: ModelStateContainer
|
102
124
|
) -> QParam:
|
103
|
-
if isinstance(ctype, ClassicalList
|
125
|
+
if isinstance(ctype, (ClassicalList, ClassicalArray)):
|
104
126
|
return QParamList(expr_str, ctype, qmodule=qmodule)
|
105
127
|
elif isinstance(ctype, Struct):
|
106
128
|
return QParamStruct(expr_str, ctype, qmodule=qmodule)
|
classiq/qmod/qmod_struct.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import dataclasses
|
2
|
-
from typing import Any,
|
2
|
+
from typing import Any, Type
|
3
3
|
|
4
4
|
from typing_extensions import dataclass_transform
|
5
5
|
|
@@ -16,7 +16,7 @@ def _qmod_val_to_expr_str(val: Any) -> str:
|
|
16
16
|
)
|
17
17
|
return f"struct_literal({type(val).__name__}, {kwargs_str})"
|
18
18
|
|
19
|
-
if isinstance(val,
|
19
|
+
if isinstance(val, list):
|
20
20
|
elements_str = ", ".join([_qmod_val_to_expr_str(elem) for elem in val])
|
21
21
|
return f"[{elements_str}]"
|
22
22
|
|
@@ -24,7 +24,7 @@ def _qmod_val_to_expr_str(val: Any) -> str:
|
|
24
24
|
|
25
25
|
|
26
26
|
@dataclass_transform()
|
27
|
-
def
|
27
|
+
def struct(user_class: Type) -> Type:
|
28
28
|
def _new_repr(self: Any) -> str:
|
29
29
|
return _qmod_val_to_expr_str(self)
|
30
30
|
|