qiskit 2.0.3__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0__cp39-abi3-macosx_11_0_arm64.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.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +19 -1
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +104 -20
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +504 -0
- qiskit/circuit/classical/expr/__init__.py +1 -1
- qiskit/circuit/classical/expr/expr.py +104 -446
- qiskit/circuit/classical/expr/visitors.py +6 -0
- qiskit/circuit/classical/types/types.py +7 -130
- qiskit/circuit/controlflow/box.py +32 -7
- qiskit/circuit/delay.py +11 -9
- qiskit/circuit/library/arithmetic/adders/adder.py +4 -4
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +2 -2
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +8 -4
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
- qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
- qiskit/circuit/library/basis_change/qft.py +2 -2
- qiskit/circuit/library/blueprintcircuit.py +6 -0
- qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_or.py +3 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
- qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
- qiskit/circuit/library/fourier_checking.py +2 -2
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
- qiskit/circuit/library/generalized_gates/gms.py +5 -1
- qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +5 -1
- qiskit/circuit/library/generalized_gates/uc.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +21 -2
- qiskit/circuit/library/graph_state.py +2 -2
- qiskit/circuit/library/grover_operator.py +2 -2
- qiskit/circuit/library/hidden_linear_function.py +2 -2
- qiskit/circuit/library/iqp.py +2 -2
- qiskit/circuit/library/n_local/efficient_su2.py +2 -2
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
- qiskit/circuit/library/n_local/n_local.py +4 -3
- qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
- qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
- qiskit/circuit/library/n_local/two_local.py +2 -2
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +3 -2
- qiskit/circuit/library/phase_estimation.py +2 -2
- qiskit/circuit/library/standard_gates/dcx.py +11 -12
- qiskit/circuit/library/standard_gates/ecr.py +21 -24
- qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +22 -45
- qiskit/circuit/library/standard_gates/i.py +1 -1
- qiskit/circuit/library/standard_gates/iswap.py +13 -31
- qiskit/circuit/library/standard_gates/p.py +19 -26
- qiskit/circuit/library/standard_gates/r.py +11 -17
- qiskit/circuit/library/standard_gates/rx.py +21 -45
- qiskit/circuit/library/standard_gates/rxx.py +7 -22
- qiskit/circuit/library/standard_gates/ry.py +21 -39
- qiskit/circuit/library/standard_gates/ryy.py +13 -28
- qiskit/circuit/library/standard_gates/rz.py +18 -35
- qiskit/circuit/library/standard_gates/rzx.py +7 -22
- qiskit/circuit/library/standard_gates/rzz.py +7 -19
- qiskit/circuit/library/standard_gates/s.py +44 -39
- qiskit/circuit/library/standard_gates/swap.py +25 -38
- qiskit/circuit/library/standard_gates/sx.py +34 -41
- qiskit/circuit/library/standard_gates/t.py +18 -27
- qiskit/circuit/library/standard_gates/u.py +8 -24
- qiskit/circuit/library/standard_gates/u1.py +28 -52
- qiskit/circuit/library/standard_gates/u2.py +9 -9
- qiskit/circuit/library/standard_gates/u3.py +24 -40
- qiskit/circuit/library/standard_gates/x.py +190 -336
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
- qiskit/circuit/library/standard_gates/y.py +19 -23
- qiskit/circuit/library/standard_gates/z.py +31 -38
- qiskit/circuit/parameter.py +14 -5
- qiskit/circuit/parameterexpression.py +109 -75
- qiskit/circuit/quantumcircuit.py +172 -99
- qiskit/circuit/quantumcircuitdata.py +1 -0
- qiskit/circuit/random/__init__.py +37 -2
- qiskit/circuit/random/utils.py +445 -56
- qiskit/circuit/tools/pi_check.py +5 -13
- qiskit/compiler/transpiler.py +1 -1
- qiskit/converters/circuit_to_instruction.py +2 -2
- qiskit/dagcircuit/dagnode.py +8 -3
- qiskit/primitives/__init__.py +2 -2
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +0 -3
- qiskit/primitives/containers/observables_array.py +192 -108
- qiskit/primitives/primitive_job.py +29 -10
- qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
- qiskit/qasm3/__init__.py +106 -12
- qiskit/qasm3/ast.py +15 -1
- qiskit/qasm3/exporter.py +59 -36
- qiskit/qasm3/printer.py +12 -0
- qiskit/qpy/__init__.py +182 -6
- qiskit/qpy/binary_io/circuits.py +256 -24
- qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
- qiskit/qpy/binary_io/schedules.py +12 -32
- qiskit/qpy/binary_io/value.py +36 -18
- qiskit/qpy/common.py +11 -3
- qiskit/qpy/formats.py +17 -1
- qiskit/qpy/interface.py +52 -12
- qiskit/qpy/type_keys.py +7 -1
- qiskit/quantum_info/__init__.py +10 -0
- qiskit/quantum_info/operators/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
- qiskit/result/sampled_expval.py +3 -1
- qiskit/synthesis/__init__.py +10 -0
- qiskit/synthesis/arithmetic/__init__.py +1 -1
- qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
- qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
- qiskit/synthesis/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +10 -7
- qiskit/synthesis/evolution/qdrift.py +10 -7
- qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
- qiskit/synthesis/multi_controlled/__init__.py +4 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
- qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
- qiskit/synthesis/unitary/qsd.py +80 -9
- qiskit/transpiler/__init__.py +10 -3
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +5 -2
- qiskit/transpiler/passes/layout/dense_layout.py +26 -6
- qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
- qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
- qiskit/transpiler/passes/layout/vf2_utils.py +10 -0
- qiskit/transpiler/passes/optimization/__init__.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
- qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
- qiskit/transpiler/passes/routing/sabre_swap.py +4 -2
- qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
- qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
- qiskit/transpiler/passes/synthesis/__init__.py +1 -0
- qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
- qiskit/transpiler/passes/synthesis/hls_plugins.py +494 -93
- qiskit/transpiler/passes/synthesis/plugin.py +4 -0
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
- qiskit/transpiler/passmanager_config.py +3 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
- qiskit/transpiler/preset_passmanagers/common.py +101 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
- qiskit/transpiler/preset_passmanagers/level3.py +2 -2
- qiskit/transpiler/target.py +15 -2
- qiskit/utils/optionals.py +6 -5
- qiskit/visualization/circuit/_utils.py +5 -3
- qiskit/visualization/circuit/latex.py +9 -2
- qiskit/visualization/circuit/matplotlib.py +26 -4
- qiskit/visualization/circuit/qcstyle.py +9 -157
- qiskit/visualization/dag/__init__.py +13 -0
- qiskit/visualization/dag/dagstyle.py +103 -0
- qiskit/visualization/dag/styles/__init__.py +13 -0
- qiskit/visualization/dag/styles/color.json +10 -0
- qiskit/visualization/dag/styles/plain.json +5 -0
- qiskit/visualization/dag_visualization.py +169 -98
- qiskit/visualization/style.py +223 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/METADATA +7 -6
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/RECORD +178 -169
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/entry_points.txt +6 -0
- qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
- qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/WHEEL +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/licenses/LICENSE.txt +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/top_level.txt +0 -0
@@ -18,16 +18,16 @@ from __future__ import annotations
|
|
18
18
|
from dataclasses import dataclass
|
19
19
|
from enum import IntEnum
|
20
20
|
from typing import Callable, Union
|
21
|
-
|
22
21
|
import numbers
|
23
22
|
import operator
|
24
23
|
|
25
24
|
import numpy
|
26
|
-
import symengine
|
27
25
|
|
28
|
-
from qiskit.circuit.exceptions import CircuitError
|
29
|
-
from qiskit.exceptions import QiskitError
|
30
26
|
from qiskit.utils.optionals import HAS_SYMPY
|
27
|
+
from qiskit.circuit.exceptions import CircuitError
|
28
|
+
import qiskit._accelerate.circuit
|
29
|
+
|
30
|
+
SymbolExpr = qiskit._accelerate.circuit.ParameterExpression
|
31
31
|
|
32
32
|
# This type is redefined at the bottom to insert the full reference to "ParameterExpression", so it
|
33
33
|
# can safely be used by runtime type-checkers like Sphinx. Mypy does not need this because it
|
@@ -126,15 +126,23 @@ class ParameterExpression:
|
|
126
126
|
symbol_map (Dict[Parameter, [ParameterExpression, float, or int]]):
|
127
127
|
Mapping of :class:`Parameter` instances to the :class:`sympy.Symbol`
|
128
128
|
serving as their placeholder in expr.
|
129
|
-
expr (
|
129
|
+
expr (SymbolExpr or str): Expression with Rust's SymbolExprPy or string
|
130
130
|
"""
|
131
131
|
# NOTE: `Parameter.__init__` does not call up to this method, since this method is dependent
|
132
132
|
# on `Parameter` instances already being initialized enough to be hashable. If changing
|
133
133
|
# this method, check that `Parameter.__init__` and `__setstate__` are still valid.
|
134
|
-
|
135
|
-
|
136
|
-
|
134
|
+
if isinstance(expr, SymbolExpr):
|
135
|
+
self._parameter_symbols = symbol_map
|
136
|
+
self._symbol_expr = expr
|
137
|
+
else:
|
138
|
+
self._symbol_expr = SymbolExpr.Expression(expr)
|
139
|
+
self._parameter_symbols = {}
|
140
|
+
# reconstruct symbols from input parameters
|
141
|
+
for param in symbol_map.keys():
|
142
|
+
self._parameter_symbols[param] = SymbolExpr.Symbol(param.name)
|
137
143
|
self._name_map: dict | None = None
|
144
|
+
self._parameter_keys = frozenset(p._hash_key() for p in self._parameter_symbols)
|
145
|
+
|
138
146
|
self._standalone_param = False
|
139
147
|
if _qpy_replay is not None:
|
140
148
|
self._qpy_replay = _qpy_replay
|
@@ -162,7 +170,7 @@ class ParameterExpression:
|
|
162
170
|
new_replay = self._qpy_replay.copy()
|
163
171
|
new_replay.append(new_op)
|
164
172
|
conjugated = ParameterExpression(
|
165
|
-
self._parameter_symbols,
|
173
|
+
self._parameter_symbols, self._symbol_expr.conjugate(), _qpy_replay=new_replay
|
166
174
|
)
|
167
175
|
return conjugated
|
168
176
|
|
@@ -213,9 +221,9 @@ class ParameterExpression:
|
|
213
221
|
symbol_values = {}
|
214
222
|
for parameter, value in parameter_values.items():
|
215
223
|
if (param_expr := self._parameter_symbols.get(parameter)) is not None:
|
216
|
-
symbol_values[param_expr] = value
|
224
|
+
symbol_values[str(param_expr)] = value
|
217
225
|
|
218
|
-
bound_symbol_expr = self._symbol_expr.
|
226
|
+
bound_symbol_expr = self._symbol_expr.bind(symbol_values)
|
219
227
|
|
220
228
|
# Don't use sympy.free_symbols to count remaining parameters here.
|
221
229
|
# sympy will in some cases reduce the expression and remove even
|
@@ -279,14 +287,14 @@ class ParameterExpression:
|
|
279
287
|
new_parameter_symbols = {
|
280
288
|
p: s for p, s in self._parameter_symbols.items() if p not in parameter_map
|
281
289
|
}
|
282
|
-
symbol_type =
|
290
|
+
symbol_type = SymbolExpr.Symbol
|
283
291
|
|
284
292
|
# If new_param is an expr, we'll need to construct a matching sympy expr
|
285
293
|
# but with our sympy symbols instead of theirs.
|
286
294
|
symbol_map = {}
|
287
295
|
for old_param, new_param in parameter_map.items():
|
288
296
|
if (old_symbol := self._parameter_symbols.get(old_param)) is not None:
|
289
|
-
symbol_map[old_symbol] = new_param._symbol_expr
|
297
|
+
symbol_map[str(old_symbol)] = new_param._symbol_expr
|
290
298
|
for p in new_param.parameters:
|
291
299
|
new_parameter_symbols[p] = symbol_type(p.name)
|
292
300
|
|
@@ -399,7 +407,13 @@ class ParameterExpression:
|
|
399
407
|
return out_expr
|
400
408
|
|
401
409
|
def gradient(self, param) -> Union["ParameterExpression", complex]:
|
402
|
-
"""Get the derivative of a parameter expression w.r.t. a specified parameter
|
410
|
+
"""Get the derivative of a real parameter expression w.r.t. a specified parameter.
|
411
|
+
|
412
|
+
.. note::
|
413
|
+
|
414
|
+
This method assumes that the parameter expression represents a **real expression only**.
|
415
|
+
Calling this method on a parameter expression that contains complex values, or binding
|
416
|
+
complex values to parameters in the expression is undefined behavior.
|
403
417
|
|
404
418
|
Args:
|
405
419
|
param (Parameter): Parameter w.r.t. which we want to take the derivative
|
@@ -422,24 +436,20 @@ class ParameterExpression:
|
|
422
436
|
|
423
437
|
# Compute the gradient of the parameter expression w.r.t. param
|
424
438
|
key = self._parameter_symbols[param]
|
425
|
-
expr_grad =
|
439
|
+
expr_grad = self._symbol_expr.derivative(key)
|
426
440
|
|
427
441
|
# generate the new dictionary of symbols
|
428
442
|
# this needs to be done since in the derivative some symbols might disappear (e.g.
|
429
443
|
# when deriving linear expression)
|
430
444
|
parameter_symbols = {}
|
431
445
|
for parameter, symbol in self._parameter_symbols.items():
|
432
|
-
if symbol in expr_grad.
|
446
|
+
if symbol.name in expr_grad.symbols():
|
433
447
|
parameter_symbols[parameter] = symbol
|
434
448
|
# If the gradient corresponds to a parameter expression then return the new expression.
|
435
449
|
if len(parameter_symbols) > 0:
|
436
450
|
return ParameterExpression(parameter_symbols, expr=expr_grad, _qpy_replay=qpy_replay)
|
437
451
|
# If no free symbols left, return a complex or float gradient
|
438
|
-
|
439
|
-
if expr_grad_cplx.imag != 0:
|
440
|
-
return expr_grad_cplx
|
441
|
-
else:
|
442
|
-
return float(expr_grad)
|
452
|
+
return expr_grad.value()
|
443
453
|
|
444
454
|
def __add__(self, other):
|
445
455
|
return self._apply_operation(operator.add, other, op_code=_OPCode.ADD)
|
@@ -492,54 +502,49 @@ class ParameterExpression:
|
|
492
502
|
|
493
503
|
def sin(self):
|
494
504
|
"""Sine of a ParameterExpression"""
|
495
|
-
return self._call(
|
505
|
+
return self._call(SymbolExpr.sin, op_code=_OPCode.SIN)
|
496
506
|
|
497
507
|
def cos(self):
|
498
508
|
"""Cosine of a ParameterExpression"""
|
499
|
-
return self._call(
|
509
|
+
return self._call(SymbolExpr.cos, op_code=_OPCode.COS)
|
500
510
|
|
501
511
|
def tan(self):
|
502
512
|
"""Tangent of a ParameterExpression"""
|
503
|
-
return self._call(
|
513
|
+
return self._call(SymbolExpr.tan, op_code=_OPCode.TAN)
|
504
514
|
|
505
515
|
def arcsin(self):
|
506
516
|
"""Arcsin of a ParameterExpression"""
|
507
|
-
return self._call(
|
517
|
+
return self._call(SymbolExpr.asin, op_code=_OPCode.ASIN)
|
508
518
|
|
509
519
|
def arccos(self):
|
510
520
|
"""Arccos of a ParameterExpression"""
|
511
|
-
return self._call(
|
521
|
+
return self._call(SymbolExpr.acos, op_code=_OPCode.ACOS)
|
512
522
|
|
513
523
|
def arctan(self):
|
514
524
|
"""Arctan of a ParameterExpression"""
|
515
|
-
return self._call(
|
525
|
+
return self._call(SymbolExpr.atan, op_code=_OPCode.ATAN)
|
516
526
|
|
517
527
|
def exp(self):
|
518
528
|
"""Exponential of a ParameterExpression"""
|
519
|
-
return self._call(
|
529
|
+
return self._call(SymbolExpr.exp, op_code=_OPCode.EXP)
|
520
530
|
|
521
531
|
def log(self):
|
522
532
|
"""Logarithm of a ParameterExpression"""
|
523
|
-
return self._call(
|
533
|
+
return self._call(SymbolExpr.log, op_code=_OPCode.LOG)
|
524
534
|
|
525
535
|
def sign(self):
|
526
536
|
"""Sign of a ParameterExpression"""
|
527
|
-
return self._call(
|
537
|
+
return self._call(SymbolExpr.sign, op_code=_OPCode.SIGN)
|
528
538
|
|
529
539
|
def __repr__(self):
|
530
540
|
return f"{self.__class__.__name__}({str(self)})"
|
531
541
|
|
532
542
|
def __str__(self):
|
533
|
-
|
534
|
-
|
535
|
-
if not isinstance(self._symbol_expr, symengine.Basic):
|
536
|
-
raise QiskitError("Invalid ParameterExpression")
|
537
|
-
|
538
|
-
return sstr(sympify(self._symbol_expr), full_prec=False)
|
543
|
+
return str(self._symbol_expr)
|
539
544
|
|
540
545
|
def __complex__(self):
|
541
546
|
try:
|
542
|
-
return complex(self._symbol_expr)
|
547
|
+
return complex(self._symbol_expr.value())
|
543
548
|
# TypeError is for sympy, RuntimeError for symengine
|
544
549
|
except (TypeError, RuntimeError) as exc:
|
545
550
|
if self.parameters:
|
@@ -551,7 +556,7 @@ class ParameterExpression:
|
|
551
556
|
|
552
557
|
def __float__(self):
|
553
558
|
try:
|
554
|
-
return float(self._symbol_expr)
|
559
|
+
return float(self._symbol_expr.value())
|
555
560
|
# TypeError is for sympy, RuntimeError for symengine
|
556
561
|
except (TypeError, RuntimeError) as exc:
|
557
562
|
if self.parameters:
|
@@ -571,7 +576,7 @@ class ParameterExpression:
|
|
571
576
|
|
572
577
|
def __int__(self):
|
573
578
|
try:
|
574
|
-
return int(self._symbol_expr)
|
579
|
+
return int(self._symbol_expr.value())
|
575
580
|
# TypeError is for backwards compatibility, RuntimeError is raised by symengine
|
576
581
|
except RuntimeError as exc:
|
577
582
|
if self.parameters:
|
@@ -595,7 +600,7 @@ class ParameterExpression:
|
|
595
600
|
|
596
601
|
def __abs__(self):
|
597
602
|
"""Absolute of a ParameterExpression"""
|
598
|
-
return self._call(
|
603
|
+
return self._call(SymbolExpr.abs, _OPCode.ABS)
|
599
604
|
|
600
605
|
def abs(self):
|
601
606
|
"""Absolute of a ParameterExpression"""
|
@@ -613,28 +618,19 @@ class ParameterExpression:
|
|
613
618
|
if isinstance(other, ParameterExpression):
|
614
619
|
if self.parameters != other.parameters:
|
615
620
|
return False
|
616
|
-
from sympy import sympify
|
617
|
-
|
618
|
-
if not isinstance(self._symbol_expr, symengine.Basic):
|
619
|
-
raise QiskitError("Invalid ParameterExpression")
|
620
621
|
|
621
|
-
return
|
622
|
+
return self._symbol_expr == other._symbol_expr
|
622
623
|
elif isinstance(other, numbers.Number):
|
623
|
-
return
|
624
|
+
return self._symbol_expr == other
|
624
625
|
return False
|
625
626
|
|
626
627
|
def is_real(self):
|
627
628
|
"""Return whether the expression is real"""
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
# non-zero imaginary
|
634
|
-
if self._symbol_expr.imag == 0.0:
|
635
|
-
return True
|
636
|
-
return False
|
637
|
-
return self._symbol_expr.is_real
|
629
|
+
try:
|
630
|
+
val = self._symbol_expr.value()
|
631
|
+
return not isinstance(val, complex)
|
632
|
+
except RuntimeError:
|
633
|
+
return None
|
638
634
|
|
639
635
|
def numeric(self) -> int | float | complex:
|
640
636
|
"""Return a Python number representing this object, using the most restrictive of
|
@@ -667,27 +663,11 @@ class ParameterExpression:
|
|
667
663
|
raise TypeError(
|
668
664
|
f"Expression with unbound parameters '{self.parameters}' is not numeric"
|
669
665
|
)
|
670
|
-
|
671
|
-
# Integer evaluation is reliable, as far as we know.
|
672
|
-
return int(self._symbol_expr)
|
673
|
-
# We've come across several ways in which symengine's general-purpose evaluators
|
674
|
-
# introduce spurious imaginary components can get involved in the output. The most
|
675
|
-
# reliable strategy "try it and see" while forcing real floating-point evaluation.
|
676
|
-
try:
|
677
|
-
real_expr = self._symbol_expr.evalf(real=True)
|
678
|
-
except RuntimeError:
|
679
|
-
# Symengine returns `complex` if any imaginary floating-point enters at all, even if
|
680
|
-
# the result is zero. The best we can do is detect that and decay to a float.
|
681
|
-
out = complex(self._symbol_expr)
|
682
|
-
return out.real if out.imag == 0.0 else out
|
683
|
-
return float(real_expr)
|
666
|
+
return self._symbol_expr.value()
|
684
667
|
|
685
668
|
@HAS_SYMPY.require_in_call
|
686
669
|
def sympify(self):
|
687
|
-
"""Return symbolic expression as a raw Sympy
|
688
|
-
|
689
|
-
Symengine is used preferentially; if both are available, the result will always be a
|
690
|
-
``symengine`` object. Symengine is a separate library but has integration with Sympy.
|
670
|
+
"""Return symbolic expression as a raw Sympy object.
|
691
671
|
|
692
672
|
.. note::
|
693
673
|
|
@@ -695,7 +675,61 @@ class ParameterExpression:
|
|
695
675
|
Symegine expressions in its parameters, because they do not contain the tracking
|
696
676
|
information used in circuit-parameter binding and assignment.
|
697
677
|
"""
|
698
|
-
|
678
|
+
import sympy
|
679
|
+
|
680
|
+
output = None
|
681
|
+
for inst in self._qpy_replay:
|
682
|
+
if isinstance(inst, _SUBS):
|
683
|
+
sympy_binds = {}
|
684
|
+
for old, new in inst.binds.items():
|
685
|
+
if isinstance(new, ParameterExpression):
|
686
|
+
new = new.sympify()
|
687
|
+
sympy_binds[old.sympify()] = new
|
688
|
+
output = output.subs(sympy_binds, simultaneous=True)
|
689
|
+
continue
|
690
|
+
|
691
|
+
if isinstance(inst.lhs, ParameterExpression):
|
692
|
+
lhs = inst.lhs.sympify()
|
693
|
+
elif inst.lhs is None:
|
694
|
+
lhs = output
|
695
|
+
else:
|
696
|
+
lhs = inst.lhs
|
697
|
+
|
698
|
+
method_str = _OP_CODE_MAP[inst.op]
|
699
|
+
if inst.op in {0, 1, 2, 3, 4, 13, 15, 18, 19, 20}:
|
700
|
+
if inst.rhs is None:
|
701
|
+
rhs = output
|
702
|
+
elif isinstance(inst.rhs, ParameterExpression):
|
703
|
+
rhs = inst.rhs.sympify()
|
704
|
+
else:
|
705
|
+
rhs = inst.rhs
|
706
|
+
|
707
|
+
if (
|
708
|
+
not isinstance(lhs, sympy.Basic)
|
709
|
+
and isinstance(rhs, sympy.Basic)
|
710
|
+
and inst.op in [0, 2]
|
711
|
+
):
|
712
|
+
if inst.op == 0:
|
713
|
+
method_str = "__radd__"
|
714
|
+
elif inst.op == 2:
|
715
|
+
method_str = "__rmul__"
|
716
|
+
output = getattr(rhs, method_str)(lhs)
|
717
|
+
elif inst.op == _OPCode.GRAD:
|
718
|
+
output = getattr(lhs, "diff")(rhs)
|
719
|
+
else:
|
720
|
+
output = getattr(lhs, method_str)(rhs)
|
721
|
+
else:
|
722
|
+
if inst.op == _OPCode.ACOS:
|
723
|
+
output = getattr(sympy, "acos")(lhs)
|
724
|
+
elif inst.op == _OPCode.ASIN:
|
725
|
+
output = getattr(sympy, "asin")(lhs)
|
726
|
+
elif inst.op == _OPCode.ATAN:
|
727
|
+
output = getattr(sympy, "atan")(lhs)
|
728
|
+
elif inst.op == _OPCode.ABS:
|
729
|
+
output = getattr(sympy, "Abs")(lhs)
|
730
|
+
else:
|
731
|
+
output = getattr(sympy, method_str)(lhs)
|
732
|
+
return output
|
699
733
|
|
700
734
|
|
701
735
|
# Redefine the type so external imports get an evaluated reference; Sphinx needs this to understand
|