From ee6ea5317a98070979fa3759049a44d839af7d60 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Thu, 7 Nov 2024 11:23:11 -0500 Subject: [PATCH 1/2] [bug/helpers_type] Fixing typo in fast-pauli helpers calcutate --> calculate --- docs/cpp_api.rst | 15 ++++- docs/python_api.rst | 14 +++-- fast_pauli/cpp/include/__pauli_helpers.hpp | 18 +++--- fast_pauli/cpp/src/fast_pauli.cpp | 63 +++++++++++++++++++-- fast_pauli/cpp/tests/test_pauli_helpers.cpp | 6 +- 5 files changed, 93 insertions(+), 23 deletions(-) diff --git a/docs/cpp_api.rst b/docs/cpp_api.rst index 3212040..55895d5 100644 --- a/docs/cpp_api.rst +++ b/docs/cpp_api.rst @@ -1,8 +1,6 @@ C++ API ======= -.. toctree:: - :maxdepth: 2 Pauli ----- @@ -27,4 +25,15 @@ SummedPauliOp ------------- .. doxygenstruct:: fast_pauli::SummedPauliOp :project: fast_pauli - :members: \ No newline at end of file + :members: + +Helpers +------- +.. doxygenfunction:: fast_pauli::get_nontrivial_paulis + :project: fast_pauli +.. doxygenfunction:: fast_pauli::calculate_pauli_strings + :project: fast_pauli +.. doxygenfunction:: fast_pauli::calculate_pauli_strings_max_weight + :project: fast_pauli +.. doxygenfunction:: fast_pauli::get_sparse_repr + :project: fast_pauli diff --git a/docs/python_api.rst b/docs/python_api.rst index 0642e0c..71cd7d9 100644 --- a/docs/python_api.rst +++ b/docs/python_api.rst @@ -2,9 +2,6 @@ Python API ========== -.. automodule:: fast_pauli - - Pauli ----- @@ -33,4 +30,13 @@ SummedPauliOp .. autoclass:: fast_pauli.SummedPauliOp :members: - :special-members: \ No newline at end of file + :special-members: + + +Helpers +------- + +.. autofunction:: fast_pauli.helpers.calculate_pauli_strings +.. autofunction:: fast_pauli.helpers.calculate_pauli_strings_max_weight +.. autofunction:: fast_pauli.helpers.pauli_string_sparse_repr +.. autofunction:: fast_pauli.helpers.get_nontrivial_paulis diff --git a/fast_pauli/cpp/include/__pauli_helpers.hpp b/fast_pauli/cpp/include/__pauli_helpers.hpp index 5240abf..64718ce 100644 --- a/fast_pauli/cpp/include/__pauli_helpers.hpp +++ b/fast_pauli/cpp/include/__pauli_helpers.hpp @@ -30,7 +30,7 @@ namespace fast_pauli /** * @brief Get the nontrivial sets of pauli matrices given a weight. * - * @param weight + * @param weight The Pauli weight to get the nontrivial paulis for. * @return std::vector */ std::vector get_nontrivial_paulis(size_t const weight) @@ -62,8 +62,8 @@ std::vector get_nontrivial_paulis(size_t const weight) /** * @brief Get all the combinations of k indices for a given array of size n. * - * @param n - * @param k + * @param n The size of the array to get the combinations of. + * @param k The number of indices to choose. * @return std::vector> */ std::vector> idx_combinations(size_t const n, size_t const k) @@ -92,11 +92,11 @@ std::vector> idx_combinations(size_t const n, size_t const k * @brief Calculate all possible PauliStrings for a given number of qubits and * weight and return them in lexicographical order. * - * @param n_qubits - * @param weight + * @param n_qubits The number of qubits. + * @param weight The Pauli weight. * @return std::vector */ -std::vector calcutate_pauli_strings(size_t const n_qubits, size_t const weight) +std::vector calculate_pauli_strings(size_t const n_qubits, size_t const weight) { // base case if (weight == 0) @@ -137,8 +137,8 @@ std::vector calcutate_pauli_strings(size_t const n_qubits, size_t c * @brief Calculate all possible PauliStrings for a given number of qubits and * all weights less than or equal to a given weight. * - * @param n_qubits - * @param weight + * @param n_qubits The number of qubits. + * @param weight The Pauli weight. * @return std::vector */ std::vector calculate_pauli_strings_max_weight(size_t n_qubits, size_t weight) @@ -146,7 +146,7 @@ std::vector calculate_pauli_strings_max_weight(size_t n_qubits, siz std::vector result; for (size_t i = 0; i <= weight; ++i) { - auto ps = calcutate_pauli_strings(n_qubits, i); + auto ps = calculate_pauli_strings(n_qubits, i); result.insert(result.end(), ps.begin(), ps.end()); } return result; diff --git a/fast_pauli/cpp/src/fast_pauli.cpp b/fast_pauli/cpp/src/fast_pauli.cpp index f5a82d0..f6bd6b0 100644 --- a/fast_pauli/cpp/src/fast_pauli.cpp +++ b/fast_pauli/cpp/src/fast_pauli.cpp @@ -1135,9 +1135,64 @@ SummedPauliOp // Helpers // auto helpers_m = m.def_submodule("helpers"); - helpers_m.def("get_nontrivial_paulis", &fp::get_nontrivial_paulis, "weight"_a); - helpers_m.def("calcutate_pauli_strings", &fp::calcutate_pauli_strings, "n_qubits"_a, "weight"_a); + helpers_m.def("get_nontrivial_paulis", &fp::get_nontrivial_paulis, "weight"_a, + R"%(Get all nontrivial Pauli strings up to a given weight. + +Parameters +---------- +weight : int + Maximum weight of Pauli strings to return + +Returns +------- +List[str] + List of PauliStrings as strings +)%"); + + helpers_m.def("calculate_pauli_strings", &fp::calculate_pauli_strings, "n_qubits"_a, "weight"_a, + R"%(Calculate all Pauli strings for a given weight. + +Parameters +---------- +n_qubits : int + Number of qubits +weight : int + Weight of Pauli strings to return + +Returns +------- +List[PauliString] + List of PauliStrings +)%"); + helpers_m.def("calculate_pauli_strings_max_weight", &fp::calculate_pauli_strings_max_weight, "n_qubits"_a, - "weight"_a); - helpers_m.def("pauli_string_sparse_repr", &fp::get_sparse_repr, "paulis"_a); + "weight"_a, + R"%(Calculate all Pauli strings up to and including a given weight. + +Parameters +---------- +n_qubits : int + Number of qubits +weight : int + Maximum weight of Pauli strings to return + +Returns +------- +List[PauliString] + List of PauliStrings +)%"); + + helpers_m.def("pauli_string_sparse_repr", &fp::get_sparse_repr, "paulis"_a, + R"%(Get a sparse representation of a list of Pauli strings. + +Parameters +---------- +paulis : List[PauliString] + List of PauliStrings + +Returns +------- +List[Tuple[int, int]] + List of tuples representing the Pauli string in a sparse format +)%"); } \ No newline at end of file diff --git a/fast_pauli/cpp/tests/test_pauli_helpers.cpp b/fast_pauli/cpp/tests/test_pauli_helpers.cpp index bd75ce5..3f9eae3 100644 --- a/fast_pauli/cpp/tests/test_pauli_helpers.cpp +++ b/fast_pauli/cpp/tests/test_pauli_helpers.cpp @@ -110,13 +110,13 @@ TEST_CASE("idx combinations") TEST_CASE("calculate pauli strings") { { - auto res = calcutate_pauli_strings(4, 0); + auto res = calculate_pauli_strings(4, 0); CHECK(res.size() == 1); CHECK(res[0] == PauliString("IIII")); } { - auto res = calcutate_pauli_strings(2, 1); + auto res = calculate_pauli_strings(2, 1); CHECK(res.size() == 6); CHECK(res[0] == PauliString("XI")); CHECK(res[1] == PauliString("IX")); @@ -127,7 +127,7 @@ TEST_CASE("calculate pauli strings") } { - auto res = calcutate_pauli_strings(4, 2); + auto res = calculate_pauli_strings(4, 2); CHECK(res.size() == 54); CHECK(res[0] == PauliString("XXII")); CHECK(res[1] == PauliString("XIXI")); From 58469814fa7d15fadd24912650924f678f8134c0 Mon Sep 17 00:00:00 2001 From: jamesETsmith Date: Thu, 7 Nov 2024 11:52:32 -0500 Subject: [PATCH 2/2] [bug/helpers_typo] Adding tests for the helpers that we expose to python --- tests/fast_pauli/test_helpers.py | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 tests/fast_pauli/test_helpers.py diff --git a/tests/fast_pauli/test_helpers.py b/tests/fast_pauli/test_helpers.py new file mode 100644 index 0000000..6632a3c --- /dev/null +++ b/tests/fast_pauli/test_helpers.py @@ -0,0 +1,81 @@ +"""Test the helpers module.""" + +import itertools + +import pytest + +import fast_pauli as fp + + +def calculate_trusted_pauli_strings(n_qubits: int, weight: int) -> list[str]: + """Calculate all possible Pauli strings for a given number of qubits and weight. + + Parameters + ---------- + n_qubits : int + The number of qubits. + weight : int + The Pauli weight. + + Returns + ------- + list[str] + All possible Pauli strings for the given number of qubits and weight. + """ + strings = [] + nontrivial_matrix_elements = list(itertools.product(["X", "Y", "Z"], repeat=weight)) + for indices in itertools.combinations(range(n_qubits), weight): # n(n-1)/2 terms + for elements in nontrivial_matrix_elements: + pauli_string = [] + for qbit in range(n_qubits): + for el_position, i in enumerate(indices): + if i == qbit: + pauli_string.append(elements[el_position]) + break + else: + pauli_string.append("I") + strings.append("".join(pauli_string)) + return strings + + +@pytest.mark.parametrize("weight", [0, 1, 2, 3]) +def test_get_nontrivial_paulis(weight: int) -> None: + """Test the get_nontrivial_paulis function.""" + res = fp.helpers.get_nontrivial_paulis(weight) + trusted = [ + "".join(x) for x in itertools.product("XYZ", repeat=weight) if len(x) > 0 + ] + assert len(res) == len(trusted) + assert set(res) == set(trusted) + + +@pytest.mark.parametrize("n_qubits", [1, 2, 3, 4], ids=lambda x: f"nq={x}") +@pytest.mark.parametrize("weight", [1, 2, 3], ids=lambda x: f"w={x}") +def test_calculate_pauli_strings(n_qubits: int, weight: int) -> None: + """Test the calculate_pauli_strings function.""" + if n_qubits < weight: + pytest.skip("n_qubits must be greater than or equal to weight") + + res = [str(x) for x in fp.helpers.calculate_pauli_strings(n_qubits, weight)] + trusted = calculate_trusted_pauli_strings(n_qubits, weight) + + assert len(res) == len(trusted) + assert set(res) == set(trusted) + + +@pytest.mark.parametrize("n_qubits", [1, 2, 3, 4], ids=lambda x: f"nq={x}") +@pytest.mark.parametrize("weight", [1, 2, 3], ids=lambda x: f"w={x}") +def test_calculate_pauli_strings_max_weight(n_qubits: int, weight: int) -> None: + """Test the calculate_pauli_strings_max_weight function.""" + if n_qubits < weight: + pytest.skip("n_qubits must be greater than or equal to weight") + + res = [ + str(x) for x in fp.helpers.calculate_pauli_strings_max_weight(n_qubits, weight) + ] + trusted = ["I" * n_qubits] + for i in range(1, weight + 1): + trusted.extend(calculate_trusted_pauli_strings(n_qubits, i)) + + assert len(res) == len(trusted) + assert set(res) == set(trusted)