def _pauli_group_generator(n_qubits, wire_map=None): """Generator function for the Pauli group. This function is called by ``pauli_group`` in order to actually generate the group elements. They are split so that the outer function can handle input validation, while this generator is responsible for performing the actual operations. Args: n_qubits (int): The number of qubits for which to create the group. wire_map (dict[Union[str, int], int]): dictionary containing all wire labels used in the Pauli word as keys, and unique integer labels as their values. If no wire map is provided, wires will be labeled by consecutive integers between :math:`0` and ``n_qubits``. Returns: .Operation: The next Pauli word in the group. """ element_idx = 0 if not wire_map: wire_map = {wire_idx: wire_idx for wire_idx in range(n_qubits)} while element_idx < 4**n_qubits: binary_string = format(element_idx, f"#0{2*n_qubits+2}b")[2:] binary_vector = [float(b) for b in binary_string] yield binary_to_pauli(binary_vector, wire_map=wire_map) element_idx += 1
def test_binary_to_pauli_with_wire_map(self, vec, op): """Test conversion of Pauli in binary vector representation to operator form when ``wire_map`` is specified.""" wire_map = {"alice": 0, "bob": 1, "ancilla": 2} assert are_identical_pauli_words( binary_to_pauli(vec, wire_map=wire_map), op)
def pauli_mult(pauli_1, pauli_2, wire_map=None): """Multiply two Pauli words together and return the product as a Pauli word. Two Pauli operations can be multiplied together by taking the additive OR of their binary symplectic representations. Args: pauli_1 (.Operation): A Pauli word. pauli_2 (.Operation): A Pauli word to multiply with the first one. wire_map (dict[Union[str, int], int]): dictionary containing all wire labels used in the Pauli word as keys, and unique integer labels as their values. If no wire map is provided, the map will be constructed from the set of wires acted on by the input Pauli words. Returns: .Operation: The product of pauli_1 and pauli_2 as a Pauli word (ignoring the global phase). **Example** This function enables multiplication of Pauli group elements at the level of Pauli words, rather than matrices. For example, >>> from pennylane.grouping import pauli_mult >>> pauli_1 = qml.PauliX(0) @ qml.PauliZ(1) >>> pauli_2 = qml.PauliY(0) @ qml.PauliZ(1) >>> product = pauli_mult(pauli_1, pauli_2) >>> print(product) PauliZ(wires=[0]) """ if wire_map is None: wire_map = _wire_map_from_pauli_pair(pauli_1, pauli_2) # Check if pauli_1 and pauli_2 are the same; if so, the result is the Identity if are_identical_pauli_words(pauli_1, pauli_2): first_wire = list(pauli_1.wires)[0] return Identity(first_wire) # Compute binary symplectic representations pauli_1_binary = pauli_to_binary(pauli_1, wire_map=wire_map) pauli_2_binary = pauli_to_binary(pauli_2, wire_map=wire_map) bin_symp_1 = np.array([int(x) for x in pauli_1_binary]) bin_symp_2 = np.array([int(x) for x in pauli_2_binary]) # Shorthand for bitwise XOR of numpy arrays pauli_product = bin_symp_1 ^ bin_symp_2 return binary_to_pauli(pauli_product, wire_map=wire_map)
def colour_pauli_graph(self): """ Runs the graph colouring heuristic algorithm to obtain the partitioned Pauli words. Returns: list[list[Observable]]: a list of the obtained groupings. Each grouping is itself a list of Pauli word ``Observable`` instances """ if self.adj_matrix is None: self.adj_matrix = self.complement_adj_matrix_for_operator() coloured_binary_paulis = self.graph_colourer(self.binary_observables, self.adj_matrix) self.grouped_paulis = [ [binary_to_pauli(pauli_word, wire_map=self._wire_map) for pauli_word in grouping] for grouping in coloured_binary_paulis.values() ] return self.grouped_paulis
def test_binary_to_pauli_no_wire_map(self, vec, op): """Test conversion of Pauli in binary vector representation to operator form when no ``wire_map`` is specified.""" assert are_identical_pauli_words(binary_to_pauli(vec), op)