classiq 0.62.0__py3-none-any.whl → 0.63.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/__init__.py +3 -0
- classiq/_internals/api_wrapper.py +6 -26
- classiq/_internals/client.py +1 -9
- classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -8
- classiq/applications/combinatorial_helpers/optimization_model.py +5 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +106 -27
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -2
- classiq/applications/grover/grover_model_constructor.py +1 -1
- classiq/applications/libraries/qmci_library.py +2 -1
- classiq/execution/execution_session.py +66 -96
- classiq/execution/jobs.py +3 -9
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +8 -5
- classiq/interface/backend/pydantic_backend.py +1 -1
- classiq/interface/chemistry/operator.py +0 -204
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/generated_circuit_data.py +22 -7
- classiq/interface/generator/model/model.py +3 -0
- classiq/interface/generator/model/preferences/preferences.py +13 -0
- classiq/interface/generator/quantum_function_call.py +4 -2
- classiq/interface/model/handle_binding.py +50 -5
- classiq/interface/model/quantum_type.py +16 -0
- classiq/interface/server/routes.py +1 -3
- classiq/model_expansions/capturing/captured_vars.py +102 -19
- classiq/model_expansions/closure.py +19 -56
- classiq/model_expansions/function_builder.py +13 -8
- classiq/model_expansions/generative_functions.py +15 -1
- classiq/model_expansions/interpreter.py +94 -32
- classiq/model_expansions/model_tables.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +61 -2
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +3 -10
- classiq/model_expansions/quantum_operations/emitter.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +1 -2
- classiq/model_expansions/quantum_operations/repeat.py +4 -3
- classiq/model_expansions/scope.py +7 -1
- classiq/model_expansions/scope_initialization.py +34 -25
- classiq/model_expansions/transformers/var_splitter.py +57 -7
- classiq/open_library/__init__.py +4 -0
- classiq/open_library/functions/__init__.py +130 -0
- classiq/{qmod/builtins → open_library}/functions/amplitude_estimation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/discrete_sine_cosine_transform.py +6 -4
- classiq/{qmod/builtins → open_library}/functions/grover.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/linear_pauli_rotation.py +1 -1
- classiq/{qmod/builtins → open_library}/functions/modular_exponentiation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/qpe.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/state_preparation.py +6 -149
- classiq/{qmod/builtins → open_library}/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +81 -0
- classiq/{qmod/builtins → open_library}/functions/variational.py +1 -1
- classiq/qmod/builtins/functions/__init__.py +4 -130
- classiq/qmod/builtins/functions/allocation.py +150 -0
- classiq/qmod/builtins/functions/arithmetic.py +0 -34
- classiq/qmod/builtins/functions/operators.py +0 -6
- classiq/qmod/create_model_function.py +8 -162
- classiq/qmod/generative.py +0 -16
- classiq/qmod/model_state_container.py +7 -0
- classiq/qmod/native/pretty_printer.py +10 -11
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/qfunc.py +11 -12
- classiq/qmod/qmod_variable.py +1 -3
- classiq/qmod/quantum_expandable.py +21 -0
- classiq/qmod/quantum_function.py +65 -3
- {classiq-0.62.0.dist-info → classiq-0.63.1.dist-info}/METADATA +1 -1
- {classiq-0.62.0.dist-info → classiq-0.63.1.dist-info}/RECORD +74 -71
- classiq/qmod/builtins/functions/utility_functions.py +0 -43
- /classiq/{qmod/builtins → open_library}/functions/hea.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qaoa_penalty.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qft_functions.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qsvt.py +0 -0
- {classiq-0.62.0.dist-info → classiq-0.63.1.dist-info}/WHEEL +0 -0
classiq/__init__.py
CHANGED
@@ -46,6 +46,8 @@ from classiq.executor import (
|
|
46
46
|
execute_async,
|
47
47
|
set_quantum_program_execution_preferences,
|
48
48
|
)
|
49
|
+
from classiq.open_library import * # noqa: F403
|
50
|
+
from classiq.open_library import __all__ as _open_library_all
|
49
51
|
from classiq.qmod import * # noqa: F403
|
50
52
|
from classiq.qmod import __all__ as _qmod_all
|
51
53
|
from classiq.synthesis import (
|
@@ -114,6 +116,7 @@ __all__ = (
|
|
114
116
|
+ _sub_modules
|
115
117
|
+ _application_constructors_all
|
116
118
|
+ _qmod_all
|
119
|
+
+ _open_library_all
|
117
120
|
)
|
118
121
|
|
119
122
|
|
@@ -33,10 +33,6 @@ from classiq._internals.client import client
|
|
33
33
|
from classiq._internals.jobs import JobPoller
|
34
34
|
|
35
35
|
ResultType = TypeVar("ResultType", bound=pydantic.BaseModel)
|
36
|
-
CLASSIQ_ACCEPT_HEADER = "X-Classiq-Accept-Version"
|
37
|
-
|
38
|
-
_ACCEPT_HEADER = "X-Classiq-Accept-Version"
|
39
|
-
_CONTENT_TYPE_HEADER = "X-Classiq-Content-Type-Version"
|
40
36
|
|
41
37
|
|
42
38
|
class HTTPMethod(StrEnum):
|
@@ -143,16 +139,10 @@ class ApiWrapper:
|
|
143
139
|
execution_input: dict,
|
144
140
|
http_client: Optional[httpx.AsyncClient] = None,
|
145
141
|
) -> execution_request.ExecutionJobDetails:
|
146
|
-
headers = {
|
147
|
-
_ACCEPT_HEADER: "v1",
|
148
|
-
_CONTENT_TYPE_HEADER: execution_input["version"],
|
149
|
-
}
|
150
142
|
data = await cls._call_task(
|
151
143
|
http_method=HTTPMethod.POST,
|
152
|
-
|
153
|
-
url=routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH,
|
144
|
+
url=routes.EXECUTION_JOBS_FULL_PATH,
|
154
145
|
body=execution_input,
|
155
|
-
use_versioned_url=False,
|
156
146
|
http_client=http_client,
|
157
147
|
)
|
158
148
|
return execution_request.ExecutionJobDetails.model_validate(data)
|
@@ -163,12 +153,9 @@ class ApiWrapper:
|
|
163
153
|
job_id: JobID,
|
164
154
|
http_client: Optional[httpx.AsyncClient] = None,
|
165
155
|
) -> execution_request.ExecutionJobDetails:
|
166
|
-
headers = {_ACCEPT_HEADER: "v1"}
|
167
156
|
data = await cls._call_task(
|
168
157
|
http_method=HTTPMethod.GET,
|
169
|
-
|
170
|
-
url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}",
|
171
|
-
use_versioned_url=False,
|
158
|
+
url=f"{routes.EXECUTION_JOBS_FULL_PATH}/{job_id.job_id}",
|
172
159
|
http_client=http_client,
|
173
160
|
)
|
174
161
|
return execution_request.ExecutionJobDetails.model_validate(data)
|
@@ -177,14 +164,11 @@ class ApiWrapper:
|
|
177
164
|
async def call_get_execution_job_result(
|
178
165
|
cls,
|
179
166
|
job_id: JobID,
|
180
|
-
version: str,
|
181
167
|
http_client: Optional[httpx.AsyncClient] = None,
|
182
168
|
) -> classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults:
|
183
169
|
data = await cls._call_task(
|
184
170
|
http_method=HTTPMethod.GET,
|
185
|
-
url=f"{routes.
|
186
|
-
use_versioned_url=False,
|
187
|
-
headers={CLASSIQ_ACCEPT_HEADER: version},
|
171
|
+
url=f"{routes.EXECUTION_JOBS_FULL_PATH}/{job_id.job_id}/result",
|
188
172
|
http_client=http_client,
|
189
173
|
)
|
190
174
|
return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.model_validate(
|
@@ -200,11 +184,10 @@ class ApiWrapper:
|
|
200
184
|
) -> ExecutionJobDetailsV1:
|
201
185
|
data = await cls._call_task(
|
202
186
|
http_method=HTTPMethod.PATCH,
|
203
|
-
url=f"{routes.
|
187
|
+
url=f"{routes.EXECUTION_JOBS_FULL_PATH}/{job_id.job_id}",
|
204
188
|
params={
|
205
189
|
"name": name,
|
206
190
|
},
|
207
|
-
use_versioned_url=False,
|
208
191
|
http_client=http_client,
|
209
192
|
)
|
210
193
|
return ExecutionJobDetailsV1.model_validate(data)
|
@@ -217,8 +200,7 @@ class ApiWrapper:
|
|
217
200
|
) -> None:
|
218
201
|
await cls._call_task(
|
219
202
|
http_method=HTTPMethod.PUT,
|
220
|
-
url=f"{routes.
|
221
|
-
use_versioned_url=False,
|
203
|
+
url=f"{routes.EXECUTION_JOBS_FULL_PATH}/{job_id.job_id}/cancel",
|
222
204
|
allow_none=True,
|
223
205
|
http_client=http_client,
|
224
206
|
)
|
@@ -232,12 +214,11 @@ class ApiWrapper:
|
|
232
214
|
) -> ExecutionJobsQueryResultsV1:
|
233
215
|
data = await cls._call_task(
|
234
216
|
http_method=HTTPMethod.GET,
|
235
|
-
url=f"{routes.
|
217
|
+
url=f"{routes.EXECUTION_JOBS_FULL_PATH}",
|
236
218
|
params={
|
237
219
|
"offset": offset,
|
238
220
|
"limit": limit,
|
239
221
|
},
|
240
|
-
use_versioned_url=False,
|
241
222
|
http_client=http_client,
|
242
223
|
)
|
243
224
|
return ExecutionJobsQueryResultsV1.model_validate(data)
|
@@ -395,7 +376,6 @@ class ApiWrapper:
|
|
395
376
|
) -> operator.PauliOperator:
|
396
377
|
poller = JobPoller(
|
397
378
|
base_url=routes.GENERATE_HAMILTONIAN_FULL_PATH,
|
398
|
-
use_versioned_url=False,
|
399
379
|
)
|
400
380
|
result = await poller.run_pydantic(
|
401
381
|
problem, timeout_sec=None, http_client=http_client
|
classiq/_internals/client.py
CHANGED
@@ -9,14 +9,7 @@ import sys
|
|
9
9
|
import time
|
10
10
|
from collections.abc import Awaitable
|
11
11
|
from types import TracebackType
|
12
|
-
from typing import
|
13
|
-
Any,
|
14
|
-
Callable,
|
15
|
-
NoReturn,
|
16
|
-
Optional,
|
17
|
-
TypeVar,
|
18
|
-
Union,
|
19
|
-
)
|
12
|
+
from typing import Any, Callable, NoReturn, Optional, TypeVar, Union
|
20
13
|
|
21
14
|
import httpx
|
22
15
|
from typing_extensions import ParamSpec
|
@@ -170,7 +163,6 @@ class Client:
|
|
170
163
|
_UNKNOWN_VERSION = HostChecker._UNKNOWN_VERSION
|
171
164
|
_SESSION_HEADER = "Classiq-Session"
|
172
165
|
_WARNINGS_HEADER = "X-Classiq-Warnings"
|
173
|
-
_LATEST_VERSION_API_PREFIX = "/api/v1"
|
174
166
|
_HTTP_TIMEOUT_SECONDS = 3600 # Needs to be synced with load-balancer timeout
|
175
167
|
|
176
168
|
def __init__(self, conf: config.Configuration) -> None:
|
@@ -53,7 +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.
|
56
|
+
from classiq.open_library.functions.hea import full_hea
|
57
57
|
|
58
58
|
_LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
|
59
59
|
"+": "PLUS",
|
@@ -7,6 +7,7 @@ import pyomo.environ as pyo
|
|
7
7
|
|
8
8
|
from classiq.interface.combinatorial_optimization.sense import is_maximization
|
9
9
|
from classiq.interface.combinatorial_optimization.solver_types import QSolver
|
10
|
+
from classiq.interface.exceptions import ClassiqValueError
|
10
11
|
from classiq.interface.executor.vqe_result import VQESolverResult
|
11
12
|
from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
|
12
13
|
|
@@ -20,6 +21,7 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import
|
|
20
21
|
pauli_operator_to_hamiltonian,
|
21
22
|
)
|
22
23
|
from classiq.applications.combinatorial_helpers.pyomo_utils import (
|
24
|
+
add_var_domain_constraints,
|
23
25
|
convert_pyomo_to_global_presentation,
|
24
26
|
evaluate_objective,
|
25
27
|
pyomo_to_qmod_qstruct,
|
@@ -56,14 +58,30 @@ def pyo_model_to_hamiltonian(
|
|
56
58
|
def pyo_model_to_qmod_problem(
|
57
59
|
pyo_model: pyo.ConcreteModel, penalty_energy: float
|
58
60
|
) -> tuple[type[QStruct], Callable]:
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
with add_var_domain_constraints(pyo_model):
|
62
|
+
optimization_model = OptimizationModel(
|
63
|
+
pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
|
64
|
+
)
|
65
|
+
_validate_var_domains(optimization_model)
|
66
|
+
qmod_struct = pyomo_to_qmod_qstruct(
|
67
|
+
"QAOAVars", optimization_model.vars_not_encoded
|
68
|
+
)
|
69
|
+
cost_func = partial(
|
70
|
+
evaluate_objective, *optimization_model.objective_not_encoded_sympy
|
71
|
+
)
|
72
|
+
return qmod_struct, cost_func
|
73
|
+
|
74
|
+
|
75
|
+
def _validate_var_domains(model: OptimizationModel) -> None:
|
76
|
+
for var in model.vars_not_encoded:
|
77
|
+
if (
|
78
|
+
isinstance(var.bounds, tuple)
|
79
|
+
and len(var.bounds) == 2
|
80
|
+
and var.bounds[0] != 0
|
81
|
+
):
|
82
|
+
raise ClassiqValueError(
|
83
|
+
f"Bounds of variable {var.local_name} must start at 0, got {var.bounds}"
|
84
|
+
)
|
67
85
|
|
68
86
|
|
69
87
|
def _str_to_list_int(str_ints: str) -> list[int]:
|
@@ -25,6 +25,7 @@ from classiq.applications.combinatorial_helpers.encoding_mapping import Encoding
|
|
25
25
|
from classiq.applications.combinatorial_helpers.memory import InternalQuantumReg
|
26
26
|
from classiq.applications.combinatorial_helpers.pyomo_utils import (
|
27
27
|
get_field_name,
|
28
|
+
index_as_tuple,
|
28
29
|
is_index_var,
|
29
30
|
)
|
30
31
|
from classiq.applications.combinatorial_helpers.transformations import (
|
@@ -182,7 +183,10 @@ class OptimizationModel:
|
|
182
183
|
sympy_var: (
|
183
184
|
get_field_name(pyomo_var)
|
184
185
|
if not is_index_var(pyomo_var)
|
185
|
-
else (
|
186
|
+
else (
|
187
|
+
get_field_name(pyomo_var.parent_component()),
|
188
|
+
index_as_tuple(pyomo_var.index()),
|
189
|
+
)
|
186
190
|
)
|
187
191
|
for pyomo_var, sympy_var in objective_map.pyomo2sympy.items()
|
188
192
|
}
|
@@ -1,7 +1,11 @@
|
|
1
1
|
import math
|
2
2
|
import re
|
3
3
|
from collections import defaultdict
|
4
|
+
from collections.abc import Iterator
|
5
|
+
from contextlib import contextmanager
|
4
6
|
from enum import Enum
|
7
|
+
from functools import reduce
|
8
|
+
from operator import mul
|
5
9
|
from typing import Any, Optional, TypeVar, Union
|
6
10
|
|
7
11
|
import pydantic
|
@@ -14,6 +18,7 @@ from pyomo.core.base.component import ComponentData
|
|
14
18
|
from pyomo.core.base.constraint import _GeneralConstraintData
|
15
19
|
from pyomo.core.base.indexed_component import IndexedComponent
|
16
20
|
from pyomo.core.base.objective import ScalarObjective
|
21
|
+
from pyomo.core.expr.base import ExpressionBase
|
17
22
|
from pyomo.core.expr.sympy_tools import (
|
18
23
|
Pyomo2SympyVisitor,
|
19
24
|
PyomoSympyBimap,
|
@@ -268,44 +273,67 @@ def pyomo_to_qmod_qstruct(
|
|
268
273
|
|
269
274
|
|
270
275
|
def _get_qstruct_fields(vars: list[_GeneralVarData]) -> dict[str, type[QVar]]:
|
271
|
-
|
272
|
-
array_type_sizes = _get_array_sizes(array_types)
|
276
|
+
array_type_sizes = _get_array_sizes(vars)
|
273
277
|
fields: dict[str, type[QVar]] = {}
|
274
278
|
for var in vars:
|
275
279
|
_add_qmod_field(var, array_type_sizes, fields)
|
276
280
|
return fields
|
277
281
|
|
278
282
|
|
279
|
-
def
|
280
|
-
array_types: dict[str, set[
|
283
|
+
def _get_array_sizes(vars: list[_GeneralVarData]) -> dict[str, tuple[int, ...]]:
|
284
|
+
array_types: dict[str, set[tuple]] = defaultdict(set)
|
281
285
|
for var in vars:
|
282
286
|
if is_index_var(var):
|
283
|
-
array_types[var.parent_component()
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
def _get_array_sizes(array_types: dict[str, set[int]]) -> dict[str, int]:
|
287
|
+
array_types[get_field_name(var.parent_component())].add(
|
288
|
+
index_as_tuple(var.index())
|
289
|
+
)
|
288
290
|
return {
|
289
|
-
name:
|
291
|
+
name: dimensions
|
290
292
|
for name, indices in array_types.items()
|
291
|
-
if
|
293
|
+
if (dimensions := _get_indices_dimensions(indices)) is not None
|
292
294
|
}
|
293
295
|
|
294
296
|
|
297
|
+
def _get_indices_dimensions(indices: set[tuple[int, ...]]) -> Optional[tuple[int, ...]]:
|
298
|
+
indices_list = list(indices)
|
299
|
+
if len(indices) == 0:
|
300
|
+
return None
|
301
|
+
first_idx = indices_list[0]
|
302
|
+
if len(first_idx) == 0:
|
303
|
+
return None
|
304
|
+
if any(len(idx) != len(first_idx) for idx in indices_list[1:]):
|
305
|
+
return None
|
306
|
+
dimension_bounds = [(idx, idx) for idx in first_idx]
|
307
|
+
for multi_idx in indices_list[1:]:
|
308
|
+
for dim_idx, idx in enumerate(multi_idx):
|
309
|
+
dimension_bounds[dim_idx] = (
|
310
|
+
min(dimension_bounds[dim_idx][0], idx),
|
311
|
+
max(dimension_bounds[dim_idx][1], idx),
|
312
|
+
)
|
313
|
+
if any(lb != 0 for lb, ub in dimension_bounds):
|
314
|
+
return None
|
315
|
+
dimensions = tuple(ub + 1 for _, ub in dimension_bounds)
|
316
|
+
if reduce(mul, dimensions) != len(indices_list):
|
317
|
+
return None
|
318
|
+
return dimensions
|
319
|
+
|
320
|
+
|
295
321
|
def _add_qmod_field(
|
296
322
|
var: _GeneralVarData,
|
297
|
-
array_type_sizes: dict[str, int],
|
323
|
+
array_type_sizes: dict[str, tuple[int, ...]],
|
298
324
|
fields: dict[str, type[QVar]],
|
299
325
|
) -> None:
|
300
|
-
parent_name = var.parent_component()
|
326
|
+
parent_name = get_field_name(var.parent_component())
|
301
327
|
if parent_name not in array_type_sizes:
|
302
328
|
var_name = get_field_name(var)
|
303
329
|
fields[var_name] = _get_qmod_field_type(var_name, var)
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
330
|
+
return
|
331
|
+
dimensions = array_type_sizes[parent_name]
|
332
|
+
if index_as_tuple(var.index()) == tuple(0 for _ in range(len(dimensions))):
|
333
|
+
qmod_type: type[QVar] = _get_qmod_field_type(parent_name, var)
|
334
|
+
for dim in reversed(dimensions):
|
335
|
+
qmod_type = QArray[qmod_type, dim] # type:ignore[valid-type]
|
336
|
+
fields[parent_name] = qmod_type
|
309
337
|
|
310
338
|
|
311
339
|
def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]:
|
@@ -325,14 +353,12 @@ def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]
|
|
325
353
|
raise ClassiqValueError(
|
326
354
|
f"Non-integer bounds for variable {var_name!r} are not supported"
|
327
355
|
)
|
328
|
-
if lb > 0:
|
329
|
-
ub -= lb
|
330
356
|
qnum: Any = QNum # mypy shenanigans
|
331
|
-
return qnum[math.ceil(math.log2(ub - lb)), False, 0]
|
357
|
+
return qnum[math.ceil(math.log2(ub - lb + 1)), False, 0]
|
332
358
|
|
333
359
|
|
334
360
|
def evaluate_objective(
|
335
|
-
var_mapping: dict[Any, Union[str, tuple[str, int]]],
|
361
|
+
var_mapping: dict[Any, Union[str, tuple[str, tuple[int, ...]]]],
|
336
362
|
sympy_expr: sympy.Expr,
|
337
363
|
struct_obj: Any,
|
338
364
|
) -> Any:
|
@@ -340,7 +366,7 @@ def evaluate_objective(
|
|
340
366
|
sympy_var: (
|
341
367
|
getattr(struct_obj, field_accessor)
|
342
368
|
if isinstance(field_accessor, str)
|
343
|
-
else getattr(struct_obj, field_accessor[0])
|
369
|
+
else _get_item(getattr(struct_obj, field_accessor[0]), field_accessor[1])
|
344
370
|
)
|
345
371
|
for sympy_var, field_accessor in var_mapping.items()
|
346
372
|
}
|
@@ -357,12 +383,65 @@ def evaluate_objective(
|
|
357
383
|
return SymbolicExpr(expr=expr_str, is_quantum=True)
|
358
384
|
|
359
385
|
|
386
|
+
def _get_item(obj: Any, multi_index: tuple[int, ...]) -> Any:
|
387
|
+
for idx in multi_index:
|
388
|
+
obj = obj[idx]
|
389
|
+
return obj
|
390
|
+
|
391
|
+
|
360
392
|
def get_field_name(var: _GeneralVarData) -> str:
|
361
|
-
return var.local_name.replace("[", "_").replace("]", "")
|
393
|
+
return var.local_name.replace("[", "_").replace("]", "").replace(",", "_")
|
362
394
|
|
363
395
|
|
364
396
|
def is_index_var(var: _GeneralVarData) -> bool:
|
365
|
-
|
366
|
-
|
367
|
-
|
397
|
+
index = var.index()
|
398
|
+
return isinstance(index, int) or (
|
399
|
+
isinstance(index, tuple) and all(isinstance(idx, int) for idx in index)
|
368
400
|
)
|
401
|
+
|
402
|
+
|
403
|
+
def index_as_tuple(index: Union[int, tuple[int, ...]]) -> tuple[int, ...]:
|
404
|
+
if isinstance(index, int):
|
405
|
+
return (index,)
|
406
|
+
return index
|
407
|
+
|
408
|
+
|
409
|
+
@contextmanager
|
410
|
+
def add_var_domain_constraints(model: ConcreteModel) -> Iterator[None]:
|
411
|
+
vars = extract(model, _GeneralVarData)
|
412
|
+
constraints = [
|
413
|
+
constraint
|
414
|
+
for var in vars
|
415
|
+
if (constraint := _get_var_domain_constraint(var)) is not None
|
416
|
+
]
|
417
|
+
if len(constraints) == 0:
|
418
|
+
yield
|
419
|
+
return
|
420
|
+
model.var_domain_constraints = pyo.ConstraintList()
|
421
|
+
for constraint in constraints:
|
422
|
+
model.var_domain_constraints.add(constraint)
|
423
|
+
yield
|
424
|
+
model.del_component("var_domain_constraints")
|
425
|
+
|
426
|
+
|
427
|
+
def _get_var_domain_constraint(var: _GeneralVarData) -> Optional[ExpressionBase]:
|
428
|
+
bounds = var.bounds
|
429
|
+
if (
|
430
|
+
type(bounds) is not tuple
|
431
|
+
or len(bounds) != 2
|
432
|
+
or not all(isinstance(bounds[idx], int) for idx in (0, 1))
|
433
|
+
):
|
434
|
+
raise ClassiqValueError(
|
435
|
+
f"Missing bounds for variable {var.local_name}. Expected both lower and "
|
436
|
+
f"upper bounds, got {bounds}"
|
437
|
+
)
|
438
|
+
lb, ub = bounds
|
439
|
+
if ub < lb:
|
440
|
+
raise ClassiqValueError(
|
441
|
+
f"Illegal bounds for variable {var.local_name}. The upper bound ({ub}) is "
|
442
|
+
f"lesser than the lower bound ({lb})"
|
443
|
+
)
|
444
|
+
ub_norm = ub - lb + 1
|
445
|
+
if ub_norm & (ub_norm - 1) == 0:
|
446
|
+
return None
|
447
|
+
return var <= ub
|
classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py
CHANGED
@@ -33,7 +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.
|
36
|
+
from classiq.open_library.functions.qaoa_penalty import qaoa_penalty
|
37
37
|
|
38
38
|
|
39
39
|
def construct_combi_opt_py_model(
|
@@ -17,11 +17,13 @@ from classiq.applications.combinatorial_helpers.combinatorial_problem_utils impo
|
|
17
17
|
pyo_model_to_qmod_problem,
|
18
18
|
)
|
19
19
|
from classiq.execution import ExecutionSession
|
20
|
+
from classiq.open_library.functions.utility_functions import (
|
21
|
+
apply_to_all,
|
22
|
+
hadamard_transform,
|
23
|
+
)
|
20
24
|
from classiq.qmod.builtins.functions import (
|
21
25
|
RX,
|
22
26
|
allocate,
|
23
|
-
apply_to_all,
|
24
|
-
hadamard_transform,
|
25
27
|
)
|
26
28
|
from classiq.qmod.builtins.operations import phase, repeat
|
27
29
|
from classiq.qmod.cparam import CReal
|
@@ -19,7 +19,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
19
19
|
)
|
20
20
|
|
21
21
|
from classiq import RegisterUserInput
|
22
|
-
from classiq.
|
22
|
+
from classiq.open_library.functions.grover import grover_search, phase_oracle
|
23
23
|
|
24
24
|
_OUTPUT_VARIABLE_NAME = "result"
|
25
25
|
|
@@ -1,4 +1,5 @@
|
|
1
|
-
from classiq.
|
1
|
+
from classiq.open_library.functions.amplitude_estimation import amplitude_estimation
|
2
|
+
from classiq.qmod.builtins.functions import Z
|
2
3
|
from classiq.qmod.qfunc import qfunc
|
3
4
|
from classiq.qmod.qmod_variable import QArray, QBit, QNum
|
4
5
|
from classiq.qmod.quantum_callable import QCallable
|