pauli_state

Implementation of the State interface for states in Pauli bases (XBasis, YBasis, ZBasis).

Here we define several classes for different use cases:

Examples

>>> # Define |00> and |11> product states in the Z pauli basis
>>> basis_state_1 = PauliBasisState("00")
>>> basis_state_2 = PauliBasisState("11")
>>> # Create bell states (`PauliQuantumState`s) from arithmetics
>>> bell_state_p = 1. / sqrt(2) * (basis_state_1 + basis_state_2)
>>> bell_state_m = (basis_state_1 - basis_state_2).to_normalized()
>>> # Print the resulting states
>>> print(bell_state_p)
>>> # 0.7071067811865475*|00⟩ + 0.7071067811865475*|11⟩
>>> print(bell_state_m)
>>> # 0.7071067811865475*|00⟩ - 0.7071067811865475*|11⟩
class parityos.states.pauli_state.HasBitstrings(*args, **kwargs)

Bases: Protocol

A protocol for objects that provide a in iterator of bitstrings.

property bitstrings: Iterator[str]

Iterator of bitstrings.

An iterator that yields strings consisting of binary digits (e.g., “0101”, “1111”).

class parityos.states.pauli_state.OrderedPauliState

Bases: HasFrozenOrderedQubits[QubitT_co], HasPauliBasis[BasisT_co], ABC

Base class for states in a Pauli basis with a definite qubit order.

Implements reorder to create a copy with changed qubit order.

abstractmethod reorder(target_ordered_qubits: Sequence[QubitT_co] | None = None) Self

Reorder this state’s qubits to the order defined by target_ordered_qubits.

Parameters:

target_ordered_qubits – Target qubit order for bitstring. If None, sorted(self.ordered_qubits) is used. Defaults to None.

Returns:

A copy of self where qubit ordering has been changed to target_ordered_qubits.

Raises:

ParityOSException – If this state’s qubits and qubits in target_ordered_qubits are different up to ordering.

class parityos.states.pauli_state.PauliBasisState(bitstring: str, ordered_qubits: T | Iterable[T] = NOTHING, basis: type[BasisT_co] = parityos.operators.elementary_operator.Z[typing.Never])

Bases: OrderedPauliState[QubitT_co, BasisT_co], BasisState[QubitT_co]

Basis state (product state) according to a Pauli basis (either XBasis, YBasis, or ZBasis).

The state is stored as a bitstring and a sequence of qubits, where the i-th entry in bitstring determines the state of the i-th qubit as eigenstate of the chosen Pauli basis.

The state of each qubit is represented as a character “0” or “1”, where

  • The +1 eigenstate of the chosen Pauli basis is mapped to “0”

  • The -1 eigenstate of the chosen Pauli basis is mapped to “1”

See bit_to_spin_value for more details on this conversion.

Caution

The bitstring and the sequence of qubits must be of same length and the bitstring must not be empty.

Raises:
bitstring: str

string of “0” and “1” representing the state for each qubit.

ordered_qubits: tuple[QubitT_co, ...]

Ordered Qubit sequence on which the state is defined. Defaults to an integer Qubit sequence. with increasing integer ids for each entry in bitstring.

basis: type[BasisT_co]

The Pauli basis of this state represented by one of XBasis, YBasis or ZBasis. Defaults to ZBasis.

classmethod from_qubit_to_value(qubit_to_value: Mapping[QubitT_co, bool], basis: type[BasisT_co] = parityos.operators.elementary_operator.Z[typing.Never]) Self

Create a PauliBasisState from a qubit to boolean bit map and a Basis.

Parameters:
  • qubit_to_value – A mapping from Qubit to boolean, where True is mapped to “1” and False is mapped to “0” values in the bitstring.

  • basis – The Pauli basis of this state represented by one of XBasis, YBasis or ZBasis. Defaults to ZBasis.

Returns: A PauliBasisState corresponding to qubit_to_value map.

qubit_to_value: MappingProxyType

Qubit to boolean bit map representation of the Pauli basis state.

Here “1” is mapped to True and “0” is mapped to False compared to the state’s bitstring.

Example:

A PauliBasisState defined by the bitstring "001" on qubits named q_0, q_1, q_2 gives a dict like {"q_0": False, "q_1": True, "q_2": True}.

get_spin_value(qubit: QubitT_co) int

Get integer spin value (+/-1) for qubit.

The bitstrings “0” or “1”, are mapped to spin values according to:

  • “0” is mapped to the +1 eigenstate of the chosen Pauli basis

  • “1” is mapped to the -1 eigenstate of the chosen Pauli basis.

See bit_to_spin_value for more details on this conversion.

Parameters:

qubit – Qubit for which to get the integer spin value.

Returns:

Integer spin value (+/-1) of qubit in this state

Raises:

ParityOSException – If qubit is not contained in this state

flip_qubits(qubits: QubitT_co | Iterable[QubitT_co] | None = None) Self

Flip the state on every qubit in qubits.

For each qubit in qubits the state on this qubit is flipped (0 <-> 1). Qubits in qubits that are not in this state are ignored.

Note

If qubits is None (default), all qubits are flipped.

Parameters:

qubits – Qubits to flip. If None, all qubits are flipped. Defaults to None.

Returns:

Copy of self with state on all qubits in qubits flipped

reorder(target_ordered_qubits: Sequence[Qubit] | None = None) Self

Reorder this state’s qubits to the order defined by target_ordered_qubits.

Parameters:

target_ordered_qubits – Target qubit order for bitstring. If None, sorted(self.ordered_qubits) is used. Defaults to None.

Returns:

A copy of self where qubit ordering has been changed to target_ordered_qubits.

Raises:

ParityOSException – If this state’s qubits and qubits in target_ordered_qubits are different up to ordering.

__neg__() PauliQuantumState[QubitT_co, BasisT_co]

The negation operator -.

Returns:

A single-term PauliQuantumState with self as single term with amplitude -1.

__mul__(other: Symbolic | complex) PauliQuantumState[QubitT_co, BasisT_co]
__mul__(other: PauliBasisState[OtherQubitT_co, BasisT_co]) PauliBasisState[QubitT_co | OtherQubitT_co, BasisT_co]

The multiplication operator *.

Multiplication between states is to be interpreted as a tensor product.

Caution

If other is a state, it must be in the same basis and not share any qubits with self.

Parameters:

other – A Coefficient or another PauliBasisState.

Returns:

If other is a Coefficient, returns a one-term PauliQuantumState with this amplitude. If other is a PauliBasisState, returns a tensor product of this and the other basis state. The resulting basis state’s qubits are the concatenation of the qubits of self and other, no reordering is applied.

__add__(other: PauliBasisState[QubitT_co, BasisT_co]) PauliQuantumState[QubitT_co, BasisT_co]

The addition operator +.

Caution

self and other must be defined on the same set of ordered qubits in the same basis.

Parameters:

other – Another PauliBasisState.

Returns:

A PauliQuantumState as a superposition of self and other, each with amplitude 1. (not normalized).

Raises:

ParityOSException – If self and other are defined on different qubit sequences or in a different basis.

__sub__(other: PauliBasisState[QubitT_co, BasisT_co]) PauliQuantumState[QubitT_co, BasisT_co]

The subtraction operator +.

Caution

self and other must be defined on the same set of ordered qubits in the same basis.

Parameters:

other – Another PauliBasisState.

Returns:

PauliQuantumState consisting of the two PauliBasisStates, self with amplitude 1, other with amplitude -1 (not normalized).

class parityos.states.pauli_state.PauliQuantumState(bitstring_amplitude_pairs: Iterable[tuple[KeyT, Coefficient]] | Mapping[KeyT, Coefficient], ordered_qubits: T | Iterable[T] = NOTHING, basis: type[BasisT_co] = parityos.operators.elementary_operator.Z[typing.Never])

Bases: OrderedPauliState[QubitT_co, BasisT_co], HasBitstrings, Parameterized, QuantumState[QubitT_co, PauliBasisState[QubitT_co, BasisT_co]]

Quantum state as amplitude weighted superposition of basis states in the same Pauli basis.

The state is stored as a set of (bitstring, amplitude) pairs and an ordered sequence of qubits. As such it constitutes a sparse representation, as only basis states with non-zero amplitudes are stored.

For each bitstring, the i-th entry determines the state of the i-th qubit in ordered_qubits as eigenstate of the chosen Pauli basis with the following mapping:

  • The +1 eigenstate of the chosen Pauli basis is mapped to “0” in the bitstring

  • The -1 eigenstate of the chosen Pauli basis is mapped to “1” in the bitstring

See PauliBasisState for more details.

Caution

The bitstrings and sequence of qubits must be of same length.

Raises:
bitstring_amplitude_pairs: frozenset[tuple[str, Symbolic | complex]]

Collection of pairs of basis state bitstrings and their amplitude.

ordered_qubits: tuple[QubitT_co, ...]

Ordered sequence of the qubits of this state.

basis: type[BasisT_co]

The Pauli basis of this state represented by one of XBasis, YBasis or ZBasis. Defaults to ZBasis.

classmethod from_state_to_amplitude(state_to_amplitude: Mapping[PauliBasisState[QubitT_co, BasisT_co], Symbolic | complex])

Create a PauliQuantumState from mapping of PauliBasisState instances to their amplitudes.

Note

The state is not normalized upon creation.

Parameters:

state_to_amplitude – mapping of PauliBasisState instances to their amplitude.

Returns:

a PauliQuantumState as weighted superposition of PauliBasisState instances with given

amplitudes.

Raises:
state_to_amplitude: MappingProxyType

A mapping of each PauliBasisState to its amplitude, representing the quantum state.

to_normalized() Self

Get a normalized copy of this state.

The squared absolute values of the returned state’s amplitudes sum to 1, constituting a normalized state.

Returns:

A normalized copy of this state.

property bitstrings: Iterator[str]

Iterator of bitstrings.

An iterator that yields strings consisting of binary digits (e.g., “0101”, “1111”).

parameters: frozenset[Parameter]
substitute_parameters(old_to_new: Mapping[Parameter, Symbolic | complex]) Self

Substitute symbolic parameters with new symbolic expressions or numeric values.

Parameters:

old_to_new – Mapping from existing parameter symbols to new values (numeric or symbolic).

Returns:

Copy of self with replaced parameters.

flip_qubits(qubits: QubitT_co | Iterable[QubitT_co] | None = None) Self

Flip the state on every qubit in qubits.

For each qubit in qubits the state on this qubit is flipped (0 <-> 1). Qubits in qubits that are not in this state are ignored.

Note

If qubits is None (default), all qubits are flipped.

Parameters:

qubits – Qubits to flip. If None, all qubits are flipped. Defaults to None.

Returns:

Copy of self with state on all qubits in qubits flipped

bitstrings_to_amplitude: MappingProxyType

A mapping of bitstrings to their amplitude, representing the quantum state.

reorder(target_ordered_qubits: Sequence[QubitT_co] | None = None) Self

Reorder this state’s qubits to the order defined by target_ordered_qubits.

Parameters:

target_ordered_qubits – Target qubit order for bitstring. If None, sorted(self.ordered_qubits) is used. Defaults to None.

Returns:

A copy of self where qubit ordering has been changed to target_ordered_qubits.

Raises:

ParityOSException – If this state’s qubits and qubits in target_ordered_qubits are different up to ordering.

__neg__() Self

The negation operator -.

Returns:

A copy of self with the sign of all amplitudes flipped.

__mul__(other: Symbolic | complex) Self
__mul__(other: PauliBasisState[OtherQubitT_co, BasisT_co] | PauliQuantumState[OtherQubitT_co, BasisT_co]) PauliQuantumState[QubitT_co | OtherQubitT_co, BasisT_co]

The multiplication operator *.

Multiplication between states is to be interpreted as a tensor product.

Caution

If other is a state, it must be in the same basis and not share any qubits with self.

Parameters:

other – A Coefficient, a PauliBasisState or another PauliQuantumState.

Returns:

If other is a Coefficient, returns a copy of self with all amplitudes multiplied by other. If other is a PauliBasisState, returns a new PauliQuantumState with new basis states being the tensor products between the old basis states and other. If other is another PauliQuantumState, returns a full state-state multiplication with all possible pairs of terms from self and other.

Raises:

ParityOSException – For state multiplication, if self and other are defined in a different basis.

__truediv__(other: Symbolic | complex) Self

The division operator /.

Parameters:

other – The Coefficient by which to divide.

Returns:

Copy of the state with all amplitudes divided by other.

__add__(other: PauliQuantumState[QubitT_co, BasisT_co] | PauliBasisState[QubitT_co, BasisT_co]) Self

The addition operator +.

Caution

other must be in the same basis and be defined on the same qubits as self.

Parameters:

other – A PauliBasisState or another PauliQuantumState.

Returns:

If other is a PauliBasisState, returns a new quantum state with other added to self with amplitude 1. If other is another PauliQuantumState, returns a new state with the union of the basis states of self and other and their amplitudes added.

Raises:

ParityOSException – if self and other are not defined on the same sequence of qubits or are in a different basis.

__sub__(other: PauliQuantumState[QubitT_co, BasisT_co] | PauliBasisState[QubitT_co, BasisT_co]) Self

The subtraction operator -.

Parameters:

other – A PauliBasisState or another PauliQuantumState.

Returns:

-self + other, see __neg__ and __add__.

class parityos.states.pauli_state.PauliBasisStateCounts(bitstring_count_pairs: Iterable[tuple[KeyT, int]] | Mapping[KeyT, int], ordered_qubits: T | Iterable[T] = NOTHING, basis: type[BasisT_co] = parityos.operators.elementary_operator.Z[typing.Never])

Bases: OrderedPauliState[QubitT_co, BasisT_co], HasBitstrings, BasisStateCounts[QubitT_co, PauliBasisState[QubitT_co, BasisT_co]]

A statistical ensemble of basis states (PauliBasisState) in a given Pauli basis as a mapping of bitstrings to measurement counts (integer) as obtained e.g. from multiple evaluation shots on a QPU.

The ensemble is stored as a set of (bitstring, count) pairs and an ordered sequence of qubits.

See PauliBasisState for more information on the mapping of bitstrings to qubits and eigenstates of the Pauli operator.

Caution

The bitstrings and sequence of qubits must be of same length.

Raises:
bitstring_count_pairs: frozenset[tuple[str, int]]

Collection of pairs of basis state bitstrings and their counts.

ordered_qubits: tuple[QubitT_co, ...]

Ordered sequence of the qubits of this ensemble.

basis: type[BasisT_co]

The Pauli basis of this state represented by one of XBasis, YBasis or ZBasis. Defaults to ZBasis.

classmethod from_state_to_count(state_to_count: Mapping[PauliBasisState[QubitT_co, BasisT_co], int])

Create a PauliBasisStateCounts instance from a mapping of basis states to their counts.

Raises:
property bitstrings: Iterator[str]

Iterator of bitstrings.

An iterator that yields strings consisting of binary digits (e.g., “0101”, “1111”).

state_to_count: MappingProxyType

A mapping of basis states (PauliBasisState) to their measurement counts.

bitstring_to_count: dict[str, int]

A mapping of the basis state bitstrings to their measurement counts.

This is the mapping version of bitstring_count_pairs.

flip_qubits(qubits: QubitT_co | Iterable[QubitT_co] | None = None) Self

Flip the state on every qubit in qubits.

For each qubit in qubits the state on this qubit is flipped (0 <-> 1). Qubits in qubits that are not in this state are ignored.

Note

If qubits is None (default), all qubits are flipped.

Parameters:

qubits – Qubits to flip. If None, all qubits are flipped. Defaults to None.

Returns:

Copy of self with state on all qubits in qubits flipped

reorder(target_ordered_qubits: Sequence[QubitT_co] | None = None) Self

Reorder this state’s qubits to the order defined by target_ordered_qubits.

Parameters:

target_ordered_qubits – Target qubit order for bitstring. If None, sorted(self.ordered_qubits) is used. Defaults to None.

Returns:

A copy of self where qubit ordering has been changed to target_ordered_qubits.

Raises:

ParityOSException – If this state’s qubits and qubits in target_ordered_qubits are different up to ordering.

parityos.states.pauli_state.flip_qubits(qubit_bit_pairs: Iterable[tuple[QubitT_co, str]], qubits_to_flip: QubitT_co | Iterable[QubitT_co] | None) str

Flip subset of bits in an iterable of (qubit, bit) pairs.

If qubits_to_flip is None, all bits are flipped. Otherwise, only bits for qubits that appear in qubits_to_flip are flipped.

Note

Only “0” and “1” are flipped, any other input is left unchanged.

Note

Any qubits in qubits_to_flip, that are not also in qubit_bit_pairs are ignored.

Parameters:
  • qubit_bit_pairs – Pairs of qubits and their corresponding single character bit value.

  • qubits_to_flip – Subset of qubits for which bits in qubit_bit_pairs should be flipped.

Returns:

The bitstring with bits flipped if the original bit was one of (“0”, “1”) and its

corresponding qubit is in qubits_to_flip.

parityos.states.pauli_state.to_bitstring(bits: Iterable[bool]) str

Convert boolean bits to bitstring.

True is converted to “1”, False is converted to “0”.

Inverse of to_bits.

Parameters:

bits – Bits to be converted to a bitstring.

Returns: String of “0” and “1” representing the given bits.

parityos.states.pauli_state.to_bits(bitstring: str) tuple[bool, ...]

Convert bitstring to tuple of boolean bits.

“1” is converted to True, “0” is converted to False.

Inverse of to_bitstring.

Parameters:

bitstring – Bitstring to be converted to a tuple of bits.

Returns: Tuple of boolean bits representation the given bitstring.

Raises:

ParityOSException – If the given bitstring contains characters other than “0” or “1”.

parityos.states.pauli_state.evaluate_parity(state: BasisState[QubitT_co], qubits: Iterable[QubitT_co]) Parity

Compute parity of given qubits in a state.

Caution

All passed qubits must be present in the state.

Note

Any qubits in qubits that are not also in state are ignored.

Returns:

Parity of given qubits in this state.

Raises: