Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stim.DetectorErrorModel.to_simple_error_lists #744

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions doc/python_api_reference_vDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
- [`stim.DetectorErrorModel.rounded`](#stim.DetectorErrorModel.rounded)
- [`stim.DetectorErrorModel.shortest_graphlike_error`](#stim.DetectorErrorModel.shortest_graphlike_error)
- [`stim.DetectorErrorModel.to_file`](#stim.DetectorErrorModel.to_file)
- [`stim.DetectorErrorModel.to_simple_error_lists`](#stim.DetectorErrorModel.to_simple_error_lists)
- [`stim.ExplainedError`](#stim.ExplainedError)
- [`stim.ExplainedError.__init__`](#stim.ExplainedError.__init__)
- [`stim.ExplainedError.circuit_error_locations`](#stim.ExplainedError.circuit_error_locations)
Expand Down Expand Up @@ -6581,6 +6582,68 @@ def to_file(
"""
```

<a name="stim.DetectorErrorModel.to_simple_error_lists"></a>
```python
# stim.DetectorErrorModel.to_simple_error_lists

# (in class stim.DetectorErrorModel)
def to_simple_error_lists(
self,
) -> Tuple['np.ndarray[float]', List[Set[int]], List[Set[int]]]:
"""Simplifies the model into lists of chances, detection sets, and obs flips sets.

Note that this summary doesn't include information about loops, coordinates, or
suggested decompositions. Also note that this method will merge all errors with
identical symptoms, by Bernoulli summing their probabilities, and will sort the
errors. For example, the following two detector error models will give identical
results:

# dem 1
error(0.01) D1 D2 ^ D3 D4
error(0.125) D1
error(0.25) D1
detector(2, 3, 5) D1

vs

# dem 2
error(0.3125) D1
error(0.01) D1 D2 D3 D4

Returns:
A tuple of sequences (probabilities, dets, obs).

`probabilities` will be a numpy array with dtype=np.float64 and
shape=(num_errors,).

`dets` will be a list of detection event sets. Each detection
event set is a python set containing the indices of detectors
flipped by the error.

`obs` will be a list of observable flip sets. Each observable
flip set is a python set containing the indices of detectors
flipped by the error.

These sequences are paired up by index. They will have the same length, and
the combination of probabilities[k], dets[k], and obs[k] form a single
error.

Examples:
>>> import stim
>>> dem = stim.DetectorErrorModel('''
... error(0.25) D0 D1
... error(0.125) D0 D2 L1 L5
... ''')
>>> probs, dets, obs = dem.to_simple_error_lists()
>>> probs
array([0.25 , 0.125])
>>> dets
[{0, 1}, {0, 2}]
>>> obs
[set(), {1, 5}]
"""
```

<a name="stim.ExplainedError"></a>
```python
# stim.ExplainedError
Expand Down
55 changes: 55 additions & 0 deletions doc/stim.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5069,6 +5069,61 @@ class DetectorErrorModel:
>>> contents
'error(0.25) D2 D3\n'
"""
def to_simple_error_lists(
self,
) -> Tuple['np.ndarray[float]', List[Set[int]], List[Set[int]]]:
"""Simplifies the model into lists of chances, detection sets, and obs flips sets.

Note that this summary doesn't include information about loops, coordinates, or
suggested decompositions. Also note that this method will merge all errors with
identical symptoms, by Bernoulli summing their probabilities, and will sort the
errors. For example, the following two detector error models will give identical
results:

# dem 1
error(0.01) D1 D2 ^ D3 D4
error(0.125) D1
error(0.25) D1
detector(2, 3, 5) D1

vs

# dem 2
error(0.3125) D1
error(0.01) D1 D2 D3 D4

Returns:
A tuple of sequences (probabilities, dets, obs).

`probabilities` will be a numpy array with dtype=np.float64 and
shape=(num_errors,).

`dets` will be a list of detection event sets. Each detection
event set is a python set containing the indices of detectors
flipped by the error.

`obs` will be a list of observable flip sets. Each observable
flip set is a python set containing the indices of detectors
flipped by the error.

These sequences are paired up by index. They will have the same length, and
the combination of probabilities[k], dets[k], and obs[k] form a single
error.

Examples:
>>> import stim
>>> dem = stim.DetectorErrorModel('''
... error(0.25) D0 D1
... error(0.125) D0 D2 L1 L5
... ''')
>>> probs, dets, obs = dem.to_simple_error_lists()
>>> probs
array([0.25 , 0.125])
>>> dets
[{0, 1}, {0, 2}]
>>> obs
[set(), {1, 5}]
"""
class ExplainedError:
"""Describes the location of an error mechanism from a stim circuit.
"""
Expand Down
1 change: 1 addition & 0 deletions file_lists/source_files_no_main
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ src/stim/util_bot/error_decomp.cc
src/stim/util_top/circuit_inverse_unitary.cc
src/stim/util_top/circuit_to_detecting_regions.cc
src/stim/util_top/circuit_vs_amplitudes.cc
src/stim/util_top/dem_to_matrix.cc
src/stim/util_top/export_crumble_url.cc
src/stim/util_top/export_qasm.cc
src/stim/util_top/export_quirk_url.cc
Expand Down
1 change: 1 addition & 0 deletions file_lists/test_files
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ src/stim/util_top/circuit_inverse_unitary.test.cc
src/stim/util_top/circuit_to_detecting_regions.test.cc
src/stim/util_top/circuit_vs_amplitudes.test.cc
src/stim/util_top/circuit_vs_tableau.test.cc
src/stim/util_top/dem_to_matrix.test.cc
src/stim/util_top/export_crumble_url.test.cc
src/stim/util_top/export_qasm.test.cc
src/stim/util_top/export_quirk_url.test.cc
Expand Down
55 changes: 55 additions & 0 deletions glue/python/src/stim/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5069,6 +5069,61 @@ class DetectorErrorModel:
>>> contents
'error(0.25) D2 D3\n'
"""
def to_simple_error_lists(
self,
) -> Tuple['np.ndarray[float]', List[Set[int]], List[Set[int]]]:
"""Simplifies the model into lists of chances, detection sets, and obs flips sets.

Note that this summary doesn't include information about loops, coordinates, or
suggested decompositions. Also note that this method will merge all errors with
identical symptoms, by Bernoulli summing their probabilities, and will sort the
errors. For example, the following two detector error models will give identical
results:

# dem 1
error(0.01) D1 D2 ^ D3 D4
error(0.125) D1
error(0.25) D1
detector(2, 3, 5) D1

vs

# dem 2
error(0.3125) D1
error(0.01) D1 D2 D3 D4

Returns:
A tuple of sequences (probabilities, dets, obs).

`probabilities` will be a numpy array with dtype=np.float64 and
shape=(num_errors,).

`dets` will be a list of detection event sets. Each detection
event set is a python set containing the indices of detectors
flipped by the error.

`obs` will be a list of observable flip sets. Each observable
flip set is a python set containing the indices of detectors
flipped by the error.

These sequences are paired up by index. They will have the same length, and
the combination of probabilities[k], dets[k], and obs[k] form a single
error.

Examples:
>>> import stim
>>> dem = stim.DetectorErrorModel('''
... error(0.25) D0 D1
... error(0.125) D0 D2 L1 L5
... ''')
>>> probs, dets, obs = dem.to_simple_error_lists()
>>> probs
array([0.25 , 0.125])
>>> dets
[{0, 1}, {0, 2}]
>>> obs
[set(), {1, 5}]
"""
class ExplainedError:
"""Describes the location of an error mechanism from a stim circuit.
"""
Expand Down
1 change: 1 addition & 0 deletions src/stim.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
#include "stim/util_top/circuit_to_detecting_regions.h"
#include "stim/util_top/circuit_vs_amplitudes.h"
#include "stim/util_top/circuit_vs_tableau.h"
#include "stim/util_top/dem_to_matrix.h"
#include "stim/util_top/export_crumble_url.h"
#include "stim/util_top/export_qasm.h"
#include "stim/util_top/export_quirk_url.h"
Expand Down
97 changes: 97 additions & 0 deletions src/stim/dem/detector_error_model.pybind.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
#include "stim/dem/detector_error_model_target.pybind.h"
#include "stim/io/raii_file.h"
#include "stim/py/base.pybind.h"
#include "stim/py/numpy.pybind.h"
#include "stim/search/search.h"
#include "stim/simulators/dem_sampler.h"
#include "stim/util_top/dem_to_matrix.h"

using namespace stim;
using namespace stim_pybind;

std::string stim_pybind::detector_error_model_repr(const DetectorErrorModel &self) {
if (self.instructions.empty()) {
Expand Down Expand Up @@ -1196,4 +1199,98 @@ void stim_pybind::pybind_detector_error_model_methods(
... print(diagram, file=f)
)DOC")
.data());

c.def(
"to_simple_error_lists",
[](const DetectorErrorModel &self) {
auto map = dem_to_map(self);
size_t num_errors = map.size();

pybind11::list dets_list;
pybind11::list obs_list;
double *probabilities = new double[num_errors];

size_t row = 0;
for (const auto &kv : map) {
probabilities[row] = kv.second;
pybind11::set dets;
pybind11::set obs;
for (DemTarget t : kv.first) {
if (t.is_relative_detector_id()) {
dets.add(t.val());
} else {
obs.add(t.val());
}
}
dets_list.append(dets);
obs_list.append(obs);
row++;
}

auto prob_array = pybind11::array_t<double>(
{(pybind11::ssize_t)num_errors},
{(pybind11::ssize_t)sizeof(double)},
probabilities,
pybind11::capsule(probabilities, [](void *f) {
delete[] reinterpret_cast<double *>(f);
})
);

return pybind11::make_tuple(prob_array, dets_list, obs_list);
},
clean_doc_string(R"DOC(
@signature def to_simple_error_lists(self) -> Tuple['np.ndarray[float]', List[Set[int]], List[Set[int]]]:
Simplifies the model into lists of chances, detection sets, and obs flips sets.

Note that this summary doesn't include information about loops, coordinates, or
suggested decompositions. Also note that this method will merge all errors with
identical symptoms, by Bernoulli summing their probabilities, and will sort the
errors. For example, the following two detector error models will give identical
results:

# dem 1
error(0.01) D1 D2 ^ D3 D4
error(0.125) D1
error(0.25) D1
detector(2, 3, 5) D1

vs

# dem 2
error(0.3125) D1
error(0.01) D1 D2 D3 D4

Returns:
A tuple of sequences (probabilities, dets, obs).

`probabilities` will be a numpy array with dtype=np.float64 and
shape=(num_errors,).

`dets` will be a list of detection event sets. Each detection
event set is a python set containing the indices of detectors
flipped by the error.

`obs` will be a list of observable flip sets. Each observable
flip set is a python set containing the indices of detectors
flipped by the error.

These sequences are paired up by index. They will have the same length, and
the combination of probabilities[k], dets[k], and obs[k] form a single
error.

Examples:
>>> import stim
>>> dem = stim.DetectorErrorModel('''
... error(0.25) D0 D1
... error(0.125) D0 D2 L1 L5
... ''')
>>> probs, dets, obs = dem.to_simple_error_lists()
>>> probs
array([0.25 , 0.125])
>>> dets
[{0, 1}, {0, 2}]
>>> obs
[set(), {1, 5}]
)DOC")
.data());
}
39 changes: 39 additions & 0 deletions src/stim/dem/detector_error_model_pybind_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import pathlib
import tempfile

import numpy as np
import pytest

import stim
Expand Down Expand Up @@ -536,3 +537,41 @@ def test_shortest_graphlike_error_remnant():
assert len(d.shortest_graphlike_error(ignore_ungraphlike_errors=True)) == 8
assert len(c.shortest_graphlike_error()) == 8
assert len(d.shortest_graphlike_error()) == 8


def test_to_simple_error_lists():
dem = stim.DetectorErrorModel("""
error(0.125) D0 D2 L1 L5
error(0.25) D0 D1
""")
probs, dets, obs = dem.to_simple_error_lists()
np.testing.assert_array_equal(probs, np.array([0.25, 0.125], dtype=np.float64))
assert dets == [
{0, 1},
{0, 2},
]
assert obs == [
set(),
{1, 5},
]


def test_to_simple_error_lists_simplify():
dem = stim.DetectorErrorModel("""
error(0.125) D0 D2 L1 L5
error(0.25) D0 ^ D1
error(0) D0 D1
error(0) D2
""")
probs, dets, obs = dem.to_simple_error_lists()
np.testing.assert_array_equal(probs, np.array([0.25, 0.125, 0], dtype=np.float64))
assert dets == [
{0, 1},
{0, 2},
{2},
]
assert obs == [
set(),
{1, 5},
set(),
]
Loading
Loading