Skip to content

Commit de115a9

Browse files
committed
Comment addressments and other good things
1 parent 4f05248 commit de115a9

File tree

2 files changed

+73
-27
lines changed

2 files changed

+73
-27
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
build:
33
cmake -B build
44
cmake --build build --parallel
5+
cmake --install build
56
# TODO in general python build should internally trigger cmake, but for now
67
# let's keep cmake lines here as we don't have any python build process yet
78
python -m pip cache purge
@@ -17,7 +18,8 @@ tests:
1718

1819
.PHONY: benchmark
1920
benchmark:
20-
pytest benchmarks -v
21+
pytest -v benchmarks --benchmark-group-by=func --benchmark-sort=fullname \
22+
--benchmark-columns='mean,median,min,max,stddev,iqr,outliers,ops,rounds,iterations'
2123

2224
.PHONY: clean
2325
clean:

benchmarks/test_pauli_string_benchmark.py

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,32 @@
99
import fast_pauli.pypauli.operations as pp
1010

1111
# TODO add a separate benchmark for get_sparse_repr vs compose_sparse_pauli
12+
# TODO control numpy threading in a fixture for fair comparison
1213

1314

1415
@pytest.fixture
1516
def all_strings_for_qubits() -> list[str]:
1617
"""Provide sample strings for testing."""
17-
return lambda q: list(map("".join, it.product("IXYZ", repeat=q))) # type: ignore
18+
19+
def generate_paulis(qubits: int, limit: int = 1_000) -> list[str]:
20+
strings: list[str] = []
21+
for s in it.product("IXYZ", repeat=qubits):
22+
if limit and len(strings) > limit:
23+
break
24+
strings.append("".join(s))
25+
return strings
26+
27+
return generate_paulis # type: ignore
28+
29+
30+
@pytest.fixture(scope="function")
31+
def generate_random_complex(rng_seed: int = 321) -> np.ndarray:
32+
"""Generate random complex numpy array with desired shape."""
33+
rng = np.random.default_rng(rng_seed)
34+
return lambda *shape: rng.random(shape) + 1j * rng.random(shape)
35+
36+
37+
QUBITS_TO_BENCHMARK = [1, 2, 4, 10]
1838

1939

2040
# following two helper functions are going to be removed once we align interfaces:
@@ -31,22 +51,29 @@ def benchmark_dense_conversion_py(paulis: list) -> None:
3151

3252

3353
@pytest.mark.parametrize(
34-
"lang,qubits,pauli_class,bench_func",
54+
"pauli_class,qubits,lang,bench_func",
3555
it.chain(
36-
[("cpp", q, fp.PauliString, benchmark_dense_conversion_cpp) for q in [1, 2, 4]],
37-
[("py", q, pp.PauliString, benchmark_dense_conversion_py) for q in [1, 2, 4]],
56+
[
57+
(fp.PauliString, q, "cpp", benchmark_dense_conversion_cpp)
58+
for q in QUBITS_TO_BENCHMARK
59+
],
60+
[
61+
(pp.PauliString, q, "py", benchmark_dense_conversion_py)
62+
for q in QUBITS_TO_BENCHMARK
63+
],
3864
),
3965
)
4066
def test_dense_conversion_n_qubits( # type: ignore[no-untyped-def]
41-
benchmark, all_strings_for_qubits, lang, qubits, pauli_class, bench_func
67+
benchmark, all_strings_for_qubits, pauli_class, qubits, lang, bench_func
4268
) -> None:
4369
"""Benchmark dense conversion.
4470
4571
Parametrized test case to run the benchmark across
4672
all Pauli strings of given length for given PauliString class.
4773
"""
74+
n_strings_limit = 10 if qubits > 4 else None
4875
prepared_paulis = list(
49-
map(lambda s: pauli_class(s), all_strings_for_qubits(qubits))
76+
map(lambda s: pauli_class(s), all_strings_for_qubits(qubits, n_strings_limit))
5077
)
5178
benchmark(bench_func, paulis=prepared_paulis)
5279

@@ -64,27 +91,35 @@ def benchmark_apply_py(paulis: list, states: list) -> None:
6491

6592

6693
@pytest.mark.parametrize(
67-
"lang,qubits,pauli_class,bench_func",
94+
"pauli_class,qubits,lang,bench_func",
6895
it.chain(
69-
[("cpp", q, fp.PauliString, benchmark_apply_cpp) for q in [1, 2, 4]],
70-
[("py", q, pp.PauliString, benchmark_apply_py) for q in [1, 2, 4]],
96+
[(fp.PauliString, q, "cpp", benchmark_apply_cpp) for q in QUBITS_TO_BENCHMARK],
97+
[(pp.PauliString, q, "py", benchmark_apply_py) for q in QUBITS_TO_BENCHMARK],
7198
),
7299
)
73100
def test_apply_n_qubits( # type: ignore[no-untyped-def]
74-
benchmark, all_strings_for_qubits, lang, qubits, pauli_class, bench_func
101+
benchmark,
102+
all_strings_for_qubits,
103+
generate_random_complex,
104+
pauli_class,
105+
qubits,
106+
lang,
107+
bench_func,
75108
) -> None:
76109
"""Benchmark PauliString multiplication with provided state vector.
77110
78111
Parametrized test case to run the benchmark across
79112
all Pauli strings of given length for given PauliString class.
80113
"""
81-
rng = np.random.default_rng(321)
82-
dim = 1 << qubits
114+
n_dims = 1 << qubits
115+
n_strings_limit = 10 if qubits > 4 else None
83116

84117
prepared_paulis = list(
85-
map(lambda s: pauli_class(s), all_strings_for_qubits(qubits))
118+
map(lambda s: pauli_class(s), all_strings_for_qubits(qubits, n_strings_limit))
86119
)
87-
prepared_states = [rng.random(dim) for _ in range(len(prepared_paulis))]
120+
prepared_states = [
121+
generate_random_complex(n_dims) for _ in range(len(prepared_paulis))
122+
]
88123

89124
benchmark(bench_func, paulis=prepared_paulis, states=prepared_states)
90125

@@ -102,38 +137,47 @@ def benchmark_apply_batch_py(paulis: list, states: list) -> None:
102137

103138

104139
@pytest.mark.parametrize(
105-
"lang,qubits,states,pauli_class,bench_func",
140+
"pauli_class,qubits,states,lang,bench_func",
106141
it.chain(
107142
[
108-
("cpp", q, n, fp.PauliString, benchmark_apply_batch_cpp)
109-
for q in [1, 2, 4]
143+
(fp.PauliString, q, n, "cpp", benchmark_apply_batch_cpp)
144+
for q in QUBITS_TO_BENCHMARK
110145
for n in [16, 128]
111146
],
112147
[
113-
("py", q, n, pp.PauliString, benchmark_apply_batch_py)
114-
for q in [1, 2, 4]
148+
(pp.PauliString, q, n, "py", benchmark_apply_batch_py)
149+
for q in QUBITS_TO_BENCHMARK
115150
for n in [16, 128]
116151
],
117152
),
118153
)
119-
def test_apply_batch_n_qubits( # type: ignore[no-untyped-def]
120-
benchmark, all_strings_for_qubits, lang, qubits, states, pauli_class, bench_func
154+
def test_apply_batch_n_qubits_n_states( # type: ignore[no-untyped-def]
155+
benchmark,
156+
all_strings_for_qubits,
157+
generate_random_complex,
158+
pauli_class,
159+
qubits,
160+
states,
161+
lang,
162+
bench_func,
121163
) -> None:
122164
"""Benchmark PauliString multiplication with provided set of state vectors.
123165
124166
Parametrized test case to run the benchmark across
125167
all Pauli strings of given length for given PauliString class.
126168
"""
127-
rng = np.random.default_rng(321)
128-
dim = 1 << qubits
169+
n_dims = 1 << qubits
170+
n_strings_limit = 10 if qubits > 4 else None
129171

130172
prepared_paulis = list(
131-
map(lambda s: pauli_class(s), all_strings_for_qubits(qubits))
173+
map(lambda s: pauli_class(s), all_strings_for_qubits(qubits, n_strings_limit))
132174
)
133-
prepared_states = [rng.random((dim, states)) for _ in range(len(prepared_paulis))]
175+
prepared_states = [
176+
generate_random_complex(n_dims, states) for _ in range(len(prepared_paulis))
177+
]
134178

135179
benchmark(bench_func, paulis=prepared_paulis, states=prepared_states)
136180

137181

138182
if __name__ == "__main__":
139-
pytest.main()
183+
pytest.main([__file__])

0 commit comments

Comments
 (0)