qml.pauli.pauli_to_binary

pauli_to_binary(pauli_word, n_qubits=None, wire_map=None, check_is_pauli_word=True)[source]

Converts a Pauli word to the binary vector (symplectic) representation.

This functions follows convention that the first half of binary vector components specify PauliX placements while the last half specify PauliZ placements.

Parameters
  • pauli_word (Union[Identity, PauliX, PauliY, PauliZ, Tensor, Prod, SProd]) – the Pauli word to be converted to binary vector representation

  • n_qubits (int) – number of qubits to specify dimension of binary vector representation

  • wire_map (dict) – dictionary containing all wire labels used in the Pauli word as keys, and unique integer labels as their values

  • check_is_pauli_word (bool) – If True (default) then a check is run to verify that pauli_word is in fact a Pauli word.

Returns

the 2*n_qubits dimensional binary vector representation of the input Pauli word

Return type

array

Raises
  • TypeError – if the input pauli_word is not an instance of Identity, PauliX, PauliY, PauliZ or tensor products thereof

  • ValueError – if n_qubits is less than the number of wires acted on by the Pauli word

Example

If n_qubits and wire_map are both unspecified, the dimensionality of the binary vector will be 2 * len(pauli_word.wires). Regardless of wire labels, the vector components encoding Pauli operations will be read from left-to-right in the tensor product when wire_map is unspecified, e.g.,

>>> pauli_to_binary(qml.X('a') @ qml.Y('b') @ qml.Z('c'))
array([1., 1., 0., 0., 1., 1.])
>>> pauli_to_binary(qml.X('c') @ qml.Y('a') @ qml.Z('b'))
array([1., 1., 0., 0., 1., 1.])

The above cases have the same binary representation since they are equivalent up to a relabelling of the wires. To keep binary vector component enumeration consistent with wire labelling across multiple Pauli words, or define any arbitrary enumeration, one can use keyword argument wire_map to set this enumeration.

>>> wire_map = {'a': 0, 'b': 1, 'c': 2}
>>> pauli_to_binary(qml.X('a') @ qml.Y('b') @ qml.Z('c'), wire_map=wire_map)
array([1., 1., 0., 0., 1., 1.])
>>> pauli_to_binary(qml.X('c') @ qml.Y('a') @ qml.Z('b'), wire_map=wire_map)
array([1., 0., 1., 1., 1., 0.])

Now the two Pauli words are distinct in the binary vector representation, as the vector components are consistently mapped from the wire labels, rather than enumerated left-to-right.

If n_qubits is unspecified, the dimensionality of the vector representation will be inferred from the size of support of the Pauli word,

>>> pauli_to_binary(qml.X(0) @ qml.X(1))
array([1., 1., 0., 0.])
>>> pauli_to_binary(qml.X(0) @ qml.X(5))
array([1., 1., 0., 0.])

Dimensionality higher than twice the support can be specified by n_qubits,

>>> pauli_to_binary(qml.X(0) @ qml.X(1), n_qubits=6)
array([1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
>>> pauli_to_binary(qml.X(0) @ qml.X(5), n_qubits=6)
array([1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

For these Pauli words to have a consistent mapping to vector representation, we once again need to specify a wire_map.

>>> wire_map = {0:0, 1:1, 5:5}
>>> pauli_to_binary(qml.X(0) @ qml.X(1), n_qubits=6, wire_map=wire_map)
array([1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
>>> pauli_to_binary(qml.X(0) @ qml.X(5), n_qubits=6, wire_map=wire_map)
array([1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.])

Note that if n_qubits is unspecified and wire_map is specified, the dimensionality of the vector representation will be inferred from the highest integer in wire_map.values().

>>> wire_map = {0:0, 1:1, 5:5}
>>> pauli_to_binary(qml.X(0) @ qml.X(5),  wire_map=wire_map)
array([1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.])