quri_parts.core.operator package#

CommutablePauliSet#

CommutablePauliSet

commutator(op1, op2)#

Returns the commutator of op1 and op2 :math:`[text{op1},

text{op2}]`.

Parameters:
Return type:

Operator

truncate(op, atol=1e-08)#

Returns truncated operator by eliminating terms whose coefficients are smaller than atol.

Parameters:
Return type:

Operator

is_hermitian(op, atol=1e-08)#

Returns True if given operator is hermitian.

Parameters:
Return type:

bool

is_ops_close(op1, op2, rtol=1e-09, atol=0.0)#

Returns True if two operators are close to each other.

Parameters:
Return type:

bool

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:

PauliLabel

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:
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
    

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 constructor PauliLabel().

>>> 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 or Z) 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 label A)

  • 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:

PauliLabel

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:

PauliLabel

static from_str(pauli_label_str)#

Create a PauliLabel from a string representation of a Pauli String.

Parameters:

pauli_label_str (str) –

Return type:

PauliLabel

static of(pauli)#

Create a PauliLabel from an object providing a qubit index list and a SinglePauli list.

Parameters:

pauli (PauliLabelProvider) –

Return type:

PauliLabel

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:
Return type:

None

copy()#

Returns the copy of itself.

Return type:

Operator

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).

hermitian_conjugated()#
Return type:

Operator

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:

Operator

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 and Operator into scipy sparse matrix.

Parameters:
  • operator (PauliLabel | Operator) –

  • n_qubits (int | None) –

  • format (core.operator.sparse.SparseMatrixName) –

Return type:

spmatrix

Subpackages#

Submodules#