qml.grouping.pauli_to_binary

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

Converts a Pauli word to the binary vector 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]) – 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

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.PauliX('a') @ qml.PauliY('b') @ qml.PauliZ('c'))
array([1., 1., 0., 0., 1., 1.])
>>> pauli_to_binary(qml.PauliX('c') @ qml.PauliY('a') @ qml.PauliZ('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.PauliX('a') @ qml.PauliY('b') @ qml.PauliZ('c'), wire_map=wire_map)
array([1., 1., 0., 0., 1., 1.])
>>> pauli_to_binary(qml.PauliX('c') @ qml.PauliY('a') @ qml.PauliZ('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.PauliX(0) @ qml.PauliX(1))
array([1., 1., 0., 0.])
>>> pauli_to_binary(qml.PauliX(0) @ qml.PauliX(5))
array([1., 1., 0., 0.])

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

>>> pauli_to_binary(qml.PauliX(0) @ qml.PauliX(1), n_qubits=6)
array([1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
>>> pauli_to_binary(qml.PauliX(0) @ qml.PauliX(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.PauliX(0) @ qml.PauliX(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.PauliX(0) @ qml.PauliX(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.PauliX(0) @ qml.PauliX(5),  wire_map=wire_map)
array([1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.])