From c69ce50b65679d265a1cf8ee0d57adef2edbe5ac Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 25 Oct 2024 16:12:03 +0800 Subject: [PATCH 1/4] fix rounding --- .../core/quri_parts/core/sampling/__init__.py | 6 ++++- .../core/sampling/test_create_sampler.py | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/core/quri_parts/core/sampling/__init__.py b/packages/core/quri_parts/core/sampling/__init__.py index 7cd897b7..eb18fb47 100644 --- a/packages/core/quri_parts/core/sampling/__init__.py +++ b/packages/core/quri_parts/core/sampling/__init__.py @@ -438,7 +438,11 @@ def sample_from_probibility_distribution( ) -> MeasurementCounts: """Sample from a probibility distribution.""" rng = np.random.default_rng() - counts = rng.multinomial(n_sample, np.round(probibility_distribution, 12)) + rounded_prob = np.round(probibility_distribution, 12) + norm = np.sum(rounded_prob) + assert np.isclose(norm, 1.0), "Probabilty does not sum to 1.0" + rounded_prob = rounded_prob / norm + counts = rng.multinomial(n_sample, rounded_prob) return Counter(dict(((i, count) for i, count in enumerate(counts) if count > 0))) diff --git a/packages/core/tests/core/sampling/test_create_sampler.py b/packages/core/tests/core/sampling/test_create_sampler.py index 52071867..2eeff98a 100644 --- a/packages/core/tests/core/sampling/test_create_sampler.py +++ b/packages/core/tests/core/sampling/test_create_sampler.py @@ -33,6 +33,7 @@ create_parametric_sampler_from_sampler, create_parametric_state_sampler_from_state_sampler, create_sampler_from_sampling_backend, + sample_from_probibility_distribution, ) from quri_parts.core.state import ( CircuitQuantumState, @@ -43,6 +44,29 @@ ) +def test_sample_from_probibility_distribution() -> None: + norm = 1.0 + p1 = 0.4 + prob = np.array([p1, norm - p1]) + cnts = sample_from_probibility_distribution(1000, prob) + assert sum(list(cnts.values())) == 1000 + + norm = 1.000000000002 + p1 = 0.4 + prob = np.array([p1, norm - p1]) + cnts = sample_from_probibility_distribution(1000, prob) + assert sum(list(cnts.values())) == 1000 + with pytest.raises(): + rng = np.random.default_rng() + rng.multinomial(1000, prob) + + norm = 1.001 + p1 = 0.4 + prob = np.array([p1, norm - p1]) + with pytest.raises(AssertionError, match="Probabilty does not sum to 1.0"): + cnts = sample_from_probibility_distribution(1000, prob) + + def fake_sampler(circuit: NonParametricQuantumCircuit, shot: int) -> MeasurementCounts: cnt = 0.0 for g in circuit.gates: From aaa27fb0c9c6726f63dedf6fb03e0c76e69b8e96 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 25 Oct 2024 16:20:47 +0800 Subject: [PATCH 2/4] fix missing arg --- packages/core/tests/core/sampling/test_create_sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/tests/core/sampling/test_create_sampler.py b/packages/core/tests/core/sampling/test_create_sampler.py index 2eeff98a..a67289b0 100644 --- a/packages/core/tests/core/sampling/test_create_sampler.py +++ b/packages/core/tests/core/sampling/test_create_sampler.py @@ -56,7 +56,7 @@ def test_sample_from_probibility_distribution() -> None: prob = np.array([p1, norm - p1]) cnts = sample_from_probibility_distribution(1000, prob) assert sum(list(cnts.values())) == 1000 - with pytest.raises(): + with pytest.raises(AssertionError, match="Probabilty does not sum to 1.0"): rng = np.random.default_rng() rng.multinomial(1000, prob) From 4a55e7b8d94aed9b4cc3a908478e8209db683756 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 25 Oct 2024 16:40:55 +0800 Subject: [PATCH 3/4] fix test --- packages/core/tests/core/sampling/test_create_sampler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/core/tests/core/sampling/test_create_sampler.py b/packages/core/tests/core/sampling/test_create_sampler.py index a67289b0..febf237a 100644 --- a/packages/core/tests/core/sampling/test_create_sampler.py +++ b/packages/core/tests/core/sampling/test_create_sampler.py @@ -56,9 +56,6 @@ def test_sample_from_probibility_distribution() -> None: prob = np.array([p1, norm - p1]) cnts = sample_from_probibility_distribution(1000, prob) assert sum(list(cnts.values())) == 1000 - with pytest.raises(AssertionError, match="Probabilty does not sum to 1.0"): - rng = np.random.default_rng() - rng.multinomial(1000, prob) norm = 1.001 p1 = 0.4 From e590946b32e1bdd399b10f3d3bfc4c3baacc7ebf Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 25 Oct 2024 17:15:51 +0800 Subject: [PATCH 4/4] non-trivial test --- .../core/tests/core/sampling/test_create_sampler.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/core/tests/core/sampling/test_create_sampler.py b/packages/core/tests/core/sampling/test_create_sampler.py index febf237a..46e66939 100644 --- a/packages/core/tests/core/sampling/test_create_sampler.py +++ b/packages/core/tests/core/sampling/test_create_sampler.py @@ -63,6 +63,19 @@ def test_sample_from_probibility_distribution() -> None: with pytest.raises(AssertionError, match="Probabilty does not sum to 1.0"): cnts = sample_from_probibility_distribution(1000, prob) + # Potentially dangerous case: large amount of small probabilities (p < 1e-12) + # When they are rounded away, sum of the rest of the probabilities slightly > 1. + n = 2**12 + n_small = 2000 + small_prob = -np.ones(n_small) * 1e-14 + big_prob = np.ones(n - n_small) * (1 - np.sum(small_prob)) / (n - n_small) + prob = np.hstack([big_prob, small_prob]) + with pytest.raises(ValueError): + rng = np.random.default_rng() + rng.multinomial(1000, prob.round(12)) + cnts = sample_from_probibility_distribution(1000, prob) + assert sum(list(cnts.values())) == 1000 + def fake_sampler(circuit: NonParametricQuantumCircuit, shot: int) -> MeasurementCounts: cnt = 0.0