def test_group_observables_exception(self): """Tests that the ``group_observables`` function raises an exception if the lengths of coefficients and observables do not agree.""" observables = [Identity(0), PauliX(1)] coefficients = [0.5] with pytest.raises(IndexError, match="must be the same length"): group_observables(observables, coefficients)
def test_return_list_coefficients(self): """Tests that if the coefficients are given as a list, the groups are likewise lists.""" obs = [qml.PauliX(0), qml.PauliX(1)] coeffs = [1.0, 2.0] _, grouped_coeffs = group_observables(obs, coeffs) assert isinstance(grouped_coeffs[0], list)
def test_commuting_partitioning(self, observables, com_partitions_sol): com_partitions = group_observables(observables, grouping_type="commuting") # assert the correct number of partitions: n_partitions = len(com_partitions_sol) assert len(com_partitions) == n_partitions # assert each partition is of the correct length: assert all( [len(com_partitions[i]) == len(com_partitions_sol[i]) for i in range(n_partitions)] ) # assert each partition contains the same Pauli terms as the solution partition: for i, partition in enumerate(com_partitions): for j, pauli in enumerate(partition): assert are_identical_pauli_words(pauli, com_partitions_sol[i][j])
def optimize_measurements(observables, coefficients=None, grouping="qwc", colouring_method="rlf"): """Partitions then diagonalizes a list of Pauli words, facilitating simultaneous measurement of all observables within a partition. The input list of observables are partitioned into mutually qubit-wise commuting (QWC) or mutually commuting partitions by approximately solving minimum clique cover on a graph where each observable represents a vertex. The unitaries which diagonalize the partitions are then found. See `arXiv:1907.03358 <https://arxiv.org/abs/1907.03358>`_ and `arXiv:1907.09386 <https://arxiv.org/abs/1907.09386>`_ for technical details of the QWC and fully-commuting measurement-partitioning approaches respectively. Args: observables (list[Observable]): a list of Pauli words (Pauli operation instances and Tensor instances thereof) coefficients (list[float]): a list of float coefficients, for instance the weights of the Pauli words comprising a Hamiltonian grouping (str): the binary symmetric relation to use for operator partitioning colouring_method (str): the graph-colouring heuristic to use in obtaining the operator partitions Returns: tuple: * list[callable]: a list of the post-rotation templates, one for each partition * list[list[Observable]]: A list of the obtained groupings. Each grouping is itself a list of Pauli words diagonal in the measurement basis. * list[list[float]]: A list of coefficient groupings. Each coefficient grouping is itself a list of the partitions corresponding coefficients. Only output if coefficients are specified. **Example** >>> obs = [qml.PauliY(0), qml.PauliX(0) @ qml.PauliX(1), qml.PauliZ(1)] >>> coeffs = [1.43, 4.21, 0.97] >>> rotations, groupings, grouped_coeffs = optimize_measurements(obs, coeffs, 'qwc', 'rlf') >>> print(rotations) [[RY(-1.5707963267948966, wires=[0]), RY(-1.5707963267948966, wires=[1])], [RX(1.5707963267948966, wires=[0])]] >>> print(groupings) [[PauliZ(wires=[0]) @ PauliZ(wires=[1])], [PauliZ(wires=[0]), PauliZ(wires=[1])]] >>> print(grouped_coeffs) [[4.21], [1.43, 0.97]] """ if coefficients is None: grouped_obs = group_observables(observables, grouping_type=grouping, method=colouring_method) else: grouped_obs, grouped_coeffs = group_observables( observables, coefficients, grouping_type=grouping, method=colouring_method) if grouping.lower() == "qwc": ( post_rotations, diagonalized_groupings, ) = diagonalize_qwc_groupings(grouped_obs) else: raise NotImplementedError( f"Measurement reduction by '{grouping.lower()}' grouping not implemented." ) if coefficients is None: return post_rotations, diagonalized_groupings return post_rotations, diagonalized_groupings, grouped_coeffs