classiq 0.60.1__py3-none-any.whl → 0.62.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 -0
- classiq/_internals/client.py +6 -1
- classiq/applications/__init__.py +1 -1
- classiq/applications/chemistry/__init__.py +7 -7
- classiq/applications/chemistry/chemistry_model_constructor.py +17 -6
- classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +60 -9
- classiq/applications/combinatorial_optimization/__init__.py +7 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +230 -0
- classiq/applications/finance/finance_model_constructor.py +6 -6
- classiq/applications/grover/grover_model_constructor.py +3 -0
- classiq/applications/libraries/qmci_library.py +1 -10
- classiq/applications/qnn/__init__.py +1 -1
- classiq/applications/qnn/datasets/__init__.py +8 -8
- classiq/applications/qsvm/qsvm.py +1 -1
- classiq/execution/__init__.py +0 -2
- classiq/execution/execution_session.py +6 -0
- classiq/execution/jobs.py +9 -1
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +33 -15
- classiq/interface/backend/quantum_backend_providers.py +3 -1
- classiq/interface/executor/execution_preferences.py +1 -1
- classiq/interface/generator/application_apis/chemistry_declarations.py +1 -1
- classiq/interface/generator/application_apis/finance_declarations.py +2 -2
- classiq/interface/generator/arith/arithmetic.py +16 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +4 -3
- classiq/interface/generator/copy.py +47 -0
- classiq/interface/generator/expressions/expression_constants.py +3 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/generated_circuit_data.py +58 -20
- classiq/interface/generator/model/__init__.py +1 -1
- classiq/interface/generator/model/preferences/preferences.py +1 -1
- classiq/interface/generator/model/quantum_register.py +3 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +20 -32
- classiq/interface/generator/types/compilation_metadata.py +2 -1
- classiq/interface/ide/visual_model.py +1 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/model.py +2 -3
- classiq/interface/model/quantum_function_call.py +4 -7
- classiq/interface/model/quantum_function_declaration.py +7 -0
- classiq/interface/model/quantum_lambda_function.py +10 -1
- classiq/interface/model/quantum_type.py +3 -1
- classiq/model_expansions/atomic_expression_functions_defs.py +3 -1
- classiq/model_expansions/capturing/captured_vars.py +36 -17
- classiq/model_expansions/capturing/mangling_utils.py +23 -15
- classiq/model_expansions/closure.py +6 -9
- classiq/model_expansions/evaluators/arg_type_match.py +7 -7
- classiq/model_expansions/expression_evaluator.py +5 -2
- classiq/model_expansions/function_builder.py +26 -4
- classiq/model_expansions/generative_functions.py +13 -91
- classiq/model_expansions/interpreter.py +75 -46
- classiq/model_expansions/quantum_operations/call_emitter.py +42 -29
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +5 -31
- classiq/model_expansions/quantum_operations/emitter.py +29 -17
- classiq/model_expansions/quantum_operations/expression_operation.py +3 -5
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +57 -15
- classiq/model_expansions/quantum_operations/invert.py +1 -6
- classiq/model_expansions/quantum_operations/phase.py +2 -5
- classiq/model_expansions/quantum_operations/power.py +0 -4
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +19 -30
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +161 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -14
- classiq/model_expansions/scope.py +12 -16
- classiq/model_expansions/scope_initialization.py +0 -11
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +7 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +12 -2
- classiq/model_expansions/transformers/ast_renamer.py +26 -0
- classiq/model_expansions/transformers/var_splitter.py +11 -12
- classiq/model_expansions/visitors/variable_references.py +20 -12
- classiq/qmod/builtins/classical_execution_primitives.py +6 -6
- classiq/qmod/builtins/classical_functions.py +10 -10
- classiq/qmod/builtins/functions/__init__.py +89 -103
- classiq/qmod/builtins/functions/amplitude_estimation.py +1 -1
- classiq/qmod/builtins/functions/arithmetic.py +1 -1
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +6 -6
- classiq/qmod/builtins/functions/grover.py +5 -5
- classiq/qmod/builtins/functions/hea.py +1 -1
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +2 -2
- classiq/qmod/builtins/functions/modular_exponentiation.py +8 -8
- classiq/qmod/builtins/functions/operators.py +1 -1
- classiq/qmod/builtins/functions/qaoa_penalty.py +5 -5
- classiq/qmod/builtins/functions/qft_functions.py +2 -2
- classiq/qmod/builtins/functions/qpe.py +9 -12
- classiq/qmod/builtins/functions/qsvt.py +177 -15
- classiq/qmod/builtins/functions/state_preparation.py +9 -9
- classiq/qmod/builtins/functions/swap_test.py +1 -1
- classiq/qmod/builtins/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/functions/variational.py +2 -2
- classiq/qmod/builtins/operations.py +22 -83
- classiq/qmod/builtins/structs.py +9 -9
- classiq/qmod/native/pretty_printer.py +17 -19
- classiq/qmod/pretty_print/pretty_printer.py +9 -6
- classiq/qmod/python_classical_type.py +1 -5
- classiq/qmod/qmod_variable.py +2 -5
- classiq/qmod/quantum_expandable.py +20 -5
- classiq/qmod/quantum_function.py +23 -10
- classiq/qmod/semantics/static_semantics_visitor.py +34 -16
- classiq/qmod/semantics/validation/func_call_validation.py +9 -5
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
- classiq/qmod/symbolic.py +47 -47
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/METADATA +2 -1
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/RECORD +107 -103
- classiq/execution/qaoa.py +0 -86
- {classiq-0.60.1.dist-info → classiq-0.62.0.dist-info}/WHEEL +0 -0
classiq/__init__.py
CHANGED
@@ -28,8 +28,10 @@ from classiq.applications.chemistry import (
|
|
28
28
|
molecule_problem_to_qmod,
|
29
29
|
)
|
30
30
|
from classiq.applications.combinatorial_optimization import (
|
31
|
+
CombinatorialProblem,
|
31
32
|
compute_qaoa_initial_point,
|
32
33
|
construct_combinatorial_optimization_model,
|
34
|
+
execute_qaoa,
|
33
35
|
pyo_model_to_hamiltonian,
|
34
36
|
)
|
35
37
|
from classiq.applications.finance import construct_finance_model
|
classiq/_internals/client.py
CHANGED
@@ -290,7 +290,12 @@ class Client:
|
|
290
290
|
if http_client is None:
|
291
291
|
return self.async_client()
|
292
292
|
else:
|
293
|
-
|
293
|
+
if sys.version_info[0:2] < (3, 10):
|
294
|
+
# remove this `if` and the `_AsyncNullContext` class when we stop
|
295
|
+
# supporting python 3.9
|
296
|
+
return _AsyncNullContext(enter_result=http_client)
|
297
|
+
else:
|
298
|
+
return contextlib.nullcontext(enter_result=http_client)
|
294
299
|
|
295
300
|
def sync_call_api(
|
296
301
|
self,
|
classiq/applications/__init__.py
CHANGED
@@ -19,18 +19,18 @@ from .chemistry_model_constructor import (
|
|
19
19
|
)
|
20
20
|
|
21
21
|
__all__ = [
|
22
|
-
"
|
23
|
-
"
|
22
|
+
"ChemistryExecutionParameters",
|
23
|
+
"FermionicOperator",
|
24
24
|
"GroundStateProblem",
|
25
|
+
"HEAParameters",
|
26
|
+
"HVAParameters",
|
25
27
|
"HamiltonianProblem",
|
26
|
-
"
|
28
|
+
"Molecule",
|
29
|
+
"MoleculeProblem",
|
27
30
|
"PauliOperator",
|
28
|
-
"
|
31
|
+
"PauliOperators",
|
29
32
|
"SummedFermionicOperator",
|
30
33
|
"UCCParameters",
|
31
|
-
"HVAParameters",
|
32
|
-
"HEAParameters",
|
33
|
-
"ChemistryExecutionParameters",
|
34
34
|
"construct_chemistry_model",
|
35
35
|
"molecule_problem_to_qmod",
|
36
36
|
]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# flake8: noqa
|
2
2
|
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional, cast
|
4
4
|
from collections.abc import Mapping
|
5
5
|
|
6
6
|
from classiq.interface.chemistry.fermionic_operator import (
|
@@ -53,6 +53,7 @@ from classiq.applications.chemistry.chemistry_execution_parameters import (
|
|
53
53
|
)
|
54
54
|
from classiq.interface.exceptions import ClassiqError
|
55
55
|
from classiq.qmod.utilities import qmod_val_to_expr_str
|
56
|
+
from classiq.qmod.builtins.functions.hea import full_hea
|
56
57
|
|
57
58
|
_LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
|
58
59
|
"+": "PLUS",
|
@@ -489,12 +490,22 @@ def construct_chemistry_model(
|
|
489
490
|
ansatz_parameters: AnsatzParameters,
|
490
491
|
execution_parameters: ChemistryExecutionParameters,
|
491
492
|
) -> SerializedModel:
|
493
|
+
chemistry_functions = [
|
494
|
+
_get_chemistry_quantum_main(
|
495
|
+
chemistry_problem,
|
496
|
+
use_hartree_fock,
|
497
|
+
ansatz_parameters,
|
498
|
+
)
|
499
|
+
]
|
500
|
+
if isinstance(ansatz_parameters, HEAParameters):
|
501
|
+
chemistry_functions.append(
|
502
|
+
cast(
|
503
|
+
NativeFunctionDefinition,
|
504
|
+
full_hea.create_model().function_dict["full_hea"],
|
505
|
+
)
|
506
|
+
)
|
492
507
|
model = Model(
|
493
|
-
functions=
|
494
|
-
_get_chemistry_quantum_main(
|
495
|
-
chemistry_problem, use_hartree_fock, ansatz_parameters
|
496
|
-
),
|
497
|
-
],
|
508
|
+
functions=chemistry_functions,
|
498
509
|
classical_execution_code=_get_chemistry_classical_code(
|
499
510
|
chemistry_problem, execution_parameters
|
500
511
|
),
|
@@ -23,7 +23,10 @@ from classiq.applications.combinatorial_helpers import (
|
|
23
23
|
)
|
24
24
|
from classiq.applications.combinatorial_helpers.encoding_mapping import EncodingMapping
|
25
25
|
from classiq.applications.combinatorial_helpers.memory import InternalQuantumReg
|
26
|
-
from classiq.applications.combinatorial_helpers.pyomo_utils import
|
26
|
+
from classiq.applications.combinatorial_helpers.pyomo_utils import (
|
27
|
+
get_field_name,
|
28
|
+
is_index_var,
|
29
|
+
)
|
27
30
|
from classiq.applications.combinatorial_helpers.transformations import (
|
28
31
|
encoding,
|
29
32
|
ising_converter,
|
@@ -176,7 +179,11 @@ class OptimizationModel:
|
|
176
179
|
for key, value in penalty_map.pyomo2sympy.items():
|
177
180
|
objective_map.pyomo2sympy[key] = value
|
178
181
|
sympy_mapping = {
|
179
|
-
sympy_var:
|
182
|
+
sympy_var: (
|
183
|
+
get_field_name(pyomo_var)
|
184
|
+
if not is_index_var(pyomo_var)
|
185
|
+
else (get_field_name(pyomo_var.parent_component()), pyomo_var.index())
|
186
|
+
)
|
180
187
|
for pyomo_var, sympy_var in objective_map.pyomo2sympy.items()
|
181
188
|
}
|
182
189
|
self.objective_not_encoded_sympy = sympy_mapping, objective_expr
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import math
|
2
2
|
import re
|
3
|
+
from collections import defaultdict
|
3
4
|
from enum import Enum
|
4
5
|
from typing import Any, Optional, TypeVar, Union
|
5
6
|
|
@@ -24,7 +25,7 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
24
25
|
from classiq.interface.generator.functions.classical_type import Integer
|
25
26
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
26
27
|
|
27
|
-
from classiq.qmod.qmod_variable import QBit, QNum, QStruct, QVar
|
28
|
+
from classiq.qmod.qmod_variable import QArray, QBit, QNum, QStruct, QVar
|
28
29
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
29
30
|
|
30
31
|
ListVars = list[_GeneralVarData]
|
@@ -262,14 +263,51 @@ def pyomo_to_qmod_qstruct(
|
|
262
263
|
struct_name: str, vars: list[_GeneralVarData]
|
263
264
|
) -> type[QStruct]:
|
264
265
|
qmod_struct = type(struct_name, (QStruct,), {})
|
265
|
-
|
266
|
-
qmod_struct.__annotations__ = {
|
267
|
-
var_name: _get_qmod_field_type(var_name, var_data)
|
268
|
-
for var_name, var_data in var_names.items()
|
269
|
-
}
|
266
|
+
qmod_struct.__annotations__ = _get_qstruct_fields(vars)
|
270
267
|
return qmod_struct
|
271
268
|
|
272
269
|
|
270
|
+
def _get_qstruct_fields(vars: list[_GeneralVarData]) -> dict[str, type[QVar]]:
|
271
|
+
array_types = _get_array_types(vars)
|
272
|
+
array_type_sizes = _get_array_sizes(array_types)
|
273
|
+
fields: dict[str, type[QVar]] = {}
|
274
|
+
for var in vars:
|
275
|
+
_add_qmod_field(var, array_type_sizes, fields)
|
276
|
+
return fields
|
277
|
+
|
278
|
+
|
279
|
+
def _get_array_types(vars: list[_GeneralVarData]) -> dict[str, set[int]]:
|
280
|
+
array_types: dict[str, set[int]] = defaultdict(set)
|
281
|
+
for var in vars:
|
282
|
+
if is_index_var(var):
|
283
|
+
array_types[var.parent_component().name].add(var.index())
|
284
|
+
return array_types
|
285
|
+
|
286
|
+
|
287
|
+
def _get_array_sizes(array_types: dict[str, set[int]]) -> dict[str, int]:
|
288
|
+
return {
|
289
|
+
name: array_size
|
290
|
+
for name, indices in array_types.items()
|
291
|
+
if indices == set(range(array_size := len(indices)))
|
292
|
+
}
|
293
|
+
|
294
|
+
|
295
|
+
def _add_qmod_field(
|
296
|
+
var: _GeneralVarData,
|
297
|
+
array_type_sizes: dict[str, int],
|
298
|
+
fields: dict[str, type[QVar]],
|
299
|
+
) -> None:
|
300
|
+
parent_name = var.parent_component().name
|
301
|
+
if parent_name not in array_type_sizes:
|
302
|
+
var_name = get_field_name(var)
|
303
|
+
fields[var_name] = _get_qmod_field_type(var_name, var)
|
304
|
+
elif var.index() == 0:
|
305
|
+
fields[parent_name] = QArray[ # type:ignore[misc]
|
306
|
+
_get_qmod_field_type(parent_name, var),
|
307
|
+
array_type_sizes[parent_name],
|
308
|
+
]
|
309
|
+
|
310
|
+
|
273
311
|
def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]:
|
274
312
|
if var_data.domain not in SUPPORTED_TYPES:
|
275
313
|
raise ClassiqValueError(
|
@@ -294,11 +332,17 @@ def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]
|
|
294
332
|
|
295
333
|
|
296
334
|
def evaluate_objective(
|
297
|
-
var_mapping: dict,
|
335
|
+
var_mapping: dict[Any, Union[str, tuple[str, int]]],
|
336
|
+
sympy_expr: sympy.Expr,
|
337
|
+
struct_obj: Any,
|
298
338
|
) -> Any:
|
299
339
|
sympy_assignment = {
|
300
|
-
sympy_var:
|
301
|
-
|
340
|
+
sympy_var: (
|
341
|
+
getattr(struct_obj, field_accessor)
|
342
|
+
if isinstance(field_accessor, str)
|
343
|
+
else getattr(struct_obj, field_accessor[0])[field_accessor[1]]
|
344
|
+
)
|
345
|
+
for sympy_var, field_accessor in var_mapping.items()
|
302
346
|
}
|
303
347
|
|
304
348
|
# classical objective evaluation
|
@@ -315,3 +359,10 @@ def evaluate_objective(
|
|
315
359
|
|
316
360
|
def get_field_name(var: _GeneralVarData) -> str:
|
317
361
|
return var.local_name.replace("[", "_").replace("]", "")
|
362
|
+
|
363
|
+
|
364
|
+
def is_index_var(var: _GeneralVarData) -> bool:
|
365
|
+
return (
|
366
|
+
isinstance(var.index(), int)
|
367
|
+
and "[" not in var.parent_component().name # nested arrays not supported
|
368
|
+
)
|
@@ -12,17 +12,23 @@ from .combinatorial_optimization_config import OptimizerConfig, QAOAConfig
|
|
12
12
|
from .combinatorial_optimization_model_constructor import (
|
13
13
|
construct_combinatorial_optimization_model,
|
14
14
|
)
|
15
|
+
from .combinatorial_problem import (
|
16
|
+
CombinatorialProblem,
|
17
|
+
execute_qaoa,
|
18
|
+
)
|
15
19
|
|
16
20
|
__all__ = [
|
21
|
+
"CombinatorialProblem",
|
17
22
|
"EncodingType",
|
18
23
|
"OptimizerConfig",
|
19
24
|
"QAOAConfig",
|
20
25
|
"QSolver",
|
26
|
+
"compute_qaoa_initial_point",
|
21
27
|
"construct_combinatorial_optimization_model",
|
22
28
|
"examples",
|
29
|
+
"execute_qaoa",
|
23
30
|
"get_optimization_solution_from_pyo",
|
24
31
|
"pyo_model_to_hamiltonian",
|
25
|
-
"compute_qaoa_initial_point",
|
26
32
|
]
|
27
33
|
|
28
34
|
|
classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py
CHANGED
@@ -33,6 +33,7 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import
|
|
33
33
|
_pauli_terms_to_qmod,
|
34
34
|
)
|
35
35
|
from classiq.applications.combinatorial_optimization import OptimizerConfig, QAOAConfig
|
36
|
+
from classiq.qmod.builtins.functions import qaoa_penalty
|
36
37
|
|
37
38
|
|
38
39
|
def construct_combi_opt_py_model(
|
@@ -106,6 +107,7 @@ def construct_combi_opt_py_model(
|
|
106
107
|
),
|
107
108
|
],
|
108
109
|
),
|
110
|
+
*[f for f in qaoa_penalty.create_model().functions if f.name != "main"],
|
109
111
|
],
|
110
112
|
classical_execution_code=f"""
|
111
113
|
vqe_result = vqe(
|
@@ -0,0 +1,230 @@
|
|
1
|
+
import math
|
2
|
+
import re
|
3
|
+
from typing import Callable, Optional
|
4
|
+
|
5
|
+
import numpy as np
|
6
|
+
import pandas as pd
|
7
|
+
import pyomo.core as pyo
|
8
|
+
import scipy
|
9
|
+
from tqdm import tqdm
|
10
|
+
|
11
|
+
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
12
|
+
from classiq.interface.executor.result import ExecutionDetails
|
13
|
+
from classiq.interface.model.model import SerializedModel
|
14
|
+
|
15
|
+
from classiq import Constraints, Preferences
|
16
|
+
from classiq.applications.combinatorial_helpers.combinatorial_problem_utils import (
|
17
|
+
pyo_model_to_qmod_problem,
|
18
|
+
)
|
19
|
+
from classiq.execution import ExecutionSession
|
20
|
+
from classiq.qmod.builtins.functions import (
|
21
|
+
RX,
|
22
|
+
allocate,
|
23
|
+
apply_to_all,
|
24
|
+
hadamard_transform,
|
25
|
+
)
|
26
|
+
from classiq.qmod.builtins.operations import phase, repeat
|
27
|
+
from classiq.qmod.cparam import CReal
|
28
|
+
from classiq.qmod.create_model_function import create_model
|
29
|
+
from classiq.qmod.qfunc import qfunc
|
30
|
+
from classiq.qmod.qmod_parameter import CArray
|
31
|
+
from classiq.qmod.qmod_variable import Output, QVar
|
32
|
+
from classiq.synthesis import SerializedQuantumProgram, synthesize
|
33
|
+
|
34
|
+
|
35
|
+
class CombinatorialProblem:
|
36
|
+
def __init__(
|
37
|
+
self,
|
38
|
+
pyo_model: pyo.ConcreteModel,
|
39
|
+
num_layers: int,
|
40
|
+
penalty_factor: int = 1,
|
41
|
+
):
|
42
|
+
self.problem_vars_, self.cost_func = pyo_model_to_qmod_problem(
|
43
|
+
pyo_model, penalty_factor
|
44
|
+
)
|
45
|
+
self.num_layers_ = num_layers
|
46
|
+
self.model_ = None
|
47
|
+
self.qprog_ = None
|
48
|
+
self.es_ = None
|
49
|
+
self.optimized_params_ = None
|
50
|
+
self.params_trace_: list[np.ndarray] = []
|
51
|
+
self.cost_trace_: list = []
|
52
|
+
|
53
|
+
@property
|
54
|
+
def cost_trace(self) -> list:
|
55
|
+
return self.cost_trace_
|
56
|
+
|
57
|
+
@property
|
58
|
+
def params_trace(self) -> list[np.ndarray]:
|
59
|
+
return self.params_trace_
|
60
|
+
|
61
|
+
@property
|
62
|
+
def optimized_params(self) -> list:
|
63
|
+
return self.optimized_params_ # type:ignore[return-value]
|
64
|
+
|
65
|
+
def get_model(
|
66
|
+
self,
|
67
|
+
constraints: Optional[Constraints] = None,
|
68
|
+
preferences: Optional[Preferences] = None,
|
69
|
+
) -> SerializedModel:
|
70
|
+
@qfunc
|
71
|
+
def main(
|
72
|
+
params: CArray[CReal, self.num_layers_ * 2], # type:ignore[valid-type]
|
73
|
+
v: Output[self.problem_vars_], # type:ignore[name-defined]
|
74
|
+
) -> None:
|
75
|
+
allocate(v.size, v)
|
76
|
+
hadamard_transform(v)
|
77
|
+
repeat(
|
78
|
+
self.num_layers_,
|
79
|
+
lambda i: [ # type:ignore[arg-type]
|
80
|
+
phase(
|
81
|
+
-self.cost_func(v), params[i]
|
82
|
+
), # type:ignore[func-returns-value]
|
83
|
+
apply_to_all(lambda q: RX(params[self.num_layers_ + i], q), v),
|
84
|
+
],
|
85
|
+
)
|
86
|
+
|
87
|
+
self.model_ = create_model(
|
88
|
+
main, constraints=constraints, preferences=preferences
|
89
|
+
) # type:ignore[assignment]
|
90
|
+
return self.model_ # type:ignore[return-value]
|
91
|
+
|
92
|
+
def get_qprog(self) -> SerializedQuantumProgram:
|
93
|
+
if self.model_ is None:
|
94
|
+
self.get_model()
|
95
|
+
self.qprog_ = synthesize(self.model_) # type:ignore[assignment,arg-type]
|
96
|
+
return self.qprog_ # type:ignore[return-value]
|
97
|
+
|
98
|
+
def optimize(
|
99
|
+
self,
|
100
|
+
execution_preferences: Optional[ExecutionPreferences] = None,
|
101
|
+
maxiter: int = 20,
|
102
|
+
quantile: float = 1.0,
|
103
|
+
) -> list[float]:
|
104
|
+
if self.qprog_ is None:
|
105
|
+
self.get_qprog()
|
106
|
+
self.es_ = ExecutionSession(
|
107
|
+
self.qprog_, execution_preferences # type:ignore[assignment,arg-type]
|
108
|
+
)
|
109
|
+
self.params_trace_ = []
|
110
|
+
self.cost_trace_ = []
|
111
|
+
|
112
|
+
def estimate_cost_wrapper(params: np.ndarray) -> float:
|
113
|
+
cost = self.es_.estimate_cost( # type:ignore[attr-defined]
|
114
|
+
lambda state: self.cost_func(state["v"]),
|
115
|
+
{"params": params.tolist()},
|
116
|
+
quantile=quantile,
|
117
|
+
)
|
118
|
+
self.cost_trace_.append(cost)
|
119
|
+
self.params_trace_.append(params)
|
120
|
+
return cost
|
121
|
+
|
122
|
+
initial_params = (
|
123
|
+
np.concatenate(
|
124
|
+
(
|
125
|
+
np.linspace(1 / self.num_layers_, 1, self.num_layers_),
|
126
|
+
np.linspace(1, 1 / self.num_layers_, self.num_layers_),
|
127
|
+
)
|
128
|
+
)
|
129
|
+
* math.pi
|
130
|
+
)
|
131
|
+
|
132
|
+
with tqdm(total=maxiter, desc="Optimization Progress", leave=True) as pbar:
|
133
|
+
|
134
|
+
def _minimze_callback(xk: np.ndarray) -> None:
|
135
|
+
pbar.update(1) # increment progress bar
|
136
|
+
self.optimized_params_ = xk.tolist() # save recent optimized value
|
137
|
+
|
138
|
+
self.optimized_params_ = scipy.optimize.minimize(
|
139
|
+
estimate_cost_wrapper,
|
140
|
+
callback=_minimze_callback,
|
141
|
+
x0=initial_params,
|
142
|
+
method="COBYLA",
|
143
|
+
options={"maxiter": maxiter},
|
144
|
+
).x.tolist()
|
145
|
+
|
146
|
+
return self.optimized_params_ # type:ignore[return-value]
|
147
|
+
|
148
|
+
def sample_uniform(self) -> pd.DataFrame:
|
149
|
+
return self.sample([0] * self.num_layers_ * 2)
|
150
|
+
|
151
|
+
def sample(self, params: list) -> pd.DataFrame:
|
152
|
+
assert self.es_ is not None
|
153
|
+
res = self.es_.sample( # type:ignore[unreachable]
|
154
|
+
{"params": params}
|
155
|
+
)
|
156
|
+
parsed_result = [
|
157
|
+
{
|
158
|
+
"solution": {
|
159
|
+
key: value
|
160
|
+
for key, value in sampled.state["v"].items()
|
161
|
+
if not re.match(".*_slack_var_.*", key)
|
162
|
+
},
|
163
|
+
"probability": sampled.shots / res.num_shots,
|
164
|
+
"cost": self.cost_func(sampled.state["v"]),
|
165
|
+
}
|
166
|
+
for sampled in res.parsed_counts
|
167
|
+
]
|
168
|
+
return pd.DataFrame.from_records(parsed_result)
|
169
|
+
|
170
|
+
|
171
|
+
def execute_qaoa(
|
172
|
+
problem_vars: type[QVar],
|
173
|
+
cost_func: Callable,
|
174
|
+
num_layers: int,
|
175
|
+
maxiter: int,
|
176
|
+
execution_preferences: Optional[ExecutionPreferences] = None,
|
177
|
+
) -> tuple[SerializedModel, SerializedQuantumProgram, ExecutionDetails]:
|
178
|
+
"""
|
179
|
+
Implements a simple QAOA algorithm, including the creation and synthesis of the QAOA
|
180
|
+
ansatz and the classical optimization loop.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
problem_vars: the quantum type (scalar, array, or struct) of the problem variable(s)
|
184
|
+
cost_func: the arithmetic expression that evaluates the cost given an instance of the problem_vars type
|
185
|
+
num_layers: the number of layers of the QAOA ansatz
|
186
|
+
maxiter: the maximum number of iterations for the classical optimization loop
|
187
|
+
execution_preferences: the execution settings for running the QAOA ansatz
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
a tuple containing the model of the QAOA ansatz, the corresponding synthesized quantum program,
|
191
|
+
and the result of the execution with the optimized parameters
|
192
|
+
"""
|
193
|
+
|
194
|
+
@qfunc
|
195
|
+
def main(
|
196
|
+
params: CArray[CReal, num_layers * 2], # type:ignore[valid-type]
|
197
|
+
v: Output[problem_vars], # type:ignore[valid-type]
|
198
|
+
) -> None:
|
199
|
+
allocate(v.size, v) # type:ignore[attr-defined]
|
200
|
+
hadamard_transform(v)
|
201
|
+
repeat(
|
202
|
+
num_layers,
|
203
|
+
lambda i: [ # type:ignore[arg-type]
|
204
|
+
phase(-cost_func(v), params[i]), # type:ignore[func-returns-value]
|
205
|
+
apply_to_all(lambda q: RX(params[num_layers + i], q), v),
|
206
|
+
],
|
207
|
+
)
|
208
|
+
|
209
|
+
model = create_model(main)
|
210
|
+
qprog = synthesize(model)
|
211
|
+
|
212
|
+
with ExecutionSession(qprog, execution_preferences) as es:
|
213
|
+
initial_params = (
|
214
|
+
np.concatenate(
|
215
|
+
(np.linspace(0, 1, num_layers), np.linspace(1, 0, num_layers))
|
216
|
+
)
|
217
|
+
* math.pi
|
218
|
+
)
|
219
|
+
final_params = scipy.optimize.minimize(
|
220
|
+
lambda params: es.estimate_cost(
|
221
|
+
lambda state: cost_func(state["v"]),
|
222
|
+
{"params": params.tolist()},
|
223
|
+
),
|
224
|
+
x0=initial_params,
|
225
|
+
method="COBYLA",
|
226
|
+
options={"maxiter": maxiter},
|
227
|
+
).x.tolist()
|
228
|
+
result = es.sample({"params": final_params})
|
229
|
+
|
230
|
+
return model, qprog, result
|
@@ -15,7 +15,7 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
|
|
15
15
|
from classiq.interface.model.port_declaration import PortDeclaration
|
16
16
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
17
17
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
18
|
-
from classiq.interface.model.quantum_type import
|
18
|
+
from classiq.interface.model.quantum_type import QuantumNumeric
|
19
19
|
from classiq.interface.model.variable_declaration_statement import (
|
20
20
|
VariableDeclarationStatement,
|
21
21
|
)
|
@@ -68,8 +68,10 @@ def construct_finance_model(
|
|
68
68
|
positional_arg_declarations=[
|
69
69
|
PortDeclaration(
|
70
70
|
name="phase_port",
|
71
|
-
quantum_type=
|
72
|
-
|
71
|
+
quantum_type=QuantumNumeric(
|
72
|
+
size=Expression(expr=f"{phase_port_size}"),
|
73
|
+
is_signed=Expression(expr="False"),
|
74
|
+
fraction_digits=Expression(expr=f"{phase_port_size}"),
|
73
75
|
),
|
74
76
|
direction=PortDeclarationDirection.Output,
|
75
77
|
),
|
@@ -84,10 +86,8 @@ def construct_finance_model(
|
|
84
86
|
],
|
85
87
|
),
|
86
88
|
QuantumFunctionCall(
|
87
|
-
function="
|
89
|
+
function="allocate",
|
88
90
|
positional_args=[
|
89
|
-
Expression(expr=f"{phase_port_size}"),
|
90
|
-
Expression(expr="False"),
|
91
91
|
Expression(expr=f"{phase_port_size}"),
|
92
92
|
HandleBinding(name="phase_port"),
|
93
93
|
],
|
@@ -19,6 +19,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
19
19
|
)
|
20
20
|
|
21
21
|
from classiq import RegisterUserInput
|
22
|
+
from classiq.qmod.builtins.functions.grover import grover_search, phase_oracle
|
22
23
|
|
23
24
|
_OUTPUT_VARIABLE_NAME = "result"
|
24
25
|
|
@@ -151,6 +152,8 @@ def construct_grover_model(
|
|
151
152
|
),
|
152
153
|
],
|
153
154
|
),
|
155
|
+
*[f for f in grover_search.create_model().functions if f.name != "main"],
|
156
|
+
*[f for f in phase_oracle.create_model().functions if f.name != "main"],
|
154
157
|
],
|
155
158
|
)
|
156
159
|
return grover_model.get_model()
|
@@ -1,7 +1,3 @@
|
|
1
|
-
from typing import cast
|
2
|
-
|
3
|
-
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
4
|
-
|
5
1
|
from classiq.qmod.builtins.functions import Z, amplitude_estimation
|
6
2
|
from classiq.qmod.qfunc import qfunc
|
7
3
|
from classiq.qmod.qmod_variable import QArray, QBit, QNum
|
@@ -22,9 +18,4 @@ def qmci(
|
|
22
18
|
)
|
23
19
|
|
24
20
|
|
25
|
-
QMCI_LIBRARY = [
|
26
|
-
cast(
|
27
|
-
NativeFunctionDefinition,
|
28
|
-
qmci.create_model().function_dict["qmci"],
|
29
|
-
),
|
30
|
-
]
|
21
|
+
QMCI_LIBRARY = [func for func in qmci.create_model().functions if func.name != "main"]
|
@@ -13,19 +13,19 @@ from ..datasets.dataset_xor import DatasetXor
|
|
13
13
|
from ..datasets.datasets_utils import state_to_label, state_to_weights
|
14
14
|
|
15
15
|
__all__ = [
|
16
|
-
"builtin_datasets",
|
17
|
-
"DatasetNot",
|
18
|
-
"DATASET_NOT",
|
19
16
|
"DATALOADER_NOT",
|
20
|
-
"
|
21
|
-
"DATASET_XOR",
|
17
|
+
"DATALOADER_SUBSET_PARITY",
|
22
18
|
"DATALOADER_XOR",
|
23
|
-
"
|
19
|
+
"DATASET_NOT",
|
24
20
|
"DATASET_SUBSET_PARITY",
|
25
|
-
"
|
21
|
+
"DATASET_XOR",
|
22
|
+
"DatasetNot",
|
26
23
|
"DatasetParity",
|
27
|
-
"
|
24
|
+
"DatasetSubsetParity",
|
25
|
+
"DatasetXor",
|
26
|
+
"builtin_datasets",
|
28
27
|
"state_to_label",
|
28
|
+
"state_to_weights",
|
29
29
|
]
|
30
30
|
|
31
31
|
|
classiq/execution/__init__.py
CHANGED
@@ -10,7 +10,6 @@ from ..interface.executor.vqe_result import VQESolverResult
|
|
10
10
|
from .execution_session import ExecutionSession
|
11
11
|
from .iqcc import generate_iqcc_token, generate_iqcc_token_async
|
12
12
|
from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
|
13
|
-
from .qaoa import execute_qaoa
|
14
13
|
from .qnn import execute_qnn
|
15
14
|
|
16
15
|
__all__ = (
|
@@ -25,7 +24,6 @@ __all__ = (
|
|
25
24
|
"get_execution_jobs",
|
26
25
|
"get_execution_jobs_async",
|
27
26
|
"ExecutionSession",
|
28
|
-
"execute_qaoa",
|
29
27
|
"execute_qnn",
|
30
28
|
"generate_iqcc_token",
|
31
29
|
"generate_iqcc_token_async",
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import json
|
2
|
+
import random
|
2
3
|
from functools import cached_property
|
3
4
|
from types import TracebackType
|
4
5
|
from typing import Any, Callable, Optional, Union, cast
|
@@ -168,6 +169,9 @@ class ExecutionSession:
|
|
168
169
|
# because cmain is expected in some cases
|
169
170
|
self.program.model.classical_execution_code = "dummy"
|
170
171
|
|
172
|
+
self._random_seed = self.program.model.execution_preferences.random_seed
|
173
|
+
self._rng = random.Random(self._random_seed) # noqa: S311
|
174
|
+
|
171
175
|
self._async_client = client().async_client()
|
172
176
|
|
173
177
|
def __enter__(self) -> "ExecutionSession":
|
@@ -197,6 +201,8 @@ class ExecutionSession:
|
|
197
201
|
self, classical_execution_code: str, primitives_input: PrimitivesInput
|
198
202
|
) -> ExecutionJob:
|
199
203
|
execution_input = self._execution_input.copy()
|
204
|
+
execution_input["execution_preferences"]["random_seed"] = self._random_seed
|
205
|
+
self._random_seed = self._rng.randint(0, 2**32 - 1)
|
200
206
|
execution_input["classical_execution_code"] = classical_execution_code
|
201
207
|
# The use of `model_dump_json` is necessary for complex numbers serialization
|
202
208
|
execution_input["primitives_input"] = json.loads(
|