classiq 0.37.1__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.1.dist-info → classiq-0.38.0.dist-info}/METADATA +2 -1
- {classiq-0.37.1.dist-info → classiq-0.38.0.dist-info}/RECORD +222 -186
- {classiq-0.37.1.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
classiq/__init__.py
CHANGED
@@ -13,7 +13,7 @@ from classiq.interface.generator.control_state import ControlState
|
|
13
13
|
from classiq.interface.generator.expressions.enums.pauli import Pauli
|
14
14
|
from classiq.interface.generator.functions import * # noqa: F403
|
15
15
|
from classiq.interface.generator.functions import __all__ as _ifunc_all
|
16
|
-
from classiq.interface.generator.
|
16
|
+
from classiq.interface.generator.quantum_program import QuantumProgram
|
17
17
|
from classiq.interface.ide.show import show
|
18
18
|
|
19
19
|
from classiq import (
|
@@ -82,7 +82,7 @@ __all__ = (
|
|
82
82
|
"RegisterArithmeticInfo",
|
83
83
|
"ControlState",
|
84
84
|
"Analyzer",
|
85
|
-
"
|
85
|
+
"QuantumProgram",
|
86
86
|
"authenticate",
|
87
87
|
"synthesize",
|
88
88
|
"synthesize_async",
|
@@ -33,7 +33,7 @@ def widget_callback(widget_name: WidgetName) -> Callable[[WidgetFunc], Callable]
|
|
33
33
|
interactive_loop = _create_interactive_loop_async(
|
34
34
|
function=function, self=self, widget=widget
|
35
35
|
)
|
36
|
-
asyncio.ensure_future(interactive_loop)
|
36
|
+
asyncio.ensure_future(interactive_loop) # noqa: RUF006
|
37
37
|
await asyncio.sleep(SleepTime)
|
38
38
|
|
39
39
|
return wrapper
|
@@ -6,7 +6,7 @@ from ipywidgets import Combobox, HBox, VBox # type: ignore[import]
|
|
6
6
|
|
7
7
|
from classiq.interface.analyzer import analysis_params
|
8
8
|
from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
|
9
|
-
from classiq.interface.generator.
|
9
|
+
from classiq.interface.generator.quantum_program import QuantumProgram
|
10
10
|
|
11
11
|
from classiq._analyzer_extras._ipywidgets_async_extension import widget_callback
|
12
12
|
from classiq.analyzer.analyzer_utilities import (
|
@@ -22,7 +22,7 @@ class InteractiveHardware(AnalyzerUtilities):
|
|
22
22
|
def __init__(
|
23
23
|
self,
|
24
24
|
params: analysis_params.AnalysisParams,
|
25
|
-
circuit:
|
25
|
+
circuit: QuantumProgram,
|
26
26
|
available_devices: ProviderAvailableDevices,
|
27
27
|
hardware_graphs: HardwareGraphs,
|
28
28
|
) -> None:
|
@@ -70,7 +70,7 @@ class InteractiveHardware(AnalyzerUtilities):
|
|
70
70
|
) -> None:
|
71
71
|
if not provider:
|
72
72
|
return
|
73
|
-
await self.
|
73
|
+
await self._request_available_devices_async(providers=[provider])
|
74
74
|
self.devices_combobox.options = self._filter_devices_by_qubits_count(provider)
|
75
75
|
self.devices_combobox.disabled = False
|
76
76
|
self.devices_combobox.placeholder = "Choose device"
|
@@ -13,8 +13,14 @@ from classiq.interface.execution.jobs import (
|
|
13
13
|
ExecutionJobsQueryResultsV1,
|
14
14
|
)
|
15
15
|
from classiq.interface.executor import execution_request, result as execute_result
|
16
|
-
from classiq.interface.generator import
|
17
|
-
from classiq.interface.jobs import
|
16
|
+
from classiq.interface.generator import quantum_program as generator_result
|
17
|
+
from classiq.interface.jobs import (
|
18
|
+
JobDescriptionBase,
|
19
|
+
JobDescriptionFailure,
|
20
|
+
JobDescriptionSuccess,
|
21
|
+
JobID,
|
22
|
+
JSONObject,
|
23
|
+
)
|
18
24
|
from classiq.interface.model.common_model_types import ModelInput
|
19
25
|
from classiq.interface.server import routes
|
20
26
|
|
@@ -42,13 +48,15 @@ class StatusType(Protocol):
|
|
42
48
|
|
43
49
|
|
44
50
|
def _parse_job_response(
|
45
|
-
job_result:
|
51
|
+
job_result: JobDescriptionBase[JSONObject],
|
46
52
|
output_type: Type[ResultType],
|
47
53
|
) -> ResultType:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
54
|
+
if isinstance(job_result, JobDescriptionSuccess):
|
55
|
+
return output_type.parse_obj(job_result.description)
|
56
|
+
if isinstance(job_result, JobDescriptionFailure):
|
57
|
+
raise ClassiqAPIError(job_result.description.details)
|
58
|
+
|
59
|
+
raise ClassiqAPIError("Unexpected response from server")
|
52
60
|
|
53
61
|
|
54
62
|
class ApiWrapper:
|
@@ -93,14 +101,14 @@ class ApiWrapper:
|
|
93
101
|
@classmethod
|
94
102
|
async def call_generation_task(
|
95
103
|
cls, model: ModelInput
|
96
|
-
) -> generator_result.
|
104
|
+
) -> generator_result.QuantumProgram:
|
97
105
|
poller = JobPoller(base_url=routes.TASKS_GENERATE_FULL_PATH)
|
98
106
|
result = await poller.run_pydantic(model, timeout_sec=None)
|
99
|
-
return _parse_job_response(result, generator_result.
|
107
|
+
return _parse_job_response(result, generator_result.QuantumProgram)
|
100
108
|
|
101
109
|
@classmethod
|
102
110
|
async def call_execute_generated_circuit(
|
103
|
-
cls, circuit: generator_result.
|
111
|
+
cls, circuit: generator_result.QuantumProgram
|
104
112
|
) -> execution_request.ExecutionJobDetails:
|
105
113
|
execution_input = await cls._call_task_pydantic(
|
106
114
|
http_method=HTTPMethod.POST,
|
@@ -125,7 +133,7 @@ class ApiWrapper:
|
|
125
133
|
cls,
|
126
134
|
job_id: JobID,
|
127
135
|
) -> execution_request.ExecutionJobDetails:
|
128
|
-
headers = {
|
136
|
+
headers = {_ACCEPT_HEADER: "v1"}
|
129
137
|
data = await cls._call_task(
|
130
138
|
http_method=HTTPMethod.GET,
|
131
139
|
headers=headers,
|
@@ -215,7 +223,7 @@ class ApiWrapper:
|
|
215
223
|
|
216
224
|
@classmethod
|
217
225
|
async def call_analyzer_app(
|
218
|
-
cls, params: generator_result.
|
226
|
+
cls, params: generator_result.QuantumProgram
|
219
227
|
) -> analysis_result.DataID:
|
220
228
|
data = await cls._call_task_pydantic(
|
221
229
|
http_method=HTTPMethod.POST,
|
@@ -227,23 +235,23 @@ class ApiWrapper:
|
|
227
235
|
@classmethod
|
228
236
|
async def get_generated_circuit_from_qasm(
|
229
237
|
cls, params: analysis_result.QasmCode
|
230
|
-
) -> generator_result.
|
238
|
+
) -> generator_result.QuantumProgram:
|
231
239
|
data = await cls._call_task_pydantic(
|
232
240
|
http_method=HTTPMethod.POST,
|
233
241
|
url=routes.IDE_QASM_FULL_PATH,
|
234
242
|
model=params,
|
235
243
|
)
|
236
|
-
return generator_result.
|
244
|
+
return generator_result.QuantumProgram.parse_obj(data)
|
237
245
|
|
238
246
|
@classmethod
|
239
247
|
async def get_analyzer_app_data(
|
240
248
|
cls, params: analysis_result.DataID
|
241
|
-
) -> generator_result.
|
249
|
+
) -> generator_result.QuantumProgram:
|
242
250
|
data = await cls._call_task(
|
243
251
|
http_method=HTTPMethod.GET,
|
244
252
|
url=f"{routes.ANALYZER_DATA_FULL_PATH}/{params.id}",
|
245
253
|
)
|
246
|
-
return generator_result.
|
254
|
+
return generator_result.QuantumProgram.parse_obj(data)
|
247
255
|
|
248
256
|
@classmethod
|
249
257
|
async def call_rb_analysis_task(
|
@@ -1,11 +1,8 @@
|
|
1
|
-
import abc
|
2
1
|
import asyncio
|
3
2
|
import functools
|
4
|
-
import inspect
|
5
3
|
import itertools
|
6
4
|
import logging
|
7
5
|
import time
|
8
|
-
import types
|
9
6
|
from typing import (
|
10
7
|
Any,
|
11
8
|
AsyncGenerator,
|
@@ -18,8 +15,6 @@ from typing import (
|
|
18
15
|
Union,
|
19
16
|
)
|
20
17
|
|
21
|
-
from classiq.exceptions import ClassiqValueError
|
22
|
-
|
23
18
|
T = TypeVar("T")
|
24
19
|
ASYNC_SUFFIX = "_async"
|
25
20
|
|
@@ -58,74 +53,6 @@ def syncify_function(async_func: Callable[..., Awaitable[T]]) -> Callable[..., T
|
|
58
53
|
return async_wrapper
|
59
54
|
|
60
55
|
|
61
|
-
def maybe_syncify_property_function(obj: Any) -> Any:
|
62
|
-
"""
|
63
|
-
The object is the input to `property` (or to `property.setter`)
|
64
|
-
Thus, we expect it to be either a function, or a function-that-returns-a-coroutine, or None
|
65
|
-
The only thing that should be syncified is a function-that-returns-a-coroutine
|
66
|
-
"""
|
67
|
-
if inspect.iscoroutinefunction(obj):
|
68
|
-
return syncify_function(obj)
|
69
|
-
elif isinstance(obj, types.FunctionType):
|
70
|
-
return obj
|
71
|
-
elif obj is None:
|
72
|
-
return obj
|
73
|
-
else:
|
74
|
-
raise ClassiqValueError(f"Invalid type: {obj.__class__.__name__}")
|
75
|
-
|
76
|
-
|
77
|
-
def syncify_property(async_prop: property) -> property:
|
78
|
-
if inspect.iscoroutinefunction(async_prop.fset):
|
79
|
-
raise ClassiqValueError(f"Setter cannot be `async def` (in {async_prop}")
|
80
|
-
if inspect.iscoroutinefunction(async_prop.fdel):
|
81
|
-
raise ClassiqValueError(f"Deleter cannot be `async def` (in {async_prop}")
|
82
|
-
|
83
|
-
return property(
|
84
|
-
maybe_syncify_property_function(async_prop.fget),
|
85
|
-
async_prop.fset,
|
86
|
-
async_prop.fdel,
|
87
|
-
async_prop.__doc__,
|
88
|
-
)
|
89
|
-
|
90
|
-
|
91
|
-
# Explanation about metaclasses
|
92
|
-
# https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
|
93
|
-
|
94
|
-
|
95
|
-
class Asyncify(type):
|
96
|
-
def __new__(
|
97
|
-
mcls, name: str, bases: tuple, class_dict: dict # noqa: N804
|
98
|
-
) -> "Asyncify":
|
99
|
-
new_attrs = {}
|
100
|
-
|
101
|
-
for attr_name, attr_value in class_dict.items():
|
102
|
-
if attr_name.endswith(ASYNC_SUFFIX):
|
103
|
-
new_attr_name = attr_name[: -len(ASYNC_SUFFIX)]
|
104
|
-
if new_attr_name in class_dict:
|
105
|
-
raise ClassiqValueError(f"Method name collision: {new_attr_name}")
|
106
|
-
else:
|
107
|
-
new_attrs[new_attr_name] = attr_value
|
108
|
-
|
109
|
-
new_class = super().__new__(mcls, name, bases, class_dict)
|
110
|
-
|
111
|
-
for attr_name, attr_value in new_attrs.items():
|
112
|
-
if isinstance(attr_value, property):
|
113
|
-
setattr(new_class, attr_name, syncify_property(attr_value))
|
114
|
-
elif isinstance(attr_value, types.FunctionType):
|
115
|
-
setattr(new_class, attr_name, syncify_function(attr_value))
|
116
|
-
else:
|
117
|
-
raise ClassiqValueError(
|
118
|
-
f"Invalid async type: {attr_value.__class__.__name__}"
|
119
|
-
)
|
120
|
-
|
121
|
-
return new_class
|
122
|
-
|
123
|
-
|
124
|
-
# Used for resolving metaclass collision
|
125
|
-
class AsyncifyABC(Asyncify, abc.ABCMeta):
|
126
|
-
pass
|
127
|
-
|
128
|
-
|
129
56
|
def enable_jupyter_notebook() -> None:
|
130
57
|
import nest_asyncio # type: ignore[import]
|
131
58
|
|
@@ -172,7 +99,7 @@ def is_notebook() -> bool:
|
|
172
99
|
return True # Jupyter notebook or qtconsole
|
173
100
|
elif shell == "TerminalInteractiveShell":
|
174
101
|
return False # Terminal running IPython
|
175
|
-
elif "google.colab" in str(local_ipython):
|
102
|
+
elif "google.colab" in str(local_ipython): # noqa: SIM103
|
176
103
|
return True
|
177
104
|
else:
|
178
105
|
return False # Other type (?)
|
@@ -26,9 +26,9 @@ class DeviceRegistrar:
|
|
26
26
|
get_refresh_token=get_refresh_token
|
27
27
|
)
|
28
28
|
|
29
|
-
print(f"Your user code: {data['user_code']}")
|
29
|
+
print(f"Your user code: {data['user_code']}") # noqa: T201
|
30
30
|
verification_url = data["verification_uri_complete"]
|
31
|
-
print(
|
31
|
+
print( # noqa: T201
|
32
32
|
f"If a browser doesn't automatically open, please visit this URL from any trusted device: {verification_url}"
|
33
33
|
)
|
34
34
|
if not text_only:
|
@@ -68,7 +68,7 @@ class DeviceRegistrar:
|
|
68
68
|
timeout: float,
|
69
69
|
get_refresh_token: bool = True,
|
70
70
|
) -> Tokens:
|
71
|
-
async def poller():
|
71
|
+
async def poller() -> Dict[str, Any]:
|
72
72
|
nonlocal device_code
|
73
73
|
return await auth0_client.poll_tokens(device_code=device_code)
|
74
74
|
|
@@ -92,7 +92,12 @@ class DeviceRegistrar:
|
|
92
92
|
elif error_code == "expired_token":
|
93
93
|
raise ClassiqExpiredTokenError(cls._TIMEOUT_ERROR)
|
94
94
|
elif error_code == "access_denied":
|
95
|
-
error_description
|
95
|
+
error_description = data.get("error_description")
|
96
|
+
if error_description is None:
|
97
|
+
raise ClassiqAuthenticationError(
|
98
|
+
"Failed authenticating to Classiq, missing error description"
|
99
|
+
)
|
100
|
+
|
96
101
|
raise ClassiqAuthenticationError(error_description)
|
97
102
|
else:
|
98
103
|
raise ClassiqAuthenticationError(
|
@@ -9,30 +9,41 @@ from typing import Dict, Optional
|
|
9
9
|
|
10
10
|
import keyring
|
11
11
|
from keyring.backends import fail
|
12
|
+
from pydantic import BaseSettings, Field
|
12
13
|
|
13
14
|
_logger = logging.getLogger(__name__)
|
14
15
|
|
15
16
|
|
17
|
+
class PasswordManagerSettings(BaseSettings):
|
18
|
+
ACCESS_TOKEN_KEY: str = Field(
|
19
|
+
default="classiqTokenAccount", env="CLASSIQ_ACCESS_TOKEN_ACCOUNT"
|
20
|
+
)
|
21
|
+
REFRESH_TOKEN_KEY: str = Field(
|
22
|
+
default="classiqRefershTokenAccount", env="CLASSIQ_REFRESH_TOKEN_ACCOUNT"
|
23
|
+
)
|
24
|
+
|
25
|
+
|
16
26
|
class PasswordManager(abc.ABC):
|
17
27
|
_SERVICE_NAME: str = "classiqTokenService"
|
18
|
-
|
19
|
-
|
28
|
+
|
29
|
+
def __init__(self) -> None:
|
30
|
+
self._settings = PasswordManagerSettings()
|
20
31
|
|
21
32
|
@property
|
22
33
|
def access_token(self) -> Optional[str]:
|
23
|
-
return self._get(key=self.
|
34
|
+
return self._get(key=self._settings.ACCESS_TOKEN_KEY)
|
24
35
|
|
25
36
|
@access_token.setter
|
26
37
|
def access_token(self, access_token: Optional[str]) -> None:
|
27
|
-
self._set(key=self.
|
38
|
+
self._set(key=self._settings.ACCESS_TOKEN_KEY, value=access_token)
|
28
39
|
|
29
40
|
@property
|
30
41
|
def refresh_token(self) -> Optional[str]:
|
31
|
-
return self._get(key=self.
|
42
|
+
return self._get(key=self._settings.REFRESH_TOKEN_KEY)
|
32
43
|
|
33
44
|
@refresh_token.setter
|
34
45
|
def refresh_token(self, refresh_token: Optional[str]) -> None:
|
35
|
-
self._set(key=self.
|
46
|
+
self._set(key=self._settings.REFRESH_TOKEN_KEY, value=refresh_token)
|
36
47
|
|
37
48
|
@abc.abstractmethod
|
38
49
|
def _get(self, key: str) -> Optional[str]:
|
@@ -46,8 +57,9 @@ class PasswordManager(abc.ABC):
|
|
46
57
|
def _clear(self, key: str) -> None:
|
47
58
|
pass
|
48
59
|
|
60
|
+
@staticmethod
|
49
61
|
@abc.abstractmethod
|
50
|
-
def is_supported(
|
62
|
+
def is_supported() -> bool:
|
51
63
|
pass
|
52
64
|
|
53
65
|
|
@@ -71,7 +83,8 @@ class KeyringPasswordManager(PasswordManager):
|
|
71
83
|
username=key,
|
72
84
|
)
|
73
85
|
|
74
|
-
|
86
|
+
@staticmethod
|
87
|
+
def is_supported() -> bool:
|
75
88
|
return not isinstance(keyring.get_keyring(), fail.Keyring)
|
76
89
|
|
77
90
|
|
@@ -85,7 +98,8 @@ class DummyPasswordManager(PasswordManager):
|
|
85
98
|
def _clear(self, key: str) -> None:
|
86
99
|
return
|
87
100
|
|
88
|
-
|
101
|
+
@staticmethod
|
102
|
+
def is_supported() -> bool:
|
89
103
|
return True
|
90
104
|
|
91
105
|
|
@@ -125,5 +139,6 @@ class FilePasswordManager(PasswordManager):
|
|
125
139
|
token_dict.pop(key)
|
126
140
|
self._update_file(token_dict)
|
127
141
|
|
128
|
-
|
142
|
+
@staticmethod
|
143
|
+
def is_supported() -> bool:
|
129
144
|
return "windows" not in platform.platform().lower()
|
@@ -13,7 +13,7 @@ from classiq.exceptions import (
|
|
13
13
|
ClassiqPasswordManagerSelectionError,
|
14
14
|
)
|
15
15
|
|
16
|
-
PASSWORD_MANAGERS = [pm.KeyringPasswordManager
|
16
|
+
PASSWORD_MANAGERS = [pm.KeyringPasswordManager, pm.FilePasswordManager]
|
17
17
|
_logger = logging.getLogger(__name__)
|
18
18
|
|
19
19
|
|
@@ -57,7 +57,7 @@ class TokenManager:
|
|
57
57
|
return pm.FilePasswordManager()
|
58
58
|
for password_manager in PASSWORD_MANAGERS:
|
59
59
|
if password_manager.is_supported():
|
60
|
-
return password_manager
|
60
|
+
return password_manager()
|
61
61
|
raise ClassiqPasswordManagerSelectionError(
|
62
62
|
"Password Manager not found, we could not store your credentials securely. Please contact support@classiq.io"
|
63
63
|
)
|
classiq/_internals/client.py
CHANGED
@@ -6,10 +6,11 @@ import os
|
|
6
6
|
import platform
|
7
7
|
import ssl
|
8
8
|
import sys
|
9
|
-
from typing import Any, Awaitable, Callable, Dict, NoReturn, Optional, Union
|
9
|
+
from typing import Any, Awaitable, Callable, Dict, NoReturn, Optional, TypeVar, Union
|
10
10
|
|
11
11
|
import httpx
|
12
12
|
from packaging.version import Version
|
13
|
+
from typing_extensions import ParamSpec
|
13
14
|
|
14
15
|
from classiq.interface._version import VERSION as _VERSION
|
15
16
|
|
@@ -80,9 +81,13 @@ def _get_user_agent_header() -> Headers:
|
|
80
81
|
}
|
81
82
|
|
82
83
|
|
84
|
+
Ret = TypeVar("Ret")
|
85
|
+
P = ParamSpec("P")
|
86
|
+
|
87
|
+
|
83
88
|
def try_again_on_failure(
|
84
|
-
func: Callable[
|
85
|
-
) -> Callable[
|
89
|
+
func: Callable[P, Awaitable[Ret]]
|
90
|
+
) -> Callable[P, Awaitable[Ret]]:
|
86
91
|
def check_approved_api_error(error_message: str) -> bool:
|
87
92
|
for approved_api_error in APPROVED_API_ERROR_MESSAGES_FOR_RESTART:
|
88
93
|
if approved_api_error in error_message:
|
@@ -93,7 +98,7 @@ def try_again_on_failure(
|
|
93
98
|
raise TypeError("Must decorate a coroutine function")
|
94
99
|
|
95
100
|
@functools.wraps(func)
|
96
|
-
async def wrapper(*args, **kwargs):
|
101
|
+
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> Ret:
|
97
102
|
for i in range(_RETRY_COUNT):
|
98
103
|
try:
|
99
104
|
return await func(*args, **kwargs)
|
@@ -123,6 +128,9 @@ def try_again_on_failure(
|
|
123
128
|
"There is problem with the connection to Classiq's server. Trying again"
|
124
129
|
)
|
125
130
|
await asyncio.sleep(API_ERROR_SLEEP_TIME)
|
131
|
+
raise ClassiqAPIError(
|
132
|
+
"Reached max retries when trying to connect to Classiq's server"
|
133
|
+
)
|
126
134
|
|
127
135
|
return wrapper
|
128
136
|
|
@@ -186,7 +194,7 @@ class Client:
|
|
186
194
|
try:
|
187
195
|
detail = response.json()["detail"]
|
188
196
|
message += f": {detail}"
|
189
|
-
except Exception: #
|
197
|
+
except Exception: # noqa: S110
|
190
198
|
pass
|
191
199
|
raise ClassiqAPIError(message)
|
192
200
|
|
classiq/_internals/jobs.py
CHANGED
@@ -5,7 +5,12 @@ from typing import Callable, Dict, Iterable, Optional, Set, TypeVar
|
|
5
5
|
import httpx
|
6
6
|
import pydantic
|
7
7
|
|
8
|
-
from classiq.interface.jobs import
|
8
|
+
from classiq.interface.jobs import (
|
9
|
+
JobDescriptionBase,
|
10
|
+
JobDescriptionUnion,
|
11
|
+
JobID,
|
12
|
+
JSONObject,
|
13
|
+
)
|
9
14
|
|
10
15
|
from classiq._internals.async_utils import poll_for
|
11
16
|
from classiq._internals.client import client, try_again_on_failure
|
@@ -13,7 +18,7 @@ from classiq._internals.config import SDKMode
|
|
13
18
|
from classiq.exceptions import ClassiqAPIError
|
14
19
|
|
15
20
|
_URL_PATH_SEP = "/"
|
16
|
-
GeneralJobDescription =
|
21
|
+
GeneralJobDescription = JobDescriptionBase[JSONObject]
|
17
22
|
_logger = logging.getLogger(__name__)
|
18
23
|
T = TypeVar("T")
|
19
24
|
|
@@ -37,11 +42,9 @@ def _join_url_path(*parts: str) -> str:
|
|
37
42
|
def _general_job_description_parser(
|
38
43
|
json_response: JSONObject,
|
39
44
|
) -> Optional[GeneralJobDescription]:
|
40
|
-
job_description
|
41
|
-
|
42
|
-
|
43
|
-
if job_description.status.is_final():
|
44
|
-
return job_description
|
45
|
+
job_description = JobDescriptionUnion[JSONObject].parse_obj(json_response)
|
46
|
+
if job_description.__root__.status.is_final():
|
47
|
+
return job_description.__root__
|
45
48
|
return None
|
46
49
|
|
47
50
|
|
classiq/analyzer/analyzer.py
CHANGED
@@ -10,16 +10,13 @@ import plotly.graph_objects as go
|
|
10
10
|
|
11
11
|
from classiq.interface.analyzer import analysis_params
|
12
12
|
from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
|
13
|
-
from classiq.interface.generator import
|
13
|
+
from classiq.interface.generator import quantum_program as generator_result
|
14
14
|
|
15
|
-
from classiq._internals import client
|
15
|
+
from classiq._internals import async_utils, client
|
16
16
|
from classiq._internals.api_wrapper import ApiWrapper
|
17
|
-
from classiq._internals.async_utils import Asyncify
|
18
17
|
from classiq.analyzer.analyzer_utilities import (
|
19
18
|
AnalyzerUtilities,
|
20
19
|
DeviceName,
|
21
|
-
HardwareGraphs,
|
22
|
-
ProviderAvailableDevices,
|
23
20
|
ProviderNameEnum,
|
24
21
|
)
|
25
22
|
from classiq.analyzer.url_utils import circuit_page_uri, client_ide_base_url
|
@@ -34,10 +31,10 @@ if find_ipywidgets is not None:
|
|
34
31
|
from classiq._analyzer_extras.interactive_hardware import InteractiveHardware
|
35
32
|
|
36
33
|
|
37
|
-
class Analyzer(AnalyzerUtilities
|
34
|
+
class Analyzer(AnalyzerUtilities):
|
38
35
|
"""Analyzer is the wrapper object for all analysis capabilities."""
|
39
36
|
|
40
|
-
def __init__(self, circuit: generator_result.
|
37
|
+
def __init__(self, circuit: generator_result.QuantumProgram) -> None:
|
41
38
|
"""Init self.
|
42
39
|
|
43
40
|
Args:
|
@@ -47,26 +44,31 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
47
44
|
raise ClassiqAnalyzerError(
|
48
45
|
"Analysis requires a circuit with valid QASM code"
|
49
46
|
)
|
50
|
-
|
47
|
+
params: analysis_params.AnalysisParams = analysis_params.AnalysisParams(
|
51
48
|
qasm=circuit.qasm
|
52
49
|
)
|
53
|
-
|
50
|
+
super().__init__(
|
51
|
+
params=params,
|
52
|
+
circuit=circuit,
|
53
|
+
available_devices=dict(),
|
54
|
+
hardware_graphs=dict(),
|
55
|
+
)
|
56
|
+
|
54
57
|
self.hardware_comparison_table: Optional[go.Figure] = None
|
55
|
-
self.available_devices: ProviderAvailableDevices = dict()
|
56
|
-
self.hardware_graphs: HardwareGraphs = dict()
|
57
58
|
|
58
59
|
self.transpilation_params = analysis_params.AnalysisHardwareTranspilationParams(
|
59
60
|
hardware_data=self.circuit.hardware_data,
|
60
|
-
|
61
|
+
random_seed=self.circuit.model.execution_preferences.random_seed,
|
62
|
+
transpilation_option=self.circuit.model.execution_preferences.transpile_to_hardware,
|
61
63
|
)
|
62
64
|
|
63
|
-
|
65
|
+
def analyzer_app(self) -> None:
|
64
66
|
"""Opens the analyzer app with synthesis interactive results.
|
65
67
|
|
66
68
|
Returns:
|
67
69
|
None.
|
68
70
|
"""
|
69
|
-
result =
|
71
|
+
result = async_utils.run(ApiWrapper.call_analyzer_app(self.circuit))
|
70
72
|
webbrowser.open_new_tab(
|
71
73
|
urljoin(
|
72
74
|
client_ide_base_url(),
|
@@ -76,7 +78,7 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
76
78
|
)
|
77
79
|
)
|
78
80
|
|
79
|
-
|
81
|
+
def get_available_devices(
|
80
82
|
self, providers: Optional[List[ProviderNameEnum]] = None
|
81
83
|
) -> Dict[ProviderNameEnum, List[DeviceName]]:
|
82
84
|
"""Returns dict of the available devices by the providers. only devices
|
@@ -90,13 +92,13 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
90
92
|
"""
|
91
93
|
if providers is None:
|
92
94
|
providers = list(AnalyzerProviderVendor)
|
93
|
-
|
95
|
+
async_utils.run(self._request_available_devices_async(providers=providers))
|
94
96
|
return {
|
95
97
|
provider: self._filter_devices_by_qubits_count(provider)
|
96
98
|
for provider in providers
|
97
99
|
}
|
98
100
|
|
99
|
-
|
101
|
+
def plot_hardware_connectivity(
|
100
102
|
self,
|
101
103
|
provider: Optional[ProviderNameEnum] = None,
|
102
104
|
device: Optional[DeviceName] = None,
|
@@ -118,7 +120,7 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
118
120
|
available_devices=self.available_devices,
|
119
121
|
hardware_graphs=self.hardware_graphs,
|
120
122
|
)
|
121
|
-
|
123
|
+
async_utils.run(interactive_hardware.enable_interactivity_async())
|
122
124
|
if provider is not None:
|
123
125
|
interactive_hardware.providers_combobox.value = provider
|
124
126
|
if device is not None:
|
@@ -126,7 +128,7 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
126
128
|
|
127
129
|
return interactive_hardware.show_interactive_graph()
|
128
130
|
|
129
|
-
|
131
|
+
def get_hardware_comparison_table(
|
130
132
|
self,
|
131
133
|
providers: Optional[Sequence[Union[str, AnalyzerProviderVendor]]] = None,
|
132
134
|
devices: Optional[List[str]] = None,
|
@@ -148,10 +150,10 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
148
150
|
devices=devices,
|
149
151
|
transpilation_params=self.transpilation_params,
|
150
152
|
)
|
151
|
-
result =
|
153
|
+
result = async_utils.run(ApiWrapper.call_table_graphs_task(params=params))
|
152
154
|
self.hardware_comparison_table = go.Figure(json.loads(result.details))
|
153
155
|
|
154
|
-
|
156
|
+
def plot_hardware_comparison_table(
|
155
157
|
self,
|
156
158
|
providers: Optional[List[Union[str, AnalyzerProviderVendor]]] = None,
|
157
159
|
devices: Optional[List[str]] = None,
|
@@ -162,12 +164,10 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
162
164
|
Returns:
|
163
165
|
None.
|
164
166
|
"""
|
165
|
-
|
166
|
-
providers=providers, devices=devices
|
167
|
-
)
|
167
|
+
self._hardware_comparison_condition(providers=providers, devices=devices)
|
168
168
|
self.hardware_comparison_table.show() # type: ignore[union-attr]
|
169
169
|
|
170
|
-
|
170
|
+
def _hardware_comparison_condition(
|
171
171
|
self,
|
172
172
|
providers: Optional[Sequence[Union[str, AnalyzerProviderVendor]]] = None,
|
173
173
|
devices: Optional[List[str]] = None,
|
@@ -177,9 +177,7 @@ class Analyzer(AnalyzerUtilities, metaclass=Asyncify):
|
|
177
177
|
or devices is not None
|
178
178
|
or self.hardware_comparison_table is None
|
179
179
|
):
|
180
|
-
|
181
|
-
providers=providers, devices=devices
|
182
|
-
)
|
180
|
+
self.get_hardware_comparison_table(providers=providers, devices=devices)
|
183
181
|
|
184
182
|
@staticmethod
|
185
183
|
def _open_route(path: str) -> None:
|