quri_parts.core.operator package#
- CommutablePauliSet#
CommutablePauliSet
- truncate(op, atol=1e-08)#
Returns truncated operator by eliminating terms whose coefficients are smaller than
atol
.
- is_hermitian(op, atol=1e-08)#
Returns
True
if given operator is hermitian.- Parameters:
op (Operator) –
atol (float) –
- Return type:
bool
- is_ops_close(op1, op2, rtol=1e-09, atol=0.0)#
Returns
True
if two operators are close to each other.
- PAULI_IDENTITY = frozenset({})#
PauliLabel used as an identity.
- pauli_label(p)#
Create a PauliLabel.
The argument can be one of the followings:
A string representation of a Pauli string.
A
PauliLabelProvider
, an object providing a qubit index list and a SinglePauli list.An Iterable of tuple[int, int], pairs of a qubit index and a SinglePauli.
- Parameters:
p (str | PauliLabelProvider | Iterable[tuple[int, int]]) –
- Return type:
- pauli_name(p)#
Returns the name of Pauli matrix for a SinglePauli (int)
- Parameters:
p (int) –
- Return type:
str
- pauli_product(pauli1, pauli2)#
Returns the product of two PauliLabels.
Note that this function returns a tuple (PauliLabel, phase) since the multiplication of two Pauli operators can yield a Pauli operator multiplied by the imaginary unit (e.g., XY = iZ).
- Parameters:
pauli1 (PauliLabel) –
pauli2 (PauliLabel) –
- Return type:
tuple[PauliLabel, complex]
- class PauliLabel(arg=())#
Bases:
frozenset
[tuple
[int
,int
]]PauliLabel represents a label for a Pauli string, e.g.
X0 Y1 Z2
.It represents only a “label” of a multi-qubit Pauli term and does not hold a coefficient or a phase factor. This class is basically a
frozenset
of pairs of a qubit index and a SinglePauli, and also can be used as a key for a dict (Hashable).Example
>>> label = pauli_label({(0, SinglePauli.X), (1, SinglePauli.Y), (2, SinglePauli.Z)}) >>> label PauliLabel({(0, <SinglePauli.X: 1>), (1, <SinglePauli.Y: 2>), (2, <SinglePauli.Z: 3>)}) >>> str(label) 'X0 Y1 Z2' >>> for pair in label: ... print(pair) ... (0, <SinglePauli.X: 1>) (1, <SinglePauli.Y: 2>) (2, <SinglePauli.Z: 3>) >>> label.pauli_at(1) <SinglePauli.Y: 2> >>> 1 in label.qubit_indices() True >>> for i in label.qubit_indices(): ... print(f"index: {i}, operator: {label.pauli_at(i)}") ... index: 0, operator: 1 index: 1, operator: 2 index: 2, operator: 3
You can construct a PauliLabel in one of the following ways:
- With a tuples of a qubit index (int) and a Pauli matrix label (int)
>>> pauli_label({(0, 1), (1, 2), (2, 3)})
- With a tuples of a qubit index (int) and a Pauli matrix label (SinglePauli)
>>> pauli_label({(0, SinglePauli.X), (1, SinglePauli.Y), (2, SinglePauli.Z)})
- With a string representation of a Pauli string (Note that string parsing has a significant performance overhead)
>>> pauli_label("X0 Y1 Z2")
- From a qubit index list and a matrix label (SinglePauli) list
>>> PauliLabel.from_index_and_pauli_list( [0, 1, 2], [SinglePauli.X, SinglePauli.Y, SinglePauli.Z] )
- From an object providing a qubit index list and a matrix label list (
PauliLabelProvider
) >>> pauli_label(obj) # obj has get_index_list and get_pauli_id_list methods
- From an object providing a qubit index list and a matrix label list (
Note that the following code does not raise an error but creates an invalid PauliLabel. To avoid this kind of error, it is recommended to use a factory function
pauli_label()
instead of the original constructorPauliLabel()
.>>> PauliLabel("X0 Y1 Z2") # Should be pauli_label("X0 Y1 Z2") or PauliLabel.from_str("X0 Y1 Z2") PauliLabel({' ', 'Z', '0', '1', 'X', 'Y', '2'})
The string input should be given as a list of single pauli terms separated by white spaces. Each single pauli term consists of a Pauli matrix label (
X
,Y
orZ
) and a qubit index (int), possibly separated by white spaces.Valid string input examples:
X0 Y1 Z2
X 0 Y 1 Z 2
Invalid string input examples:
X0 Y1 A2
(Invalid Pauli matrix labelA
)X0Y1Z2
(No spaces between each term)X0 Y1 Z1
(Duplicate qubit indices)X0 Y Z2
(No qubit index specified)X0 1 Z2
(No Pauli matrix label specified)
Order of the terms is irrelevant when comparing two PauliLabel’s:
>>> pauli_label("X0 Y1 Z2") == pauli_label("X0 Z2 Y1") True
Performance tip: An index access by
pauli_at()
involves an iteration inside it, so it is inefficient when you want to iterate over all single Pauli terms in a PauliLabel. Instead of doing this:>>> for i in range(len(label)): ... p = label.pauli_at(i) ... # Do something with p
the following is faster:
>>> for i, p in label: ... # Do something with p
- Parameters:
arg (Iterable[tuple[int, int]]) –
- Return type:
- qubit_indices()#
Returns a Collection of qubit indices on which Pauli matrices act.
Note that this collection does not have a definite ordering.
- Return type:
Collection[int]
- pauli_at(index)#
Returns a Pauli matrix at the qubit index
index
.Returns
None
if no Pauli matrix acts on the index.- Parameters:
index (int) –
- Return type:
int | None
- property index_and_pauli_id_list: tuple[Sequence[int], Sequence[int]]#
A pair of a list of indices of qubits on which the Pauli matrices act, and a list of the Pauli matrices in the order corresponding to the index list.
- static from_index_and_pauli_list(index, pauli)#
Create a PauliLabel from a list of qubit indices and a list of Pauli matrices.
- Parameters:
index (Collection[int]) –
pauli (Collection[int]) –
- Return type:
- static from_str(pauli_label_str)#
Create a PauliLabel from a string representation of a Pauli String.
- Parameters:
pauli_label_str (str) –
- Return type:
- static of(pauli)#
Create a PauliLabel from an object providing a qubit index list and a SinglePauli list.
- Parameters:
pauli (PauliLabelProvider) –
- Return type:
- class Operator#
Bases:
dict
[PauliLabel
,complex
]Operator represents the set of single-term operators as a dict[PauliLabel, coefficient].
Coefficients can not only be real values but also complex values since Operator represents a general operator including non-Hermitian one.
Example
>>> op = Operator({pauli_label("X0"): 0.1j}) >>> op {PauliLabel({(0, <SinglePauli.X: 1>)}): 0.1j} >>> op[pauli_label("X1 Y2")] = 0.2 >>> op {PauliLabel({(0, <SinglePauli.X: 1>)}): 0.1j, PauliLabel({(1, <SinglePauli.X: 1>), (2, <SinglePauli.Y: 2>)}): 0.2} >>> str(op) '0.1j*X0 + 0.2*X1 Y2' >>> for pauli, coef in op.items(): ... print(f"Pauli: {pauli}, coefficient: {coef}") ... Pauli: X0, coefficient: 0.1j Pauli: X1 Y2, coefficient: 0.2 >>> op.constant 0.0 >>> op[PAULI_IDENTITY] = 2.0 >>> op {PauliLabel({(0, <SinglePauli.X: 1>)}): 0.1j, PauliLabel({(1, <SinglePauli.X: 1>), (2, <SinglePauli.Y: 2>)}): 0.2, PauliLabel(): 2.0} >>> op.constant 2.0 >>> op.constant = 1.0 >>> op.constant 1.0
- You can add a single-term operator by add_term() method.
>>> operator.add_term(PauliLabel({(1, 1)}), 1.0)
- By accessing by key, the coefficient is replaced with a new value.
>>> operator = Operator({pauli_label("X0"): 0.1j}) >>> op {PauliLabel({(0, <SinglePauli.X: 1>)}): 0.1j} >>> operator[pauli_label("X0")] = 0.1 >>> op {PauliLabel({(0, <SinglePauli.X: 1>)}): 0.1}
- add_term(pauli_label, coef)#
Method for adding single-term operator.
- Parameters:
pauli_label (PauliLabel) –
coef (complex) –
- Return type:
None
- property n_terms: int#
Number of all terms.
- property constant: complex#
Constant value.
Note that the constant value is a coefficient of an identity pauli term (PAULI_IDENTITY).
- class SinglePauli(value)#
Bases:
IntEnum
An integer enumeration representing Pauli matrices X, Y, Z acting on a single qubit.
- X = 1#
- Y = 2#
- Z = 3#
- transition_amp_comp_basis(op_binary_repr, m, n)#
Returns the transition amplitude \(\langle m|O|n\rangle\) of the operator \(O\)
- Parameters:
op_binary_repr (core.operator.representation._TransitionAmplitudeRepresentation) –
m (int) –
n (int) –
- Return type:
complex
- transition_amp_representation(operator)#
Returns a binary representation
_TransitionAmplitudeRepresentation
, which is the special representation designed for calculating tansition amplitudes efficiently.- Parameters:
operator (Operator) –
- Return type:
_TransitionAmplitudeRepresentation
- zero()#
Returns zero (empty) operator, which always return zero expectation value for all states.
- Return type:
- trotter_suzuki_decomposition(op, param, order)#
Trotter-Suzuki decomposition [1], a recursive formula of the approximation that decomposes an exponential function of the sum of Pauli operators into a product of the exponential function of Pauli operators. The explicit formula for the sum of Pauli operator \(A=\sum_i A_i\) is given as follows:
\[\begin{split}S_{2k}(x)&=[S_{2k-2}(p_kx)]^2S_{2k-2}((1-4p_k)x)][S_{2k-2}(p_kx)]^2,\\ S_2(x)&=\prod_{j=1}^me^{A_j x /2}\prod_{j'=m}^1 e^{A_{j'} x /2},\\ p_k&=(4-4^{1/(2k-1)})^{-1},\end{split}\]where \(k\) is an order of this decomposition and \(A_i\) is the Pauli operator.
- Parameters:
op (Operator) – An operator on the exponential.
param (complex) – The overall coefficient of the exponential. This can be not only a real but also a complex number.
order (int) – The order of the Trotter-Suzuki decomposition. An integer that satisfies >= 1.
- Returns:
List of ExponentialSinglePauli.
- Return type:
list[ExponentialSinglePauli]
- Ref:
[1]: M. Suzuki, Fractal decomposition of exponential operators with applications to many-body theories and Monte Carlo simulation, Phys. Lett. 146 319-323, 1990
- get_sparse_matrix(operator, n_qubits=None, format='csc')#
Convert
PauliLabel
andOperator
into scipy sparse matrix.- Parameters:
operator (PauliLabel | Operator) –
n_qubits (int | None) –
format (core.operator.sparse.SparseMatrixName) –
- Return type:
spmatrix
Subpackages#
Submodules#
- quri_parts.core.operator.conjugation module
- quri_parts.core.operator.operator module
- quri_parts.core.operator.pauli module
- quri_parts.core.operator.sparse module
- quri_parts.core.operator.trotter_suzuki module