clang-format everything

This commit is contained in:
Hans Dembinski 2018-07-21 17:27:18 +02:00
parent 47d4d85301
commit d4dbae92f5
53 changed files with 783 additions and 907 deletions

View File

@ -4,80 +4,75 @@
#include <iostream> #include <iostream>
int main(int, char**) { int main(int, char**) {
namespace bh = boost::histogram; namespace bh = boost::histogram;
using namespace bh::literals; // enables _c suffix using namespace bh::literals; // enables _c suffix
/* /*
create a static 1d-histogram with an axis that has 6 equidistant create a static 1d-histogram with an axis that has 6 equidistant
bins on the real line from -1.0 to 2.0, and label it as "x" bins on the real line from -1.0 to 2.0, and label it as "x"
*/ */
auto h = bh::make_static_histogram( auto h = bh::make_static_histogram(bh::axis::regular<>(6, -1.0, 2.0, "x"));
bh::axis::regular<>(6, -1.0, 2.0, "x")
);
// fill histogram with data, typically this happens in a loop // fill histogram with data, typically this happens in a loop
// STL algorithms are supported // STL algorithms are supported
auto data = { -0.5, 1.1, 0.3, 1.7 }; auto data = {-0.5, 1.1, 0.3, 1.7};
std::for_each(data.begin(), data.end(), h); std::for_each(data.begin(), data.end(), h);
/* /*
a regular axis is a sequence of semi-open bins; extra under- and a regular axis is a sequence of semi-open bins; extra under- and
overflow bins extend the axis in the default configuration overflow bins extend the axis in the default configuration
index : -1 0 1 2 3 4 5 6 index : -1 0 1 2 3 4 5 6
bin edge: -inf -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 inf bin edge: -inf -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 inf
*/ */
h(-1.5); // put in underflow bin -1 h(-1.5); // put in underflow bin -1
h(-1.0); // put in bin 0, bin interval is semi-open h(-1.0); // put in bin 0, bin interval is semi-open
h(2.0); // put in overflow bin 6, bin interval is semi-open h(2.0); // put in overflow bin 6, bin interval is semi-open
h(20.0); // put in overflow bin 6 h(20.0); // put in overflow bin 6
/* /*
do a weighted fill using bh::weight, a wrapper for any type, do a weighted fill using bh::weight, a wrapper for any type,
which may appear at the beginning of the argument list which may appear at the beginning of the argument list
*/ */
h(bh::weight(1.0), 0.1); h(bh::weight(1.0), 0.1);
/* /*
iterate over bins with a fancy histogram iterator iterate over bins with a fancy histogram iterator
- order in which bins are iterated over is an implementation detail - order in which bins are iterated over is an implementation detail
- iterator dereferences to histogram::element_type, which is defined by - iterator dereferences to histogram::element_type, which is defined by
its storage class; by default something with value() and its storage class; by default something with value() and
variance() methods; the first returns the variance() methods; the first returns the
actual count, the second returns a variance estimate of the count actual count, the second returns a variance estimate of the count
(see Rationale section for what this means) (see Rationale section for what this means)
- idx(N) method returns the index of the N-th axis - idx(N) method returns the index of the N-th axis
- bin(N_c) method returns current bin of N-th axis; the suffx _c turns - bin(N_c) method returns current bin of N-th axis; the suffx _c turns
the argument into a compile-time number, which is needed to return the argument into a compile-time number, which is needed to return
different `bin_type`s for different axes different `bin_type`s for different axes
- `bin_type` usually is a semi-open interval representing the bin, whose - `bin_type` usually is a semi-open interval representing the bin, whose
edges can be accessed with methods `lower()` and `upper()`, but the edges can be accessed with methods `lower()` and `upper()`, but the
implementation depends on the axis, please look it up in the reference implementation depends on the axis, please look it up in the reference
*/ */
std::cout.setf(std::ios_base::fixed); std::cout.setf(std::ios_base::fixed);
for (auto it = h.begin(); it != h.end(); ++it) { for (auto it = h.begin(); it != h.end(); ++it) {
const auto bin = it.bin(0_c); const auto bin = it.bin(0_c);
std::cout << "bin " << it.idx(0) << " x in [" std::cout << "bin " << it.idx(0) << " x in [" << std::setprecision(1)
<< std::setprecision(1) << std::setw(4) << bin.lower() << ", " << std::setw(4)
<< std::setw(4) << bin.lower() << ", " << bin.upper() << "): " << std::setprecision(1) << it->value()
<< std::setw(4) << bin.upper() << "): " << " +/- " << std::setprecision(3) << std::sqrt(it->variance())
<< std::setprecision(1) << std::endl;
<< it->value() << " +/- " }
<< std::setprecision(3) << std::sqrt(it->variance())
<< std::endl;
}
/* program output: (note that under- and overflow bins appear at the end) /* program output: (note that under- and overflow bins appear at the end)
bin 0 x in [-1.0, -0.5): 1 +/- 1 bin 0 x in [-1.0, -0.5): 1 +/- 1
bin 1 x in [-0.5, 0.0): 0 +/- 0 bin 1 x in [-0.5, 0.0): 0 +/- 0
bin 2 x in [ 0.0, 0.5): 1 +/- 1 bin 2 x in [ 0.0, 0.5): 1 +/- 1
bin 3 x in [ 0.5, 1.0): 0 +/- 0 bin 3 x in [ 0.5, 1.0): 0 +/- 0
bin 4 x in [ 1.0, 1.5): 0 +/- 0 bin 4 x in [ 1.0, 1.5): 0 +/- 0
bin 5 x in [ 1.5, 2.0): 0 +/- 0 bin 5 x in [ 1.5, 2.0): 0 +/- 0
bin 6 x in [ 2.0, inf): 2 +/- 1.41421 bin 6 x in [ 2.0, inf): 2 +/- 1.41421
bin -1 x in [-inf, -1): 1 +/- 1 bin -1 x in [-inf, -1): 1 +/- 1
*/ */
} }
//] //]

View File

@ -7,50 +7,43 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
// make histogram with 2 x 2 = 4 bins (not counting under-/overflow bins) // make histogram with 2 x 2 = 4 bins (not counting under-/overflow bins)
auto h = bh::make_static_histogram( auto h = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1),
bh::axis::regular<>(2, -1, 1), bh::axis::regular<>(2, 2, 4));
bh::axis::regular<>(2, 2, 4)
);
h(bh::weight(1), -0.5, 2.5); // bin index 0, 0 h(bh::weight(1), -0.5, 2.5); // bin index 0, 0
h(bh::weight(2), -0.5, 3.5); // bin index 0, 1 h(bh::weight(2), -0.5, 3.5); // bin index 0, 1
h(bh::weight(3), 0.5, 2.5); // bin index 1, 0 h(bh::weight(3), 0.5, 2.5); // bin index 1, 0
h(bh::weight(4), 0.5, 3.5); // bin index 1, 1 h(bh::weight(4), 0.5, 3.5); // bin index 1, 1
// access count value, number of indices must match number of axes // access count value, number of indices must match number of axes
std::cout << h.at(0, 0).value() << " " std::cout << h.at(0, 0).value() << " " << h.at(0, 1).value() << " "
<< h.at(0, 1).value() << " " << h.at(1, 0).value() << " " << h.at(1, 1).value() << std::endl;
<< h.at(1, 0).value() << " "
<< h.at(1, 1).value()
<< std::endl;
// prints: 1 2 3 4 // prints: 1 2 3 4
// access count variance, number of indices must match number of axes // access count variance, number of indices must match number of axes
std::cout << h.at(0, 0).variance() << " " std::cout << h.at(0, 0).variance() << " " << h.at(0, 1).variance() << " "
<< h.at(0, 1).variance() << " " << h.at(1, 0).variance() << " " << h.at(1, 1).variance()
<< h.at(1, 0).variance() << " " << std::endl;
<< h.at(1, 1).variance() // prints: 1 4 9 16
<< std::endl;
// prints: 1 4 9 16
// you can also make a copy of the type that holds the bin count // you can also make a copy of the type that holds the bin count
auto c11 = h.at(1, 1); auto c11 = h.at(1, 1);
std::cout << c11.value() << " " << c11.variance() << std::endl; std::cout << c11.value() << " " << c11.variance() << std::endl;
// prints: 4 16 // prints: 4 16
// histogram also supports access via container; using a container of // histogram also supports access via container; using a container of
// wrong size trips an assertion in debug mode // wrong size trips an assertion in debug mode
auto idx = {0, 1}; auto idx = {0, 1};
std::cout << h.at(idx).value() << std::endl; std::cout << h.at(idx).value() << std::endl;
// prints: 2 // prints: 2
// histogram also provides extended iterators // histogram also provides extended iterators
auto sum = std::accumulate(h.begin(), h.end(), auto sum = std::accumulate(h.begin(), h.end(),
typename decltype(h)::element_type(0)); typename decltype(h)::element_type(0));
std::cout << sum.value() << " " << sum.variance() << std::endl; std::cout << sum.value() << " " << sum.variance() << std::endl;
// prints: 10 30 // prints: 10 30
} }
//] //]

View File

@ -5,13 +5,12 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
// create a 2d-histogram with an "age" and an "income" axis // create a 2d-histogram with an "age" and an "income" axis
auto h = bh::make_static_histogram( auto h = bh::make_static_histogram(
bh::axis::regular<>(20, 0, 100, "age in years"), bh::axis::regular<>(20, 0, 100, "age in years"),
bh::axis::regular<>(20, 0, 100, "yearly income in $1000") bh::axis::regular<>(20, 0, 100, "yearly income in $1000"));
);
// do something with h // do something with h
} }
//] //]

View File

@ -5,10 +5,11 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
// create a 1d-histogram for dice throws with integer values from 1 to 6 // create a 1d-histogram for dice throws with integer values from 1 to 6
auto h = bh::make_static_histogram(bh::axis::integer<>(1, 7, "eyes", bh::axis::uoflow::off)); auto h = bh::make_static_histogram(
bh::axis::integer<>(1, 7, "eyes", bh::axis::uoflow::off));
// do something with h // do something with h
} }
//] //]

View File

@ -7,36 +7,33 @@ namespace bh = boost::histogram;
// custom axis, which adapts builtin integer axis // custom axis, which adapts builtin integer axis
struct custom_axis : public bh::axis::integer<> { struct custom_axis : public bh::axis::integer<> {
using value_type = const char*; // type that is fed to the axis using value_type = const char*; // type that is fed to the axis
using integer::integer; // inherit ctors of base using integer::integer; // inherit ctors of base
// the customization point // the customization point
// - accept const char* and convert to int // - accept const char* and convert to int
// - then call index method of base class // - then call index method of base class
int index(value_type s) const { int index(value_type s) const { return integer::index(std::atoi(s)); }
return integer::index(std::atoi(s));
}
}; };
int main() { int main() {
auto h = bh::make_static_histogram(custom_axis(0, 3)); auto h = bh::make_static_histogram(custom_axis(0, 3));
h("-10"); h("-10");
h("0"); h("0");
h("1"); h("1");
h("9"); h("9");
for (auto xi : h.axis()) { for (auto xi : h.axis()) {
std::cout << "bin " << xi.idx() << " [" << xi.lower() << ", " std::cout << "bin " << xi.idx() << " [" << xi.lower() << ", "
<< xi.upper() << ") " << h.at(xi).value() << xi.upper() << ") " << h.at(xi).value() << std::endl;
<< std::endl; }
}
/* prints: /* prints:
bin 0 [0, 1) 1 bin 0 [0, 1) 1
bin 1 [1, 2] 1 bin 1 [1, 2] 1
bin 2 [2, 3] 0 bin 2 [2, 3] 0
*/ */
} }
//] //]

View File

@ -6,12 +6,11 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
// create static histogram with array_storage, using int as counter type // create static histogram with array_storage, using int as counter type
auto h = bh::make_static_histogram_with<bh::array_storage<int>>( auto h = bh::make_static_histogram_with<bh::array_storage<int>>(
bh::axis::regular<>(10, 0, 1) bh::axis::regular<>(10, 0, 1));
);
// do something with h // do something with h
} }
//] //]

View File

@ -1,38 +1,37 @@
//[ guide_fill_histogram //[ guide_fill_histogram
#include <boost/histogram.hpp> #include <boost/histogram.hpp>
#include <vector>
#include <utility> #include <utility>
#include <vector>
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
auto h = bh::make_static_histogram(bh::axis::integer<>(0, 4), auto h = bh::make_static_histogram(bh::axis::integer<>(0, 4),
bh::axis::regular<>(10, 0, 5)); bh::axis::regular<>(10, 0, 5));
// fill histogram, number of arguments must be equal to number of axes // fill histogram, number of arguments must be equal to number of axes
h(0, 1.1); // increases bin counter by one h(0, 1.1); // increases bin counter by one
h(bh::weight(2), 3, 3.4); // increase bin counter by 2 instead of 1 h(bh::weight(2), 3, 3.4); // increase bin counter by 2 instead of 1
// histogram also supports fills from a container of values; a container // histogram also supports fills from a container of values; a container
// of wrong size trips an assertion in debug mode // of wrong size trips an assertion in debug mode
auto xy1 = std::make_pair(4, 3.1); auto xy1 = std::make_pair(4, 3.1);
h(xy1); h(xy1);
auto xy2 = std::vector<double>({3.0, 4.9}); auto xy2 = std::vector<double>({3.0, 4.9});
h(xy2); h(xy2);
// functional-style processing is also supported // functional-style processing is also supported
std::vector<std::pair<int, double>> input_data{ std::vector<std::pair<int, double>> input_data{
{0, 1.2}, {2, 3.4}, {4, 5.6} {0, 1.2}, {2, 3.4}, {4, 5.6}};
}; // Note that std::for_each takes the functor by value, thus it makes a
// Note that std::for_each takes the functor by value, thus it makes a // potentially expensive copy of your histogram. Passing freshly created
// potentially expensive copy of your histogram. Passing freshly created // histograms is ok, though, because of return-value-optimization
// histograms is ok, though, because of return-value-optimization auto h2 =
auto h2 = std::for_each(input_data.begin(), input_data.end(), std::for_each(input_data.begin(), input_data.end(),
bh::make_static_histogram( bh::make_static_histogram(bh::axis::integer<>(0, 4),
bh::axis::integer<>(0, 4), bh::axis::regular<>(10, 0, 5)));
bh::axis::regular<>(10, 0, 5))); // h is filled
// h is filled
} }
//] //]

View File

@ -6,52 +6,52 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
// make two histograms // make two histograms
auto h1 = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1)); auto h1 = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1));
auto h2 = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1)); auto h2 = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1));
h1(-0.5); // counts are: 1 0 h1(-0.5); // counts are: 1 0
h2(0.5); // counts are: 0 1 h2(0.5); // counts are: 0 1
// add them // add them
auto h3 = h1; auto h3 = h1;
h3 += h2; // counts are: 1 1 h3 += h2; // counts are: 1 1
// adding multiple histograms at once is efficient and does not create // adding multiple histograms at once is efficient and does not create
// superfluous temporaries since operator+ functions are overloaded to // superfluous temporaries since operator+ functions are overloaded to
// accept and return rvalue references where possible // accept and return rvalue references where possible
auto h4 = h1 + h2 + h3; // counts are: 2 2 auto h4 = h1 + h2 + h3; // counts are: 2 2
std::cout << h4.at(0).value() << " " << h4.at(1).value() << std::endl; std::cout << h4.at(0).value() << " " << h4.at(1).value() << std::endl;
// prints: 2 2 // prints: 2 2
// multiply by number // multiply by number
h4 *= 2; // counts are: 4 4 h4 *= 2; // counts are: 4 4
// divide by number // divide by number
auto h5 = h4 / 4; // counts are: 1 1 auto h5 = h4 / 4; // counts are: 1 1
std::cout << h5.at(0).value() << " " << h5.at(1).value() << std::endl; std::cout << h5.at(0).value() << " " << h5.at(1).value() << std::endl;
// prints: 1 1 // prints: 1 1
// compare histograms // compare histograms
std::cout << (h4 == 4 * h5) << " " << (h4 != h5) << std::endl; std::cout << (h4 == 4 * h5) << " " << (h4 != h5) << std::endl;
// prints: 1 1 // prints: 1 1
// note: special effect of multiplication on counter variance // note: special effect of multiplication on counter variance
auto h = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1)); auto h = bh::make_static_histogram(bh::axis::regular<>(2, -1, 1));
h(-0.5); // counts are: 1 0 h(-0.5); // counts are: 1 0
std::cout << "value " << (2 * h).at(0).value() std::cout << "value " << (2 * h).at(0).value() << " "
<< " " << (h + h).at(0).value() << "\n" << (h + h).at(0).value() << "\n"
<< "variance " << (2 * h).at(0).variance() << "variance " << (2 * h).at(0).variance() << " "
<< " " << (h + h).at(0).variance() << std::endl; << (h + h).at(0).variance() << std::endl;
// equality operator also checks variances, so the statement is false // equality operator also checks variances, so the statement is false
std::cout << (h + h == 2 * h) << std::endl; std::cout << (h + h == 2 * h) << std::endl;
/* prints: /* prints:
value 2 2 value 2 2
variance 4 2 variance 4 2
0 0
*/ */
} }
//] //]

View File

@ -7,56 +7,51 @@ namespace bh = boost::histogram;
// example of a generic function for histograms, this one sums all entries // example of a generic function for histograms, this one sums all entries
template <typename... Ts> template <typename... Ts>
typename bh::histogram<Ts...>::element_type sum(const bh::histogram<Ts...>& h) { typename bh::histogram<Ts...>::element_type sum(
auto result = typename bh::histogram<Ts...>::element_type(0); const bh::histogram<Ts...>& h) {
for (auto x : h) auto result = typename bh::histogram<Ts...>::element_type(0);
result += x; for (auto x : h) result += x;
return result; return result;
} }
int main() { int main() {
using namespace bh::literals; // enables _c suffix using namespace bh::literals; // enables _c suffix
// make a 2d histogram // make a 2d histogram
auto h = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1), auto h = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1),
bh::axis::integer<>(0, 4)); bh::axis::integer<>(0, 4));
h(-0.9, 0); h(-0.9, 0);
h(0.9, 3); h(0.9, 3);
h(0.1, 2); h(0.1, 2);
auto hr0 = h.reduce_to(0_c); // keep only first axis auto hr0 = h.reduce_to(0_c); // keep only first axis
auto hr1 = h.reduce_to(1_c); // keep only second axis auto hr1 = h.reduce_to(1_c); // keep only second axis
/* /*
reduce does not remove counts; returned histograms are summed over reduce does not remove counts; returned histograms are summed over
the removed axes, so h, hr0, and hr1 have same number of total counts the removed axes, so h, hr0, and hr1 have same number of total counts
*/ */
std::cout << sum(h).value() << " " std::cout << sum(h).value() << " " << sum(hr0).value() << " "
<< sum(hr0).value() << " " << sum(hr1).value() << std::endl;
<< sum(hr1).value() << std::endl; // prints: 3 3 3
// prints: 3 3 3
for (auto yi : h.axis(1_c)) { for (auto yi : h.axis(1_c)) {
for (auto xi : h.axis(0_c)) { for (auto xi : h.axis(0_c)) { std::cout << h.at(xi, yi).value() << " "; }
std::cout << h.at(xi, yi).value() << " ";
}
std::cout << std::endl;
}
// prints: 1 0 0
// 0 0 0
// 0 1 0
// 0 0 1
for (auto xi : hr0.axis())
std::cout << hr0.at(xi).value() << " ";
std::cout << std::endl; std::cout << std::endl;
// prints: 1 1 1 }
// prints: 1 0 0
// 0 0 0
// 0 1 0
// 0 0 1
for (auto yi : hr1.axis()) for (auto xi : hr0.axis()) std::cout << hr0.at(xi).value() << " ";
std::cout << hr1.at(yi).value() << " "; std::cout << std::endl;
std::cout << std::endl; // prints: 1 1 1
// prints: 1 0 1 1
for (auto yi : hr1.axis()) std::cout << hr1.at(yi).value() << " ";
std::cout << std::endl;
// prints: 1 0 1 1
} }
//] //]

View File

@ -1,42 +1,42 @@
//[ guide_histogram_serialization //[ guide_histogram_serialization
#include <boost/histogram.hpp>
#include <boost/histogram/serialization.hpp> // includes serialization code
#include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_oarchive.hpp>
#include <boost/histogram.hpp>
#include <boost/histogram/serialization.hpp> // includes serialization code
#include <sstream> #include <sstream>
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
auto a = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1, "r"), auto a = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1, "r"),
bh::axis::integer<>(0, 2, "i")); bh::axis::integer<>(0, 2, "i"));
a(0.5, 1); a(0.5, 1);
std::string buf; // holds persistent representation std::string buf; // holds persistent representation
// store histogram // store histogram
{ {
std::ostringstream os; std::ostringstream os;
boost::archive::text_oarchive oa(os); boost::archive::text_oarchive oa(os);
oa << a; oa << a;
buf = os.str(); buf = os.str();
} }
auto b = decltype(a)(); // create a default-constructed second histogram auto b = decltype(a)(); // create a default-constructed second histogram
std::cout << "before restore " << (a == b) << std::endl; std::cout << "before restore " << (a == b) << std::endl;
// prints: before restore 0 // prints: before restore 0
// load histogram // load histogram
{ {
std::istringstream is(buf); std::istringstream is(buf);
boost::archive::text_iarchive ia(is); boost::archive::text_iarchive ia(is);
ia >> b; ia >> b;
} }
std::cout << "after restore " << (a == b) << std::endl; std::cout << "after restore " << (a == b) << std::endl;
// prints: after restore 1 // prints: after restore 1
} }
//] //]

View File

@ -7,33 +7,32 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
namespace axis = boost::histogram::axis; namespace axis = boost::histogram::axis;
enum { A, B, C }; enum { A, B, C };
auto h = bh::make_static_histogram( auto h = bh::make_static_histogram(
axis::regular<>(2, -1, 1, "regular1", axis::uoflow::off), axis::regular<>(2, -1, 1, "regular1", axis::uoflow::off),
axis::regular<double, axis::transform::log>(2, 1, 10, "regular2"), axis::regular<double, axis::transform::log>(2, 1, 10, "regular2"),
axis::circular<>(4, 0.1, 1.0, "polar"), axis::circular<>(4, 0.1, 1.0, "polar"),
axis::variable<>({-1, 0, 1}, "variable", axis::uoflow::off), axis::variable<>({-1, 0, 1}, "variable", axis::uoflow::off),
axis::category<>({A, B, C}, "category"), axis::category<>({A, B, C}, "category"),
axis::integer<>(-1, 1, "integer", axis::uoflow::off) axis::integer<>(-1, 1, "integer", axis::uoflow::off));
);
std::cout << h << std::endl; std::cout << h << std::endl;
/* prints: /* prints:
histogram( histogram(
regular(2, -1, 1, label='regular1', uoflow=False), regular(2, -1, 1, label='regular1', uoflow=False),
regular_log(2, 1, 10, label='regular2'), regular_log(2, 1, 10, label='regular2'),
circular(4, phase=0.1, perimeter=1, label='polar'), circular(4, phase=0.1, perimeter=1, label='polar'),
variable(-1, 0, 1, label='variable', uoflow=False), variable(-1, 0, 1, label='variable', uoflow=False),
category(0, 1, 2, label='category'), category(0, 1, 2, label='category'),
integer(-1, 1, label='integer', uoflow=False), integer(-1, 1, label='integer', uoflow=False),
) )
*/ */
} }
//] //]

View File

@ -6,15 +6,15 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
// create vector of axes, axis::any is a polymorphic axis type // create vector of axes, axis::any is a polymorphic axis type
auto v = std::vector<bh::axis::any_std>(); auto v = std::vector<bh::axis::any_std>();
v.push_back(bh::axis::regular<>(100, -1, 1)); v.push_back(bh::axis::regular<>(100, -1, 1));
v.push_back(bh::axis::integer<>(1, 7)); v.push_back(bh::axis::integer<>(1, 7));
// create dynamic histogram (make_static_histogram be used with iterators) // create dynamic histogram (make_static_histogram be used with iterators)
auto h = bh::make_dynamic_histogram(v.begin(), v.end()); auto h = bh::make_dynamic_histogram(v.begin(), v.end());
// do something with h // do something with h
} }
//] //]

View File

@ -5,14 +5,14 @@
namespace bh = boost::histogram; namespace bh = boost::histogram;
int main() { int main() {
/* /*
create a 1d-histogram in default configuration which create a 1d-histogram in default configuration which
covers the real line from -1 to 1 in 100 bins, the same covers the real line from -1 to 1 in 100 bins, the same
call with `make_dynamic_histogram` would also work call with `make_dynamic_histogram` would also work
*/ */
auto h = bh::make_static_histogram(bh::axis::regular<>(100, -1, 1)); auto h = bh::make_static_histogram(bh::axis::regular<>(100, -1, 1));
// do something with h // do something with h
} }
//] //]

View File

@ -1,7 +1,7 @@
//[ guide_mixed_cpp_python_part_cpp //[ guide_mixed_cpp_python_part_cpp
#include <boost/python.hpp>
#include <boost/histogram.hpp> #include <boost/histogram.hpp>
#include <boost/python.hpp>
namespace bh = boost::histogram; namespace bh = boost::histogram;
namespace bp = boost::python; namespace bp = boost::python;
@ -9,13 +9,10 @@ namespace bp = boost::python;
// function that runs in C++ and accepts reference to dynamic histogram // function that runs in C++ and accepts reference to dynamic histogram
void process(bh::dynamic_histogram<>& h) { void process(bh::dynamic_histogram<>& h) {
// fill histogram, in reality this would be arbitrarily complex code // fill histogram, in reality this would be arbitrarily complex code
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) h(0.25 * i, i);
h(0.25 * i, i);
} }
// a minimal Python module, which exposes the process function to Python // a minimal Python module, which exposes the process function to Python
BOOST_PYTHON_MODULE(cpp_filler) { BOOST_PYTHON_MODULE(cpp_filler) { bp::def("process", process); }
bp::def("process", process);
}
//] //]

View File

@ -20,7 +20,8 @@ histogram<T, A, S>&& operator+(histogram<T, A, S>&& a,
} }
template <typename T, typename A, typename S> template <typename T, typename A, typename S>
histogram<T, A, S>&& operator+(histogram<T, A, S>&& a, histogram<T, A, S>&& b) { histogram<T, A, S>&& operator+(histogram<T, A, S>&& a,
histogram<T, A, S>&& b) {
a += b; a += b;
return std::move(a); return std::move(a);
} }

View File

@ -28,7 +28,7 @@ enum class uoflow { off = 0, only_oflow = 1, on = 2 };
/// Base class for all axes /// Base class for all axes
class base { class base {
public: public:
/// Returns the number of bins without overflow/underflow. /// Returns the number of bins without overflow/underflow.
int size() const noexcept { return size_; } int size() const noexcept { return size_; }
/// Returns the number of bins, including overflow/underflow if enabled. /// Returns the number of bins, including overflow/underflow if enabled.
@ -40,14 +40,12 @@ class base {
/// Change the label of an axis. /// Change the label of an axis.
void label(string_view label) { label_.assign(label.begin(), label.end()); } void label(string_view label) { label_.assign(label.begin(), label.end()); }
protected: protected:
base(unsigned size, string_view label, axis::uoflow uo) base(unsigned size, string_view label, axis::uoflow uo)
: size_(size), : size_(size),
shape_(size + static_cast<int>(uo)), shape_(size + static_cast<int>(uo)),
label_(label.begin(), label.end()) { label_(label.begin(), label.end()) {
if (size_ == 0) { if (size_ == 0) { throw std::invalid_argument("bins > 0 required"); }
throw std::invalid_argument("bins > 0 required");
}
} }
base() = default; base() = default;
@ -73,7 +71,7 @@ class base {
return size_ == rhs.size_ && shape_ == rhs.shape_ && label_ == rhs.label_; return size_ == rhs.size_ && shape_ == rhs.shape_ && label_ == rhs.label_;
} }
private: private:
int size_ = 0, shape_ = 0; int size_ = 0, shape_ = 0;
std::string label_; std::string label_;
@ -85,7 +83,7 @@ class base {
/// Iterator mixin, uses CRTP to inject iterator logic into Derived. /// Iterator mixin, uses CRTP to inject iterator logic into Derived.
template <typename Derived> template <typename Derived>
class iterator_mixin { class iterator_mixin {
public: public:
using const_iterator = iterator_over<Derived>; using const_iterator = iterator_over<Derived>;
using const_reverse_iterator = reverse_iterator_over<Derived>; using const_reverse_iterator = reverse_iterator_over<Derived>;

View File

@ -16,7 +16,7 @@ namespace axis {
template <typename Axis> template <typename Axis>
class interval_view { class interval_view {
public: public:
interval_view(int idx, const Axis& axis) : idx_(idx), axis_(axis) {} interval_view(int idx, const Axis& axis) : idx_(idx), axis_(axis) {}
interval_view(const interval_view&) = default; interval_view(const interval_view&) = default;
@ -32,7 +32,9 @@ class interval_view {
auto upper() const noexcept -> decltype(std::declval<Axis&>().lower(0)) { auto upper() const noexcept -> decltype(std::declval<Axis&>().lower(0)) {
return axis_.lower(idx_ + 1); return axis_.lower(idx_ + 1);
} }
typename Axis::value_type width() const noexcept { return upper() - lower(); } typename Axis::value_type width() const noexcept {
return upper() - lower();
}
bool operator==(const interval_view& rhs) const noexcept { bool operator==(const interval_view& rhs) const noexcept {
return idx_ == rhs.idx_ && axis_ == rhs.axis_; return idx_ == rhs.idx_ && axis_ == rhs.axis_;
@ -43,7 +45,7 @@ class interval_view {
explicit operator int() const noexcept { return idx_; } explicit operator int() const noexcept { return idx_; }
private: private:
const int idx_; const int idx_;
const Axis& axis_; const Axis& axis_;
}; };

View File

@ -14,17 +14,18 @@ namespace histogram {
namespace axis { namespace axis {
template <typename Axis> template <typename Axis>
class iterator_over : public iterator_facade<iterator_over<Axis>, class iterator_over
typename Axis::bin_type, : public iterator_facade<iterator_over<Axis>, typename Axis::bin_type,
random_access_traversal_tag, random_access_traversal_tag,
typename Axis::bin_type> { typename Axis::bin_type> {
public: public:
explicit iterator_over(const Axis& axis, int idx) : axis_(axis), idx_(idx) {} explicit iterator_over(const Axis& axis, int idx)
: axis_(axis), idx_(idx) {}
iterator_over(const iterator_over&) = default; iterator_over(const iterator_over&) = default;
iterator_over& operator=(const iterator_over&) = default; iterator_over& operator=(const iterator_over&) = default;
protected: protected:
void increment() noexcept { ++idx_; } void increment() noexcept { ++idx_; }
void decrement() noexcept { --idx_; } void decrement() noexcept { --idx_; }
void advance(int n) noexcept { idx_ += n; } void advance(int n) noexcept { idx_ += n; }
@ -43,18 +44,17 @@ class iterator_over : public iterator_facade<iterator_over<Axis>,
template <typename Axis> template <typename Axis>
class reverse_iterator_over class reverse_iterator_over
: public iterator_facade<reverse_iterator_over<Axis>, : public iterator_facade<
typename Axis::bin_type, reverse_iterator_over<Axis>, typename Axis::bin_type,
random_access_traversal_tag, random_access_traversal_tag, typename Axis::bin_type> {
typename Axis::bin_type> { public:
public:
explicit reverse_iterator_over(const Axis& axis, int idx) explicit reverse_iterator_over(const Axis& axis, int idx)
: axis_(axis), idx_(idx) {} : axis_(axis), idx_(idx) {}
reverse_iterator_over(const reverse_iterator_over&) = default; reverse_iterator_over(const reverse_iterator_over&) = default;
reverse_iterator_over& operator=(const reverse_iterator_over&) = default; reverse_iterator_over& operator=(const reverse_iterator_over&) = default;
protected: protected:
void increment() noexcept { --idx_; } void increment() noexcept { --idx_; }
void decrement() noexcept { ++idx_; } void decrement() noexcept { ++idx_; }
void advance(int n) noexcept { idx_ -= n; } void advance(int n) noexcept { idx_ -= n; }

View File

@ -20,15 +20,9 @@ namespace histogram {
namespace axis { namespace axis {
namespace detail { namespace detail {
inline string_view to_string(const transform::identity&) { inline string_view to_string(const transform::identity&) { return {}; }
return {}; inline string_view to_string(const transform::log&) { return {"_log", 4}; }
} inline string_view to_string(const transform::sqrt&) { return {"_sqrt", 5}; }
inline string_view to_string(const transform::log&) {
return {"_log", 4};
}
inline string_view to_string(const transform::sqrt&) {
return {"_sqrt", 5};
}
} // namespace detail } // namespace detail
template <typename T> template <typename T>
@ -52,36 +46,30 @@ inline std::ostream& operator<<(std::ostream& os,
os << ", label="; os << ", label=";
::boost::histogram::detail::escape(os, a.label()); ::boost::histogram::detail::escape(os, a.label());
} }
if (!a.uoflow()) { if (!a.uoflow()) { os << ", uoflow=False"; }
os << ", uoflow=False";
}
os << ")"; os << ")";
return os; return os;
} }
template <typename RealType> template <typename RealType>
inline std::ostream& operator<<( inline std::ostream& operator<<(
std::ostream& os, std::ostream& os, const regular<RealType, axis::transform::pow>& a) {
const regular<RealType, axis::transform::pow>& a) {
os << "regular_pow(" << a.size() << ", " << a[0].lower() << ", " os << "regular_pow(" << a.size() << ", " << a[0].lower() << ", "
<< a[a.size()].lower() << ", " << a.transform().power; << a[a.size()].lower() << ", " << a.transform().power;
if (!a.label().empty()) { if (!a.label().empty()) {
os << ", label="; os << ", label=";
::boost::histogram::detail::escape(os, a.label()); ::boost::histogram::detail::escape(os, a.label());
} }
if (!a.uoflow()) { if (!a.uoflow()) { os << ", uoflow=False"; }
os << ", uoflow=False";
}
os << ")"; os << ")";
return os; return os;
} }
template <typename RealType> template <typename RealType>
inline std::ostream& operator<<(std::ostream& os, const circular<RealType>& a) { inline std::ostream& operator<<(std::ostream& os,
const circular<RealType>& a) {
os << "circular(" << a.size(); os << "circular(" << a.size();
if (a.phase() != 0.0) { if (a.phase() != 0.0) { os << ", phase=" << a.phase(); }
os << ", phase=" << a.phase();
}
if (a.perimeter() != RealType(::boost::histogram::detail::two_pi)) { if (a.perimeter() != RealType(::boost::histogram::detail::two_pi)) {
os << ", perimeter=" << a.perimeter(); os << ", perimeter=" << a.perimeter();
} }
@ -94,18 +82,15 @@ inline std::ostream& operator<<(std::ostream& os, const circular<RealType>& a) {
} }
template <typename RealType> template <typename RealType>
inline std::ostream& operator<<(std::ostream& os, const variable<RealType>& a) { inline std::ostream& operator<<(std::ostream& os,
const variable<RealType>& a) {
os << "variable(" << a[0].lower(); os << "variable(" << a[0].lower();
for (int i = 1; i <= a.size(); ++i) { for (int i = 1; i <= a.size(); ++i) { os << ", " << a[i].lower(); }
os << ", " << a[i].lower();
}
if (!a.label().empty()) { if (!a.label().empty()) {
os << ", label="; os << ", label=";
::boost::histogram::detail::escape(os, a.label()); ::boost::histogram::detail::escape(os, a.label());
} }
if (!a.uoflow()) { if (!a.uoflow()) { os << ", uoflow=False"; }
os << ", uoflow=False";
}
os << ")"; os << ")";
return os; return os;
} }
@ -117,9 +102,7 @@ inline std::ostream& operator<<(std::ostream& os, const integer<IntType>& a) {
os << ", label="; os << ", label=";
::boost::histogram::detail::escape(os, a.label()); ::boost::histogram::detail::escape(os, a.label());
} }
if (!a.uoflow()) { if (!a.uoflow()) { os << ", uoflow=False"; }
os << ", uoflow=False";
}
os << ")"; os << ")";
return os; return os;
} }

View File

@ -97,7 +97,7 @@ struct pow {
return power == other.power; return power == other.power;
} }
private: private:
friend ::boost::serialization::access; friend ::boost::serialization::access;
template <class Archive> template <class Archive>
void serialize(Archive&, unsigned); void serialize(Archive&, unsigned);
@ -114,7 +114,7 @@ template <typename RealType, typename Transform>
class regular : public base, class regular : public base,
public iterator_mixin<regular<RealType, Transform>>, public iterator_mixin<regular<RealType, Transform>>,
Transform { Transform {
public: public:
using value_type = RealType; using value_type = RealType;
using bin_type = interval_view<regular>; using bin_type = interval_view<regular>;
@ -127,11 +127,8 @@ class regular : public base,
* \param uoflow whether to add under-/overflow bins. * \param uoflow whether to add under-/overflow bins.
* \param trans arguments passed to the transform. * \param trans arguments passed to the transform.
*/ */
regular(unsigned n, regular(unsigned n, value_type lower, value_type upper,
value_type lower, string_view label = {}, axis::uoflow uo = axis::uoflow::on,
value_type upper,
string_view label = {},
axis::uoflow uo = axis::uoflow::on,
Transform trans = Transform()) Transform trans = Transform())
: base(n, label, uo), : base(n, label, uo),
Transform(trans), Transform(trans),
@ -177,8 +174,8 @@ class regular : public base,
bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); } bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); }
bool operator==(const regular& o) const noexcept { bool operator==(const regular& o) const noexcept {
return base::operator==(o) && Transform::operator==(o) && min_ == o.min_ && return base::operator==(o) && Transform::operator==(o) &&
delta_ == o.delta_; min_ == o.min_ && delta_ == o.delta_;
} }
/// Access properties of the transform. /// Access properties of the transform.
@ -186,7 +183,7 @@ class regular : public base,
return static_cast<const Transform&>(*this); return static_cast<const Transform&>(*this);
} }
private: private:
value_type min_ = 0.0, delta_ = 1.0; value_type min_ = 0.0, delta_ = 1.0;
friend class ::boost::serialization::access; friend class ::boost::serialization::access;
@ -202,7 +199,7 @@ class regular : public base,
*/ */
template <typename RealType> template <typename RealType>
class circular : public base, public iterator_mixin<circular<RealType>> { class circular : public base, public iterator_mixin<circular<RealType>> {
public: public:
using value_type = RealType; using value_type = RealType;
using bin_type = interval_view<circular>; using bin_type = interval_view<circular>;
@ -213,8 +210,7 @@ class circular : public base, public iterator_mixin<circular<RealType>> {
* \param perimeter range after which value wraps around. * \param perimeter range after which value wraps around.
* \param label description of the axis. * \param label description of the axis.
*/ */
explicit circular(unsigned n, explicit circular(unsigned n, value_type phase = 0.0,
value_type phase = 0.0,
value_type perimeter = boost::histogram::detail::two_pi, value_type perimeter = boost::histogram::detail::two_pi,
string_view label = {}) string_view label = {})
: base(n, label, axis::uoflow::off), : base(n, label, axis::uoflow::off),
@ -230,7 +226,8 @@ class circular : public base, public iterator_mixin<circular<RealType>> {
/// Returns the bin index for the passed argument. /// Returns the bin index for the passed argument.
int index(value_type x) const noexcept { int index(value_type x) const noexcept {
const value_type z = (x - phase_) / perimeter_; const value_type z = (x - phase_) / perimeter_;
const int i = static_cast<int>(std::floor(z * base::size())) % base::size(); const int i =
static_cast<int>(std::floor(z * base::size())) % base::size();
return i + (i < 0) * base::size(); return i + (i < 0) * base::size();
} }
@ -250,7 +247,7 @@ class circular : public base, public iterator_mixin<circular<RealType>> {
value_type perimeter() const { return perimeter_; } value_type perimeter() const { return perimeter_; }
value_type phase() const { return phase_; } value_type phase() const { return phase_; }
private: private:
value_type phase_ = 0.0, perimeter_ = 1.0; value_type phase_ = 0.0, perimeter_ = 1.0;
friend class ::boost::serialization::access; friend class ::boost::serialization::access;
@ -265,7 +262,7 @@ class circular : public base, public iterator_mixin<circular<RealType>> {
*/ */
template <typename RealType> template <typename RealType>
class variable : public base, public iterator_mixin<variable<RealType>> { class variable : public base, public iterator_mixin<variable<RealType>> {
public: public:
using value_type = RealType; using value_type = RealType;
using bin_type = interval_view<variable>; using bin_type = interval_view<variable>;
@ -275,8 +272,7 @@ class variable : public base, public iterator_mixin<variable<RealType>> {
* \param label description of the axis. * \param label description of the axis.
* \param uoflow whether to add under-/overflow bins. * \param uoflow whether to add under-/overflow bins.
*/ */
variable(std::initializer_list<value_type> x, variable(std::initializer_list<value_type> x, string_view label = {},
string_view label = {},
axis::uoflow uo = axis::uoflow::on) axis::uoflow uo = axis::uoflow::on)
: base(x.size() - 1, label, uo), x_(new value_type[x.size()]) { : base(x.size() - 1, label, uo), x_(new value_type[x.size()]) {
if (x.size() >= 2) { if (x.size() >= 2) {
@ -288,9 +284,7 @@ class variable : public base, public iterator_mixin<variable<RealType>> {
} }
template <typename Iterator> template <typename Iterator>
variable(Iterator begin, variable(Iterator begin, Iterator end, string_view label = {},
Iterator end,
string_view label = {},
axis::uoflow uo = axis::uoflow::on) axis::uoflow uo = axis::uoflow::on)
: base(std::distance(begin, end) - 1, label, uo), : base(std::distance(begin, end) - 1, label, uo),
x_(new value_type[std::distance(begin, end)]) { x_(new value_type[std::distance(begin, end)]) {
@ -299,7 +293,8 @@ class variable : public base, public iterator_mixin<variable<RealType>> {
} }
variable() = default; variable() = default;
variable(const variable& o) : base(o), x_(new value_type[base::size() + 1]) { variable(const variable& o)
: base(o), x_(new value_type[base::size() + 1]) {
std::copy(o.x_.get(), o.x_.get() + base::size() + 1, x_.get()); std::copy(o.x_.get(), o.x_.get() + base::size() + 1, x_.get());
} }
variable& operator=(const variable& o) { variable& operator=(const variable& o) {
@ -321,9 +316,7 @@ class variable : public base, public iterator_mixin<variable<RealType>> {
/// Returns the starting edge of the bin. /// Returns the starting edge of the bin.
value_type lower(int i) const noexcept { value_type lower(int i) const noexcept {
if (i < 0) { if (i < 0) { return -std::numeric_limits<value_type>::infinity(); }
return -std::numeric_limits<value_type>::infinity();
}
if (i > base::size()) { if (i > base::size()) {
return std::numeric_limits<value_type>::infinity(); return std::numeric_limits<value_type>::infinity();
} }
@ -333,13 +326,11 @@ class variable : public base, public iterator_mixin<variable<RealType>> {
bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); } bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); }
bool operator==(const variable& o) const noexcept { bool operator==(const variable& o) const noexcept {
if (!base::operator==(o)) { if (!base::operator==(o)) { return false; }
return false;
}
return std::equal(x_.get(), x_.get() + base::size() + 1, o.x_.get()); return std::equal(x_.get(), x_.get() + base::size() + 1, o.x_.get());
} }
private: private:
std::unique_ptr<value_type[]> x_; // smaller size compared to std::vector std::unique_ptr<value_type[]> x_; // smaller size compared to std::vector
friend class ::boost::serialization::access; friend class ::boost::serialization::access;
@ -354,7 +345,7 @@ class variable : public base, public iterator_mixin<variable<RealType>> {
*/ */
template <typename IntType> template <typename IntType>
class integer : public base, public iterator_mixin<integer<IntType>> { class integer : public base, public iterator_mixin<integer<IntType>> {
public: public:
using value_type = IntType; using value_type = IntType;
using bin_type = interval_view<integer>; using bin_type = interval_view<integer>;
@ -365,9 +356,7 @@ class integer : public base, public iterator_mixin<integer<IntType>> {
* \param label description of the axis. * \param label description of the axis.
* \param uoflow whether to add under-/overflow bins. * \param uoflow whether to add under-/overflow bins.
*/ */
integer(value_type lower, integer(value_type lower, value_type upper, string_view label = {},
value_type upper,
string_view label = {},
axis::uoflow uo = axis::uoflow::on) axis::uoflow uo = axis::uoflow::on)
: base(upper - lower, label, uo), min_(lower) { : base(upper - lower, label, uo), min_(lower) {
if (!(lower < upper)) { if (!(lower < upper)) {
@ -389,12 +378,8 @@ class integer : public base, public iterator_mixin<integer<IntType>> {
/// Returns lower edge of the integral bin. /// Returns lower edge of the integral bin.
value_type lower(int i) const noexcept { value_type lower(int i) const noexcept {
if (i < 0) { if (i < 0) { return -std::numeric_limits<value_type>::max(); }
return -std::numeric_limits<value_type>::max(); if (i > base::size()) { return std::numeric_limits<value_type>::max(); }
}
if (i > base::size()) {
return std::numeric_limits<value_type>::max();
}
return min_ + i; return min_ + i;
} }
@ -404,7 +389,7 @@ class integer : public base, public iterator_mixin<integer<IntType>> {
return base::operator==(o) && min_ == o.min_; return base::operator==(o) && min_ == o.min_;
} }
private: private:
value_type min_ = 0; value_type min_ = 0;
friend class ::boost::serialization::access; friend class ::boost::serialization::access;
@ -423,7 +408,7 @@ template <typename T>
class category : public base, public iterator_mixin<category<T>> { class category : public base, public iterator_mixin<category<T>> {
using map_type = bimap<T, int>; using map_type = bimap<T, int>;
public: public:
using value_type = T; using value_type = T;
using bin_type = value_view<category>; using bin_type = value_view<category>;
@ -446,10 +431,8 @@ class category : public base, public iterator_mixin<category<T>> {
category(std::initializer_list<value_type> seq, string_view label = {}) category(std::initializer_list<value_type> seq, string_view label = {})
: base(seq.size(), label, axis::uoflow::off), map_(new map_type()) { : base(seq.size(), label, axis::uoflow::off), map_(new map_type()) {
int index = 0; int index = 0;
for (const auto& x : seq) for (const auto& x : seq) map_->insert({x, index++});
map_->insert({x, index++}); if (index == 0) throw std::invalid_argument("sequence is empty");
if (index == 0)
throw std::invalid_argument("sequence is empty");
} }
template <typename Iterator, template <typename Iterator,
@ -458,17 +441,14 @@ class category : public base, public iterator_mixin<category<T>> {
: base(std::distance(begin, end), label, axis::uoflow::off), : base(std::distance(begin, end), label, axis::uoflow::off),
map_(new map_type()) { map_(new map_type()) {
int index = 0; int index = 0;
while (begin != end) while (begin != end) map_->insert({*begin++, index++});
map_->insert({*begin++, index++}); if (index == 0) throw std::invalid_argument("iterator range is empty");
if (index == 0)
throw std::invalid_argument("iterator range is empty");
} }
/// Returns the bin index for the passed argument. /// Returns the bin index for the passed argument.
int index(const value_type& x) const noexcept { int index(const value_type& x) const noexcept {
auto it = map_->left.find(x); auto it = map_->left.find(x);
if (it == map_->left.end()) if (it == map_->left.end()) return base::size();
return base::size();
return it->second; return it->second;
} }
@ -487,7 +467,7 @@ class category : public base, public iterator_mixin<category<T>> {
std::equal(map_->begin(), map_->end(), o.map_->begin()); std::equal(map_->begin(), map_->end(), o.map_->begin());
} }
private: private:
std::unique_ptr<map_type> map_; std::unique_ptr<map_type> map_;
friend class ::boost::serialization::access; friend class ::boost::serialization::access;

View File

@ -16,7 +16,7 @@ namespace axis {
template <typename Axis> template <typename Axis>
class value_view { class value_view {
public: public:
value_view(int idx, const Axis& axis) : idx_(idx), axis_(axis) {} value_view(int idx, const Axis& axis) : idx_(idx), axis_(axis) {}
value_view(const value_view&) = default; value_view(const value_view&) = default;
@ -39,7 +39,7 @@ class value_view {
explicit operator int() const noexcept { return idx_; } explicit operator int() const noexcept { return idx_; }
private: private:
const int idx_; const int idx_;
const Axis& axis_; const Axis& axis_;
}; };

View File

@ -59,15 +59,13 @@ struct axes_assign_vecvar_tuple {
}; };
template <typename... Ts> template <typename... Ts>
inline bool axes_equal_impl(mp11::mp_true, inline bool axes_equal_impl(mp11::mp_true, const std::tuple<Ts...>& t,
const std::tuple<Ts...>& t,
const std::tuple<Ts...>& u) { const std::tuple<Ts...>& u) {
return t == u; return t == u;
} }
template <typename... Ts, typename... Us> template <typename... Ts, typename... Us>
inline bool axes_equal_impl(mp11::mp_false, inline bool axes_equal_impl(mp11::mp_false, const std::tuple<Ts...>&,
const std::tuple<Ts...>&,
const std::tuple<Us...>&) { const std::tuple<Us...>&) {
return false; return false;
} }
@ -75,27 +73,28 @@ inline bool axes_equal_impl(mp11::mp_false,
} // namespace } // namespace
template <typename... Ts, typename... Us> template <typename... Ts, typename... Us>
inline bool axes_equal(const std::tuple<Ts...>& t, const std::tuple<Us...>& u) { inline bool axes_equal(const std::tuple<Ts...>& t,
const std::tuple<Us...>& u) {
return axes_equal_impl( return axes_equal_impl(
mp11::mp_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>(), t, u); mp11::mp_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>(), t, u);
} }
template <typename... Ts, typename... Us> template <typename... Ts, typename... Us>
inline void axes_assign(std::tuple<Ts...>& t, const std::tuple<Us...>& u) { inline void axes_assign(std::tuple<Ts...>& t, const std::tuple<Us...>& u) {
static_assert(std::is_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>::value, static_assert(
"cannot assign incompatible axes"); std::is_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>::value,
"cannot assign incompatible axes");
t = u; t = u;
} }
template <typename... Ts, typename... Us> template <typename... Ts, typename... Us>
inline bool axes_equal(const std::tuple<Ts...>& t, inline bool axes_equal(const std::tuple<Ts...>& t,
const std::vector<axis::any<Us...>>& u) { const std::vector<axis::any<Us...>>& u) {
if (sizeof...(Ts) != u.size()) if (sizeof...(Ts) != u.size()) return false;
return false;
bool equal = true; bool equal = true;
auto fn = auto fn =
axes_equal_tuple_vecvar<std::tuple<Ts...>, std::vector<axis::any<Us...>>>( axes_equal_tuple_vecvar<std::tuple<Ts...>,
equal, t, u); std::vector<axis::any<Us...>>>(equal, t, u);
mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>(fn); mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>(fn);
return equal; return equal;
} }
@ -126,11 +125,9 @@ inline void axes_assign(std::vector<axis::any<Ts...>>& t,
template <typename... Ts, typename... Us> template <typename... Ts, typename... Us>
inline bool axes_equal(const std::vector<axis::any<Ts...>>& t, inline bool axes_equal(const std::vector<axis::any<Ts...>>& t,
const std::vector<axis::any<Us...>>& u) { const std::vector<axis::any<Us...>>& u) {
if (t.size() != u.size()) if (t.size() != u.size()) return false;
return false;
for (std::size_t i = 0; i < t.size(); ++i) { for (std::size_t i = 0; i < t.size(); ++i) {
if (t[i] != u[i]) if (t[i] != u[i]) return false;
return false;
} }
return true; return true;
} }
@ -138,9 +135,7 @@ inline bool axes_equal(const std::vector<axis::any<Ts...>>& t,
template <typename... Ts, typename... Us> template <typename... Ts, typename... Us>
inline void axes_assign(std::vector<axis::any<Ts...>>& t, inline void axes_assign(std::vector<axis::any<Ts...>>& t,
const std::vector<axis::any<Us...>>& u) { const std::vector<axis::any<Us...>>& u) {
for (std::size_t i = 0; i < t.size(); ++i) { for (std::size_t i = 0; i < t.size(); ++i) { t[i] = u[i]; }
t[i] = u[i];
}
} }
struct field_count_visitor : public static_visitor<void> { struct field_count_visitor : public static_visitor<void> {

View File

@ -7,8 +7,8 @@
#ifndef _BOOST_HISTOGRAM_DETAIL_INDEX_CACHE_HPP_ #ifndef _BOOST_HISTOGRAM_DETAIL_INDEX_CACHE_HPP_
#define _BOOST_HISTOGRAM_DETAIL_INDEX_CACHE_HPP_ #define _BOOST_HISTOGRAM_DETAIL_INDEX_CACHE_HPP_
#include <memory>
#include <cstddef> #include <cstddef>
#include <memory>
namespace boost { namespace boost {
namespace histogram { namespace histogram {
@ -62,8 +62,7 @@ struct index_cache {
} }
void operator()(std::size_t idx) { void operator()(std::size_t idx) {
if (idx == idx_) if (idx == idx_) return;
return;
idx_ = idx; idx_ = idx;
auto dim_ptr = dims_.get(); auto dim_ptr = dims_.get();
auto dim = dim_; auto dim = dim_;

View File

@ -32,8 +32,9 @@ struct index_mapper {
s1 *= ni; s1 *= ni;
++bi; ++bi;
} }
std::sort(dims.begin(), dims.end(), std::sort(dims.begin(), dims.end(), [](const dim& a, const dim& b) {
[](const dim& a, const dim& b) { return a.stride1 > b.stride1; }); return a.stride1 > b.stride1;
});
nfirst = s1; nfirst = s1;
} }
@ -49,7 +50,7 @@ struct index_mapper {
return first < nfirst; return first < nfirst;
} }
private: private:
std::size_t nfirst; std::size_t nfirst;
struct dim { struct dim {
std::size_t stride1, stride2; std::size_t stride1, stride2;

View File

@ -55,16 +55,14 @@ struct no_container_tag {};
template <typename T> template <typename T>
using classify_container = typename std::conditional< using classify_container = typename std::conditional<
is_static_container<T>::value, is_static_container<T>::value, static_container_tag,
static_container_tag,
typename std::conditional<is_dynamic_container<T>::value, typename std::conditional<is_dynamic_container<T>::value,
dynamic_container_tag, dynamic_container_tag,
no_container_tag>::type>::type; no_container_tag>::type>::type;
template <typename T, template <typename T, typename = decltype(std::declval<T&>().size(),
typename = decltype(std::declval<T&>().size(), std::declval<T&>().increase(0),
std::declval<T&>().increase(0), std::declval<T&>()[0])>
std::declval<T&>()[0])>
struct requires_storage {}; struct requires_storage {};
template <typename T, template <typename T,
@ -72,11 +70,10 @@ template <typename T,
struct requires_iterator {}; struct requires_iterator {};
template <typename T> template <typename T>
using requires_axis = decltype(std::declval<T&>().size(), using requires_axis =
std::declval<T&>().shape(), decltype(std::declval<T&>().size(), std::declval<T&>().shape(),
std::declval<T&>().uoflow(), std::declval<T&>().uoflow(), std::declval<T&>().label(),
std::declval<T&>().label(), std::declval<T&>()[0]);
std::declval<T&>()[0]);
namespace { namespace {
struct bool_mask_impl { struct bool_mask_impl {
@ -108,13 +105,11 @@ using mp_at_c = mp11::mp_at_c<rm_cv_ref<T>, D>;
template <typename T1, typename T2> template <typename T1, typename T2>
using copy_qualifiers = mp11::mp_if< using copy_qualifiers = mp11::mp_if<
std::is_rvalue_reference<T1>, std::is_rvalue_reference<T1>, T2&&,
T2&&,
mp11::mp_if< mp11::mp_if<
std::is_lvalue_reference<T1>, std::is_lvalue_reference<T1>,
mp11::mp_if<std::is_const<typename std::remove_reference<T1>::type>, mp11::mp_if<std::is_const<typename std::remove_reference<T1>::type>,
const T2&, const T2&, T2&>,
T2&>,
mp11::mp_if<std::is_const<T1>, const T2, T2>>>; mp11::mp_if<std::is_const<T1>, const T2, T2>>>;
template <typename S, typename L> template <typename S, typename L>

View File

@ -41,11 +41,8 @@ inline void escape(std::ostream& os, const string_view s) {
// the following is highly optimized code that runs in a hot loop; // the following is highly optimized code that runs in a hot loop;
// please measure the performance impact of changes // please measure the performance impact of changes
inline void lin(std::size_t& out, inline void lin(std::size_t& out, std::size_t& stride, const int axis_size,
std::size_t& stride, const int axis_shape, int j) noexcept {
const int axis_size,
const int axis_shape,
int j) noexcept {
BOOST_ASSERT_MSG(stride == 0 || (-1 <= j && j <= axis_size), BOOST_ASSERT_MSG(stride == 0 || (-1 <= j && j <= axis_size),
"index must be in bounds for this algorithm"); "index must be in bounds for this algorithm");
j += (j < 0) * (axis_size + 2); // wrap around if j < 0 j += (j < 0) * (axis_size + 2); // wrap around if j < 0
@ -53,7 +50,8 @@ inline void lin(std::size_t& out,
#ifndef _MSC_VER #ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wstrict-overflow" #pragma GCC diagnostic ignored "-Wstrict-overflow"
#endif #endif
stride *= (j < axis_shape) * axis_shape; // stride == 0 indicates out-of-range stride *=
(j < axis_shape) * axis_shape; // stride == 0 indicates out-of-range
} }
template <typename T> template <typename T>
@ -84,8 +82,7 @@ inline void fill_storage(S& s, std::size_t idx) {
template <typename S> template <typename S>
inline auto storage_get(const S& s, std::size_t idx, bool error) -> inline auto storage_get(const S& s, std::size_t idx, bool error) ->
typename S::const_reference { typename S::const_reference {
if (error) if (error) throw std::out_of_range("bin index out of range");
throw std::out_of_range("bin index out of range");
return s[idx]; return s[idx];
} }

View File

@ -54,7 +54,7 @@ template <typename Axes, typename Storage>
class histogram<dynamic_tag, Axes, Storage> { class histogram<dynamic_tag, Axes, Storage> {
static_assert(mp11::mp_size<Axes>::value > 0, "at least one axis required"); static_assert(mp11::mp_size<Axes>::value > 0, "at least one axis required");
public: public:
using any_axis_type = mp11::mp_rename<Axes, axis::any>; using any_axis_type = mp11::mp_rename<Axes, axis::any>;
using axes_type = std::vector<any_axis_type>; using axes_type = std::vector<any_axis_type>;
using element_type = typename Storage::element_type; using element_type = typename Storage::element_type;
@ -62,15 +62,14 @@ class histogram<dynamic_tag, Axes, Storage> {
using const_iterator = iterator_over<histogram>; using const_iterator = iterator_over<histogram>;
using iterator = const_iterator; using iterator = const_iterator;
public: public:
histogram() = default; histogram() = default;
histogram(const histogram&) = default; histogram(const histogram&) = default;
histogram(histogram&&) = default; histogram(histogram&&) = default;
histogram& operator=(const histogram&) = default; histogram& operator=(const histogram&) = default;
histogram& operator=(histogram&&) = default; histogram& operator=(histogram&&) = default;
template <typename Axis0, template <typename Axis0, typename... Axis,
typename... Axis,
typename = detail::requires_axis<Axis0>> typename = detail::requires_axis<Axis0>>
explicit histogram(Axis0&& axis0, Axis&&... axis) explicit histogram(Axis0&& axis0, Axis&&... axis)
: axes_({any_axis_type(std::forward<Axis0>(axis0)), : axes_({any_axis_type(std::forward<Axis0>(axis0)),
@ -161,9 +160,7 @@ class histogram<dynamic_tag, Axes, Storage> {
"(did you use weight() in the wrong place?)"); "(did you use weight() in the wrong place?)");
std::size_t idx = 0, stride = 1; std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, std::forward<Ts>(ts)...); xlin<0>(idx, stride, std::forward<Ts>(ts)...);
if (stride) { if (stride) { detail::fill_storage(storage_, idx); }
detail::fill_storage(storage_, idx);
}
} }
template <typename T> template <typename T>
@ -183,9 +180,7 @@ class histogram<dynamic_tag, Axes, Storage> {
"fill arguments does not match histogram dimension"); "fill arguments does not match histogram dimension");
std::size_t idx = 0, stride = 1; std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, std::forward<Ts>(ts)...); xlin<0>(idx, stride, std::forward<Ts>(ts)...);
if (stride) { if (stride) { detail::fill_storage(storage_, idx, std::move(w)); }
detail::fill_storage(storage_, idx, std::move(w));
}
} }
template <typename W, typename T> template <typename W, typename T>
@ -260,8 +255,7 @@ class histogram<dynamic_tag, Axes, Storage> {
template <typename... Ts> template <typename... Ts>
histogram reduce_to(int n, Ts... ts) const { histogram reduce_to(int n, Ts... ts) const {
std::vector<bool> b(dim(), false); std::vector<bool> b(dim(), false);
for (const auto& i : {n, int(ts)...}) for (const auto& i : {n, int(ts)...}) b[i] = true;
b[i] = true;
return reduce_impl(b); return reduce_impl(b);
} }
@ -269,8 +263,7 @@ class histogram<dynamic_tag, Axes, Storage> {
template <typename Iterator, typename = detail::requires_iterator<Iterator>> template <typename Iterator, typename = detail::requires_iterator<Iterator>>
histogram reduce_to(Iterator begin, Iterator end) const { histogram reduce_to(Iterator begin, Iterator end) const {
std::vector<bool> b(dim(), false); std::vector<bool> b(dim(), false);
for (; begin != end; ++begin) for (; begin != end; ++begin) b[*begin] = true;
b[*begin] = true;
return reduce_impl(b); return reduce_impl(b);
} }
@ -280,7 +273,7 @@ class histogram<dynamic_tag, Axes, Storage> {
return const_iterator(*this, storage_.size()); return const_iterator(*this, storage_.size());
} }
private: private:
axes_type axes_; axes_type axes_;
Storage storage_; Storage storage_;
mutable detail::index_cache index_cache_; mutable detail::index_cache index_cache_;
@ -402,9 +395,7 @@ class histogram<dynamic_tag, Axes, Storage> {
noexcept {} noexcept {}
template <int N, typename T> template <int N, typename T>
void xlin_get(mp11::mp_int<N>, void xlin_get(mp11::mp_int<N>, std::size_t& idx, std::size_t& stride,
std::size_t& idx,
std::size_t& stride,
T&& t) const { T&& t) const {
constexpr unsigned D = detail::mp_size<T>::value - N; constexpr unsigned D = detail::mp_size<T>::value - N;
apply_visitor( apply_visitor(
@ -434,7 +425,8 @@ class histogram<dynamic_tag, Axes, Storage> {
const auto a_size = a.size(); const auto a_size = a.size();
const auto a_shape = a.shape(); const auto a_shape = a.shape();
const auto j = detail::indirect_int_cast(*iter++); const auto j = detail::indirect_int_cast(*iter++);
stride *= (-1 <= j && j <= a_size); // set stride to zero, if j is invalid stride *=
(-1 <= j && j <= a_size); // set stride to zero, if j is invalid
detail::lin(idx, stride, a_size, a_shape, j); detail::lin(idx, stride, a_size, a_shape, j);
} }
} }
@ -444,9 +436,7 @@ class histogram<dynamic_tag, Axes, Storage> {
noexcept {} noexcept {}
template <long unsigned int N, typename T> template <long unsigned int N, typename T>
void lin_get(mp11::mp_size_t<N>, void lin_get(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
std::size_t& idx,
std::size_t& stride,
const T& t) const noexcept { const T& t) const noexcept {
constexpr long unsigned int D = detail::mp_size<T>::value - N; constexpr long unsigned int D = detail::mp_size<T>::value - N;
const auto& a = axes_[D]; const auto& a = axes_[D];
@ -464,17 +454,14 @@ class histogram<dynamic_tag, Axes, Storage> {
auto axes_iter = axes_.begin(); auto axes_iter = axes_.begin();
auto n_iter = n.begin(); auto n_iter = n.begin();
for (const auto& bi : b) { for (const auto& bi : b) {
if (bi) if (bi) axes.emplace_back(*axes_iter);
axes.emplace_back(*axes_iter);
*n_iter = axes_iter->shape(); *n_iter = axes_iter->shape();
++axes_iter; ++axes_iter;
++n_iter; ++n_iter;
} }
histogram h(std::move(axes)); histogram h(std::move(axes));
detail::index_mapper m(n, b); detail::index_mapper m(n, b);
do { do { h.storage_.add(m.second, storage_[m.first]); } while (m.next());
h.storage_.add(m.second, storage_[m.first]);
} while (m.next());
return h; return h;
} }
@ -499,25 +486,22 @@ make_dynamic_histogram(Axis&&... axis) {
template <typename Storage, typename... Axis> template <typename Storage, typename... Axis>
dynamic_histogram< dynamic_histogram<
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>, mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>, Storage>
Storage>
make_dynamic_histogram_with(Axis&&... axis) { make_dynamic_histogram_with(Axis&&... axis) {
return dynamic_histogram< return dynamic_histogram<
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>, Storage>( mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>,
std::forward<Axis>(axis)...); Storage>(std::forward<Axis>(axis)...);
} }
template <typename Iterator, typename = detail::requires_iterator<Iterator>> template <typename Iterator, typename = detail::requires_iterator<Iterator>>
dynamic_histogram< dynamic_histogram<
detail::mp_set_union<axis::types, typename Iterator::value_type::types>> detail::mp_set_union<axis::types, typename Iterator::value_type::types>>
make_dynamic_histogram(Iterator begin, Iterator end) { make_dynamic_histogram(Iterator begin, Iterator end) {
return dynamic_histogram< return dynamic_histogram<detail::mp_set_union<
detail::mp_set_union<axis::types, typename Iterator::value_type::types>>( axis::types, typename Iterator::value_type::types>>(begin, end);
begin, end);
} }
template <typename Storage, template <typename Storage, typename Iterator,
typename Iterator,
typename = detail::requires_iterator<Iterator>> typename = detail::requires_iterator<Iterator>>
dynamic_histogram< dynamic_histogram<
detail::mp_set_union<axis::types, typename Iterator::value_type::types>, detail::mp_set_union<axis::types, typename Iterator::value_type::types>,

View File

@ -27,7 +27,8 @@ struct sqrt;
struct pow; struct pow;
} // namespace transform } // namespace transform
template <typename RealType = double, typename Transform = transform::identity> template <typename RealType = double,
typename Transform = transform::identity>
class regular; class regular;
template <typename RealType = double> template <typename RealType = double>
class circular; class circular;
@ -42,10 +43,8 @@ using types = mp11::mp_list<axis::regular<double, axis::transform::identity>,
axis::regular<double, axis::transform::log>, axis::regular<double, axis::transform::log>,
axis::regular<double, axis::transform::sqrt>, axis::regular<double, axis::transform::sqrt>,
axis::regular<double, axis::transform::pow>, axis::regular<double, axis::transform::pow>,
axis::circular<double>, axis::circular<double>, axis::variable<double>,
axis::variable<double>, axis::integer<int>, axis::category<int>,
axis::integer<int>,
axis::category<int>,
axis::category<std::string>>; axis::category<std::string>>;
template <typename... Ts> template <typename... Ts>

View File

@ -21,11 +21,10 @@ namespace histogram {
template <typename Histogram> template <typename Histogram>
class iterator_over class iterator_over
: public iterator_facade<iterator_over<Histogram>, : public iterator_facade<
typename Histogram::element_type, iterator_over<Histogram>, typename Histogram::element_type,
random_access_traversal_tag, random_access_traversal_tag, typename Histogram::const_reference> {
typename Histogram::const_reference> { public:
public:
iterator_over(const Histogram& h, std::size_t idx) iterator_over(const Histogram& h, std::size_t idx)
: histogram_(h), idx_(idx) {} : histogram_(h), idx_(idx) {}
@ -55,7 +54,7 @@ class iterator_over
return histogram_.axis(dim)[idx(dim)]; return histogram_.axis(dim)[idx(dim)];
} }
private: private:
bool equal(const iterator_over& rhs) const noexcept { bool equal(const iterator_over& rhs) const noexcept {
return &histogram_ == &rhs.histogram_ && idx_ == rhs.idx_; return &histogram_ == &rhs.histogram_ && idx_ == rhs.idx_;
} }

View File

@ -34,7 +34,8 @@ inline std::ostream& operator<<(std::ostream& os, const histogram<Ts...>& h) {
} }
template <typename T> template <typename T>
inline std::ostream& operator<<(std::ostream& os, const weight_counter<T>& x) { inline std::ostream& operator<<(std::ostream& os,
const weight_counter<T>& x) {
os << "weight_counter(" << x.value() << ", " << x.variance() << ")"; os << "weight_counter(" << x.value() << ", " << x.variance() << ")";
return os; return os;
} }

View File

@ -41,14 +41,14 @@ struct serialize_helper {
template <typename RealType> template <typename RealType>
template <class Archive> template <class Archive>
void weight_counter<RealType>::serialize(Archive& ar, unsigned /* version */) { void weight_counter<RealType>::serialize(Archive& ar,
unsigned /* version */) {
ar& w; ar& w;
ar& w2; ar& w2;
} }
template <class Archive, typename Container> template <class Archive, typename Container>
void serialize(Archive& ar, void serialize(Archive& ar, array_storage<Container>& store,
array_storage<Container>& store,
unsigned /* version */) { unsigned /* version */) {
ar& store.array_; ar& store.array_;
} }

View File

@ -39,7 +39,7 @@ class histogram<static_tag, Axes, Storage> {
using axes_size = mp11::mp_size<Axes>; using axes_size = mp11::mp_size<Axes>;
static_assert(axes_size::value > 0, "at least one axis required"); static_assert(axes_size::value > 0, "at least one axis required");
public: public:
using axes_type = mp11::mp_rename<Axes, std::tuple>; using axes_type = mp11::mp_rename<Axes, std::tuple>;
using element_type = typename Storage::element_type; using element_type = typename Storage::element_type;
using const_reference = typename Storage::const_reference; using const_reference = typename Storage::const_reference;
@ -52,8 +52,7 @@ class histogram<static_tag, Axes, Storage> {
histogram& operator=(const histogram& rhs) = default; histogram& operator=(const histogram& rhs) = default;
histogram& operator=(histogram&& rhs) = default; histogram& operator=(histogram&& rhs) = default;
template <typename Axis0, template <typename Axis0, typename... Axis,
typename... Axis,
typename = detail::requires_axis<Axis0>> typename = detail::requires_axis<Axis0>>
explicit histogram(Axis0&& axis0, Axis&&... axis) explicit histogram(Axis0&& axis0, Axis&&... axis)
: axes_(std::forward<Axis0>(axis0), std::forward<Axis>(axis)...) { : axes_(std::forward<Axis0>(axis0), std::forward<Axis>(axis)...) {
@ -154,8 +153,7 @@ class histogram<static_tag, Axes, Storage> {
"fill arguments do not match histogram dimension"); "fill arguments do not match histogram dimension");
std::size_t idx = 0, stride = 1; std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, ts...); xlin<0>(idx, stride, ts...);
if (stride) if (stride) detail::fill_storage(storage_, idx);
detail::fill_storage(storage_, idx);
} }
template <typename T> template <typename T>
@ -172,8 +170,7 @@ class histogram<static_tag, Axes, Storage> {
// case with one argument is ambiguous, is specialized below // case with one argument is ambiguous, is specialized below
std::size_t idx = 0, stride = 1; std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, ts...); xlin<0>(idx, stride, ts...);
if (stride) if (stride) detail::fill_storage(storage_, idx, std::move(w));
detail::fill_storage(storage_, idx, std::move(w));
} }
// TODO: remove as obsolete // TODO: remove as obsolete
@ -253,8 +250,9 @@ class histogram<static_tag, Axes, Storage> {
auto reduce_to(mp11::mp_int<N>, Ns...) const auto reduce_to(mp11::mp_int<N>, Ns...) const
-> static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>, -> static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>,
Storage> { Storage> {
using HR = static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>, using HR =
Storage>; static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>,
Storage>;
auto hr = auto hr =
HR(detail::make_sub_tuple<axes_type, mp11::mp_int<N>, Ns...>(axes_)); HR(detail::make_sub_tuple<axes_type, mp11::mp_int<N>, Ns...>(axes_));
const auto b = detail::bool_mask<mp11::mp_int<N>, Ns...>(dim(), true); const auto b = detail::bool_mask<mp11::mp_int<N>, Ns...>(dim(), true);
@ -264,9 +262,11 @@ class histogram<static_tag, Axes, Storage> {
const_iterator begin() const noexcept { return const_iterator(*this, 0); } const_iterator begin() const noexcept { return const_iterator(*this, 0); }
const_iterator end() const noexcept { return const_iterator(*this, size()); } const_iterator end() const noexcept {
return const_iterator(*this, size());
}
private: private:
axes_type axes_; axes_type axes_;
Storage storage_; Storage storage_;
mutable detail::index_cache index_cache_; mutable detail::index_cache index_cache_;
@ -350,13 +350,11 @@ class histogram<static_tag, Axes, Storage> {
} }
template <typename Iterator> template <typename Iterator>
void xlin_iter(mp11::mp_size_t<0>, std::size_t&, std::size_t&, Iterator) const void xlin_iter(mp11::mp_size_t<0>, std::size_t&, std::size_t&,
noexcept {} Iterator) const noexcept {}
template <long unsigned int N, typename Iterator> template <long unsigned int N, typename Iterator>
void xlin_iter(mp11::mp_size_t<N>, void xlin_iter(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
std::size_t& idx,
std::size_t& stride,
Iterator iter) const { Iterator iter) const {
constexpr unsigned D = axes_size::value - N; constexpr unsigned D = axes_size::value - N;
const auto a_size = std::get<D>(axes_).size(); const auto a_size = std::get<D>(axes_).size();
@ -380,13 +378,11 @@ class histogram<static_tag, Axes, Storage> {
} }
template <typename Iterator> template <typename Iterator>
void lin_iter(mp11::mp_size_t<0>, std::size_t&, std::size_t&, Iterator) const void lin_iter(mp11::mp_size_t<0>, std::size_t&, std::size_t&,
noexcept {} Iterator) const noexcept {}
template <long unsigned int N, typename Iterator> template <long unsigned int N, typename Iterator>
void lin_iter(mp11::mp_size_t<N>, void lin_iter(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
std::size_t& idx,
std::size_t& stride,
Iterator iter) const noexcept { Iterator iter) const noexcept {
constexpr unsigned D = axes_size::value - N; constexpr unsigned D = axes_size::value - N;
const auto a_size = std::get<D>(axes_).size(); const auto a_size = std::get<D>(axes_).size();
@ -402,9 +398,7 @@ class histogram<static_tag, Axes, Storage> {
noexcept {} noexcept {}
template <long unsigned int N, typename T> template <long unsigned int N, typename T>
void xlin_get(mp11::mp_size_t<N>, void xlin_get(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
std::size_t& idx,
std::size_t& stride,
T&& t) const { T&& t) const {
constexpr unsigned D = detail::mp_size<T>::value - N; constexpr unsigned D = detail::mp_size<T>::value - N;
const auto a_size = std::get<D>(axes_).size(); const auto a_size = std::get<D>(axes_).size();
@ -419,9 +413,7 @@ class histogram<static_tag, Axes, Storage> {
noexcept {} noexcept {}
template <long unsigned int N, typename T> template <long unsigned int N, typename T>
void lin_get(mp11::mp_size_t<N>, void lin_get(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
std::size_t& idx,
std::size_t& stride,
T&& t) const noexcept { T&& t) const noexcept {
constexpr unsigned D = detail::mp_size<T>::value - N; constexpr unsigned D = detail::mp_size<T>::value - N;
const auto a_size = std::get<D>(axes_).size(); const auto a_size = std::get<D>(axes_).size();
@ -437,9 +429,7 @@ class histogram<static_tag, Axes, Storage> {
detail::shape_vector_visitor v(dim()); detail::shape_vector_visitor v(dim());
for_each_axis(v); for_each_axis(v);
detail::index_mapper m(v.shapes, b); detail::index_mapper m(v.shapes, b);
do { do { h.storage_.add(m.second, storage_[m.first]); } while (m.next());
h.storage_.add(m.second, storage_[m.first]);
} while (m.next());
} }
template <typename T, typename A, typename S> template <typename T, typename A, typename S>

View File

@ -54,7 +54,7 @@ inline T* alloc(std::size_t s) {
} }
class array_base { class array_base {
public: public:
explicit array_base(const std::size_t s) : size(s) {} explicit array_base(const std::size_t s) : size(s) {}
array_base() = default; array_base() = default;
array_base(const array_base&) = default; array_base(const array_base&) = default;
@ -72,7 +72,7 @@ class array_base {
template <typename T> template <typename T>
class array : public array_base { class array : public array_base {
public: public:
explicit array(const std::size_t s) : array_base(s), ptr(alloc<T>(s)) { explicit array(const std::size_t s) : array_base(s), ptr(alloc<T>(s)) {
std::fill(begin(), end(), T(0)); std::fill(begin(), end(), T(0));
} }
@ -118,23 +118,19 @@ class array : public array_base {
const T* begin() const { return ptr.get(); } const T* begin() const { return ptr.get(); }
const T* end() const { return ptr.get() + size; } const T* end() const { return ptr.get() + size; }
private: private:
std::unique_ptr<T[]> ptr; std::unique_ptr<T[]> ptr;
}; };
template <> template <>
class array<void> : public array_base { class array<void> : public array_base {
public: public:
using array_base::array_base; using array_base::array_base;
}; };
using any_array = variant<array<void>, using any_array =
array<uint8_t>, variant<array<void>, array<uint8_t>, array<uint16_t>, array<uint32_t>,
array<uint16_t>, array<uint64_t>, array<mp_int>, array<wcount>>;
array<uint32_t>,
array<uint64_t>,
array<mp_int>,
array<wcount>>;
template <typename T> template <typename T>
struct next_type; struct next_type;
@ -159,8 +155,7 @@ using next = typename next_type<T>::type;
template <typename T> template <typename T>
inline bool safe_increase(T& t) { inline bool safe_increase(T& t) {
if (t == std::numeric_limits<T>::max()) if (t == std::numeric_limits<T>::max()) return false;
return false;
++t; ++t;
return true; return true;
} }
@ -176,8 +171,7 @@ inline bool safe_assign(T& t, const U& u) {
template <typename T, typename U> template <typename T, typename U>
inline bool safe_radd(T& t, const U& u) { inline bool safe_radd(T& t, const U& u) {
if (static_cast<T>(std::numeric_limits<T>::max() - t) < u) if (static_cast<T>(std::numeric_limits<T>::max() - t) < u) return false;
return false;
t += static_cast<T>(u); t += static_cast<T>(u);
return true; return true;
} }
@ -185,8 +179,7 @@ inline bool safe_radd(T& t, const U& u) {
// float rounding is a mess, the equal sign is necessary here // float rounding is a mess, the equal sign is necessary here
template <typename T> template <typename T>
inline bool safe_radd(T& t, const double u) { inline bool safe_radd(T& t, const double u) {
if ((std::numeric_limits<T>::max() - t) <= u) if ((std::numeric_limits<T>::max() - t) <= u) return false;
return false;
t += u; t += u;
return true; return true;
} }
@ -390,24 +383,22 @@ struct rmul_visitor : public static_visitor<void> {
} }
void operator()(array<void>&) const {} void operator()(array<void>&) const {}
void operator()(array<wcount>& lhs) const { void operator()(array<wcount>& lhs) const {
for (std::size_t i = 0; i != lhs.size; ++i) for (std::size_t i = 0; i != lhs.size; ++i) lhs[i] *= x;
lhs[i] *= x;
} }
}; };
struct bicmp_visitor : public static_visitor<bool> { struct bicmp_visitor : public static_visitor<bool> {
template <typename T, typename U> template <typename T, typename U>
bool operator()(const array<T>& b1, const array<U>& b2) const { bool operator()(const array<T>& b1, const array<U>& b2) const {
if (b1.size != b2.size) if (b1.size != b2.size) return false;
return false;
return std::equal(b1.begin(), b1.end(), b2.begin()); return std::equal(b1.begin(), b1.end(), b2.begin());
} }
template <typename T> template <typename T>
bool operator()(const array<T>& b1, const array<void>& b2) const { bool operator()(const array<T>& b1, const array<void>& b2) const {
if (b1.size != b2.size) if (b1.size != b2.size) return false;
return false; return std::all_of(b1.begin(), b1.end(),
return std::all_of(b1.begin(), b1.end(), [](const T& t) { return t == 0; }); [](const T& t) { return t == 0; });
} }
template <typename T> template <typename T>
@ -425,11 +416,12 @@ struct bicmp_visitor : public static_visitor<bool> {
class adaptive_storage { class adaptive_storage {
using buffer_type = detail::any_array; using buffer_type = detail::any_array;
public: public:
using element_type = detail::wcount; using element_type = detail::wcount;
using const_reference = element_type; using const_reference = element_type;
explicit adaptive_storage(std::size_t s) : buffer_(detail::array<void>(s)) {} explicit adaptive_storage(std::size_t s)
: buffer_(detail::array<void>(s)) {}
adaptive_storage() = default; adaptive_storage() = default;
adaptive_storage(const adaptive_storage&) = default; adaptive_storage(const adaptive_storage&) = default;
@ -450,9 +442,7 @@ class adaptive_storage {
adaptive_storage& operator=(const RHS& rhs) { adaptive_storage& operator=(const RHS& rhs) {
// no check for self-assign needed, default operator above is better match // no check for self-assign needed, default operator above is better match
const auto n = rhs.size(); const auto n = rhs.size();
if (size() != n) { if (size() != n) { buffer_ = detail::array<void>(n); }
buffer_ = detail::array<void>(n);
}
using T = typename RHS::element_type; using T = typename RHS::element_type;
for (std::size_t i = 0; i < n; ++i) { for (std::size_t i = 0; i < n; ++i) {
apply_visitor(detail::assign_visitor<T>(buffer_, i, rhs[i]), buffer_); apply_visitor(detail::assign_visitor<T>(buffer_, i, rhs[i]), buffer_);
@ -477,7 +467,8 @@ class adaptive_storage {
apply_visitor(detail::radd_visitor<double>(buffer_, i, x.value()), apply_visitor(detail::radd_visitor<double>(buffer_, i, x.value()),
buffer_); buffer_);
} else { } else {
apply_visitor(detail::radd_visitor<element_type>(buffer_, i, x), buffer_); apply_visitor(detail::radd_visitor<element_type>(buffer_, i, x),
buffer_);
} }
} }
@ -517,9 +508,9 @@ class adaptive_storage {
template <typename RHS> template <typename RHS>
adaptive_storage& operator+=(const RHS& rhs) { adaptive_storage& operator+=(const RHS& rhs) {
for (std::size_t i = 0, n = size(); i < n; ++i) for (std::size_t i = 0, n = size(); i < n; ++i)
apply_visitor( apply_visitor(detail::radd_visitor<typename RHS::element_type>(
detail::radd_visitor<typename RHS::element_type>(buffer_, i, rhs[i]), buffer_, i, rhs[i]),
buffer_); buffer_);
return *this; return *this;
} }
@ -529,7 +520,7 @@ class adaptive_storage {
return *this; return *this;
} }
private: private:
buffer_type buffer_; buffer_type buffer_;
friend class ::boost::python::access; friend class ::boost::python::access;

View File

@ -24,7 +24,7 @@ namespace histogram {
template <typename T> template <typename T>
class array_storage { class array_storage {
public: public:
using element_type = T; using element_type = T;
using const_reference = const T&; using const_reference = const T&;
@ -81,30 +81,29 @@ class array_storage {
array_[i] += x; array_[i] += x;
} }
const_reference operator[](std::size_t i) const noexcept { return array_[i]; } const_reference operator[](std::size_t i) const noexcept {
return array_[i];
}
template <typename U> template <typename U>
bool operator==(const array_storage<U>& rhs) const noexcept { bool operator==(const array_storage<U>& rhs) const noexcept {
if (size_ != rhs.size_) if (size_ != rhs.size_) return false;
return false;
return std::equal(array_.get(), array_.get() + size_, rhs.array_.get()); return std::equal(array_.get(), array_.get() + size_, rhs.array_.get());
} }
template <typename S> template <typename S>
array_storage& operator+=(const S& rhs) noexcept { array_storage& operator+=(const S& rhs) noexcept {
for (std::size_t i = 0; i < size_; ++i) for (std::size_t i = 0; i < size_; ++i) add(i, rhs[i]);
add(i, rhs[i]);
return *this; return *this;
} }
template <typename U> template <typename U>
array_storage& operator*=(const U& x) noexcept { array_storage& operator*=(const U& x) noexcept {
for (std::size_t i = 0; i < size_; ++i) for (std::size_t i = 0; i < size_; ++i) array_[i] *= x;
array_[i] *= x;
return *this; return *this;
} }
private: private:
std::size_t size_ = 0; std::size_t size_ = 0;
std::unique_ptr<element_type[]> array_; std::unique_ptr<element_type[]> array_;

View File

@ -12,22 +12,16 @@
namespace boost { namespace boost {
namespace histogram { namespace histogram {
template <typename S1, template <typename S1, typename S2, typename = detail::requires_storage<S1>,
typename S2,
typename = detail::requires_storage<S1>,
typename = detail::requires_storage<S2>> typename = detail::requires_storage<S2>>
bool operator==(const S1& s1, const S2& s2) noexcept { bool operator==(const S1& s1, const S2& s2) noexcept {
if (s1.size() != s2.size()) if (s1.size() != s2.size()) return false;
return false;
for (std::size_t i = 0, n = s1.size(); i < n; ++i) for (std::size_t i = 0, n = s1.size(); i < n; ++i)
if (!(s1[i] == s2[i])) if (!(s1[i] == s2[i])) return false;
return false;
return true; return true;
} }
template <typename S1, template <typename S1, typename S2, typename = detail::requires_storage<S1>,
typename S2,
typename = detail::requires_storage<S1>,
typename = detail::requires_storage<S2>> typename = detail::requires_storage<S2>>
bool operator!=(const S1& s1, const S2& s2) noexcept { bool operator!=(const S1& s1, const S2& s2) noexcept {
return !operator==(s1, s2); return !operator==(s1, s2);

View File

@ -21,7 +21,7 @@ namespace histogram {
/// Double counter which holds a sum of weights and a sum of squared weights /// Double counter which holds a sum of weights and a sum of squared weights
template <typename RealType> template <typename RealType>
class weight_counter { class weight_counter {
public: public:
/// Beware: For performance reasons counters are not initialized /// Beware: For performance reasons counters are not initialized
weight_counter() = default; weight_counter() = default;
weight_counter(const weight_counter&) = default; weight_counter(const weight_counter&) = default;
@ -108,7 +108,7 @@ class weight_counter {
return static_cast<T>(w); return static_cast<T>(w);
} }
private: private:
friend class ::boost::serialization::access; friend class ::boost::serialization::access;
template <class Archive> template <class Archive>

View File

@ -4,33 +4,34 @@
// (See accompanying file LICENSE_1_0.txt // (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt) // or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "utility.hpp"
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/histogram/axis/types.hpp>
#include <boost/histogram/axis/any.hpp> #include <boost/histogram/axis/any.hpp>
#include <boost/histogram/axis/ostream_operators.hpp> #include <boost/histogram/axis/ostream_operators.hpp>
#include <boost/histogram/axis/types.hpp>
#include <boost/histogram/detail/utility.hpp> #include <boost/histogram/detail/utility.hpp>
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/def_visitor.hpp> #include <boost/python/def_visitor.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/python/make_constructor.hpp> #include <boost/python/make_constructor.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/python/to_python_converter.hpp> #include <boost/python/to_python_converter.hpp>
#include "utility.hpp"
#ifdef HAVE_NUMPY #ifdef HAVE_NUMPY
#include <boost/python/numpy.hpp> #include <boost/python/numpy.hpp>
namespace np = boost::python::numpy; namespace np = boost::python::numpy;
#endif #endif
#include <sstream>
#include <type_traits>
#include <vector>
#include <utility>
#include <iostream> #include <iostream>
#include <sstream>
#include <stdexcept> #include <stdexcept>
#include <type_traits>
#include <utility>
#include <vector>
namespace bp = boost::python; namespace bp = boost::python;
namespace bh = boost::histogram; namespace bh = boost::histogram;
namespace bha = boost::histogram::axis; namespace bha = boost::histogram::axis;
template <typename T> bp::str generic_repr(const T &t) { template <typename T>
bp::str generic_repr(const T& t) {
std::ostringstream os; std::ostringstream os;
os << t; os << t;
return os.str().c_str(); return os.str().c_str();
@ -56,19 +57,15 @@ generic_iterator make_generic_iterator(bp::object self) {
} }
template <typename Axis> template <typename Axis>
struct axis_value_view_to_python struct axis_value_view_to_python {
{ static PyObject* convert(const bha::value_view<Axis>& i) {
static PyObject* convert(const bha::value_view<Axis> &i)
{
return bp::incref(bp::object(i.value()).ptr()); return bp::incref(bp::object(i.value()).ptr());
} }
}; };
template <typename Axis> template <typename Axis>
struct axis_interval_view_to_python struct axis_interval_view_to_python {
{ static PyObject* convert(const bha::interval_view<Axis>& i) {
static PyObject* convert(const bha::interval_view<Axis> &i)
{
return bp::incref(bp::make_tuple(i.lower(), i.upper()).ptr()); return bp::incref(bp::make_tuple(i.lower(), i.upper()).ptr());
} }
}; };
@ -96,10 +93,8 @@ bp::object variable_init(bp::tuple args, bp::dict kwargs) {
if (k == "label") if (k == "label")
label = boost::string_view(bp::extract<const char*>(v), bp::len(v)); label = boost::string_view(bp::extract<const char*>(v), bp::len(v));
else if (k == "uoflow") { else if (k == "uoflow") {
if (!bp::extract<bool>(v)) if (!bp::extract<bool>(v)) uo = bha::uoflow::off;
uo = bha::uoflow::off; } else {
}
else {
std::stringstream s; std::stringstream s;
s << "keyword " << k << " not recognized"; s << "keyword " << k << " not recognized";
PyErr_SetString(PyExc_KeyError, s.str().c_str()); PyErr_SetString(PyExc_KeyError, s.str().c_str());
@ -142,46 +137,51 @@ bp::object category_init(bp::tuple args, bp::dict kwargs) {
return self.attr("__init__")(bha::category<>(c.begin(), c.end(), label)); return self.attr("__init__")(bha::category<>(c.begin(), c.end(), label));
} }
template <typename T> void axis_set_label(T& t, bp::str s) { template <typename T>
t.label({bp::extract<const char*>(s)(), void axis_set_label(T& t, bp::str s) {
static_cast<std::size_t>(bp::len(s))}); t.label(
{bp::extract<const char*>(s)(), static_cast<std::size_t>(bp::len(s))});
} }
template <typename T> bp::str axis_get_label(const T& t) { template <typename T>
bp::str axis_get_label(const T& t) {
auto s = t.label(); auto s = t.label();
return {s.data(), s.size()}; return {s.data(), s.size()};
} }
template <typename A> bp::object axis_getitem(const A &a, int i) { template <typename A>
bp::object axis_getitem(const A& a, int i) {
if (i < -1 * a.uoflow() || i >= a.size() + 1 * a.uoflow()) if (i < -1 * a.uoflow() || i >= a.size() + 1 * a.uoflow())
throw std::out_of_range("index out of bounds"); throw std::out_of_range("index out of bounds");
return bp::make_tuple(a.lower(i), a.lower(i+1)); return bp::make_tuple(a.lower(i), a.lower(i + 1));
} }
template <> bp::object axis_getitem<bha::category<>>(const bha::category<> &a, int i) { template <>
if (i < 0 || i >= a.size()) bp::object axis_getitem<bha::category<>>(const bha::category<>& a, int i) {
throw std::out_of_range("index out of bounds"); if (i < 0 || i >= a.size()) throw std::out_of_range("index out of bounds");
return bp::object(a.value(i)); return bp::object(a.value(i));
} }
#ifdef HAVE_NUMPY #ifdef HAVE_NUMPY
template <typename Axis> bp::object axis_array_interface(const Axis& axis) { template <typename Axis>
bp::object axis_array_interface(const Axis& axis) {
using T = typename std::decay<typename Axis::value_type>::type; using T = typename std::decay<typename Axis::value_type>::type;
bp::dict d; bp::dict d;
auto shape = bp::make_tuple(axis.size()+1); auto shape = bp::make_tuple(axis.size() + 1);
d["shape"] = shape; d["shape"] = shape;
d["typestr"] = bp::dtype_typestr<T>(); d["typestr"] = bp::dtype_typestr<T>();
// make new array, and pass it to Python // make new array, and pass it to Python
auto a = np::empty(shape, np::dtype::get_builtin<T>()); auto a = np::empty(shape, np::dtype::get_builtin<T>());
auto buf = reinterpret_cast<T*>(a.get_data()); auto buf = reinterpret_cast<T*>(a.get_data());
for (auto i = 0; i < axis.size()+1; ++i) for (auto i = 0; i < axis.size() + 1; ++i) buf[i] = axis.lower(i);
buf[i] = axis.lower(i);
d["data"] = a; d["data"] = a;
d["version"] = 3; d["version"] = 3;
return d; return d;
} }
template <> bp::object axis_array_interface<bha::category<>>(const bha::category<>& axis) { template <>
bp::object axis_array_interface<bha::category<>>(
const bha::category<>& axis) {
bp::dict d; bp::dict d;
auto shape = bp::make_tuple(axis.size()); auto shape = bp::make_tuple(axis.size());
d["shape"] = shape; d["shape"] = shape;
@ -189,8 +189,7 @@ template <> bp::object axis_array_interface<bha::category<>>(const bha::category
// make new array, and pass it to Python // make new array, and pass it to Python
auto a = np::empty(shape, np::dtype::get_builtin<int>()); auto a = np::empty(shape, np::dtype::get_builtin<int>());
auto buf = reinterpret_cast<int*>(a.get_data()); auto buf = reinterpret_cast<int*>(a.get_data());
for (auto i = 0; i < axis.size(); ++i) for (auto i = 0; i < axis.size(); ++i) buf[i] = axis.value(i);
buf[i] = axis.value(i);
d["data"] = a; d["data"] = a;
d["version"] = 3; d["version"] = 3;
return d; return d;
@ -199,15 +198,16 @@ template <> bp::object axis_array_interface<bha::category<>>(const bha::category
template <class T> template <class T>
struct axis_suite : public bp::def_visitor<axis_suite<T>> { struct axis_suite : public bp::def_visitor<axis_suite<T>> {
template <class Class> static void visit(Class &cl) { template <class Class>
cl.add_property( static void visit(Class& cl) {
"shape", &T::shape, cl.add_property("shape", &T::shape,
"Number of bins, including over-/underflow bins if they are present."); "Number of bins, including over-/underflow bins if they "
cl.add_property( "are present.");
"label", axis_get_label<T>, axis_set_label<T>, cl.add_property("label", axis_get_label<T>, axis_set_label<T>,
"Name or description for the axis."); "Name or description for the axis.");
cl.def("index", &T::index, ":param float x: value" cl.def("index", &T::index,
"\n:returns: bin index for the passed value", ":param float x: value"
"\n:returns: bin index for the passed value",
bp::args("self", "x")); bp::args("self", "x"));
cl.def("__len__", &T::size, cl.def("__len__", &T::size,
":returns: number of bins, excluding over-/underflow bins.", ":returns: number of bins, excluding over-/underflow bins.",
@ -227,39 +227,35 @@ struct axis_suite : public bp::def_visitor<axis_suite<T>> {
}; };
template <typename Transform> template <typename Transform>
bha::regular<double, Transform>* regular_init( bha::regular<double, Transform>* regular_init(unsigned bin, double lower,
unsigned bin, double lower, double upper, double upper, bp::str pylabel,
bp::str pylabel, bool with_uoflow) bool with_uoflow) {
{
const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off; const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off;
return new bha::regular<double, Transform>(bin, lower, upper, return new bha::regular<double, Transform>(
{bp::extract<const char*>(pylabel)(), bin, lower, upper, {bp::extract<const char*>(pylabel)(),
static_cast<std::size_t>(bp::len(pylabel))}, static_cast<std::size_t>(bp::len(pylabel))},
uo); uo);
} }
bha::regular<double, bha::transform::pow>* regular_pow_init( bha::regular<double, bha::transform::pow>* regular_pow_init(
unsigned bin, double lower, double upper, double power, unsigned bin, double lower, double upper, double power, bp::str pylabel,
bp::str pylabel, bool with_uoflow) bool with_uoflow) {
{
using namespace ::boost::python; using namespace ::boost::python;
const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off; const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off;
return new bha::regular<double, bha::transform::pow>( return new bha::regular<double, bha::transform::pow>(
bin, lower, upper, bin, lower, upper, {extract<const char*>(pylabel)(),
{extract<const char*>(pylabel)(), static_cast<std::size_t>(bp::len(pylabel))},
static_cast<std::size_t>(bp::len(pylabel))},
uo, power); uo, power);
} }
bha::integer<>* integer_init(int lower, int upper, bha::integer<>* integer_init(int lower, int upper, bp::str pylabel,
bp::str pylabel, bool with_uoflow) bool with_uoflow) {
{
using namespace ::boost::python; using namespace ::boost::python;
const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off; const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off;
return new bha::integer<>(lower, upper, return new bha::integer<>(lower, upper,
{extract<const char*>(pylabel)(), {extract<const char*>(pylabel)(),
static_cast<std::size_t>(bp::len(pylabel))}, static_cast<std::size_t>(bp::len(pylabel))},
uo); uo);
} }
void register_axis_types() { void register_axis_types() {
@ -268,32 +264,34 @@ void register_axis_types() {
docstring_options dopt(true, true, false); docstring_options dopt(true, true, false);
class_<generic_iterator>("generic_iterator", init<object>()) class_<generic_iterator>("generic_iterator", init<object>())
.def("__iter__", &generic_iterator::self, return_internal_reference<>()) .def("__iter__", &generic_iterator::self, return_internal_reference<>())
.def("__next__", &generic_iterator::next) // Python3 .def("__next__", &generic_iterator::next) // Python3
.def("next", &generic_iterator::next) // Python2 .def("next", &generic_iterator::next) // Python2
; ;
class_<bha::regular<>>( class_<bha::regular<>>("regular",
"regular", "Axis for real-valued data and bins of equal width."
"Axis for real-valued data and bins of equal width." "\nBinning is a O(1) operation.",
"\nBinning is a O(1) operation.", no_init)
no_init) .def("__init__",
.def("__init__", make_constructor(regular_init<bha::transform::identity>, make_constructor(regular_init<bha::transform::identity>,
default_call_policies(), default_call_policies(),
(arg("bin"), arg("lower"), arg("upper"), (arg("bin"), arg("lower"), arg("upper"),
arg("label") = "", arg("uoflow") = true))) arg("label") = "", arg("uoflow") = true)))
.def(axis_suite<bha::regular<>>()); .def(axis_suite<bha::regular<>>());
#define BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(x) \ #define BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(x) \
class_<bha::regular<double, bha::transform::x>>( \ class_<bha::regular<double, bha::transform::x>>( \
"regular_"#x, \ "regular_" #x, \
"Axis for real-valued data and bins of equal width in "#x"-space." \ "Axis for real-valued data and bins of equal width in " #x \
"\nBinning is a O(1) operation.", \ "-space." \
no_init) \ "\nBinning is a O(1) operation.", \
.def("__init__", make_constructor(regular_init<bha::transform::x>, \ no_init) \
default_call_policies(), \ .def("__init__", \
(arg("bin"), arg("lower"), arg("upper"), \ make_constructor(regular_init<bha::transform::x>, \
arg("label") = "", arg("uoflow") = true))) \ default_call_policies(), \
(arg("bin"), arg("lower"), arg("upper"), \
arg("label") = "", arg("uoflow") = true))) \
.def(axis_suite<bha::regular<double, bha::transform::x>>()) .def(axis_suite<bha::regular<double, bha::transform::x>>())
BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(log); BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(log);
@ -305,10 +303,11 @@ void register_axis_types() {
"Axis for real-valued data and bins of equal width in power-space." "Axis for real-valued data and bins of equal width in power-space."
"\nBinning is a O(1) operation.", "\nBinning is a O(1) operation.",
no_init) no_init)
.def("__init__", make_constructor(regular_pow_init, .def("__init__",
default_call_policies(), make_constructor(
(arg("bin"), arg("lower"), arg("upper"), arg("power"), regular_pow_init, default_call_policies(),
arg("label") = "", arg("uoflow") = true))) (arg("bin"), arg("lower"), arg("upper"), arg("power"),
arg("label") = "", arg("uoflow") = true)))
.def(axis_suite<bha::regular<double, bha::transform::pow>>()); .def(axis_suite<bha::regular<double, bha::transform::pow>>());
class_<bha::circular<>>( class_<bha::circular<>>(
@ -320,8 +319,7 @@ void register_axis_types() {
no_init) no_init)
.def(init<unsigned, double, double, const char*>( .def(init<unsigned, double, double, const char*>(
(arg("self"), arg("bin"), arg("phase") = 0.0, (arg("self"), arg("bin"), arg("phase") = 0.0,
arg("perimeter") = bh::detail::two_pi, arg("perimeter") = bh::detail::two_pi, arg("label") = "")))
arg("label") = "")))
.def(axis_suite<bha::circular<>>()); .def(axis_suite<bha::circular<>>());
class_<bha::variable<>>( class_<bha::variable<>>(
@ -331,7 +329,7 @@ void register_axis_types() {
"\nthe problem domain allows it, prefer a regular axis.", "\nthe problem domain allows it, prefer a regular axis.",
no_init) no_init)
.def("__init__", raw_function(variable_init)) .def("__init__", raw_function(variable_init))
.def(init<const bha::variable<> &>()) .def(init<const bha::variable<>&>())
.def(axis_suite<bha::variable<>>()); .def(axis_suite<bha::variable<>>());
class_<bha::integer<>>( class_<bha::integer<>>(
@ -340,10 +338,10 @@ void register_axis_types() {
"\nthat are one integer wide. Faster than a regular axis." "\nthat are one integer wide. Faster than a regular axis."
"\nBinning is a O(1) operation.", "\nBinning is a O(1) operation.",
no_init) no_init)
.def("__init__", make_constructor(integer_init, .def("__init__",
default_call_policies(), make_constructor(integer_init, default_call_policies(),
(arg("lower"), arg("upper"), arg("label") = "", (arg("lower"), arg("upper"), arg("label") = "",
arg("uoflow") = true))) arg("uoflow") = true)))
.def(axis_suite<bha::integer<>>()); .def(axis_suite<bha::integer<>>());
class_<bha::category<>>( class_<bha::category<>>(
@ -354,6 +352,6 @@ void register_axis_types() {
"\nBinning is a O(1) operation.", "\nBinning is a O(1) operation.",
no_init) no_init)
.def("__init__", raw_function(category_init)) .def("__init__", raw_function(category_init))
.def(init<const bha::category<> &>()) .def(init<const bha::category<>&>())
.def(axis_suite<bha::category<>>()); .def(axis_suite<bha::category<>>());
} }

View File

@ -4,18 +4,18 @@
// (See accompanying file LICENSE_1_0.txt // (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt) // or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "serialization_suite.hpp" #include <boost/histogram/detail/cat.hpp>
#include "utility.hpp"
#include <boost/histogram/dynamic_histogram.hpp> #include <boost/histogram/dynamic_histogram.hpp>
#include <boost/histogram/storage/adaptive_storage.hpp>
#include <boost/histogram/ostream_operators.hpp> #include <boost/histogram/ostream_operators.hpp>
#include <boost/histogram/serialization.hpp> #include <boost/histogram/serialization.hpp>
#include <boost/histogram/detail/cat.hpp> #include <boost/histogram/storage/adaptive_storage.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/raw_function.hpp> #include <boost/python/raw_function.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/variant/apply_visitor.hpp> #include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp> #include <boost/variant/static_visitor.hpp>
#include "serialization_suite.hpp"
#include "utility.hpp"
#ifdef HAVE_NUMPY #ifdef HAVE_NUMPY
#include <boost/python/numpy.hpp> #include <boost/python/numpy.hpp>
namespace np = boost::python::numpy; namespace np = boost::python::numpy;
@ -44,8 +44,8 @@ public:
using array = bh::detail::array<T>; using array = bh::detail::array<T>;
struct dtype_visitor : public boost::static_visitor<str> { struct dtype_visitor : public boost::static_visitor<str> {
list & shapes, & strides; list &shapes, &strides;
dtype_visitor(list &sh, list &st) : shapes(sh), strides(st) {} dtype_visitor(list& sh, list& st) : shapes(sh), strides(st) {}
template <typename T> template <typename T>
str operator()(const array<T>& /*unused*/) const { str operator()(const array<T>& /*unused*/) const {
strides.append(sizeof(T)); strides.append(sizeof(T));
@ -85,26 +85,25 @@ public:
// double array, fill it and pass it // double array, fill it and pass it
auto a = np::empty(tuple(shapes), np::dtype::get_builtin<double>()); auto a = np::empty(tuple(shapes), np::dtype::get_builtin<double>());
for (auto i = 0l, n = bp::len(shapes); i < n; ++i) for (auto i = 0l, n = bp::len(shapes); i < n; ++i)
const_cast<Py_intptr_t*>(a.get_strides())[i] = bp::extract<int>(strides[i]); const_cast<Py_intptr_t*>(a.get_strides())[i] =
auto *buf = (double *)a.get_data(); bp::extract<int>(strides[i]);
for (auto i = 0ul; i < b.size; ++i) auto* buf = (double*)a.get_data();
buf[i] = static_cast<double>(b[i]); for (auto i = 0ul; i < b.size; ++i) buf[i] = static_cast<double>(b[i]);
return a; return a;
} }
}; };
static object array_interface(const pyhistogram &self) { static object array_interface(const pyhistogram& self) {
dict d; dict d;
list shapes; list shapes;
list strides; list strides;
auto &b = self.storage_.buffer_; auto& b = self.storage_.buffer_;
d["typestr"] = boost::apply_visitor(dtype_visitor(shapes, strides), b); d["typestr"] = boost::apply_visitor(dtype_visitor(shapes, strides), b);
for (auto i = 0u; i < self.dim(); ++i) { for (auto i = 0u; i < self.dim(); ++i) {
if (i) strides.append(strides[-1] * shapes[-1]); if (i) strides.append(strides[-1] * shapes[-1]);
shapes.append(self.axis(i).shape()); shapes.append(self.axis(i).shape());
} }
if (self.dim() == 0) if (self.dim() == 0) shapes.append(0);
shapes.append(0);
d["shape"] = tuple(shapes); d["shape"] = tuple(shapes);
d["strides"] = tuple(strides); d["strides"] = tuple(strides);
d["data"] = boost::apply_visitor(data_visitor(shapes, strides), b); d["data"] = boost::apply_visitor(data_visitor(shapes, strides), b);
@ -117,7 +116,8 @@ public:
} // namespace boost } // namespace boost
struct axis_visitor : public boost::static_visitor<bp::object> { struct axis_visitor : public boost::static_visitor<bp::object> {
template <typename T> bp::object operator()(const T &t) const { template <typename T>
bp::object operator()(const T& t) const {
return bp::object(t); return bp::object(t);
} }
}; };
@ -126,9 +126,10 @@ struct axes_appender {
bp::object obj; bp::object obj;
pyhistogram::axes_type& axes; pyhistogram::axes_type& axes;
bool& success; bool& success;
axes_appender(bp::object o, pyhistogram::axes_type& a, axes_appender(bp::object o, pyhistogram::axes_type& a, bool& s)
bool& s) : obj(o), axes(a), success(s) {} : obj(o), axes(a), success(s) {}
template <typename A> void operator()(const A&) const { template <typename A>
void operator()(const A&) const {
if (success) return; if (success) return;
bp::extract<const A&> get_axis(obj); bp::extract<const A&> get_axis(obj);
if (get_axis.check()) { if (get_axis.check()) {
@ -138,9 +139,8 @@ struct axes_appender {
} }
}; };
bp::object histogram_axis(const pyhistogram &self, int i) { bp::object histogram_axis(const pyhistogram& self, int i) {
if (i < 0) if (i < 0) i += self.dim();
i += self.dim();
if (i < 0 || i >= int(self.dim())) if (i < 0 || i >= int(self.dim()))
throw std::out_of_range("axis index out of range"); throw std::out_of_range("axis index out of range");
return boost::apply_visitor(axis_visitor(), self.axis(i)); return boost::apply_visitor(axis_visitor(), self.axis(i));
@ -163,8 +163,7 @@ bp::object histogram_init(bp::tuple args, bp::dict kwargs) {
bp::object pa = args[i + 1]; bp::object pa = args[i + 1];
bool success = false; bool success = false;
boost::mp11::mp_for_each<pyhistogram::any_axis_type::types>( boost::mp11::mp_for_each<pyhistogram::any_axis_type::types>(
axes_appender(pa, axes, success) axes_appender(pa, axes, success));
);
if (!success) { if (!success) {
std::string msg = "require an axis object, got "; std::string msg = "require an axis object, got ";
msg += bp::extract<std::string>(pa.attr("__class__"))(); msg += bp::extract<std::string>(pa.attr("__class__"))();
@ -204,8 +203,7 @@ struct fetcher {
} }
const T& operator[](long i) const noexcept { const T& operator[](long i) const noexcept {
if (n > 0) if (n > 0) return carray[i];
return carray[i];
return value; return value;
} }
}; };
@ -220,18 +218,20 @@ struct span {
bp::object histogram_fill(bp::tuple args, bp::dict kwargs) { bp::object histogram_fill(bp::tuple args, bp::dict kwargs) {
const auto nargs = bp::len(args); const auto nargs = bp::len(args);
pyhistogram &self = bp::extract<pyhistogram &>(args[0]); pyhistogram& self = bp::extract<pyhistogram&>(args[0]);
const unsigned dim = nargs - 1; const unsigned dim = nargs - 1;
if (dim != self.dim()) { if (dim != self.dim()) {
PyErr_SetString(PyExc_ValueError, "number of arguments and dimension do not match"); PyErr_SetString(PyExc_ValueError,
"number of arguments and dimension do not match");
bp::throw_error_already_set(); bp::throw_error_already_set();
} }
if (dim > BOOST_HISTOGRAM_AXIS_LIMIT) { if (dim > BOOST_HISTOGRAM_AXIS_LIMIT) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
bh::detail::cat("too many arguments, maximum is ", bh::detail::cat("too many arguments, maximum is ",
BOOST_HISTOGRAM_AXIS_LIMIT).c_str()); BOOST_HISTOGRAM_AXIS_LIMIT)
.c_str());
bp::throw_error_already_set(); bp::throw_error_already_set();
} }
@ -241,7 +241,8 @@ bp::object histogram_fill(bp::tuple args, bp::dict kwargs) {
fetch[d].assign(args[1 + d]); fetch[d].assign(args[1 + d]);
if (fetch[d].n > 0) { if (fetch[d].n > 0) {
if (n > 0 && fetch[d].n != n) { if (n > 0 && fetch[d].n != n) {
PyErr_SetString(PyExc_ValueError, "lengths of sequences do not match"); PyErr_SetString(PyExc_ValueError,
"lengths of sequences do not match");
bp::throw_error_already_set(); bp::throw_error_already_set();
} }
n = fetch[d].n; n = fetch[d].n;
@ -261,7 +262,8 @@ bp::object histogram_fill(bp::tuple args, bp::dict kwargs) {
fetch_weight.assign(kwargs.get("weight")); fetch_weight.assign(kwargs.get("weight"));
if (fetch_weight.n > 0) { if (fetch_weight.n > 0) {
if (n > 0 && fetch_weight.n != n) { if (n > 0 && fetch_weight.n != n) {
PyErr_SetString(PyExc_ValueError, "length of weight sequence does not match"); PyErr_SetString(PyExc_ValueError,
"length of weight sequence does not match");
bp::throw_error_already_set(); bp::throw_error_already_set();
} }
n = fetch_weight.n; n = fetch_weight.n;
@ -275,22 +277,18 @@ bp::object histogram_fill(bp::tuple args, bp::dict kwargs) {
for (auto i = 0l; i < n; ++i) for (auto i = 0l; i < n; ++i)
self(bh::weight(fetch_weight[i]), fetch[0][i]); self(bh::weight(fetch_weight[i]), fetch[0][i]);
} else { } else {
for (auto i = 0l; i < n; ++i) for (auto i = 0l; i < n; ++i) self(fetch[0][i]);
self(fetch[0][i]);
} }
} else { } else {
double v[BOOST_HISTOGRAM_AXIS_LIMIT]; double v[BOOST_HISTOGRAM_AXIS_LIMIT];
if (fetch_weight.n >= 0) { if (fetch_weight.n >= 0) {
for (auto i = 0l; i < n; ++i) { for (auto i = 0l; i < n; ++i) {
for (auto d = 0u; d < dim; ++d) for (auto d = 0u; d < dim; ++d) v[d] = fetch[d][i];
v[d] = fetch[d][i];
self(bh::weight(fetch_weight[i]), span<double>{v, dim}); self(bh::weight(fetch_weight[i]), span<double>{v, dim});
} }
} } else {
else {
for (auto i = 0l; i < n; ++i) { for (auto i = 0l; i < n; ++i) {
for (auto d = 0u; d < dim; ++d) for (auto d = 0u; d < dim; ++d) v[d] = fetch[d][i];
v[d] = fetch[d][i];
self(span<double>{v, dim}); self(span<double>{v, dim});
} }
} }
@ -318,20 +316,20 @@ bp::object histogram_getitem(const pyhistogram& self, bp::object args) {
if (dim > BOOST_HISTOGRAM_AXIS_LIMIT) { if (dim > BOOST_HISTOGRAM_AXIS_LIMIT) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
bh::detail::cat("too many arguments, maximum is ", bh::detail::cat("too many arguments, maximum is ",
BOOST_HISTOGRAM_AXIS_LIMIT).c_str()); BOOST_HISTOGRAM_AXIS_LIMIT)
.c_str());
bp::throw_error_already_set(); bp::throw_error_already_set();
} }
int idx[BOOST_HISTOGRAM_AXIS_LIMIT]; int idx[BOOST_HISTOGRAM_AXIS_LIMIT];
for (unsigned i = 0; i < dim; ++i) for (unsigned i = 0; i < dim; ++i) idx[i] = bp::extract<int>(args[i]);
idx[i] = bp::extract<int>(args[i]);
return bp::object(self.at(span<int>{idx, self.dim()})); return bp::object(self.at(span<int>{idx, self.dim()}));
} }
bp::object histogram_at(bp::tuple args, bp::dict kwargs) { bp::object histogram_at(bp::tuple args, bp::dict kwargs) {
const pyhistogram & self = bp::extract<const pyhistogram &>(args[0]); const pyhistogram& self = bp::extract<const pyhistogram&>(args[0]);
if (kwargs) { if (kwargs) {
PyErr_SetString(PyExc_RuntimeError, "no keyword arguments allowed"); PyErr_SetString(PyExc_RuntimeError, "no keyword arguments allowed");
@ -343,14 +341,15 @@ bp::object histogram_at(bp::tuple args, bp::dict kwargs) {
} }
bp::object histogram_reduce_to(bp::tuple args, bp::dict kwargs) { bp::object histogram_reduce_to(bp::tuple args, bp::dict kwargs) {
const pyhistogram &self = bp::extract<const pyhistogram &>(args[0]); const pyhistogram& self = bp::extract<const pyhistogram&>(args[0]);
const unsigned nargs = bp::len(args) - 1; const unsigned nargs = bp::len(args) - 1;
if (nargs > BOOST_HISTOGRAM_AXIS_LIMIT) { if (nargs > BOOST_HISTOGRAM_AXIS_LIMIT) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
bh::detail::cat("too many arguments, maximum is ", bh::detail::cat("too many arguments, maximum is ",
BOOST_HISTOGRAM_AXIS_LIMIT).c_str()); BOOST_HISTOGRAM_AXIS_LIMIT)
.c_str());
bp::throw_error_already_set(); bp::throw_error_already_set();
} }
@ -360,84 +359,86 @@ bp::object histogram_reduce_to(bp::tuple args, bp::dict kwargs) {
} }
int idx[BOOST_HISTOGRAM_AXIS_LIMIT]; int idx[BOOST_HISTOGRAM_AXIS_LIMIT];
for (auto i = 0u; i < nargs; ++i) for (auto i = 0u; i < nargs; ++i) idx[i] = bp::extract<int>(args[1 + i]);
idx[i] = bp::extract<int>(args[1 + i]);
return bp::object(self.reduce_to(idx, idx + nargs)); return bp::object(self.reduce_to(idx, idx + nargs));
} }
std::string histogram_repr(const pyhistogram &h) { std::string histogram_repr(const pyhistogram& h) {
return bh::detail::cat(h); return bh::detail::cat(h);
} }
double element_value(const pyhistogram::element_type& b) { double element_value(const pyhistogram::element_type& b) { return b.value(); }
return b.value();
}
double element_variance(const pyhistogram::element_type& b) { double element_variance(const pyhistogram::element_type& b) {
return b.variance(); return b.variance();
} }
double element_getitem(const pyhistogram::element_type& e, int i) { double element_getitem(const pyhistogram::element_type& e, int i) {
if (i < 0 || i > 1) if (i < 0 || i > 1) throw std::out_of_range("element_getitem");
throw std::out_of_range("element_getitem");
return i == 0 ? e.value() : e.variance(); return i == 0 ? e.value() : e.variance();
} }
int element_len(const pyhistogram::element_type&) { return 2; } int element_len(const pyhistogram::element_type&) { return 2; }
std::string element_repr(const pyhistogram::element_type& e) { std::string element_repr(const pyhistogram::element_type& e) {
return bh::detail::cat("histogram.element(", e.value(), ", ", e.variance(), ")"); return bh::detail::cat("histogram.element(", e.value(), ", ", e.variance(),
")");
} }
void register_histogram() { void register_histogram() {
bp::docstring_options dopt(true, true, false); bp::docstring_options dopt(true, true, false);
bp::scope s = bp::class_<pyhistogram, boost::shared_ptr<pyhistogram>>( bp::scope s =
"histogram", "N-dimensional histogram for real-valued data.", bp::no_init) bp::class_<pyhistogram, boost::shared_ptr<pyhistogram>>(
.def("__init__", bp::raw_function(histogram_init), "histogram", "N-dimensional histogram for real-valued data.",
":param axis args: axis objects" bp::no_init)
"\nPass one or more axis objects to configure the histogram.") .def("__init__", bp::raw_function(histogram_init),
// shadowed C++ ctors ":param axis args: axis objects"
.def(bp::init<const pyhistogram &>()) "\nPass one or more axis objects to configure the histogram.")
// .def(bp::init<pyhistogram &&>()) // shadowed C++ ctors
.def(bp::init<const pyhistogram&>())
// .def(bp::init<pyhistogram &&>())
#ifdef HAVE_NUMPY #ifdef HAVE_NUMPY
.add_property("__array_interface__", &bp::access::array_interface) .add_property("__array_interface__", &bp::access::array_interface)
#endif #endif
.add_property("dim", &pyhistogram::dim) .add_property("dim", &pyhistogram::dim)
.def("axis", histogram_axis, bp::arg("i") = 0, .def("axis", histogram_axis, bp::arg("i") = 0,
":param int i: axis index" ":param int i: axis index"
"\n:return: corresponding axis object") "\n:return: corresponding axis object")
.def("__call__", bp::raw_function(histogram_fill), .def(
":param double args: values (number must match dimension)" "__call__", bp::raw_function(histogram_fill),
"\n:keyword double weight: optional weight" ":param double args: values (number must match dimension)"
"\n" "\n:keyword double weight: optional weight"
"\nIf Numpy support is enabled, 1d-arrays can be passed instead of" "\n"
"\nvalues, which must be equal in lenght. Arrays and values can" "\nIf Numpy support is enabled, 1d-arrays can be passed "
"\nbe mixed arbitrarily in the same call.") "instead of"
.def("__len__", &pyhistogram::size, "\nvalues, which must be equal in lenght. Arrays and values can"
":return: total number of bins, including under- and overflow") "\nbe mixed arbitrarily in the same call.")
.def("at", bp::raw_function(histogram_at), .def("__len__", &pyhistogram::size,
":param int args: indices of the bin (number must match dimension)" ":return: total number of bins, including under- and overflow")
"\n:return: bin content") .def("at", bp::raw_function(histogram_at),
.def("__getitem__", histogram_getitem, ":param int args: indices of the bin (number must match "
":param int args: indices of the bin (number must match dimension)" "dimension)"
"\n:return: bin content") "\n:return: bin content")
.def("reduce_to", bp::raw_function(histogram_reduce_to), .def("__getitem__", histogram_getitem,
":param int args: indices of the axes in the reduced histogram" ":param int args: indices of the bin (number must match "
"\n:return: reduced histogram with subset of axes") "dimension)"
.def("__iter__", bp::iterator<pyhistogram>()) "\n:return: bin content")
.def("__repr__", histogram_repr, .def("reduce_to", bp::raw_function(histogram_reduce_to),
":return: string representation of the histogram") ":param int args: indices of the axes in the reduced histogram"
.def(bp::self == bp::self) "\n:return: reduced histogram with subset of axes")
.def(bp::self != bp::self) .def("__iter__", bp::iterator<pyhistogram>())
.def(bp::self += bp::self) .def("__repr__", histogram_repr,
.def(bp::self *= double()) ":return: string representation of the histogram")
.def(bp::self * double()) .def(bp::self == bp::self)
.def(double() * bp::self) .def(bp::self != bp::self)
.def(bp::self + bp::self) .def(bp::self += bp::self)
.def_pickle(bh::serialization_suite<pyhistogram>()) .def(bp::self *= double())
; .def(bp::self * double())
.def(double() * bp::self)
.def(bp::self + bp::self)
.def_pickle(bh::serialization_suite<pyhistogram>());
bp::class_<pyhistogram::element_type>( bp::class_<pyhistogram::element_type>(
"element", "Holds value and variance of bin count.", "element", "Holds value and variance of bin count.",
@ -453,6 +454,5 @@ void register_histogram() {
.def(bp::self + bp::self) .def(bp::self + bp::self)
.def(bp::self + double()) .def(bp::self + double())
.def(double() + bp::self) .def(double() + bp::self)
.def("__repr__", element_repr) .def("__repr__", element_repr);
;
} }

View File

@ -5,10 +5,10 @@
// or copy at http://www.boost.org/LICENSE_1_0.txt) // or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/python/module.hpp> #include <boost/python/module.hpp>
#include <boost/python/scope.hpp>
#include <boost/python/object.hpp> #include <boost/python/object.hpp>
#include <boost/python/scope.hpp>
#ifdef HAVE_NUMPY #ifdef HAVE_NUMPY
# include <boost/python/numpy.hpp> #include <boost/python/numpy.hpp>
#endif #endif
void register_axis_types(); void register_axis_types();
@ -23,9 +23,7 @@ BOOST_PYTHON_MODULE(histogram) {
#else #else
current.attr("HAVE_NUMPY") = false; current.attr("HAVE_NUMPY") = false;
#endif #endif
object axis_module = object( object axis_module = object(borrowed(PyImport_AddModule("histogram.axis")));
borrowed(PyImport_AddModule("histogram.axis"))
);
current.attr("axis") = axis_module; current.attr("axis") = axis_module;
{ {
scope current = axis_module; scope current = axis_module;

View File

@ -31,11 +31,11 @@ namespace detail {
class python_bytes_sink : public iostreams::sink { class python_bytes_sink : public iostreams::sink {
public: public:
python_bytes_sink(PyObject **pstr) : pstr_(pstr), len_(0), pos_(0) { python_bytes_sink(PyObject** pstr) : pstr_(pstr), len_(0), pos_(0) {
BOOST_ASSERT(*pstr == 0); BOOST_ASSERT(*pstr == 0);
} }
std::streamsize write(const char *s, std::streamsize n) { std::streamsize write(const char* s, std::streamsize n) {
if (len_ == 0) { if (len_ == 0) {
*pstr_ = PyBytes_FromStringAndSize(s, n); *pstr_ = PyBytes_FromStringAndSize(s, n);
if (*pstr_ == 0) // no point trying to recover from allocation error if (*pstr_ == 0) // no point trying to recover from allocation error
@ -47,7 +47,7 @@ public:
if (_PyBytes_Resize(pstr_, len_) == -1) if (_PyBytes_Resize(pstr_, len_) == -1)
std::abort(); // no point trying to recover from allocation error std::abort(); // no point trying to recover from allocation error
} }
char *b = PyBytes_AS_STRING(*pstr_); char* b = PyBytes_AS_STRING(*pstr_);
std::copy(s, s + n, b + pos_); std::copy(s, s + n, b + pos_);
} }
pos_ += n; pos_ += n;
@ -55,17 +55,18 @@ public:
} }
private: private:
PyObject **pstr_; PyObject** pstr_;
std::streamsize len_, pos_; std::streamsize len_, pos_;
}; };
} // namespace detail } // namespace detail
template <class T> struct serialization_suite : python::pickle_suite { template <class T>
struct serialization_suite : python::pickle_suite {
static python::tuple getstate(python::object obj) { static python::tuple getstate(python::object obj) {
PyObject *pobj = 0; PyObject* pobj = 0;
iostreams::stream<detail::python_bytes_sink> os(&pobj); iostreams::stream<detail::python_bytes_sink> os(&pobj);
archive::text_oarchive oa(os); archive::text_oarchive oa(os);
oa << python::extract<const T &>(obj)(); oa << python::extract<const T&>(obj)();
os.flush(); os.flush();
return python::make_tuple(obj.attr("__dict__"), return python::make_tuple(obj.attr("__dict__"),
python::object(python::handle<>(pobj))); python::object(python::handle<>(pobj)));
@ -81,7 +82,7 @@ template <class T> struct serialization_suite : python::pickle_suite {
iostreams::stream<iostreams::array_source> is(PyBytes_AS_STRING(o.ptr()), iostreams::stream<iostreams::array_source> is(PyBytes_AS_STRING(o.ptr()),
PyBytes_Size(o.ptr())); PyBytes_Size(o.ptr()));
archive::text_iarchive ia(is); archive::text_iarchive ia(is);
ia >> python::extract<T &>(obj)(); ia >> python::extract<T&>(obj)();
} }
static bool getstate_manages_dict() { return true; } static bool getstate_manages_dict() { return true; }

View File

@ -8,22 +8,22 @@
#define _BOOST_HISTOGRAM_PYTHON_UTILITY_HPP_ #define _BOOST_HISTOGRAM_PYTHON_UTILITY_HPP_
#include <boost/python/str.hpp> #include <boost/python/str.hpp>
#include <type_traits>
#include <stdexcept> #include <stdexcept>
#include <type_traits>
namespace boost { namespace boost {
namespace python { namespace python {
template <typename T> template <typename T>
str dtype_typestr() { str dtype_typestr() {
str s; str s;
if (std::is_floating_point<T>::value) if (std::is_floating_point<T>::value)
s = "|f"; s = "|f";
else if (std::is_integral<T>::value) else if (std::is_integral<T>::value)
s = std::is_unsigned<T>::value ? "|u" : "|i"; s = std::is_unsigned<T>::value ? "|u" : "|i";
else else
throw std::invalid_argument("T must be a builtin arithmetic type"); throw std::invalid_argument("T must be a builtin arithmetic type");
s += str(sizeof(T)); s += str(sizeof(T));
return s; return s;
} }
} // python } // python
} // boost } // boost

View File

@ -190,8 +190,7 @@ void convert_array_storage_impl() {
array_storage<float> t(std::size_t(1)); array_storage<float> t(std::size_t(1));
t.increase(0); t.increase(0);
while (t[0] < 1e20) while (t[0] < 1e20) t.add(0, t[0]);
t.add(0, t[0]);
auto d = aref; auto d = aref;
d = t; d = t;
BOOST_TEST(d == t); BOOST_TEST(d == t);

View File

@ -51,7 +51,8 @@ int main() {
{ {
axis::regular<> a{4, -2, 2}; axis::regular<> a{4, -2, 2};
BOOST_TEST_EQ(a[-1].lower(), -std::numeric_limits<double>::infinity()); BOOST_TEST_EQ(a[-1].lower(), -std::numeric_limits<double>::infinity());
BOOST_TEST_EQ(a[a.size()].upper(), std::numeric_limits<double>::infinity()); BOOST_TEST_EQ(a[a.size()].upper(),
std::numeric_limits<double>::infinity());
axis::regular<> b; axis::regular<> b;
BOOST_TEST_NOT(a == b); BOOST_TEST_NOT(a == b);
b = a; b = a;
@ -149,7 +150,8 @@ int main() {
{ {
axis::variable<> a{-1, 0, 1}; axis::variable<> a{-1, 0, 1};
BOOST_TEST_EQ(a[-1].lower(), -std::numeric_limits<double>::infinity()); BOOST_TEST_EQ(a[-1].lower(), -std::numeric_limits<double>::infinity());
BOOST_TEST_EQ(a[a.size()].upper(), std::numeric_limits<double>::infinity()); BOOST_TEST_EQ(a[a.size()].upper(),
std::numeric_limits<double>::infinity());
axis::variable<> b; axis::variable<> b;
BOOST_TEST_NOT(a == b); BOOST_TEST_NOT(a == b);
b = a; b = a;
@ -258,7 +260,8 @@ int main() {
a6 = a1; a6 = a1;
BOOST_TEST_EQ(a6, a1); BOOST_TEST_EQ(a6, a1);
axis::any<axis::regular<>, axis::integer<>> a7(axis::integer<>(0, 2)); axis::any<axis::regular<>, axis::integer<>> a7(axis::integer<>(0, 2));
BOOST_TEST_THROWS(axis::any<axis::regular<>> a8(a7), std::invalid_argument); BOOST_TEST_THROWS(axis::any<axis::regular<>> a8(a7),
std::invalid_argument);
BOOST_TEST_THROWS(a4 = a7, std::invalid_argument); BOOST_TEST_THROWS(a4 = a7, std::invalid_argument);
} }
@ -288,14 +291,13 @@ int main() {
axes.push_back(axis::regular<double, axis::transform::pow>( axes.push_back(axis::regular<double, axis::transform::pow>(
2, 1, 10, "regular4", axis::uoflow::off, -0.5)); 2, 1, 10, "regular4", axis::uoflow::off, -0.5));
axes.push_back(axis::circular<>(4, 0.1, 1.0, "polar")); axes.push_back(axis::circular<>(4, 0.1, 1.0, "polar"));
axes.push_back(axis::variable<>({-1, 0, 1}, "variable", axis::uoflow::off)); axes.push_back(
axis::variable<>({-1, 0, 1}, "variable", axis::uoflow::off));
axes.push_back(axis::category<>({A, B, C}, "category")); axes.push_back(axis::category<>({A, B, C}, "category"));
axes.push_back(axis::category<std::string>({a, b}, "category2")); axes.push_back(axis::category<std::string>({a, b}, "category2"));
axes.push_back(axis::integer<>(-1, 1, "integer", axis::uoflow::off)); axes.push_back(axis::integer<>(-1, 1, "integer", axis::uoflow::off));
std::ostringstream os; std::ostringstream os;
for (const auto& a : axes) { for (const auto& a : axes) { os << a << "\n"; }
os << a << "\n";
}
const std::string ref = const std::string ref =
"regular(2, -1, 1, label='regular1')\n" "regular(2, -1, 1, label='regular1')\n"
"regular_log(2, 1, 10, label='regular2', uoflow=False)\n" "regular_log(2, 1, 10, label='regular2', uoflow=False)\n"
@ -343,7 +345,8 @@ int main() {
std_vector1 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1}, std_vector1 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
axis::category<>{A, B, C}}; axis::category<>{A, B, C}};
std::vector<axis::any<axis::regular<>, axis::variable<>, axis::category<>>> std::vector<
axis::any<axis::regular<>, axis::variable<>, axis::category<>>>
std_vector2 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1}, std_vector2 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
axis::category<>{{A, B, C}}}; axis::category<>{{A, B, C}}};
@ -365,8 +368,8 @@ int main() {
std::make_tuple(axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1}, std::make_tuple(axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
axis::category<>{{A, B}}); axis::category<>{{A, B}});
auto tuple3 = auto tuple3 = std::make_tuple(axis::regular<>{2, -1, 1},
std::make_tuple(axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1}); axis::variable<>{-1, 0, 1});
BOOST_TEST(detail::axes_equal(std_vector1, tuple1)); BOOST_TEST(detail::axes_equal(std_vector1, tuple1));
BOOST_TEST(detail::axes_equal(tuple1, std_vector1)); BOOST_TEST(detail::axes_equal(tuple1, std_vector1));
@ -383,7 +386,8 @@ int main() {
std_vector1 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1}, std_vector1 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
axis::category<>{A, B, C}}; axis::category<>{A, B, C}};
std::vector<axis::any<axis::regular<>, axis::variable<>, axis::category<>>> std::vector<
axis::any<axis::regular<>, axis::variable<>, axis::category<>>>
std_vector2 = {axis::regular<>{2, -2, 2}, axis::variable<>{-2, 0, 2}, std_vector2 = {axis::regular<>{2, -2, 2}, axis::variable<>{-2, 0, 2},
axis::category<>{A, B}}; axis::category<>{A, B}};

View File

@ -3,6 +3,7 @@
using namespace boost::histogram; using namespace boost::histogram;
int main() { int main() {
auto h = make_dynamic_histogram(axis::integer<>(0, 2), axis::integer<>(0, 2)); auto h =
make_dynamic_histogram(axis::integer<>(0, 2), axis::integer<>(0, 2));
h.at(std::make_pair(-2, 0)); h.at(std::make_pair(-2, 0));
} }

View File

@ -3,6 +3,7 @@
using namespace boost::histogram; using namespace boost::histogram;
int main() { int main() {
auto h = make_dynamic_histogram(axis::integer<>(0, 2), axis::integer<>(0, 2)); auto h =
make_dynamic_histogram(axis::integer<>(0, 2), axis::integer<>(0, 2));
h.at(std::vector<int>({-2, 0})); h.at(std::vector<int>({-2, 0}));
} }

View File

@ -3,6 +3,7 @@
using namespace boost::histogram; using namespace boost::histogram;
int main() { int main() {
auto h = make_static_histogram(axis::integer<>(0, 2), axis::integer<>(0, 2)); auto h =
make_static_histogram(axis::integer<>(0, 2), axis::integer<>(0, 2));
h.at(std::vector<int>(-2, 0)); h.at(std::vector<int>(-2, 0));
} }

View File

@ -76,8 +76,8 @@ void run_tests() {
// init_2 // init_2
{ {
auto h = make_histogram<adaptive_storage>(Type(), axis::regular<>{3, -1, 1}, auto h = make_histogram<adaptive_storage>(
axis::integer<>{-1, 2}); Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2});
BOOST_TEST_EQ(h.dim(), 2); BOOST_TEST_EQ(h.dim(), 2);
BOOST_TEST_EQ(h.size(), 25); BOOST_TEST_EQ(h.size(), 25);
BOOST_TEST_EQ(h.axis(0_c).shape(), 5); BOOST_TEST_EQ(h.axis(0_c).shape(), 5);
@ -89,9 +89,9 @@ void run_tests() {
// init_3 // init_3
{ {
auto h = make_histogram<adaptive_storage>(Type(), axis::regular<>{3, -1, 1}, auto h = make_histogram<adaptive_storage>(
axis::integer<>{-1, 2}, Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2},
axis::circular<>{3}); axis::circular<>{3});
BOOST_TEST_EQ(h.dim(), 3); BOOST_TEST_EQ(h.dim(), 3);
BOOST_TEST_EQ(h.size(), 75); BOOST_TEST_EQ(h.size(), 75);
auto h2 = make_histogram<array_storage<unsigned>>( auto h2 = make_histogram<array_storage<unsigned>>(
@ -136,8 +136,9 @@ void run_tests() {
h(0, 0); h(0, 0);
auto h2 = decltype(h)(h); auto h2 = decltype(h)(h);
BOOST_TEST(h2 == h); BOOST_TEST(h2 == h);
auto h3 = static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>, auto h3 =
array_storage<unsigned>>(h); static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>,
array_storage<unsigned>>(h);
BOOST_TEST_EQ(h3, h); BOOST_TEST_EQ(h3, h);
} }
@ -153,8 +154,9 @@ void run_tests() {
// test self-assign // test self-assign
h2 = h2; h2 = h2;
BOOST_TEST_EQ(h, h2); BOOST_TEST_EQ(h, h2);
auto h3 = static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>, auto h3 =
array_storage<unsigned>>(); static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>,
array_storage<unsigned>>();
h3 = h; h3 = h;
BOOST_TEST_EQ(h, h3); BOOST_TEST_EQ(h, h3);
} }
@ -183,8 +185,8 @@ void run_tests() {
// axis methods // axis methods
{ {
enum { A = 3, B = 5 }; enum { A = 3, B = 5 };
auto a = make_histogram<adaptive_storage>(Type(), auto a = make_histogram<adaptive_storage>(
axis::regular<>(1, 1, 2, "foo")); Type(), axis::regular<>(1, 1, 2, "foo"));
BOOST_TEST_EQ(a.axis().size(), 1); BOOST_TEST_EQ(a.axis().size(), 1);
BOOST_TEST_EQ(a.axis().shape(), 3); BOOST_TEST_EQ(a.axis().shape(), 3);
BOOST_TEST_EQ(a.axis().index(1), 0); BOOST_TEST_EQ(a.axis().index(1), 0);
@ -203,7 +205,8 @@ void run_tests() {
b.axis().label("foo"); b.axis().label("foo");
BOOST_TEST_EQ(b.axis().label(), "foo"); BOOST_TEST_EQ(b.axis().label(), "foo");
auto c = make_histogram<adaptive_storage>(Type(), axis::category<>({A, B})); auto c =
make_histogram<adaptive_storage>(Type(), axis::category<>({A, B}));
BOOST_TEST_EQ(c.axis().size(), 2); BOOST_TEST_EQ(c.axis().size(), 2);
BOOST_TEST_EQ(c.axis().shape(), 2); BOOST_TEST_EQ(c.axis().shape(), 2);
BOOST_TEST_EQ(c.axis().index(A), 0); BOOST_TEST_EQ(c.axis().index(A), 0);
@ -227,7 +230,8 @@ void run_tests() {
BOOST_TEST(c != b); BOOST_TEST(c != b);
BOOST_TEST(a == c); BOOST_TEST(a == c);
BOOST_TEST(c == a); BOOST_TEST(c == a);
auto d = make_histogram<adaptive_storage>(Type(), axis::regular<>(2, 0, 1)); auto d =
make_histogram<adaptive_storage>(Type(), axis::regular<>(2, 0, 1));
BOOST_TEST(c != d); BOOST_TEST(c != d);
BOOST_TEST(d != c); BOOST_TEST(d != c);
c(0); c(0);
@ -425,8 +429,8 @@ void run_tests() {
// add_1 // add_1
{ {
auto a = make_histogram<adaptive_storage>(Type(), axis::integer<>(0, 2)); auto a = make_histogram<adaptive_storage>(Type(), axis::integer<>(0, 2));
auto b = auto b = make_histogram<array_storage<unsigned>>(Type(),
make_histogram<array_storage<unsigned>>(Type(), axis::integer<>(0, 2)); axis::integer<>(0, 2));
a(0); // 1 0 a(0); // 1 0
b(1); // 0 1 b(1); // 0 1
auto a2 = a; auto a2 = a;
@ -477,8 +481,8 @@ void run_tests() {
{ {
auto a = auto a =
make_histogram<array_storage<char>>(Type(), axis::integer<>(-1, 2)); make_histogram<array_storage<char>>(Type(), axis::integer<>(-1, 2));
auto b = auto b = make_histogram<array_storage<unsigned>>(Type(),
make_histogram<array_storage<unsigned>>(Type(), axis::integer<>(-1, 2)); axis::integer<>(-1, 2));
a(-1); a(-1);
b(1); b(1);
auto c = a; auto c = a;
@ -896,8 +900,8 @@ void run_mixed_tests() {
{ {
auto a = make_histogram<adaptive_storage>(T1{}, axis::regular<>{3, 0, 3}, auto a = make_histogram<adaptive_storage>(T1{}, axis::regular<>{3, 0, 3},
axis::integer<>(0, 2)); axis::integer<>(0, 2));
auto b = make_histogram<array_storage<int>>(T2{}, axis::regular<>{3, 0, 3}, auto b = make_histogram<array_storage<int>>(
axis::integer<>(0, 2)); T2{}, axis::regular<>{3, 0, 3}, axis::integer<>(0, 2));
BOOST_TEST_EQ(a, b); BOOST_TEST_EQ(a, b);
auto b2 = make_histogram<adaptive_storage>(T2{}, axis::integer<>{0, 3}, auto b2 = make_histogram<adaptive_storage>(T2{}, axis::integer<>{0, 3},
axis::integer<>(0, 2)); axis::integer<>(0, 2));
@ -926,8 +930,8 @@ void run_mixed_tests() {
{ {
auto a = make_histogram<adaptive_storage>(T1{}, axis::regular<>{3, 0, 3}, auto a = make_histogram<adaptive_storage>(T1{}, axis::regular<>{3, 0, 3},
axis::integer<>(0, 2)); axis::integer<>(0, 2));
auto b = make_histogram<array_storage<int>>(T2{}, axis::regular<>{3, 0, 3}, auto b = make_histogram<array_storage<int>>(
axis::integer<>(0, 2)); T2{}, axis::regular<>{3, 0, 3}, axis::integer<>(0, 2));
a(1, 1); a(1, 1);
BOOST_TEST_NE(a, b); BOOST_TEST_NE(a, b);
b = a; b = a;

View File

@ -4,11 +4,11 @@
// (See accompanying file LICENSE_1_0.txt // (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt) // or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "utility.hpp"
#include <boost/histogram/detail/index_mapper.hpp>
#include <boost/core/lightweight_test.hpp> #include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp> #include <boost/core/lightweight_test_trait.hpp>
#include <boost/histogram/detail/index_mapper.hpp>
#include <vector> #include <vector>
#include "utility.hpp"
using namespace boost::histogram::detail; using namespace boost::histogram::detail;

View File

@ -135,7 +135,8 @@ int main() {
BOOST_TEST_TRAIT_TRUE((std::is_same<copy_qualifiers<int&, long>, long&>)); BOOST_TEST_TRAIT_TRUE((std::is_same<copy_qualifiers<int&, long>, long&>));
BOOST_TEST_TRAIT_TRUE( BOOST_TEST_TRAIT_TRUE(
(std::is_same<copy_qualifiers<const int&, long>, const long&>)); (std::is_same<copy_qualifiers<const int&, long>, const long&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<copy_qualifiers<int&&, long>, long&&>)); BOOST_TEST_TRAIT_TRUE(
(std::is_same<copy_qualifiers<int&&, long>, long&&>));
} }
// mp_set_union // mp_set_union
@ -153,8 +154,8 @@ int main() {
BOOST_TEST_TRAIT_TRUE((std::is_same<selection<T, i0>, std::tuple<char>>)); BOOST_TEST_TRAIT_TRUE((std::is_same<selection<T, i0>, std::tuple<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<selection<T, i1>, std::tuple<int>>)); BOOST_TEST_TRAIT_TRUE((std::is_same<selection<T, i1>, std::tuple<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<selection<T, i2>, std::tuple<long>>)); BOOST_TEST_TRAIT_TRUE((std::is_same<selection<T, i2>, std::tuple<long>>));
BOOST_TEST_TRAIT_TRUE( BOOST_TEST_TRAIT_TRUE((
(std::is_same<selection<T, i0, i1, i2>, std::tuple<char, int, long>>)); std::is_same<selection<T, i0, i1, i2>, std::tuple<char, int, long>>));
BOOST_TEST_TRAIT_TRUE( BOOST_TEST_TRAIT_TRUE(
(std::is_same<selection<T, i0, i1>, std::tuple<char, int>>)); (std::is_same<selection<T, i0, i1>, std::tuple<char, int>>));
BOOST_TEST_TRAIT_TRUE( BOOST_TEST_TRAIT_TRUE(

View File

@ -6,12 +6,12 @@
#include <algorithm> #include <algorithm>
#include <boost/histogram.hpp> #include <boost/histogram.hpp>
#include <boost/mp11.hpp>
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <limits> #include <limits>
#include <random>
#include <memory> #include <memory>
#include <boost/mp11.hpp> #include <random>
using namespace boost::histogram; using namespace boost::histogram;
using boost::mp11::mp_list; using boost::mp11::mp_list;
@ -21,12 +21,10 @@ std::unique_ptr<double[]> random_array(unsigned n, int type) {
std::default_random_engine gen(1); std::default_random_engine gen(1);
if (type) { // type == 1 if (type) { // type == 1
std::normal_distribution<> d(0.5, 0.3); std::normal_distribution<> d(0.5, 0.3);
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
r[i] = d(gen);
} else { // type == 0 } else { // type == 0
std::uniform_real_distribution<> d(0.0, 1.0); std::uniform_real_distribution<> d(0.0, 1.0);
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
r[i] = d(gen);
} }
return r; return r;
} }
@ -58,8 +56,7 @@ double compare_1d(unsigned n, int distrib) {
for (unsigned k = 0; k < 20; ++k) { for (unsigned k = 0; k < 20; ++k) {
auto h = Histogram(axis::regular<>(100, 0, 1)); auto h = Histogram(axis::regular<>(100, 0, 1));
auto t = clock(); auto t = clock();
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) h(r[i]);
h(r[i]);
t = clock() - t; t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC); best = std::min(best, double(t) / CLOCKS_PER_SEC);
} }
@ -73,10 +70,10 @@ double compare_2d(unsigned n, int distrib) {
auto best = std::numeric_limits<double>::max(); auto best = std::numeric_limits<double>::max();
for (unsigned k = 0; k < 20; ++k) { for (unsigned k = 0; k < 20; ++k) {
auto h = Histogram(axis::regular<>(100, 0, 1), axis::regular<>(100, 0, 1)); auto h =
Histogram(axis::regular<>(100, 0, 1), axis::regular<>(100, 0, 1));
auto t = clock(); auto t = clock();
for (unsigned i = 0; i < n / 2; ++i) for (unsigned i = 0; i < n / 2; ++i) h(r[2 * i], r[2 * i + 1]);
h(r[2 * i], r[2 * i + 1]);
t = clock() - t; t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC); best = std::min(best, double(t) / CLOCKS_PER_SEC);
} }
@ -136,9 +133,8 @@ int main() {
else else
printf("normal distribution\n"); printf("normal distribution\n");
printf("hs_ss %.3f\n", printf("hs_ss %.3f\n",
compare_1d< compare_1d<static_histogram<mp_list<axis::regular<>>,
static_histogram<mp_list<axis::regular<>>, array_storage<int>>>( array_storage<int>>>(nfill, itype));
nfill, itype));
printf("hs_sd %.3f\n", printf("hs_sd %.3f\n",
compare_1d< compare_1d<
static_histogram<mp_list<axis::regular<>>, adaptive_storage>>( static_histogram<mp_list<axis::regular<>>, adaptive_storage>>(
@ -147,8 +143,8 @@ int main() {
compare_1d<dynamic_histogram<axis::types, array_storage<int>>>( compare_1d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype)); nfill, itype));
printf("hd_sd %.3f\n", printf("hd_sd %.3f\n",
compare_1d<dynamic_histogram<axis::types, adaptive_storage>>(nfill, compare_1d<dynamic_histogram<axis::types, adaptive_storage>>(
itype)); nfill, itype));
} }
printf("2D\n"); printf("2D\n");
@ -169,8 +165,8 @@ int main() {
compare_2d<dynamic_histogram<axis::types, array_storage<int>>>( compare_2d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype)); nfill, itype));
printf("hd_sd %.3f\n", printf("hd_sd %.3f\n",
compare_2d<dynamic_histogram<axis::types, adaptive_storage>>(nfill, compare_2d<dynamic_histogram<axis::types, adaptive_storage>>(
itype)); nfill, itype));
} }
printf("3D\n"); printf("3D\n");
@ -191,8 +187,8 @@ int main() {
compare_3d<dynamic_histogram<axis::types, array_storage<int>>>( compare_3d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype)); nfill, itype));
printf("hd_sd %.3f\n", printf("hd_sd %.3f\n",
compare_3d<dynamic_histogram<axis::types, adaptive_storage>>(nfill, compare_3d<dynamic_histogram<axis::types, adaptive_storage>>(
itype)); nfill, itype));
} }
printf("6D\n"); printf("6D\n");
@ -215,7 +211,7 @@ int main() {
compare_6d<dynamic_histogram<axis::types, array_storage<int>>>( compare_6d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype)); nfill, itype));
printf("hd_sd %.3f\n", printf("hd_sd %.3f\n",
compare_6d<dynamic_histogram<axis::types, adaptive_storage>>(nfill, compare_6d<dynamic_histogram<axis::types, adaptive_storage>>(
itype)); nfill, itype));
} }
} }

View File

@ -11,20 +11,18 @@
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <limits> #include <limits>
#include <random>
#include <memory> #include <memory>
#include <random>
std::unique_ptr<double[]> random_array(unsigned n, int type) { std::unique_ptr<double[]> random_array(unsigned n, int type) {
std::unique_ptr<double[]> r(new double[n]); std::unique_ptr<double[]> r(new double[n]);
std::default_random_engine gen(1); std::default_random_engine gen(1);
if (type) { // type == 1 if (type) { // type == 1
std::normal_distribution<> d(0.5, 0.3); std::normal_distribution<> d(0.5, 0.3);
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
r[i] = d(gen);
} else { // type == 0 } else { // type == 0
std::uniform_real_distribution<> d(0.0, 1.0); std::uniform_real_distribution<> d(0.0, 1.0);
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
r[i] = d(gen);
} }
return r; return r;
} }
@ -37,8 +35,7 @@ void compare_1d(unsigned n, int distrib) {
gsl_histogram* h = gsl_histogram_alloc(100); gsl_histogram* h = gsl_histogram_alloc(100);
gsl_histogram_set_ranges_uniform(h, 0, 1); gsl_histogram_set_ranges_uniform(h, 0, 1);
auto t = clock(); auto t = clock();
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) gsl_histogram_increment(h, r[i]);
gsl_histogram_increment(h, r[i]);
t = clock() - t; t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC); best = std::min(best, double(t) / CLOCKS_PER_SEC);
gsl_histogram_free(h); gsl_histogram_free(h);

View File

@ -13,20 +13,18 @@
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <limits> #include <limits>
#include <random>
#include <memory> #include <memory>
#include <random>
std::unique_ptr<double[]> random_array(unsigned n, int type) { std::unique_ptr<double[]> random_array(unsigned n, int type) {
std::unique_ptr<double[]> r(new double[n]); std::unique_ptr<double[]> r(new double[n]);
std::default_random_engine gen(1); std::default_random_engine gen(1);
if (type) { // type == 1 if (type) { // type == 1
std::normal_distribution<> d(0.5, 0.3); std::normal_distribution<> d(0.5, 0.3);
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
r[i] = d(gen);
} else { // type == 0 } else { // type == 0
std::uniform_real_distribution<> d(0.0, 1.0); std::uniform_real_distribution<> d(0.0, 1.0);
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
r[i] = d(gen);
} }
return r; return r;
} }
@ -38,8 +36,7 @@ void compare_1d(unsigned n, int distrib) {
for (unsigned k = 0; k < 20; ++k) { for (unsigned k = 0; k < 20; ++k) {
TH1I hroot("", "", 100, 0, 1); TH1I hroot("", "", 100, 0, 1);
auto t = clock(); auto t = clock();
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i) hroot.Fill(r[i]);
hroot.Fill(r[i]);
t = clock() - t; t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
} }
@ -53,8 +50,7 @@ void compare_2d(unsigned n, int distrib) {
for (unsigned k = 0; k < 20; ++k) { for (unsigned k = 0; k < 20; ++k) {
TH2I hroot("", "", 100, 0, 1, 100, 0, 1); TH2I hroot("", "", 100, 0, 1, 100, 0, 1);
auto t = clock(); auto t = clock();
for (unsigned i = 0; i < n / 2; ++i) for (unsigned i = 0; i < n / 2; ++i) hroot.Fill(r[2 * i], r[2 * i + 1]);
hroot.Fill(r[2 * i], r[2 * i + 1]);
t = clock() - t; t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
} }
@ -87,9 +83,7 @@ void compare_6d(unsigned n, int distrib) {
THnI hroot("", "", 6, &bin.front(), &min.front(), &max.front()); THnI hroot("", "", 6, &bin.front(), &min.front(), &max.front());
auto t = clock(); auto t = clock();
for (unsigned i = 0; i < n / 6; ++i) { for (unsigned i = 0; i < n / 6; ++i) { hroot.Fill(r.get() + 6 * i); }
hroot.Fill(r.get() + 6 * i);
}
t = clock() - t; t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
} }

View File

@ -22,8 +22,7 @@ namespace std { // never add to std, we only do it to get ADL working
template <typename T> template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) { ostream& operator<<(ostream& os, const vector<T>& v) {
os << "[ "; os << "[ ";
for (const auto& x : v) for (const auto& x : v) os << x << " ";
os << x << " ";
os << "]"; os << "]";
return os; return os;
} }