Skip to content

Commit 6184366

Browse files
committed
fix: faster picking when slices are made
1 parent 2d1ea1e commit 6184366

File tree

5 files changed

+28
-23
lines changed

5 files changed

+28
-23
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#### Bug fixes
1313
* Support custom setters on AxesTuple subclasses. [#627][]
14-
* Faster picking if slices are not also used [#645][]
14+
* Faster picking if slices are not also used [#645][] or if they are [#648][] (1000x or more in some cases)
1515
* Throw an error when an AxesTuple setter is the wrong length (inspired by zip strict in Python 3.10) [#627][]
1616
* Fix error thrown on comparison with axis and non-axis object [#631][]
1717
* Static typing no longer thinks `storage=` is required [#604][]
@@ -29,6 +29,7 @@
2929
[#636]: https://github.com/scikit-hep/boost-histogram/pull/636
3030
[#645]: https://github.com/scikit-hep/boost-histogram/pull/645
3131
[#647]: https://github.com/scikit-hep/boost-histogram/pull/647
32+
[#648]: https://github.com/scikit-hep/boost-histogram/pull/648
3233

3334
## Version 1.1
3435

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ write_to = "src/boost_histogram/version.py"
1111

1212
[tool.pytest.ini_options]
1313
junit_family = "xunit2"
14-
addopts = "--benchmark-disable -Wd --strict-markers"
14+
addopts = "--benchmark-disable -Wd --strict-markers -ra"
1515
xfail_strict = true
1616
testpaths = ["tests"]
1717
required_plugins = ["pytest-benchmark"]

src/boost_histogram/_core/algorithm.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import enum
22
import typing
33

44
class reduce_command:
5+
iaxis: int
56
def __repr__(self) -> str: ...
67

78
class slice_mode(enum.Enum):

src/boost_histogram/_internal/hist.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -841,17 +841,33 @@ def __getitem__( # noqa: C901
841841
assert isinstance(stop, int)
842842
slices.append(_core.algorithm.slice_and_rebin(i, start, stop, merge))
843843

844-
if slices:
845-
logger.debug("Reduce with %s", slices)
846-
reduced = self._hist.reduce(*slices)
847-
elif pick_set or pick_each or integrations:
848-
# Can avoid a copy in these cases, will be copied anyway
849-
logger.debug("Reduce is empty, but picking or slicing, so no copy needed")
844+
# Will be updated below
845+
if slices or pick_set or pick_each or integrations:
850846
reduced = self._hist
851847
else:
852-
logger.debug("Reduce is empty, just making a copy")
848+
logger.debug("Reduce actions are all empty, just making a copy")
853849
reduced = copy.copy(self._hist)
854850

851+
if pick_each:
852+
tuple_slice = tuple(
853+
pick_each.get(i, slice(None)) for i in range(reduced.rank())
854+
)
855+
logger.debug("Slices for pick each: %s", tuple_slice)
856+
axes = [
857+
reduced.axis(i) for i in range(reduced.rank()) if i not in pick_each
858+
]
859+
logger.debug("Axes: %s", axes)
860+
new_reduced = reduced.__class__(axes)
861+
new_reduced.view(flow=True)[...] = reduced.view(flow=True)[tuple_slice]
862+
reduced = new_reduced
863+
integrations = {i - sum(j <= i for j in pick_each) for i in integrations}
864+
for slice_ in slices:
865+
slice_.iaxis -= sum(j <= slice_.iaxis for j in pick_each)
866+
867+
if slices:
868+
logger.debug("Reduce with %s", slices)
869+
reduced = reduced.reduce(*slices)
870+
855871
if pick_set:
856872
warnings.warn(
857873
"List indexing selection is experimental. Removed bins are not placed in overflow."
@@ -880,20 +896,6 @@ def __getitem__( # noqa: C901
880896
new_reduced.view(flow=True)[...] = reduced_view
881897
reduced = new_reduced
882898

883-
if pick_each:
884-
tuple_slice = tuple(
885-
pick_each.get(i, slice(None)) for i in range(reduced.rank())
886-
)
887-
logger.debug("Slices for pick each: %s", tuple_slice)
888-
axes = [
889-
reduced.axis(i) for i in range(reduced.rank()) if i not in pick_each
890-
]
891-
logger.debug("Axes: %s", axes)
892-
new_reduced = reduced.__class__(axes)
893-
new_reduced.view(flow=True)[...] = reduced.view(flow=True)[tuple_slice]
894-
reduced = new_reduced
895-
integrations = {i - sum(j <= i for j in pick_each) for i in integrations}
896-
897899
if integrations:
898900
projections = [i for i in range(reduced.rank()) if i not in integrations]
899901
reduced = reduced.project(*projections)

src/register_algorithm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
void register_algorithms(py::module& algorithm) {
1111
py::class_<bh::algorithm::reduce_command>(algorithm, "reduce_command")
1212
.def(py::init<bh::algorithm::reduce_command>())
13+
.def_readwrite("iaxis", &bh::algorithm::reduce_command::iaxis)
1314
.def("__repr__", [](const bh::algorithm::reduce_command& self) {
1415
using range_t = bh::algorithm::reduce_command::range_t;
1516

0 commit comments

Comments
 (0)