TLDR: efficiently compute the non-zero elements for a Pauli string
https://arxiv.org/abs/2301.00560import fast_pauli as fp
P1 = fp.PauliString('XYZ')
P2 = fp.PauliString('YZX')
# Access dim and n_qubits
print(f"dim = {P1.dim}")
print(f"n_qubits = {P1.n_qubits}")
# Add two Pauli strings. Returns a PauliOp
P3 = P1 + P2
# Multiply two Pauli strings.
phase, new_string = P1 @ P2
coeffs = np.array([0.5, 0.5], dtype=complex)
pauli_strings = ['XYZ', 'YYZ']
O = fp.PauliOp(coeffs, pauli_strings)
# Apply O to a batch of 1000 states
states = np.random.rand(8, 1000).astype(np.complex128)
states/= np.linalg.norm(states, axis=0)[None,:]
new_states = O.apply(states)
# Compute the expectation value of O w.r.t states
values = O.expectation_value(states)
v = np.random.rand(2**N).astype(np.complex128)
op = fp.PauliOp(np.ones(len(pauli_strings)), pauli_strings)
op.apply(v)
v = Statevector(np.random.rand(2**N).astype(np.complex128))
op = SparsePauliOp(
pauli_strings, coeffs=np.ones(len(pauli_strings))
)
v.evolve(op)
op = fp.PauliOp(coeffs, pauli_strings)
op.expectation_value(v_batch)
op = SparsePauliOp(pauli_strings, coeffs=coeffs)
state_batch = [Statevector(v) for v in v_batch]
results = [s.expectation_value(op) for s in state_batch] # noqa: F841
# Convert a fast_pauli PauliOp to a Qiskit SparsePauliOp
O = fp.PauliOp([1], ['XYZ'])
qiskit_op = fp.to_qiskit(O)
fast_pauli_op = fp.from_qiskit(qiskit_op)
# Convert fast_pauli PauliString to a Qiskit Pauli object
P = fp.PauliString('XYZ')
qiskit_pauli = fp.to_qiskit(P)