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

Allow adding constants #261

Closed
HDembinski opened this issue Nov 28, 2019 · 10 comments · Fixed by #370
Closed

Allow adding constants #261

HDembinski opened this issue Nov 28, 2019 · 10 comments · Fixed by #370
Milestone

Comments

@HDembinski
Copy link
Member

Consider the following code (from my analysis), which sums up histograms generated in different threads:

h_tot = None
for h in generate_histograms():
  if h_tot is None:
    h_tot = h
  else:
    h_tot += h

It would be nicer to be able to write it like this (or something similar)

h_tot = 0
for h in generate_histograms():
   h_tot = h_tot + h

We currently don't allow adding numbers to histograms. So to get this feature, we should allow this. Adding a number to a histogram would only be allowed if that is supported by the underlying accumulator.

@HDembinski HDembinski changed the title Allow adding zero as a neutral element Allow adding constants Nov 28, 2019
@HDembinski HDembinski added this to the 0.7.0 milestone Nov 28, 2019
@henryiii
Copy link
Member

henryiii commented Nov 28, 2019

This is useful, though you should be able to do (assuming this is all you are doing):

import functools, operator

h_tot = functools.reduce(operator.add, generate_histograms())

Allowing scalar addition might even enable (there's a caveat in the docs about expecting numeric types here, but I've used it for things like this before, and histograms are numeric of sorts):

h_tot = sum(generate_histograms())

@HDembinski
Copy link
Member Author

HDembinski commented Nov 28, 2019

You are right, I could write it in more clever ways and then it would already work, but it is also nice to support the naive way (but I think we agree on that). This is again about muscle memory, I know that this trick works with numpy arrays, and I kinda assume it should work with bh.

@HDembinski
Copy link
Member Author

HDembinski commented Nov 28, 2019

Note that adding may trigger a storage conversion:

bh.Histogram(bh.axis.Integer(0, 3), storage=bh.storage.Int64()) + 0.5

This should convert the Histogram storage to Double() for symmetry with numpy arrays.

When you add two histograms with different storage in Boost.Histogram, the C++ code selects the common type for the result. So int + double yields double, for instance.

@HDembinski
Copy link
Member Author

The same thing happens when you scale.

@HDembinski
Copy link
Member Author

HDembinski commented Nov 28, 2019

Turns out the Python code currently does not support adding histograms with different storages.

h = bhc.histogram(bhc.axis.regular(10, 0, 1), storage=bhc.storage.int64())
h2 = bhc.histogram(bhc.axis.regular(10, 0, 1), storage=bhc.storage.double())

In [19]: h + h2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-19-360da8eb62ae> in <module>
----> 1 h + h2

~/Code/boost-histogram/boost_histogram/_internal/hist.py in __add__(self, other)
    127
    128     def __add__(self, other):
--> 129         return self.__class__(self._hist + other._hist)
    130
    131     def __eq__(self, other):

TypeError: unsupported operand type(s) for +: 'boost_histogram._core.hist.any_int64' and 'boost_histogram._core.hist.any_double'

@henryiii henryiii modified the milestones: 0.7.0, 0.8.0 Mar 11, 2020
@LovelyBuggies
Copy link
Collaborator

LovelyBuggies commented Apr 2, 2020

I think this issue (adding const & fix add func) could be solved together with #289 , as they are all related to storage type. Besides, I think this snippet should work, but currently NOT.

>>> h = bh.Histogram(bh.axis.Regular(10, 0, 1), storage=bh.storage.Int64())
>>> h2 = bh.Histogram(bh.axis.Regular(10, 0, 1), storage=bh.storage.Double())
>>> assert h == h2

It looks like maybe __eq__ also needs to be renewed.

--- Update ---
Oh, I see they are all marked as 0.8.0 milestone, that's good!

@henryiii
Copy link
Member

henryiii commented Jun 3, 2020

@HDembinski, is h += 1.0; not supported in Boost.Histogram? This doesn't seem to work in C++:

  std::vector<double> v = {1.0, 2.0, 3.0, 4.0, 5.0};
  auto h = bh::make_histogram(bh::axis::variable<>(v));
  h += 1.0;

Should it be? Or should the be Python only?

@henryiii
Copy link
Member

henryiii commented Jun 3, 2020

And what does h += 1 do to the flow bins? Should this really just be a special case for 0 false-like, to enable the trick above? (0 or None)

@HDembinski
Copy link
Member Author

It is not supported currently, because the operation seemed to make little sense for a real histogram. But it can easily be added.

@henryiii
Copy link
Member

henryiii commented Jun 3, 2020

I'm thinking it is probably best in Python to allow False-like (0, 0.0, None, False) to do nothing when added to a histogram, and disallow adding non-False values, since they are ambiguous. For a real histogram, I don't think adding a constant to all bins makes physical sense, especially if bins are not equal size or you have flow bins; if you want to add values using [] = syntax, then you can control exactly what gets added, and that already works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants