classiq 0.88.0__py3-none-any.whl → 0.90.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.
Potentially problematic release.
This version of classiq might be problematic. Click here for more details.
- classiq/__init__.py +1 -0
- classiq/_internals/api_wrapper.py +16 -32
- classiq/_internals/config.py +1 -1
- classiq/analyzer/show_interactive_hack.py +26 -1
- classiq/applications/chemistry/chemistry_model_constructor.py +14 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +9 -6
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +16 -8
- classiq/evaluators/classical_expression.py +63 -41
- classiq/evaluators/control.py +31 -52
- classiq/evaluators/expression_evaluator.py +8 -4
- classiq/evaluators/parameter_types.py +200 -104
- classiq/evaluators/qmod_annotated_expression.py +10 -9
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +2 -2
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +1 -1
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +66 -5
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +12 -37
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +8 -17
- classiq/evaluators/qmod_node_evaluators/measurement_evaluation.py +1 -1
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +7 -1
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +0 -1
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +9 -1
- classiq/evaluators/qmod_node_evaluators/utils.py +33 -0
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +4 -7
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +2 -26
- classiq/interface/analyzer/result.py +4 -0
- classiq/interface/backend/backend_preferences.py +1 -1
- classiq/interface/chemistry/ground_state_problem.py +16 -2
- classiq/interface/executor/optimizer_preferences.py +0 -112
- classiq/interface/generator/application_apis/chemistry_declarations.py +3 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -7
- classiq/interface/generator/arith/register_user_input.py +1 -1
- classiq/interface/generator/expressions/evaluated_expression.py +3 -13
- classiq/interface/generator/expressions/expression_types.py +8 -22
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +2 -2
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +1 -2
- classiq/interface/generator/functions/classical_type.py +24 -3
- classiq/interface/generator/functions/concrete_types.py +1 -1
- classiq/interface/generator/functions/function_declaration.py +0 -4
- classiq/interface/generator/functions/type_name.py +25 -0
- classiq/interface/generator/generated_circuit_data.py +4 -0
- classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
- classiq/interface/generator/preferences/qasm_to_qmod_params.py +14 -0
- classiq/interface/generator/quantum_function_call.py +3 -3
- classiq/interface/generator/user_defined_function_params.py +0 -3
- classiq/interface/helpers/model_normalizer.py +0 -6
- classiq/interface/ide/ide_data.py +1 -1
- classiq/interface/ide/visual_model.py +3 -2
- classiq/interface/model/block.py +5 -1
- classiq/interface/model/handle_binding.py +2 -2
- classiq/interface/model/port_declaration.py +2 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +16 -12
- classiq/interface/model/quantum_lambda_function.py +1 -1
- classiq/interface/model/quantum_statement.py +2 -4
- classiq/interface/model/quantum_type.py +47 -4
- classiq/interface/server/routes.py +2 -3
- classiq/model_expansions/atomic_expression_functions_defs.py +4 -22
- classiq/model_expansions/capturing/captured_vars.py +7 -3
- classiq/model_expansions/closure.py +8 -0
- classiq/model_expansions/interpreters/base_interpreter.py +84 -22
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +1 -1
- classiq/model_expansions/interpreters/generative_interpreter.py +7 -5
- classiq/model_expansions/quantum_operations/allocate.py +92 -21
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +28 -27
- classiq/model_expansions/quantum_operations/call_emitter.py +32 -26
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -2
- classiq/model_expansions/quantum_operations/emitter.py +39 -69
- classiq/model_expansions/quantum_operations/expression_evaluator.py +13 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -5
- classiq/model_expansions/quantum_operations/variable_decleration.py +16 -11
- classiq/model_expansions/scope.py +36 -29
- classiq/model_expansions/scope_initialization.py +3 -6
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +6 -2
- classiq/model_expansions/transformers/model_renamer.py +35 -64
- classiq/model_expansions/transformers/type_modifier_inference.py +6 -6
- classiq/model_expansions/visitors/boolean_expression_transformers.py +7 -31
- classiq/model_expansions/visitors/symbolic_param_inference.py +9 -3
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/state_preparation.py +140 -5
- classiq/qmod/builtins/functions/allocation.py +8 -8
- classiq/qmod/builtins/functions/arithmetic.py +1 -1
- classiq/qmod/builtins/functions/chemistry.py +64 -0
- classiq/qmod/builtins/functions/exponentiation.py +7 -13
- classiq/qmod/builtins/functions/qsvm.py +1 -1
- classiq/qmod/builtins/operations.py +38 -10
- classiq/qmod/generative.py +2 -4
- classiq/qmod/native/pretty_printer.py +1 -1
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/qmod_constant.py +1 -1
- classiq/qmod/qmod_parameter.py +2 -2
- classiq/qmod/qmod_variable.py +62 -16
- classiq/qmod/quantum_expandable.py +1 -1
- classiq/synthesis.py +37 -1
- classiq/visualization.py +1 -1
- {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/METADATA +2 -2
- {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/RECORD +98 -102
- classiq/evaluators/arg_type_match.py +0 -168
- classiq/evaluators/classical_type_inference.py +0 -121
- classiq/interface/combinatorial_optimization/optimization_problem.py +0 -17
- classiq/interface/combinatorial_optimization/result.py +0 -9
- classiq/model_expansions/transformers/ast_renamer.py +0 -26
- {classiq-0.88.0.dist-info → classiq-0.90.0.dist-info}/WHEEL +0 -0
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import copy
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
|
6
6
|
|
|
7
|
-
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import LogicalXor
|
|
8
|
-
|
|
9
7
|
|
|
10
8
|
class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
11
9
|
"""
|
|
@@ -36,13 +34,13 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
36
34
|
self._is_convertible = False
|
|
37
35
|
return node
|
|
38
36
|
|
|
39
|
-
def visit_BinOp(self, node: ast.BinOp) ->
|
|
37
|
+
def visit_BinOp(self, node: ast.BinOp) -> ast.AST:
|
|
40
38
|
self.generic_visit(node)
|
|
41
39
|
self._is_convertible = self._is_bool(node)
|
|
42
40
|
if not self._is_convertible:
|
|
43
41
|
return node
|
|
44
42
|
|
|
45
|
-
return self.
|
|
43
|
+
return self._convert_bin_op_to_bool_op(node)
|
|
46
44
|
|
|
47
45
|
def visit_UnaryOp(self, node: ast.UnaryOp) -> ast.AST:
|
|
48
46
|
self.generic_visit(node)
|
|
@@ -70,9 +68,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
70
68
|
return self._simplify_trivial_equality(node)
|
|
71
69
|
|
|
72
70
|
def visit_Call(self, node: ast.Call) -> ast.Call:
|
|
73
|
-
self._is_convertible =
|
|
74
|
-
isinstance(node.func, ast.Name) and node.func.id == LogicalXor.__name__
|
|
75
|
-
)
|
|
71
|
+
self._is_convertible = False
|
|
76
72
|
return node
|
|
77
73
|
|
|
78
74
|
def _is_bool(self, node: ast.AST) -> bool:
|
|
@@ -97,9 +93,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
97
93
|
and isinstance(node.ops[0], (ast.Eq, ast.NotEq))
|
|
98
94
|
)
|
|
99
95
|
if isinstance(node, ast.Call):
|
|
100
|
-
return
|
|
101
|
-
isinstance(node.func, ast.Name) and node.func.id == LogicalXor.__name__
|
|
102
|
-
)
|
|
96
|
+
return False
|
|
103
97
|
return False
|
|
104
98
|
|
|
105
99
|
def _convert_bin_op_to_bool_op(self, node: ast.BinOp) -> ast.AST:
|
|
@@ -116,11 +110,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
116
110
|
if not (
|
|
117
111
|
isinstance(node.left, ast.Constant) or isinstance(node.right, ast.Constant)
|
|
118
112
|
):
|
|
119
|
-
return ast.
|
|
120
|
-
func=ast.Name(LogicalXor.__name__),
|
|
121
|
-
args=[node.left, node.right],
|
|
122
|
-
keywords=[],
|
|
123
|
-
)
|
|
113
|
+
return ast.BinOp(left=node.left, op=ast.BitXor(), right=node.right)
|
|
124
114
|
|
|
125
115
|
if isinstance(node.left, ast.Constant):
|
|
126
116
|
constant = node.left.value
|
|
@@ -128,10 +118,7 @@ class BooleanExpressionOptimizer(ast.NodeTransformer):
|
|
|
128
118
|
else:
|
|
129
119
|
if TYPE_CHECKING:
|
|
130
120
|
assert isinstance(node.right, ast.Constant)
|
|
131
|
-
|
|
132
|
-
constant = node.right.value
|
|
133
|
-
except AttributeError as e:
|
|
134
|
-
raise e
|
|
121
|
+
constant = node.right.value
|
|
135
122
|
other = node.left
|
|
136
123
|
|
|
137
124
|
return other if constant == 0 else ast.UnaryOp(op=ast.Not(), operand=other)
|
|
@@ -201,14 +188,3 @@ class BooleanExpressionFuncLibAdapter(ast.NodeTransformer):
|
|
|
201
188
|
return node
|
|
202
189
|
self.generic_visit(node)
|
|
203
190
|
return ast.UnaryOp(op=ast.Not(), operand=node.operand)
|
|
204
|
-
|
|
205
|
-
def visit_BinOp(self, node: ast.BinOp) -> Union[ast.BinOp, ast.Call]:
|
|
206
|
-
"""Due to Sympy crap, we need to translate the Xor nodes to our LogicalXor"""
|
|
207
|
-
if not (self._is_boolean_optimized and isinstance(node.op, ast.BitXor)):
|
|
208
|
-
return node
|
|
209
|
-
self.generic_visit(node)
|
|
210
|
-
return ast.Call(
|
|
211
|
-
func=ast.Name(LogicalXor.__name__),
|
|
212
|
-
args=[node.left, node.right],
|
|
213
|
-
keywords=[],
|
|
214
|
-
)
|
|
@@ -100,6 +100,7 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
100
100
|
)
|
|
101
101
|
self._inferred_funcs: set[str] = set()
|
|
102
102
|
self._scope: Mapping[str, ClassicalType] = {}
|
|
103
|
+
self._quantum_scope: set[str] = set()
|
|
103
104
|
self._scope_operands: dict[str, QuantumOperandDeclaration] = {}
|
|
104
105
|
|
|
105
106
|
def infer(self) -> None:
|
|
@@ -109,16 +110,19 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
109
110
|
@contextmanager
|
|
110
111
|
def function_context(
|
|
111
112
|
self,
|
|
112
|
-
func_name: Optional[str],
|
|
113
113
|
scope: Mapping[str, ClassicalType],
|
|
114
|
+
quantum_scope: set[str],
|
|
114
115
|
scope_operands: dict[str, QuantumOperandDeclaration],
|
|
115
116
|
) -> Iterator[None]:
|
|
116
117
|
prev_scope = self._scope
|
|
117
118
|
self._scope = scope
|
|
119
|
+
prev_quantum_scope = self._quantum_scope
|
|
120
|
+
self._quantum_scope = quantum_scope
|
|
118
121
|
prev_scope_ops = self._scope_operands
|
|
119
122
|
self._scope_operands = scope_operands
|
|
120
123
|
yield
|
|
121
124
|
self._scope = prev_scope
|
|
125
|
+
self._quantum_scope = prev_quantum_scope
|
|
122
126
|
self._scope_operands = prev_scope_ops
|
|
123
127
|
|
|
124
128
|
def _infer_func_params(self, func: NativeFunctionDefinition) -> None:
|
|
@@ -126,8 +130,9 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
126
130
|
return
|
|
127
131
|
self._inferred_funcs.add(func.name)
|
|
128
132
|
scope = {param.name: param.classical_type for param in func.param_decls}
|
|
133
|
+
quantum_scope = set(func.port_names)
|
|
129
134
|
scope_operands = func.operand_declarations_dict
|
|
130
|
-
with self.function_context(
|
|
135
|
+
with self.function_context(scope, quantum_scope, scope_operands):
|
|
131
136
|
for param in func.positional_arg_declarations:
|
|
132
137
|
for expr in _get_param_expressions(param):
|
|
133
138
|
self._process_compile_time_expression(expr.expr)
|
|
@@ -139,13 +144,14 @@ class SymbolicParamInference(ModelVisitor):
|
|
|
139
144
|
cast(str, param.name): param.classical_type
|
|
140
145
|
for param in func.named_func_decl.param_decls
|
|
141
146
|
}
|
|
147
|
+
quantum_scope = set(self._quantum_scope) | set(func.named_func_decl.port_names)
|
|
142
148
|
scope_operands = self._scope_operands | nameables_to_dict(
|
|
143
149
|
cast(
|
|
144
150
|
Sequence[QuantumOperandDeclaration],
|
|
145
151
|
func.named_func_decl.operand_declarations,
|
|
146
152
|
)
|
|
147
153
|
)
|
|
148
|
-
with self.function_context(
|
|
154
|
+
with self.function_context(scope, quantum_scope, scope_operands):
|
|
149
155
|
self.visit(func.body)
|
|
150
156
|
|
|
151
157
|
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
|
@@ -101,6 +101,7 @@ __all__ = [
|
|
|
101
101
|
"inplace_c_modular_multiply",
|
|
102
102
|
"inplace_prepare_complex_amplitudes",
|
|
103
103
|
"inplace_prepare_int",
|
|
104
|
+
"inplace_prepare_sparse_amplitudes",
|
|
104
105
|
"lcu",
|
|
105
106
|
"lcu_pauli",
|
|
106
107
|
"linear_pauli_rotations",
|
|
@@ -117,6 +118,7 @@ __all__ = [
|
|
|
117
118
|
"prepare_ghz_state",
|
|
118
119
|
"prepare_int",
|
|
119
120
|
"prepare_linear_amplitudes",
|
|
121
|
+
"prepare_sparse_amplitudes",
|
|
120
122
|
"prepare_uniform_interval_state",
|
|
121
123
|
"prepare_uniform_trimmed_state",
|
|
122
124
|
"projector_controlled_double_phase",
|
|
@@ -24,6 +24,7 @@ from classiq.qmod.builtins.operations import (
|
|
|
24
24
|
control,
|
|
25
25
|
if_,
|
|
26
26
|
inplace_add,
|
|
27
|
+
inplace_xor,
|
|
27
28
|
repeat,
|
|
28
29
|
within_apply,
|
|
29
30
|
)
|
|
@@ -326,7 +327,7 @@ def _classical_hadamard_transform(arr: list[float]) -> np.ndarray:
|
|
|
326
327
|
@qfunc
|
|
327
328
|
def apply_phase_table(
|
|
328
329
|
phases: list[float],
|
|
329
|
-
target: QArray[QBit, Literal["log(
|
|
330
|
+
target: QArray[QBit, Literal["log(phases.len, 2)"]],
|
|
330
331
|
) -> None:
|
|
331
332
|
alphas = -2 * _classical_hadamard_transform(phases) / np.sqrt(len(phases))
|
|
332
333
|
|
|
@@ -343,7 +344,7 @@ def apply_phase_table(
|
|
|
343
344
|
def inplace_prepare_complex_amplitudes(
|
|
344
345
|
magnitudes: CArray[CReal],
|
|
345
346
|
phases: list[float],
|
|
346
|
-
target: QArray[QBit, Literal["log(
|
|
347
|
+
target: QArray[QBit, Literal["log(magnitudes.len, 2)"]],
|
|
347
348
|
) -> None:
|
|
348
349
|
"""
|
|
349
350
|
|
|
@@ -358,14 +359,15 @@ def inplace_prepare_complex_amplitudes(
|
|
|
358
359
|
target: The quantum variable to act upon.
|
|
359
360
|
"""
|
|
360
361
|
inplace_prepare_amplitudes(magnitudes, 0, target)
|
|
361
|
-
|
|
362
|
+
if not np.allclose(phases, 0, atol=1e-12):
|
|
363
|
+
apply_phase_table(phases, target)
|
|
362
364
|
|
|
363
365
|
|
|
364
366
|
@qfunc
|
|
365
367
|
def prepare_complex_amplitudes(
|
|
366
368
|
magnitudes: CArray[CReal],
|
|
367
369
|
phases: list[float],
|
|
368
|
-
out: Output[QArray[QBit, Literal["log(
|
|
370
|
+
out: Output[QArray[QBit, Literal["log(magnitudes.len, 2)"]]],
|
|
369
371
|
) -> None:
|
|
370
372
|
"""
|
|
371
373
|
|
|
@@ -486,7 +488,7 @@ def _zero_ctrl_rot(ctrl: QNum, target: QBit, theta: CReal) -> None:
|
|
|
486
488
|
|
|
487
489
|
@qfunc
|
|
488
490
|
def prepare_linear_amplitudes(x: QArray) -> None:
|
|
489
|
-
"""
|
|
491
|
+
"""
|
|
490
492
|
[Qmod Classiq-library function]
|
|
491
493
|
|
|
492
494
|
Initializes a quantum variable in a state with linear amplitudes:
|
|
@@ -511,3 +513,136 @@ def prepare_linear_amplitudes(x: QArray) -> None:
|
|
|
511
513
|
_zero_ctrl_rot(x[0:k], x[k], thetas[k])
|
|
512
514
|
|
|
513
515
|
hadamard_transform(x)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
@qfunc
|
|
519
|
+
def swap_states(a: int, b: int, target: QArray) -> None:
|
|
520
|
+
"""
|
|
521
|
+
Swap 2 computational basis states a and b, leave all other states untouched.
|
|
522
|
+
|
|
523
|
+
Args:
|
|
524
|
+
a: 1st state number.
|
|
525
|
+
b: 2nd state number.
|
|
526
|
+
target: The quantum variable to act upon.
|
|
527
|
+
"""
|
|
528
|
+
assert a != b, "a and b should be different"
|
|
529
|
+
diff = a ^ b
|
|
530
|
+
diff_indices = [i for i in range(target.len) if (diff >> i) & 1]
|
|
531
|
+
anchor = diff_indices[0]
|
|
532
|
+
anchor_bit = (a >> anchor) & 1
|
|
533
|
+
|
|
534
|
+
# a hack for the binding (should be improved after we have cast
|
|
535
|
+
target_without_anchor = []
|
|
536
|
+
if anchor > 0:
|
|
537
|
+
target_without_anchor.append(target[0:anchor])
|
|
538
|
+
if anchor < target.len - 1:
|
|
539
|
+
target_without_anchor.append(target[anchor + 1 : target.len])
|
|
540
|
+
|
|
541
|
+
@qfunc
|
|
542
|
+
def _xor_if_equal(n: CInt, ctrl: QNum, target: QBit) -> None:
|
|
543
|
+
target ^= ctrl == n
|
|
544
|
+
|
|
545
|
+
def _remove_bit(x: int, j: int) -> int:
|
|
546
|
+
"""
|
|
547
|
+
Remove bit j from integer x (0 = least significant bit)
|
|
548
|
+
and shift higher bits down.
|
|
549
|
+
"""
|
|
550
|
+
low = x & ((1 << j) - 1) # bits below j
|
|
551
|
+
high = x >> (j + 1) # bits above j
|
|
552
|
+
return low | (high << j)
|
|
553
|
+
|
|
554
|
+
within_apply(
|
|
555
|
+
# make the states equal except the anchor qubit
|
|
556
|
+
lambda: [
|
|
557
|
+
inplace_xor(target[anchor] != anchor_bit, target[i])
|
|
558
|
+
for i in diff_indices[1:]
|
|
559
|
+
],
|
|
560
|
+
# do the actual swapping
|
|
561
|
+
lambda: _xor_if_equal(
|
|
562
|
+
_remove_bit(a, anchor), target_without_anchor, target[anchor]
|
|
563
|
+
),
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
@qfunc
|
|
568
|
+
def inplace_prepare_sparse_amplitudes(
|
|
569
|
+
states: list[int], amplitudes: list[complex], target: QArray
|
|
570
|
+
) -> None:
|
|
571
|
+
"""
|
|
572
|
+
[Qmod Classiq-library function]
|
|
573
|
+
|
|
574
|
+
Prepares a quantum state with the given (complex) amplitudes. The input is given sparse format, as a list of non-zero states and their corresponding amplitudes.
|
|
575
|
+
Notice that the function is only suitable sparse states. Inspired by https://arxiv.org/abs/2310.19309.
|
|
576
|
+
|
|
577
|
+
For example, `inplace_prepare_sparse_amplitudes([1, 8], [np.sqrt(0.5), np.sqrt(0.5)], target)` will prepare the state sqrt(0.5)|1> + sqrt(0.5)|8>
|
|
578
|
+
on the target variable, assuming it starts in the |0> state.
|
|
579
|
+
|
|
580
|
+
Complexity: Asymptotic gate complexity is $O(dn)$ where d is the number of states and n is the target number of qubits.
|
|
581
|
+
|
|
582
|
+
Args:
|
|
583
|
+
states: A list of distinct computational basis indices to populate. Each integer corresponds to the basis state in the computational basis.
|
|
584
|
+
amplitudes: A list of complex amplitudes for the corresponding entries in `states`. Must have the same length as `states`.
|
|
585
|
+
target: The quantum variable on which the state is to be prepared. Its size must be sufficient to represent all states in `states`.
|
|
586
|
+
"""
|
|
587
|
+
assert len(amplitudes) == len(
|
|
588
|
+
states
|
|
589
|
+
), "amplitudes and states should have the same size"
|
|
590
|
+
assert (
|
|
591
|
+
max(list(states)) <= 2**target.len
|
|
592
|
+
), "the target quantum variable is not large enough to populate all states"
|
|
593
|
+
assert len(set(states)) == len(states), "all states should be distinct"
|
|
594
|
+
|
|
595
|
+
# prepare a dense state
|
|
596
|
+
dense_size = max(int(np.ceil(np.log2(len(states)))), 1)
|
|
597
|
+
dense_amplitudes = np.zeros(2**dense_size, dtype=complex)
|
|
598
|
+
|
|
599
|
+
## make sure the states with number smaller than the dense state size are located in their place already
|
|
600
|
+
for i, state in enumerate(states):
|
|
601
|
+
if state < len(dense_amplitudes):
|
|
602
|
+
dense_amplitudes[state] = amplitudes[i]
|
|
603
|
+
|
|
604
|
+
## make a swap list for all other states
|
|
605
|
+
swap_list = []
|
|
606
|
+
free_index = 0
|
|
607
|
+
for i, state in enumerate(states):
|
|
608
|
+
if state < len(dense_amplitudes):
|
|
609
|
+
continue # already populated
|
|
610
|
+
while dense_amplitudes[free_index]:
|
|
611
|
+
free_index += 1 # index is not free
|
|
612
|
+
|
|
613
|
+
dense_amplitudes[free_index] = amplitudes[i]
|
|
614
|
+
swap_list.append((free_index, state))
|
|
615
|
+
free_index += 1
|
|
616
|
+
|
|
617
|
+
inplace_prepare_complex_amplitudes(
|
|
618
|
+
np.abs(dense_amplitudes), np.angle(dense_amplitudes), target[0:dense_size]
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
# swap all required states
|
|
622
|
+
sparse_size = max(int(np.ceil(np.log2(max(list(states) + [1])))), 1)
|
|
623
|
+
for a, b in swap_list:
|
|
624
|
+
swap_states(a, b, target[0:sparse_size])
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
@qfunc
|
|
628
|
+
def prepare_sparse_amplitudes(
|
|
629
|
+
states: list[int], amplitudes: list[complex], out: Output[QArray]
|
|
630
|
+
) -> None:
|
|
631
|
+
"""
|
|
632
|
+
[Qmod Classiq-library function]
|
|
633
|
+
|
|
634
|
+
Initializes and prepares a quantum state with the given (complex) amplitudes. The input is given sparse format, as a list of non-zero states and their corresponding amplitudes.
|
|
635
|
+
Notice that the function is only suitable sparse states. Inspired by https://arxiv.org/abs/2310.19309.
|
|
636
|
+
|
|
637
|
+
For example, `prepare_sparse_amplitudes([1, 8], [np.sqrt(0.5), np.sqrt(0.5)], out)` will and allocate it to be of size 4 qubits, and
|
|
638
|
+
prepare it in the state sqrt(0.5)|1> + sqrt(0.5)|8>.
|
|
639
|
+
|
|
640
|
+
Complexity: Asymptotic gate complexity is $O(dn)$ where d is the number of states and n is the required number of qubits.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
states: A list of distinct computational basis indices to populate. Each integer corresponds to the basis state in the computational basis.
|
|
644
|
+
amplitudes: A list of complex amplitudes for the corresponding entries in `states`. Must have the same length as `states`.
|
|
645
|
+
out: The allocated quantum variable.
|
|
646
|
+
"""
|
|
647
|
+
allocate(max(int(np.ceil(np.log2(max(states)))), 1), out)
|
|
648
|
+
inplace_prepare_sparse_amplitudes(states, amplitudes, out)
|
|
@@ -25,7 +25,7 @@ def free(in_: Permutable[Input[QArray[QBit]]]) -> None:
|
|
|
25
25
|
def prepare_state(
|
|
26
26
|
probabilities: CArray[CReal],
|
|
27
27
|
bound: CReal,
|
|
28
|
-
out: Output[QArray[QBit, Literal["log(
|
|
28
|
+
out: Output[QArray[QBit, Literal["log(probabilities.len, 2)"]]],
|
|
29
29
|
) -> None:
|
|
30
30
|
"""
|
|
31
31
|
[Qmod core-library function]
|
|
@@ -54,7 +54,7 @@ def prepare_state(
|
|
|
54
54
|
def prepare_amplitudes(
|
|
55
55
|
amplitudes: CArray[CReal],
|
|
56
56
|
bound: CReal,
|
|
57
|
-
out: Output[QArray[QBit, Literal["log(
|
|
57
|
+
out: Output[QArray[QBit, Literal["log(amplitudes.len, 2)"]]],
|
|
58
58
|
) -> None:
|
|
59
59
|
"""
|
|
60
60
|
[Qmod core-library function]
|
|
@@ -83,7 +83,7 @@ def prepare_amplitudes(
|
|
|
83
83
|
def inplace_prepare_state(
|
|
84
84
|
probabilities: CArray[CReal],
|
|
85
85
|
bound: CReal,
|
|
86
|
-
target: QArray[QBit, Literal["log(
|
|
86
|
+
target: QArray[QBit, Literal["log(probabilities.len, 2)"]],
|
|
87
87
|
) -> None:
|
|
88
88
|
"""
|
|
89
89
|
[Qmod core-library function]
|
|
@@ -106,7 +106,7 @@ def inplace_prepare_state(
|
|
|
106
106
|
def inplace_prepare_amplitudes(
|
|
107
107
|
amplitudes: CArray[CReal],
|
|
108
108
|
bound: CReal,
|
|
109
|
-
target: QArray[QBit, Literal["log(
|
|
109
|
+
target: QArray[QBit, Literal["log(amplitudes.len, 2)"]],
|
|
110
110
|
) -> None:
|
|
111
111
|
"""
|
|
112
112
|
[Qmod core-library function]
|
|
@@ -129,7 +129,7 @@ def inplace_prepare_amplitudes(
|
|
|
129
129
|
def inplace_prepare_amplitudes_approx(
|
|
130
130
|
amplitudes: CArray[CReal],
|
|
131
131
|
bound: CReal,
|
|
132
|
-
target: QArray[QBit, Literal["log(
|
|
132
|
+
target: QArray[QBit, Literal["log(amplitudes.len, 2)"]],
|
|
133
133
|
) -> None:
|
|
134
134
|
pass
|
|
135
135
|
|
|
@@ -138,7 +138,7 @@ def inplace_prepare_amplitudes_approx(
|
|
|
138
138
|
def prepare_amplitudes_approx(
|
|
139
139
|
amplitudes: CArray[CReal],
|
|
140
140
|
bound: CReal,
|
|
141
|
-
out: Output[QArray[QBit, Literal["log(
|
|
141
|
+
out: Output[QArray[QBit, Literal["log(amplitudes.len, 2)"]]],
|
|
142
142
|
) -> None:
|
|
143
143
|
pass
|
|
144
144
|
|
|
@@ -147,7 +147,7 @@ def prepare_amplitudes_approx(
|
|
|
147
147
|
def inplace_prepare_state_approx(
|
|
148
148
|
probabilities: CArray[CReal],
|
|
149
149
|
bound: CReal,
|
|
150
|
-
target: QArray[QBit, Literal["log(
|
|
150
|
+
target: QArray[QBit, Literal["log(probabilities.len, 2)"]],
|
|
151
151
|
) -> None:
|
|
152
152
|
pass
|
|
153
153
|
|
|
@@ -156,6 +156,6 @@ def inplace_prepare_state_approx(
|
|
|
156
156
|
def prepare_state_approx(
|
|
157
157
|
probabilities: CArray[CReal],
|
|
158
158
|
bound: CReal,
|
|
159
|
-
out: Output[QArray[QBit, Literal["log(
|
|
159
|
+
out: Output[QArray[QBit, Literal["log(probabilities.len, 2)"]]],
|
|
160
160
|
) -> None:
|
|
161
161
|
pass
|
|
@@ -16,7 +16,7 @@ from classiq.qmod.qmod_variable import (
|
|
|
16
16
|
@qfunc(external=True)
|
|
17
17
|
def unitary(
|
|
18
18
|
elements: CArray[CArray[CReal]],
|
|
19
|
-
target: QArray[QBit, Literal["log(
|
|
19
|
+
target: QArray[QBit, Literal["log(elements[0].len, 2)"]],
|
|
20
20
|
) -> None:
|
|
21
21
|
"""
|
|
22
22
|
[Qmod core-library function]
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
|
4
|
+
|
|
1
5
|
from classiq.qmod.builtins.structs import (
|
|
2
6
|
FockHamiltonianProblem,
|
|
3
7
|
MoleculeProblem,
|
|
@@ -13,6 +17,16 @@ def molecule_ucc(
|
|
|
13
17
|
excitations: CArray[CInt],
|
|
14
18
|
qbv: QArray[QBit],
|
|
15
19
|
) -> None:
|
|
20
|
+
warnings.warn(
|
|
21
|
+
(
|
|
22
|
+
"The function `molecule_ucc` is deprecated and will no "
|
|
23
|
+
"longer be supported starting on 2025-09-18 at the earliest. "
|
|
24
|
+
"For more information on Classiq's chemistry application, see "
|
|
25
|
+
"https://docs.classiq.io/latest/explore/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application/."
|
|
26
|
+
),
|
|
27
|
+
category=ClassiqDeprecationWarning,
|
|
28
|
+
stacklevel=2,
|
|
29
|
+
)
|
|
16
30
|
pass
|
|
17
31
|
|
|
18
32
|
|
|
@@ -22,6 +36,16 @@ def molecule_hva(
|
|
|
22
36
|
reps: CInt,
|
|
23
37
|
qbv: QArray[QBit],
|
|
24
38
|
) -> None:
|
|
39
|
+
warnings.warn(
|
|
40
|
+
(
|
|
41
|
+
"The function `molecule_hva` is deprecated and will no "
|
|
42
|
+
"longer be supported starting on 2025-09-18 at the earliest. "
|
|
43
|
+
"For more information on Classiq's chemistry application, see "
|
|
44
|
+
"https://docs.classiq.io/latest/explore/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application/."
|
|
45
|
+
),
|
|
46
|
+
category=ClassiqDeprecationWarning,
|
|
47
|
+
stacklevel=2,
|
|
48
|
+
)
|
|
25
49
|
pass
|
|
26
50
|
|
|
27
51
|
|
|
@@ -30,6 +54,16 @@ def molecule_hartree_fock(
|
|
|
30
54
|
molecule_problem: MoleculeProblem,
|
|
31
55
|
qbv: QArray[QBit],
|
|
32
56
|
) -> None:
|
|
57
|
+
warnings.warn(
|
|
58
|
+
(
|
|
59
|
+
"The function `molecule_hartree_fock` is deprecated and will no "
|
|
60
|
+
"longer be supported starting on 2025-09-18 at the earliest. "
|
|
61
|
+
"For more information on Classiq's chemistry application, see "
|
|
62
|
+
"https://docs.classiq.io/latest/explore/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application/."
|
|
63
|
+
),
|
|
64
|
+
category=ClassiqDeprecationWarning,
|
|
65
|
+
stacklevel=2,
|
|
66
|
+
)
|
|
33
67
|
pass
|
|
34
68
|
|
|
35
69
|
|
|
@@ -39,6 +73,16 @@ def fock_hamiltonian_ucc(
|
|
|
39
73
|
excitations: CArray[CInt],
|
|
40
74
|
qbv: QArray[QBit],
|
|
41
75
|
) -> None:
|
|
76
|
+
warnings.warn(
|
|
77
|
+
(
|
|
78
|
+
"The function `fock_hamiltonian_ucc` is deprecated and will no "
|
|
79
|
+
"longer be supported starting on 2025-09-18 at the earliest. "
|
|
80
|
+
"For more information on Classiq's chemistry application, see "
|
|
81
|
+
"https://docs.classiq.io/latest/explore/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application/."
|
|
82
|
+
),
|
|
83
|
+
category=ClassiqDeprecationWarning,
|
|
84
|
+
stacklevel=2,
|
|
85
|
+
)
|
|
42
86
|
pass
|
|
43
87
|
|
|
44
88
|
|
|
@@ -48,6 +92,16 @@ def fock_hamiltonian_hva(
|
|
|
48
92
|
reps: CInt,
|
|
49
93
|
qbv: QArray[QBit],
|
|
50
94
|
) -> None:
|
|
95
|
+
warnings.warn(
|
|
96
|
+
(
|
|
97
|
+
"The function `fock_hamiltonian_hva` is deprecated and will no "
|
|
98
|
+
"longer be supported starting on 2025-09-18 at the earliest. "
|
|
99
|
+
"For more information on Classiq's chemistry application, see "
|
|
100
|
+
"https://docs.classiq.io/latest/explore/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application/."
|
|
101
|
+
),
|
|
102
|
+
category=ClassiqDeprecationWarning,
|
|
103
|
+
stacklevel=2,
|
|
104
|
+
)
|
|
51
105
|
pass
|
|
52
106
|
|
|
53
107
|
|
|
@@ -56,4 +110,14 @@ def fock_hamiltonian_hartree_fock(
|
|
|
56
110
|
fock_hamiltonian_problem: FockHamiltonianProblem,
|
|
57
111
|
qbv: QArray[QBit],
|
|
58
112
|
) -> None:
|
|
113
|
+
warnings.warn(
|
|
114
|
+
(
|
|
115
|
+
"The function `fock_hamiltonian_hartree_fock` is deprecated and will no "
|
|
116
|
+
"longer be supported starting on 2025-09-18 at the earliest. "
|
|
117
|
+
"For more information on Classiq's chemistry application, see "
|
|
118
|
+
"https://docs.classiq.io/latest/explore/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application/."
|
|
119
|
+
),
|
|
120
|
+
category=ClassiqDeprecationWarning,
|
|
121
|
+
stacklevel=2,
|
|
122
|
+
)
|
|
59
123
|
pass
|
|
@@ -14,7 +14,7 @@ from classiq.qmod.qmod_variable import QArray, QBit
|
|
|
14
14
|
def single_pauli_exponent(
|
|
15
15
|
pauli_string: CArray[Pauli],
|
|
16
16
|
coefficient: CReal,
|
|
17
|
-
qbv: QArray[QBit, Literal["
|
|
17
|
+
qbv: QArray[QBit, Literal["pauli_string.len"]],
|
|
18
18
|
) -> None:
|
|
19
19
|
"""
|
|
20
20
|
[Qmod core-library function]
|
|
@@ -33,9 +33,7 @@ def single_pauli_exponent(
|
|
|
33
33
|
def commuting_paulis_exponent(
|
|
34
34
|
pauli_operator: CArray[PauliTerm],
|
|
35
35
|
evolution_coefficient: CReal,
|
|
36
|
-
qbv: QArray[
|
|
37
|
-
QBit, Literal["get_field(get_field(pauli_operator[0], 'pauli'), 'len')"]
|
|
38
|
-
],
|
|
36
|
+
qbv: QArray[QBit, Literal["pauli_operator[0].pauli.len"]],
|
|
39
37
|
) -> None:
|
|
40
38
|
"""
|
|
41
39
|
[Qmod core-library function]
|
|
@@ -113,11 +111,11 @@ def multi_suzuki_trotter(
|
|
|
113
111
|
@qfunc(external=True)
|
|
114
112
|
def parametric_suzuki_trotter(
|
|
115
113
|
paulis: CArray[CArray[Pauli]],
|
|
116
|
-
coefficients: CArray[CReal, Literal["
|
|
114
|
+
coefficients: CArray[CReal, Literal["paulis.len"]],
|
|
117
115
|
evolution_coefficient: CReal,
|
|
118
116
|
order: CInt,
|
|
119
117
|
repetitions: CInt,
|
|
120
|
-
qbv: QArray[QBit, Literal["
|
|
118
|
+
qbv: QArray[QBit, Literal["paulis[0].len"]],
|
|
121
119
|
) -> None:
|
|
122
120
|
"""
|
|
123
121
|
[Qmod core-library function]
|
|
@@ -147,7 +145,7 @@ def sparse_suzuki_trotter(
|
|
|
147
145
|
evolution_coefficient: CReal,
|
|
148
146
|
order: CInt,
|
|
149
147
|
repetitions: CInt,
|
|
150
|
-
qbv: QArray[QBit, Literal["
|
|
148
|
+
qbv: QArray[QBit, Literal["pauli_operator.num_qubits"]],
|
|
151
149
|
) -> None:
|
|
152
150
|
"""
|
|
153
151
|
[Qmod core-library function]
|
|
@@ -174,9 +172,7 @@ def qdrift(
|
|
|
174
172
|
pauli_operator: CArray[PauliTerm],
|
|
175
173
|
evolution_coefficient: CReal,
|
|
176
174
|
num_qdrift: CInt,
|
|
177
|
-
qbv: QArray[
|
|
178
|
-
QBit, Literal["get_field(get_field(pauli_operator[0], 'pauli'), 'len')"]
|
|
179
|
-
],
|
|
175
|
+
qbv: QArray[QBit, Literal["pauli_operator[0].pauli.len"]],
|
|
180
176
|
) -> None:
|
|
181
177
|
"""
|
|
182
178
|
[Qmod core-library function]
|
|
@@ -199,9 +195,7 @@ def exponentiation_with_depth_constraint(
|
|
|
199
195
|
pauli_operator: CArray[PauliTerm],
|
|
200
196
|
evolution_coefficient: CReal,
|
|
201
197
|
max_depth: CInt,
|
|
202
|
-
qbv: QArray[
|
|
203
|
-
QBit, Literal["get_field(get_field(pauli_operator[0], 'pauli'), 'len')"]
|
|
204
|
-
],
|
|
198
|
+
qbv: QArray[QBit, Literal["pauli_operator[0].pauli.len"]],
|
|
205
199
|
) -> None:
|
|
206
200
|
"""
|
|
207
201
|
[Qmod core-library function]
|
|
@@ -11,7 +11,7 @@ from classiq.qmod.qmod_variable import QArray, QBit
|
|
|
11
11
|
@qfunc(external=True)
|
|
12
12
|
def pauli_feature_map(
|
|
13
13
|
feature_map: QSVMFeatureMapPauli,
|
|
14
|
-
qbv: QArray[QBit, Literal["
|
|
14
|
+
qbv: QArray[QBit, Literal["feature_map.feature_dimension"]],
|
|
15
15
|
) -> None:
|
|
16
16
|
pass
|
|
17
17
|
|