diff --git a/doc/python_api_reference_vDev.md b/doc/python_api_reference_vDev.md
index a4b62d067..081c06d0b 100644
--- a/doc/python_api_reference_vDev.md
+++ b/doc/python_api_reference_vDev.md
@@ -172,8 +172,8 @@ API references for stable versions are kept on the [stim github wiki](https://gi
- [`stim.ExplainedError.dem_error_terms`](#stim.ExplainedError.dem_error_terms)
- [`stim.FlipSimulator`](#stim.FlipSimulator)
- [`stim.FlipSimulator.__init__`](#stim.FlipSimulator.__init__)
- - [`stim.FlipSimulator.apply_pauli_errors`](#stim.FlipSimulator.apply_pauli_errors)
- [`stim.FlipSimulator.batch_size`](#stim.FlipSimulator.batch_size)
+ - [`stim.FlipSimulator.broadcast_pauli_errors`](#stim.FlipSimulator.broadcast_pauli_errors)
- [`stim.FlipSimulator.do`](#stim.FlipSimulator.do)
- [`stim.FlipSimulator.get_detector_flips`](#stim.FlipSimulator.get_detector_flips)
- [`stim.FlipSimulator.get_measurement_flips`](#stim.FlipSimulator.get_measurement_flips)
@@ -6132,12 +6132,34 @@ def __init__(
"""
```
-
+
```python
-# stim.FlipSimulator.apply_pauli_errors
+# stim.FlipSimulator.batch_size
# (in class stim.FlipSimulator)
-def apply_pauli_errors(
+@property
+def batch_size(
+ self,
+) -> int:
+ """Returns the number of instances being simulated by the simulator.
+
+ Examples:
+ >>> import stim
+ >>> sim = stim.FlipSimulator(batch_size=256)
+ >>> sim.batch_size
+ 256
+ >>> sim = stim.FlipSimulator(batch_size=42)
+ >>> sim.batch_size
+ 42
+ """
+```
+
+
+```python
+# stim.FlipSimulator.broadcast_pauli_errors
+
+# (in class stim.FlipSimulator)
+def broadcast_pauli_errors(
self,
*,
pauli: Union[str, int],
@@ -6149,7 +6171,7 @@ def apply_pauli_errors(
pauli: The pauli, specified as an integer or string.
Uses the convention 0=I, 1=X, 2=Y, 3=Z.
Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.
- mask: a bool array with shape (qubit, simulation_instance)
+ mask: a np.bool_ array with shape (qubit, simulation_instance)
The pauli error is only applied to qubits q and simulation indices k
where mask[q, k] == True
@@ -6161,34 +6183,19 @@ def apply_pauli_errors(
... num_qubits=3,
... disable_stabilizer_randomization=True,
... )
- >>> sim.apply_pauli_errors(
+ >>> sim.broadcast_pauli_errors(
... pauli='X',
... mask=np.asarray([[True, False],[False, False],[True, True]]),
... )
>>> sim.peek_pauli_flips()
[stim.PauliString("+X_X"), stim.PauliString("+__X")]
- """
-```
-
-
-```python
-# stim.FlipSimulator.batch_size
-
-# (in class stim.FlipSimulator)
-@property
-def batch_size(
- self,
-) -> int:
- """Returns the number of instances being simulated by the simulator.
- Examples:
- >>> import stim
- >>> sim = stim.FlipSimulator(batch_size=256)
- >>> sim.batch_size
- 256
- >>> sim = stim.FlipSimulator(batch_size=42)
- >>> sim.batch_size
- 42
+ >>> sim.broadcast_pauli_errors(
+ ... pauli='Z',
+ ... mask=np.asarray([[False, True],[False, False],[True, True]]),
+ ... )
+ >>> sim.peek_pauli_flips()
+ [stim.PauliString("+X_Y"), stim.PauliString("+Z_Y")]
"""
```
diff --git a/doc/stim.pyi b/doc/stim.pyi
index ca1b6b983..67c2f3677 100644
--- a/doc/stim.pyi
+++ b/doc/stim.pyi
@@ -4655,7 +4655,22 @@ class FlipSimulator:
>>> import stim
>>> sim = stim.FlipSimulator(batch_size=256)
"""
- def apply_pauli_errors(
+ @property
+ def batch_size(
+ self,
+ ) -> int:
+ """Returns the number of instances being simulated by the simulator.
+
+ Examples:
+ >>> import stim
+ >>> sim = stim.FlipSimulator(batch_size=256)
+ >>> sim.batch_size
+ 256
+ >>> sim = stim.FlipSimulator(batch_size=42)
+ >>> sim.batch_size
+ 42
+ """
+ def broadcast_pauli_errors(
self,
*,
pauli: Union[str, int],
@@ -4667,7 +4682,7 @@ class FlipSimulator:
pauli: The pauli, specified as an integer or string.
Uses the convention 0=I, 1=X, 2=Y, 3=Z.
Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.
- mask: a bool array with shape (qubit, simulation_instance)
+ mask: a np.bool_ array with shape (qubit, simulation_instance)
The pauli error is only applied to qubits q and simulation indices k
where mask[q, k] == True
@@ -4679,27 +4694,19 @@ class FlipSimulator:
... num_qubits=3,
... disable_stabilizer_randomization=True,
... )
- >>> sim.apply_pauli_errors(
+ >>> sim.broadcast_pauli_errors(
... pauli='X',
... mask=np.asarray([[True, False],[False, False],[True, True]]),
... )
>>> sim.peek_pauli_flips()
[stim.PauliString("+X_X"), stim.PauliString("+__X")]
- """
- @property
- def batch_size(
- self,
- ) -> int:
- """Returns the number of instances being simulated by the simulator.
- Examples:
- >>> import stim
- >>> sim = stim.FlipSimulator(batch_size=256)
- >>> sim.batch_size
- 256
- >>> sim = stim.FlipSimulator(batch_size=42)
- >>> sim.batch_size
- 42
+ >>> sim.broadcast_pauli_errors(
+ ... pauli='Z',
+ ... mask=np.asarray([[False, True],[False, False],[True, True]]),
+ ... )
+ >>> sim.peek_pauli_flips()
+ [stim.PauliString("+X_Y"), stim.PauliString("+Z_Y")]
"""
def do(
self,
diff --git a/glue/python/src/stim/__init__.pyi b/glue/python/src/stim/__init__.pyi
index ca1b6b983..67c2f3677 100644
--- a/glue/python/src/stim/__init__.pyi
+++ b/glue/python/src/stim/__init__.pyi
@@ -4655,7 +4655,22 @@ class FlipSimulator:
>>> import stim
>>> sim = stim.FlipSimulator(batch_size=256)
"""
- def apply_pauli_errors(
+ @property
+ def batch_size(
+ self,
+ ) -> int:
+ """Returns the number of instances being simulated by the simulator.
+
+ Examples:
+ >>> import stim
+ >>> sim = stim.FlipSimulator(batch_size=256)
+ >>> sim.batch_size
+ 256
+ >>> sim = stim.FlipSimulator(batch_size=42)
+ >>> sim.batch_size
+ 42
+ """
+ def broadcast_pauli_errors(
self,
*,
pauli: Union[str, int],
@@ -4667,7 +4682,7 @@ class FlipSimulator:
pauli: The pauli, specified as an integer or string.
Uses the convention 0=I, 1=X, 2=Y, 3=Z.
Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.
- mask: a bool array with shape (qubit, simulation_instance)
+ mask: a np.bool_ array with shape (qubit, simulation_instance)
The pauli error is only applied to qubits q and simulation indices k
where mask[q, k] == True
@@ -4679,27 +4694,19 @@ class FlipSimulator:
... num_qubits=3,
... disable_stabilizer_randomization=True,
... )
- >>> sim.apply_pauli_errors(
+ >>> sim.broadcast_pauli_errors(
... pauli='X',
... mask=np.asarray([[True, False],[False, False],[True, True]]),
... )
>>> sim.peek_pauli_flips()
[stim.PauliString("+X_X"), stim.PauliString("+__X")]
- """
- @property
- def batch_size(
- self,
- ) -> int:
- """Returns the number of instances being simulated by the simulator.
- Examples:
- >>> import stim
- >>> sim = stim.FlipSimulator(batch_size=256)
- >>> sim.batch_size
- 256
- >>> sim = stim.FlipSimulator(batch_size=42)
- >>> sim.batch_size
- 42
+ >>> sim.broadcast_pauli_errors(
+ ... pauli='Z',
+ ... mask=np.asarray([[False, True],[False, False],[True, True]]),
+ ... )
+ >>> sim.peek_pauli_flips()
+ [stim.PauliString("+X_Y"), stim.PauliString("+Z_Y")]
"""
def do(
self,
diff --git a/src/stim/simulators/frame_simulator.pybind.cc b/src/stim/simulators/frame_simulator.pybind.cc
index f9a10c1a6..f521cad5c 100644
--- a/src/stim/simulators/frame_simulator.pybind.cc
+++ b/src/stim/simulators/frame_simulator.pybind.cc
@@ -772,7 +772,7 @@ void stim_pybind::pybind_frame_simulator_methods(
.data());
c.def(
- "apply_pauli_errors",
+ "broadcast_pauli_errors",
[](FrameSimulator &self,
const pybind11::object &pauli,
const pybind11::object &mask
@@ -780,6 +780,9 @@ void stim_pybind::pybind_frame_simulator_methods(
uint8_t p = 255;
try {
p = pybind11::cast(pauli);
+ if (p >= 4) {
+ throw pybind11::cast_error();
+ }
} catch (const pybind11::cast_error &) {
try {
std::string s = pybind11::cast(pauli);
@@ -791,53 +794,53 @@ void stim_pybind::pybind_frame_simulator_methods(
p = 3;
} else if (s == "I" || s == "_") {
p = 0;
+ } else {
+ throw pybind11::cast_error();
}
} catch (const pybind11::cast_error &) {
+ throw std::invalid_argument(
+ "broadcast_pauli_errors only accepts pauli arguments in ['I', '_', 'X', 'Y', 'Z', 0,1,2,3]");
}
}
bool flip_z_part = p & 2;
- bool flip_x_part = 6 >> p & 1; // 0b0110 >> p & 0b0001
-
- if (pybind11::isinstance>(mask)) {
- // can use pybind11::isinstance>
- // to check for dense c_ordered array for copying, if this is too slow for you
- const pybind11::array_t &arr = pybind11::cast>(mask);
- if (arr.ndim() == 2) {
- //pybind11::ssize_t???
- size_t major = arr.shape(0);
- size_t minor = arr.shape(1);
- //size_t major_stride = arr.strides(0);
- //size_t minor_stride = arr.strides(1);
- auto u = arr.unchecked<2>();
- for (size_t i = 0; i < major; i++){
- for (size_t j = 0; j < minor; j++){
- auto b = u.data(i, j);
- self.x_table[i][j] ^= *b & flip_x_part;
- self.z_table[i][j] ^= *b & flip_z_part;
- }
- }
- } else {
- throw std::invalid_argument(
- "apply_pauli_errors currently only supports a mask that is a 2D bool numpy array");
- }
- } else {
- throw std::invalid_argument(
- "apply_pauli_errors currently only supports a mask that is a 2D bool numpy array");
+ bool flip_x_part = (0b0110 >> p) & 1; // parity of 2 bit number
+
+
+ if (!pybind11::isinstance>(mask)) {
+ throw std::invalid_argument(
+ "broadcast_pauli_errors can only accept mask that is a 2D array of np.bool_");
+ }
+ const pybind11::array_t &arr = pybind11::cast>(mask);
+
+ if (arr.ndim() != 2) {
+ throw std::invalid_argument(
+ "broadcast_pauli_errors can only accept mask that is a 2D array of np.bool_");
+ }
+
+ size_t major = arr.shape(0);
+ size_t minor = arr.shape(1);
+ auto u = arr.unchecked<2>();
+ for (size_t i = 0; i < major; i++){
+ for (size_t j = 0; j < minor; j++){
+ auto b = u.data(i, j);
+ self.x_table[i][j] ^= *b & flip_x_part;
+ self.z_table[i][j] ^= *b & flip_z_part;
}
+ }
},
pybind11::kw_only(),
pybind11::arg("pauli"),
pybind11::arg("mask"),
clean_doc_string(R"DOC(
- @signature def apply_pauli_errors(self, *, pauli: Union[str, int], mask: np.ndarray) -> None:
+ @signature def broadcast_pauli_errors(self, *, pauli: Union[str, int], mask: np.ndarray) -> None:
Applies a pauli over all qubits in all simulation indices, filtered by mask.
Args:
pauli: The pauli, specified as an integer or string.
Uses the convention 0=I, 1=X, 2=Y, 3=Z.
Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.
- mask: a bool array with shape (qubit, simulation_instance)
+ mask: a np.bool_ array with shape (qubit, simulation_instance)
The pauli error is only applied to qubits q and simulation indices k
where mask[q, k] == True
@@ -849,12 +852,20 @@ void stim_pybind::pybind_frame_simulator_methods(
... num_qubits=3,
... disable_stabilizer_randomization=True,
... )
- >>> sim.apply_pauli_errors(
+ >>> sim.broadcast_pauli_errors(
... pauli='X',
... mask=np.asarray([[True, False],[False, False],[True, True]]),
... )
>>> sim.peek_pauli_flips()
[stim.PauliString("+X_X"), stim.PauliString("+__X")]
+
+ >>> sim.broadcast_pauli_errors(
+ ... pauli='Z',
+ ... mask=np.asarray([[False, True],[False, False],[True, True]]),
+ ... )
+ >>> sim.peek_pauli_flips()
+ [stim.PauliString("+X_Y"), stim.PauliString("+Z_Y")]
+
)DOC")
.data());
}
diff --git a/src/stim/simulators/frame_simulator_pybind_test.py b/src/stim/simulators/frame_simulator_pybind_test.py
index 87fa2baf2..8ceb96283 100644
--- a/src/stim/simulators/frame_simulator_pybind_test.py
+++ b/src/stim/simulators/frame_simulator_pybind_test.py
@@ -216,13 +216,13 @@ def test_set_pauli_flip():
stim.PauliString('XZ___'),
]
-def test_apply_pauli_errors():
+def test_broadcast_pauli_errors():
sim = stim.FlipSimulator(
batch_size=2,
num_qubits=3,
disable_stabilizer_randomization=True,
)
- sim.apply_pauli_errors(
+ sim.broadcast_pauli_errors(
pauli='X',
mask=np.asarray([
[True, False],
@@ -235,7 +235,7 @@ def test_apply_pauli_errors():
stim.PauliString("+X_X"),
stim.PauliString("+__X")
]
- sim.apply_pauli_errors(
+ sim.broadcast_pauli_errors(
pauli='Z',
mask=np.asarray([
[True, True],
@@ -248,7 +248,7 @@ def test_apply_pauli_errors():
stim.PauliString("+YZX"),
stim.PauliString("+Z_X")
]
- sim.apply_pauli_errors(
+ sim.broadcast_pauli_errors(
pauli='Y',
mask=np.asarray([
[True, False],
@@ -261,6 +261,19 @@ def test_apply_pauli_errors():
stim.PauliString("+_ZX"),
stim.PauliString("+ZYZ")
]
+ sim.broadcast_pauli_errors(
+ pauli='I',
+ mask=np.asarray([
+ [True, True],
+ [False, True],
+ [True, True]]
+ ),
+ )
+ peek = sim.peek_pauli_flips()
+ assert peek == [
+ stim.PauliString("+_ZX"),
+ stim.PauliString("+ZYZ")
+ ]
# do it again with ints
sim = stim.FlipSimulator(
@@ -268,7 +281,7 @@ def test_apply_pauli_errors():
num_qubits=3,
disable_stabilizer_randomization=True,
)
- sim.apply_pauli_errors(
+ sim.broadcast_pauli_errors(
pauli=1,
mask=np.asarray([
[True, False],
@@ -281,7 +294,7 @@ def test_apply_pauli_errors():
stim.PauliString("+X_X"),
stim.PauliString("+__X")
]
- sim.apply_pauli_errors(
+ sim.broadcast_pauli_errors(
pauli=3,
mask=np.asarray([
[True, True],
@@ -294,7 +307,7 @@ def test_apply_pauli_errors():
stim.PauliString("+YZX"),
stim.PauliString("+Z_X")
]
- sim.apply_pauli_errors(
+ sim.broadcast_pauli_errors(
pauli=2,
mask=np.asarray([
[True, False],
@@ -307,6 +320,38 @@ def test_apply_pauli_errors():
stim.PauliString("+_ZX"),
stim.PauliString("+ZYZ")
]
+ sim.broadcast_pauli_errors(
+ pauli=0,
+ mask=np.asarray([
+ [True, True],
+ [False, True],
+ [True, True]]
+ ),
+ )
+ peek = sim.peek_pauli_flips()
+ assert peek == [
+ stim.PauliString("+_ZX"),
+ stim.PauliString("+ZYZ")
+ ]
+
+ with pytest.raises(Exception):
+ sim.broadcast_pauli_errors(
+ pauli='whoops',
+ mask=np.asarray([
+ [True, True],
+ [False, True],
+ [True, True]]
+ ),
+ )
+ with pytest.raises(Exception):
+ sim.broadcast_pauli_errors(
+ pauli=4,
+ mask=np.asarray([
+ [True, True],
+ [False, True],
+ [True, True]]
+ ),
+ )
def test_repro_heralded_pauli_channel_1_bug():