Commit 610ca8c
committed
[mathcore] Fix TKDTreeBinning::FindBin returning out-of-range bins
TKDTreeBinning computed fNBins independently from the kd-tree it builds.
SetNBins picks a bucket size of fDataSize / nBins (integer division), but
the underlying TKDTree creates ceil(fNPoints / bucketSize) terminal nodes.
When the requested number of bins does not divide the data size evenly, the
bucket size is rounded down and the tree ends up with more terminal nodes
than fNBins. Since FindBin returns a terminal-node index, it could return a
value >= GetNBins(), pointing at a bin with no edges and no content:
```c++
binning.GetNBins() # 1001
binning.FindBin([1.2, 0.5, 0.5, 0.5, 0.5]) # 1004
binning.GetBinContent(1004) # RuntimeWarning: No such bin
```
Set fNBins to the actual number of terminal nodes (GetNNodes() + 1) after
building the tree, so FindBin always returns an index within
[0, GetNBins()) and every bin has valid edges and content. This also
self-corrects existing objects on read-back, as the Streamer rebuilds the
tree via SetNBins.
Also fix SetBinsContent to read the per-node point counts directly from the
tree (GetNPointsNode) instead of an incorrect last-bin heuristic, so bin
contents are exact and sum to the data size.
Add a regression test covering the non-evenly-dividing case.
Closes #10786.
🤖 Done with the help of AI.1 parent 55780de commit 610ca8c
1 file changed
Lines changed: 8 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
139 | 142 | | |
140 | 143 | | |
141 | 144 | | |
| |||
238 | 241 | | |
239 | 242 | | |
240 | 243 | | |
241 | | - | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
242 | 247 | | |
| 248 | + | |
243 | 249 | | |
244 | | - | |
245 | | - | |
246 | | - | |
| 250 | + | |
247 | 251 | | |
248 | 252 | | |
249 | 253 | | |
| |||
0 commit comments