classiq 0.33.0__py3-none-any.whl → 0.35.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/_internals/api_wrapper.py +61 -23
- classiq/_internals/client.py +4 -1
- classiq/_internals/jobs.py +9 -2
- classiq/applications_model_constructors/grover_model_constructor.py +1 -1
- classiq/execution/__init__.py +9 -2
- classiq/execution/jobs.py +84 -11
- classiq/executor.py +3 -10
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +17 -0
- classiq/interface/backend/pydantic_backend.py +8 -0
- classiq/interface/backend/quantum_backend_providers.py +15 -1
- classiq/interface/chemistry/ground_state_problem.py +1 -1
- classiq/interface/chemistry/operator.py +198 -0
- classiq/interface/execution/jobs.py +28 -0
- classiq/interface/executor/execution_request.py +2 -12
- classiq/interface/generator/arith/arithmetic_expression_validator.py +1 -0
- classiq/interface/generator/arith/arithmetic_param_getters.py +12 -0
- classiq/interface/generator/arith/binary_ops.py +34 -0
- classiq/interface/generator/expressions/expression.py +3 -0
- classiq/interface/generator/expressions/qmod_sized_proxy.py +12 -2
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/function_params.py +4 -0
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +2 -2
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +42 -105
- classiq/interface/generator/generated_circuit.py +8 -44
- classiq/interface/generator/generated_circuit_data.py +2 -11
- classiq/interface/generator/model/preferences/preferences.py +4 -2
- classiq/interface/generator/quantum_function_call.py +1 -1
- classiq/interface/hardware.py +2 -0
- classiq/interface/ide/show.py +1 -14
- classiq/interface/model/bind_operation.py +10 -0
- classiq/interface/model/handle_binding.py +18 -0
- classiq/interface/model/model.py +12 -3
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +2 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
- classiq/interface/model/quantum_expressions/quantum_expression.py +9 -6
- classiq/interface/model/quantum_function_call.py +9 -339
- classiq/interface/model/quantum_statement.py +3 -2
- classiq/interface/server/routes.py +8 -6
- classiq/model/function_handler.pyi +86 -85
- classiq/qmod/__init__.py +2 -2
- classiq/qmod/builtins/__init__.py +8 -0
- classiq/{interface/model/clients/qmod/qmod_builtins.py → qmod/builtins/functions.py} +46 -165
- classiq/qmod/builtins/operations.py +19 -0
- classiq/qmod/builtins/structs.py +128 -0
- classiq/qmod/declaration_inferrer.py +34 -17
- classiq/qmod/model_state_container.py +6 -3
- classiq/qmod/qmod_parameter.py +24 -8
- classiq/qmod/qmod_variable.py +4 -4
- classiq/qmod/quantum_callable.py +2 -2
- classiq/qmod/quantum_expandable.py +7 -3
- classiq/qmod/quantum_function.py +9 -9
- {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/METADATA +1 -1
- {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/RECORD +56 -55
- classiq/interface/model/clients/qmod/__init__.py +0 -0
- classiq/interface/model/semantics.py +0 -15
- classiq/qmod/qmod_builtins.py +0 -4
- /classiq/interface/{model/clients → execution}/__init__.py +0 -0
- {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/WHEEL +0 -0
@@ -224,6 +224,204 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
224
224
|
frozen = True
|
225
225
|
|
226
226
|
|
227
|
+
class PauliOperatorV1(HashablePydanticBaseModel):
|
228
|
+
"""
|
229
|
+
Specification of a Pauli sum operator.
|
230
|
+
"""
|
231
|
+
|
232
|
+
pauli_list: PydanticPauliList = pydantic.Field(
|
233
|
+
description="A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].",
|
234
|
+
)
|
235
|
+
is_hermitian: bool = pydantic.Field(default=False)
|
236
|
+
has_complex_coefficients: bool = pydantic.Field(default=True)
|
237
|
+
|
238
|
+
def show(self) -> str:
|
239
|
+
if self.is_hermitian:
|
240
|
+
# If the operator is hermitian then the coefficients must be numeric
|
241
|
+
return "\n".join(
|
242
|
+
f"{summand[1].real:+.3f} * {summand[0]}" for summand in self.pauli_list # type: ignore[union-attr]
|
243
|
+
)
|
244
|
+
return "\n".join(
|
245
|
+
f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
|
246
|
+
)
|
247
|
+
|
248
|
+
@pydantic.validator("pauli_list", each_item=True, pre=True)
|
249
|
+
def _validate_pauli_monomials(
|
250
|
+
cls, monomial: Tuple[PydanticPauliMonomialStr, ParameterComplexType]
|
251
|
+
) -> Tuple[PydanticPauliMonomialStr, ParameterComplexType]:
|
252
|
+
_PauliMonomialLengthValidator( # type: ignore[call-arg]
|
253
|
+
monomial=monomial
|
254
|
+
) # Validate the length of the monomial.
|
255
|
+
coeff = cls._validate_monomial_coefficient(monomial[1])
|
256
|
+
parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff) # type: ignore[call-arg]
|
257
|
+
return (parsed_monomial.string, parsed_monomial.coeff)
|
258
|
+
|
259
|
+
@staticmethod
|
260
|
+
def _validate_monomial_coefficient(
|
261
|
+
coeff: Union[sympy.Expr, ParameterComplexType]
|
262
|
+
) -> ParameterComplexType:
|
263
|
+
if isinstance(coeff, str):
|
264
|
+
validate_expression_str(coeff)
|
265
|
+
elif isinstance(coeff, sympy.Expr):
|
266
|
+
coeff = str(coeff)
|
267
|
+
return coeff
|
268
|
+
|
269
|
+
@pydantic.validator("pauli_list")
|
270
|
+
def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
|
271
|
+
if not all_equal(len(summand[0]) for summand in pauli_list):
|
272
|
+
raise ValueError("Pauli strings have incompatible lengths.")
|
273
|
+
return pauli_list
|
274
|
+
|
275
|
+
@pydantic.root_validator
|
276
|
+
def _validate_hermitianity(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
277
|
+
pauli_list = values.get("pauli_list", [])
|
278
|
+
if all(isinstance(summand[1], complex) for summand in pauli_list):
|
279
|
+
values["is_hermitian"] = all(
|
280
|
+
np.isclose(complex(summand[1]).real, summand[1])
|
281
|
+
for summand in pauli_list
|
282
|
+
)
|
283
|
+
if values.get("is_hermitian", False):
|
284
|
+
values["has_complex_coefficients"] = False
|
285
|
+
values["pauli_list"] = [
|
286
|
+
(summand[0], complex(summand[1].real)) for summand in pauli_list
|
287
|
+
]
|
288
|
+
else:
|
289
|
+
values["has_complex_coefficients"] = not all(
|
290
|
+
np.isclose(complex(summand[1]).real, summand[1])
|
291
|
+
for summand in pauli_list
|
292
|
+
if isinstance(summand[1], complex)
|
293
|
+
)
|
294
|
+
return values
|
295
|
+
|
296
|
+
def __mul__(self, coefficient: complex) -> "PauliOperatorV1":
|
297
|
+
multiplied_ising = [
|
298
|
+
(monomial[0], self._multiply_monomial_coefficient(monomial[1], coefficient))
|
299
|
+
for monomial in self.pauli_list
|
300
|
+
]
|
301
|
+
return self.__class__(pauli_list=multiplied_ising)
|
302
|
+
|
303
|
+
@staticmethod
|
304
|
+
def _multiply_monomial_coefficient(
|
305
|
+
monomial_coefficient: ParameterComplexType, coefficient: complex
|
306
|
+
) -> ParameterComplexType:
|
307
|
+
if isinstance(monomial_coefficient, ParameterType):
|
308
|
+
return str(sympy.sympify(monomial_coefficient) * coefficient)
|
309
|
+
return monomial_coefficient * coefficient
|
310
|
+
|
311
|
+
@property
|
312
|
+
def is_commutative(self) -> bool:
|
313
|
+
return all(
|
314
|
+
self._is_sub_pauli_commutative(
|
315
|
+
[summand[0][qubit_num] for summand in self.pauli_list]
|
316
|
+
)
|
317
|
+
for qubit_num in range(self.num_qubits)
|
318
|
+
)
|
319
|
+
|
320
|
+
@staticmethod
|
321
|
+
def _is_sub_pauli_commutative(qubit_pauli_string: Union[List[str], str]) -> bool:
|
322
|
+
unique_paulis = set(qubit_pauli_string) - {"I"}
|
323
|
+
return len(unique_paulis) <= 1
|
324
|
+
|
325
|
+
@property
|
326
|
+
def num_qubits(self) -> int:
|
327
|
+
return len(self.pauli_list[0][0])
|
328
|
+
|
329
|
+
def to_matrix(self) -> np.ndarray:
|
330
|
+
if not all(isinstance(summand[1], complex) for summand in self.pauli_list):
|
331
|
+
raise ClassiqValueError(
|
332
|
+
"Supporting only Hamiltonian with numeric coefficients."
|
333
|
+
)
|
334
|
+
return sum(
|
335
|
+
cast(complex, summand[1]) * to_pauli_matrix(summand[0])
|
336
|
+
for summand in self.pauli_list
|
337
|
+
) # type: ignore[return-value]
|
338
|
+
|
339
|
+
@staticmethod
|
340
|
+
def _extend_pauli_string(
|
341
|
+
pauli_string: PydanticPauliMonomialStr, num_extra_qubits: int
|
342
|
+
) -> PydanticPauliMonomialStr:
|
343
|
+
return "I" * num_extra_qubits + pauli_string
|
344
|
+
|
345
|
+
def extend(self, num_extra_qubits: int) -> "PauliOperatorV1":
|
346
|
+
new_pauli_list = [
|
347
|
+
(self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
|
348
|
+
for (pauli_string, coeff) in self.pauli_list
|
349
|
+
]
|
350
|
+
return self.copy(update={"pauli_list": new_pauli_list}, deep=True)
|
351
|
+
|
352
|
+
@staticmethod
|
353
|
+
def _reorder_pauli_string(
|
354
|
+
pauli_string: PydanticPauliMonomialStr,
|
355
|
+
order: Collection[int],
|
356
|
+
new_num_qubits: int,
|
357
|
+
) -> PydanticPauliMonomialStr:
|
358
|
+
reversed_pauli_string = pauli_string[::-1]
|
359
|
+
reversed_new_pauli_string = ["I"] * new_num_qubits
|
360
|
+
|
361
|
+
for logical_pos, actual_pos in enumerate(order):
|
362
|
+
reversed_new_pauli_string[actual_pos] = reversed_pauli_string[logical_pos]
|
363
|
+
|
364
|
+
return "".join(reversed(reversed_new_pauli_string))
|
365
|
+
|
366
|
+
@staticmethod
|
367
|
+
def _validate_reorder(
|
368
|
+
order: Collection[int],
|
369
|
+
num_qubits: int,
|
370
|
+
num_extra_qubits: int,
|
371
|
+
) -> None:
|
372
|
+
if num_extra_qubits < 0:
|
373
|
+
raise ValueError("Number of extra qubits cannot be negative")
|
374
|
+
|
375
|
+
if len(order) != num_qubits:
|
376
|
+
raise ValueError("The qubits order doesn't match the Pauli operator")
|
377
|
+
|
378
|
+
if len(order) != len(set(order)):
|
379
|
+
raise ValueError("The qubits order is not one-to-one")
|
380
|
+
|
381
|
+
if not all(pos < num_qubits + num_extra_qubits for pos in order):
|
382
|
+
raise ValueError("The qubits order contains qubits which do no exist")
|
383
|
+
|
384
|
+
@classmethod
|
385
|
+
def reorder(
|
386
|
+
cls,
|
387
|
+
operator: "PauliOperatorV1",
|
388
|
+
order: Collection[int],
|
389
|
+
num_extra_qubits: int = 0,
|
390
|
+
) -> "PauliOperatorV1":
|
391
|
+
cls._validate_reorder(order, operator.num_qubits, num_extra_qubits)
|
392
|
+
|
393
|
+
new_num_qubits = operator.num_qubits + num_extra_qubits
|
394
|
+
new_pauli_list = [
|
395
|
+
(cls._reorder_pauli_string(pauli_string, order, new_num_qubits), coeff)
|
396
|
+
for pauli_string, coeff in operator.pauli_list
|
397
|
+
]
|
398
|
+
return cls(pauli_list=new_pauli_list)
|
399
|
+
|
400
|
+
@classmethod
|
401
|
+
def from_unzipped_lists(
|
402
|
+
cls,
|
403
|
+
operators: List[List[Pauli]],
|
404
|
+
coefficients: Optional[List[complex]] = None,
|
405
|
+
) -> "PauliOperatorV1":
|
406
|
+
if coefficients is None:
|
407
|
+
coefficients = [1] * len(operators)
|
408
|
+
|
409
|
+
if len(operators) != len(coefficients):
|
410
|
+
raise ValueError(
|
411
|
+
f"The number of coefficients ({len(coefficients)}) must be equal to the number of pauli operators ({len(operators)})"
|
412
|
+
)
|
413
|
+
|
414
|
+
return cls(
|
415
|
+
pauli_list=[
|
416
|
+
(pauli_integers_to_str(op), coeff)
|
417
|
+
for op, coeff in zip(operators, coefficients)
|
418
|
+
]
|
419
|
+
)
|
420
|
+
|
421
|
+
class Config:
|
422
|
+
frozen = True
|
423
|
+
|
424
|
+
|
227
425
|
# This class validates the length of a monomial.
|
228
426
|
@pydantic.dataclasses.dataclass
|
229
427
|
class _PauliMonomialLengthValidator:
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import List, Optional
|
3
|
+
|
4
|
+
from pydantic import BaseModel, Extra
|
5
|
+
|
6
|
+
from classiq.interface.jobs import JobStatus
|
7
|
+
|
8
|
+
|
9
|
+
class ExecutionJobDetailsV1(BaseModel, extra=Extra.ignore):
|
10
|
+
id: str
|
11
|
+
|
12
|
+
name: Optional[str]
|
13
|
+
start_time: datetime
|
14
|
+
end_time: Optional[datetime]
|
15
|
+
|
16
|
+
provider: Optional[str]
|
17
|
+
backend_name: Optional[str]
|
18
|
+
|
19
|
+
status: JobStatus
|
20
|
+
|
21
|
+
num_shots: Optional[int]
|
22
|
+
program_id: Optional[str]
|
23
|
+
|
24
|
+
error: Optional[str]
|
25
|
+
|
26
|
+
|
27
|
+
class ExecutionJobsQueryResultsV1(BaseModel, extra=Extra.ignore):
|
28
|
+
results: List[ExecutionJobDetailsV1]
|
@@ -15,10 +15,7 @@ from classiq.interface.executor.quantum_program import (
|
|
15
15
|
)
|
16
16
|
from classiq.interface.executor.result import EstimationResult, ExecutionDetails
|
17
17
|
from classiq.interface.executor.vqe_result import VQESolverResult
|
18
|
-
from classiq.interface.generator.generated_circuit import
|
19
|
-
ExecutionCircuit,
|
20
|
-
GeneratedCircuit,
|
21
|
-
)
|
18
|
+
from classiq.interface.generator.generated_circuit import GeneratedCircuit
|
22
19
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
23
20
|
from classiq.interface.jobs import JobStatus
|
24
21
|
|
@@ -29,10 +26,6 @@ class GeneratedCircuitExecution(GeneratedCircuit):
|
|
29
26
|
execution_type: Literal["generated_circuit"] = "generated_circuit"
|
30
27
|
|
31
28
|
|
32
|
-
class BareGeneratedCircuitExecution(ExecutionCircuit):
|
33
|
-
execution_type: Literal["bare_generated_circuit"] = "bare_generated_circuit"
|
34
|
-
|
35
|
-
|
36
29
|
class QuantumProgramExecution(QuantumProgram):
|
37
30
|
execution_type: Literal["quantum_program"] = "quantum_program"
|
38
31
|
|
@@ -42,10 +35,7 @@ class EstimateOperatorsExecution(OperatorsEstimation):
|
|
42
35
|
|
43
36
|
|
44
37
|
ExecutionPayloads = Union[
|
45
|
-
GeneratedCircuitExecution,
|
46
|
-
BareGeneratedCircuitExecution,
|
47
|
-
QuantumProgramExecution,
|
48
|
-
EstimateOperatorsExecution,
|
38
|
+
GeneratedCircuitExecution, QuantumProgramExecution, EstimateOperatorsExecution
|
49
39
|
]
|
50
40
|
|
51
41
|
|
@@ -25,6 +25,7 @@ from classiq.interface.generator.arith.binary_ops import (
|
|
25
25
|
Modulo,
|
26
26
|
Multiplier,
|
27
27
|
NotEqual,
|
28
|
+
Power,
|
28
29
|
RegisterOrInt,
|
29
30
|
RShift,
|
30
31
|
Subtractor,
|
@@ -155,6 +156,16 @@ def multiplier_params_getter(
|
|
155
156
|
return Multiplier(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
|
156
157
|
|
157
158
|
|
159
|
+
def power_params_getter(
|
160
|
+
left_arg: RegisterArithmeticInfo,
|
161
|
+
right_arg: int,
|
162
|
+
output_size: Optional[int] = None,
|
163
|
+
inplace_arg: Optional[str] = None,
|
164
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
165
|
+
) -> ArithmeticOperationParams:
|
166
|
+
return Power(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
|
167
|
+
|
168
|
+
|
158
169
|
def min_params_getter(
|
159
170
|
left_arg: RegisterOrFloat,
|
160
171
|
right_arg: RegisterOrFloat,
|
@@ -367,4 +378,5 @@ params_getter_map: Dict[str, ParamsGetter] = dict(
|
|
367
378
|
Mod=modulo_params_getter,
|
368
379
|
min=min_params_getter,
|
369
380
|
max=max_params_getter,
|
381
|
+
Pow=power_params_getter,
|
370
382
|
)
|
@@ -413,6 +413,40 @@ class LessEqual(Comparator):
|
|
413
413
|
output_name = "is_less_equal"
|
414
414
|
|
415
415
|
|
416
|
+
class Power(BinaryOpParams[RegisterArithmeticInfo, pydantic.PositiveInt]):
|
417
|
+
output_name = "powered"
|
418
|
+
|
419
|
+
@pydantic.validator("right_arg", pre=True)
|
420
|
+
def _validate_legal_power(cls, right_arg: Any) -> pydantic.PositiveInt:
|
421
|
+
if not float(right_arg).is_integer():
|
422
|
+
raise ValueError("Power must be an integer")
|
423
|
+
if right_arg <= 0:
|
424
|
+
raise ValueError("Power must be greater than one")
|
425
|
+
return int(right_arg)
|
426
|
+
|
427
|
+
def _get_result_bounds(self) -> Tuple[float, float]:
|
428
|
+
if (self.right_arg % 2) or min(self.left_arg.bounds) >= 0:
|
429
|
+
return (
|
430
|
+
self.left_arg.bounds[0] ** self.right_arg,
|
431
|
+
self.left_arg.bounds[1] ** self.right_arg,
|
432
|
+
)
|
433
|
+
return 0.0, max(abs(bound) for bound in self.left_arg.bounds) ** self.right_arg
|
434
|
+
|
435
|
+
def _get_result_register(self) -> RegisterArithmeticInfo:
|
436
|
+
if self.output_size:
|
437
|
+
return RegisterArithmeticInfo(size=self.output_size)
|
438
|
+
|
439
|
+
fraction_places: int = self.left_arg.fraction_places * self.right_arg
|
440
|
+
bounds = self._get_result_bounds()
|
441
|
+
size = number_utils.bounds_to_integer_part_size(*bounds) + fraction_places
|
442
|
+
return RegisterArithmeticInfo(
|
443
|
+
size=size,
|
444
|
+
is_signed=self.left_arg.is_signed and (self.right_arg % 2 == 1),
|
445
|
+
fraction_places=fraction_places,
|
446
|
+
bounds=bounds,
|
447
|
+
)
|
448
|
+
|
449
|
+
|
416
450
|
class EffectiveUnaryOpParams(
|
417
451
|
InplacableBinaryOpParams[RegisterArithmeticInfo, RightDataT], Generic[RightDataT]
|
418
452
|
):
|
@@ -1,6 +1,16 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
from sympy import Symbol
|
2
|
+
|
3
|
+
|
4
|
+
class QmodSizedProxy(Symbol):
|
5
|
+
def __new__(cls, name, **assumptions):
|
6
|
+
return super().__new__(cls, name, **assumptions)
|
7
|
+
|
8
|
+
def __init__(self, name: str, size: int) -> None:
|
3
9
|
self._size = size
|
4
10
|
|
11
|
+
@property
|
12
|
+
def size(self) -> int:
|
13
|
+
return self.args[0]
|
14
|
+
|
5
15
|
def __len__(self) -> int:
|
6
16
|
return self._size
|
@@ -18,6 +18,7 @@ from classiq.interface.generator.arith.binary_ops import (
|
|
18
18
|
Modulo,
|
19
19
|
Multiplier,
|
20
20
|
NotEqual,
|
21
|
+
Power,
|
21
22
|
RShift,
|
22
23
|
Subtractor,
|
23
24
|
)
|
@@ -136,6 +137,7 @@ function_param_library_without_self_reference: FunctionParamLibrary = (
|
|
136
137
|
WeightedAdder,
|
137
138
|
LinearPauliRotations,
|
138
139
|
Multiplier,
|
140
|
+
Power,
|
139
141
|
LinearGCI,
|
140
142
|
HartreeFock,
|
141
143
|
UCC,
|
@@ -441,11 +441,11 @@ ADD_FUNCTION = QuantumFunctionDeclaration(
|
|
441
441
|
port_declarations={
|
442
442
|
"left": PortDeclaration(
|
443
443
|
name="left",
|
444
|
-
direction=PortDeclarationDirection.
|
444
|
+
direction=PortDeclarationDirection.Inout,
|
445
445
|
),
|
446
446
|
"right": PortDeclaration(
|
447
447
|
name="right",
|
448
|
-
direction=PortDeclarationDirection.
|
448
|
+
direction=PortDeclarationDirection.Inout,
|
449
449
|
),
|
450
450
|
"result": PortDeclaration(
|
451
451
|
name="result",
|