clang-format

This commit is contained in:
Hans Dembinski 2018-07-21 17:28:14 +02:00
parent 699bb519c5
commit bfc437b7bd
53 changed files with 1784 additions and 1507 deletions

88
.clang-format Normal file
View File

@ -0,0 +1,88 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 78
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...

View File

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

View File

@ -10,42 +10,42 @@ namespace br = boost::random;
namespace bh = boost::histogram;
int main() {
/*
create a dynamic histogram with the factory `make_dynamic_histogram`
- axis can be passed directly just like for `make_static_histogram`
- in addition, the factory also accepts iterators over a sequence of
axis::any, the polymorphic type that can hold concrete axis types
*/
std::vector<bh::axis::any_std> axes;
axes.emplace_back(bh::axis::category<std::string>({"red", "blue"}));
axes.emplace_back(bh::axis::regular<>(5, -5, 5, "x"));
axes.emplace_back(bh::axis::regular<>(5, -5, 5, "y"));
auto h = bh::make_dynamic_histogram(axes.begin(), axes.end());
/*
create a dynamic histogram with the factory `make_dynamic_histogram`
- axis can be passed directly just like for `make_static_histogram`
- in addition, the factory also accepts iterators over a sequence of
axis::any, the polymorphic type that can hold concrete axis types
*/
std::vector<bh::axis::any_std> axes;
axes.emplace_back(bh::axis::category<std::string>({"red", "blue"}));
axes.emplace_back(bh::axis::regular<>(5, -5, 5, "x"));
axes.emplace_back(bh::axis::regular<>(5, -5, 5, "y"));
auto h = bh::make_dynamic_histogram(axes.begin(), axes.end());
// fill histogram with random numbers
br::mt19937 gen;
br::normal_distribution<> norm;
for (int i = 0; i < 1000; ++i)
h(i % 2 ? "red" : "blue", norm(gen), norm(gen));
// fill histogram with random numbers
br::mt19937 gen;
br::normal_distribution<> norm;
for (int i = 0; i < 1000; ++i)
h(i % 2 ? "red" : "blue", norm(gen), norm(gen));
/*
print dynamic histogram by iterating over bins
- for most axis types, the for loop looks just like for a static
histogram, except that we can pass runtime numbers, too
- if the [bin type] of the axis is not convertible to a
double interval, one needs to cast axis::any before looping;
this is here the case for the category axis
*/
using cas = bh::axis::category<std::string>;
for (auto cbin : bh::axis::cast<cas>(h.axis(0))) {
std::printf("%s\n", cbin.value().c_str());
for (auto ybin : h.axis(2)) { // rows
for (auto xbin : h.axis(1)) { // columns
std::printf("%3.0f ", h.at(cbin, xbin, ybin).value());
}
std::printf("\n");
}
/*
print dynamic histogram by iterating over bins
- for most axis types, the for loop looks just like for a static
histogram, except that we can pass runtime numbers, too
- if the [bin type] of the axis is not convertible to a
double interval, one needs to cast axis::any before looping;
this is here the case for the category axis
*/
using cas = bh::axis::category<std::string>;
for (auto cbin : bh::axis::cast<cas>(h.axis(0))) {
std::printf("%s\n", cbin.value().c_str());
for (auto ybin : h.axis(2)) { // rows
for (auto xbin : h.axis(1)) { // columns
std::printf("%3.0f ", h.at(cbin, xbin, ybin).value());
}
std::printf("\n");
}
}
}
//]

View File

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

View File

@ -5,13 +5,12 @@
namespace bh = boost::histogram;
int main() {
// create a 2d-histogram with an "age" and an "income" axis
auto h = bh::make_static_histogram(
bh::axis::regular<>(20, 0, 100, "age in years"),
bh::axis::regular<>(20, 0, 100, "yearly income in $1000")
);
// create a 2d-histogram with an "age" and an "income" axis
auto h = bh::make_static_histogram(
bh::axis::regular<>(20, 0, 100, "age in years"),
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;
int main() {
// 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));
// 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));
// 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
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
// - accept const char* and convert to int
// - then call index method of base class
int index(value_type s) const {
return integer::index(std::atoi(s));
}
// the customization point
// - accept const char* and convert to int
// - then call index method of base class
int index(value_type s) const { return integer::index(std::atoi(s)); }
};
int main() {
auto h = bh::make_static_histogram(custom_axis(0, 3));
h("-10");
h("0");
h("1");
h("9");
auto h = bh::make_static_histogram(custom_axis(0, 3));
h("-10");
h("0");
h("1");
h("9");
for (auto xi : h.axis()) {
std::cout << "bin " << xi.idx() << " [" << xi.lower() << ", "
<< xi.upper() << ") " << h.at(xi).value()
<< std::endl;
}
for (auto xi : h.axis()) {
std::cout << "bin " << xi.idx() << " [" << xi.lower() << ", "
<< xi.upper() << ") " << h.at(xi).value() << std::endl;
}
/* prints:
bin 0 [0, 1) 1
bin 1 [1, 2] 1
bin 2 [2, 3] 0
*/
/* prints:
bin 0 [0, 1) 1
bin 1 [1, 2] 1
bin 2 [2, 3] 0
*/
}
//]

View File

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

View File

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

View File

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

View File

@ -7,56 +7,51 @@ namespace bh = boost::histogram;
// example of a generic function for histograms, this one sums all entries
template <typename... Ts>
typename bh::histogram<Ts...>::element_type sum(const bh::histogram<Ts...>& h) {
auto result = typename bh::histogram<Ts...>::element_type(0);
for (auto x : h)
result += x;
return result;
typename bh::histogram<Ts...>::element_type sum(
const bh::histogram<Ts...>& h) {
auto result = typename bh::histogram<Ts...>::element_type(0);
for (auto x : h) result += x;
return result;
}
int main() {
using namespace bh::literals; // enables _c suffix
using namespace bh::literals; // enables _c suffix
// make a 2d histogram
auto h = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1),
bh::axis::integer<>(0, 4));
// make a 2d histogram
auto h = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1),
bh::axis::integer<>(0, 4));
h(-0.9, 0);
h(0.9, 3);
h(0.1, 2);
h(-0.9, 0);
h(0.9, 3);
h(0.1, 2);
auto hr0 = h.reduce_to(0_c); // keep only first axis
auto hr1 = h.reduce_to(1_c); // keep only second axis
auto hr0 = h.reduce_to(0_c); // keep only first axis
auto hr1 = h.reduce_to(1_c); // keep only second axis
/*
reduce does not remove counts; returned histograms are summed over
the removed axes, so h, hr0, and hr1 have same number of total counts
*/
std::cout << sum(h).value() << " "
<< sum(hr0).value() << " "
<< sum(hr1).value() << std::endl;
// prints: 3 3 3
/*
reduce does not remove counts; returned histograms are summed over
the removed axes, so h, hr0, and hr1 have same number of total counts
*/
std::cout << sum(h).value() << " " << sum(hr0).value() << " "
<< sum(hr1).value() << std::endl;
// prints: 3 3 3
for (auto yi : h.axis(1_c)) {
for (auto xi : h.axis(0_c)) {
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() << " ";
for (auto yi : h.axis(1_c)) {
for (auto xi : h.axis(0_c)) { std::cout << h.at(xi, yi).value() << " "; }
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())
std::cout << hr1.at(yi).value() << " ";
std::cout << std::endl;
// prints: 1 0 1 1
for (auto xi : hr0.axis()) std::cout << hr0.at(xi).value() << " ";
std::cout << std::endl;
// prints: 1 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
#include <boost/histogram.hpp>
#include <boost/histogram/serialization.hpp> // includes serialization code
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/histogram.hpp>
#include <boost/histogram/serialization.hpp> // includes serialization code
#include <sstream>
namespace bh = boost::histogram;
int main() {
auto a = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1, "r"),
bh::axis::integer<>(0, 2, "i"));
a(0.5, 1);
auto a = bh::make_static_histogram(bh::axis::regular<>(3, -1, 1, "r"),
bh::axis::integer<>(0, 2, "i"));
a(0.5, 1);
std::string buf; // holds persistent representation
std::string buf; // holds persistent representation
// store histogram
{
std::ostringstream os;
boost::archive::text_oarchive oa(os);
oa << a;
buf = os.str();
}
// store histogram
{
std::ostringstream os;
boost::archive::text_oarchive oa(os);
oa << a;
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;
// prints: before restore 0
std::cout << "before restore " << (a == b) << std::endl;
// prints: before restore 0
// load histogram
{
std::istringstream is(buf);
boost::archive::text_iarchive ia(is);
ia >> b;
}
// load histogram
{
std::istringstream is(buf);
boost::archive::text_iarchive ia(is);
ia >> b;
}
std::cout << "after restore " << (a == b) << std::endl;
// prints: after restore 1
std::cout << "after restore " << (a == b) << std::endl;
// prints: after restore 1
}
//]

View File

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

View File

@ -6,15 +6,15 @@
namespace bh = boost::histogram;
int main() {
// create vector of axes, axis::any is a polymorphic axis type
auto v = std::vector<bh::axis::any_std>();
v.push_back(bh::axis::regular<>(100, -1, 1));
v.push_back(bh::axis::integer<>(1, 7));
// create vector of axes, axis::any is a polymorphic axis type
auto v = std::vector<bh::axis::any_std>();
v.push_back(bh::axis::regular<>(100, -1, 1));
v.push_back(bh::axis::integer<>(1, 7));
// create dynamic histogram (make_static_histogram be used with iterators)
auto h = bh::make_dynamic_histogram(v.begin(), v.end());
// create dynamic histogram (make_static_histogram be used with iterators)
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;
int main() {
/*
create a 1d-histogram in default configuration which
covers the real line from -1 to 1 in 100 bins, the same
call with `make_dynamic_histogram` would also work
*/
auto h = bh::make_static_histogram(bh::axis::regular<>(100, -1, 1));
/*
create a 1d-histogram in default configuration which
covers the real line from -1 to 1 in 100 bins, the same
call with `make_dynamic_histogram` would also work
*/
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
#include <boost/python.hpp>
#include <boost/histogram.hpp>
#include <boost/python.hpp>
namespace bh = boost::histogram;
namespace bp = boost::python;
@ -9,13 +9,10 @@ namespace bp = boost::python;
// function that runs in C++ and accepts reference to dynamic histogram
void process(bh::dynamic_histogram<>& h) {
// fill histogram, in reality this would be arbitrarily complex code
for (int i = 0; i < 4; ++i)
h(0.25 * i, i);
for (int i = 0; i < 4; ++i) h(0.25 * i, i);
}
// a minimal Python module, which exposes the process function to Python
BOOST_PYTHON_MODULE(cpp_filler) {
bp::def("process", process);
}
BOOST_PYTHON_MODULE(cpp_filler) { bp::def("process", process); }
//]

View File

@ -13,67 +13,68 @@ namespace boost {
namespace histogram {
template <typename T, typename A, typename S>
histogram<T, A, S> &&operator+(histogram<T, A, S> &&a,
const histogram<T, A, S> &b) {
histogram<T, A, S>&& operator+(histogram<T, A, S>&& a,
const histogram<T, A, S>& b) {
a += b;
return std::move(a);
}
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;
return std::move(a);
}
template <typename T, typename A, typename S>
histogram<T, A, S> &&operator+(const histogram<T, A, S> &a,
histogram<T, A, S> &&b) {
histogram<T, A, S>&& operator+(const histogram<T, A, S>& a,
histogram<T, A, S>&& b) {
b += a;
return std::move(b);
}
template <typename T, typename A, typename S>
histogram<T, A, S> operator+(const histogram<T, A, S> &a,
const histogram<T, A, S> &b) {
histogram<T, A, S> operator+(const histogram<T, A, S>& a,
const histogram<T, A, S>& b) {
histogram<T, A, S> r(a);
r += b;
return r;
}
template <typename T, typename A, typename S>
histogram<T, A, S> &&operator*(histogram<T, A, S> &&a, const double x) {
histogram<T, A, S>&& operator*(histogram<T, A, S>&& a, const double x) {
a *= x;
return std::move(a);
}
template <typename T, typename A, typename S>
histogram<T, A, S> &&operator*(const double x, histogram<T, A, S> &&b) {
histogram<T, A, S>&& operator*(const double x, histogram<T, A, S>&& b) {
b *= x;
return std::move(b);
}
template <typename T, typename A, typename S>
histogram<T, A, S> operator*(const histogram<T, A, S> &a, const double x) {
histogram<T, A, S> operator*(const histogram<T, A, S>& a, const double x) {
auto r = a;
r *= x;
return r;
}
template <typename T, typename A, typename S>
histogram<T, A, S> operator*(const double x, const histogram<T, A, S> &b) {
histogram<T, A, S> operator*(const double x, const histogram<T, A, S>& b) {
auto r = b;
r *= x;
return r;
}
template <typename T, typename A, typename S>
histogram<T, A, S> &&operator/(histogram<T, A, S> &&a, const double x) {
histogram<T, A, S>&& operator/(histogram<T, A, S>&& a, const double x) {
a /= x;
return std::move(a);
}
template <typename T, typename A, typename S>
histogram<T, A, S> operator/(const histogram<T, A, S> &a, const double x) {
histogram<T, A, S> operator/(const histogram<T, A, S>& a, const double x) {
auto r = a;
r /= x;
return r;

View File

@ -33,19 +33,29 @@ namespace axis {
namespace detail {
struct size_visitor : public static_visitor<int> {
template <typename A> int operator()(const A &a) const { return a.size(); }
template <typename A>
int operator()(const A& a) const {
return a.size();
}
};
struct shape_visitor : public static_visitor<int> {
template <typename A> int operator()(const A &a) const { return a.shape(); }
template <typename A>
int operator()(const A& a) const {
return a.shape();
}
};
struct uoflow_visitor : public static_visitor<bool> {
template <typename A> bool operator()(const A &a) const { return a.uoflow(); }
template <typename A>
bool operator()(const A& a) const {
return a.uoflow();
}
};
struct get_label_visitor : public static_visitor<string_view> {
template <typename A>::boost::string_view operator()(const A &a) const {
template <typename A>
::boost::string_view operator()(const A& a) const {
return a.label();
}
};
@ -53,19 +63,25 @@ struct get_label_visitor : public static_visitor<string_view> {
struct set_label_visitor : public static_visitor<void> {
const ::boost::string_view label;
set_label_visitor(const ::boost::string_view x) : label(x) {}
template <typename A> void operator()(A &a) const { a.label(label); }
template <typename A>
void operator()(A& a) const {
a.label(label);
}
};
struct index_visitor : public static_visitor<int> {
const double x;
explicit index_visitor(const double arg) : x(arg) {}
template <typename Axis> int operator()(const Axis &a) const {
template <typename Axis>
int operator()(const Axis& a) const {
return impl(std::is_convertible<double, typename Axis::value_type>(), a);
}
template <typename Axis> int impl(std::true_type, const Axis &a) const {
template <typename Axis>
int impl(std::true_type, const Axis& a) const {
return a.index(x);
}
template <typename Axis> int impl(std::false_type, const Axis &) const {
template <typename Axis>
int impl(std::false_type, const Axis&) const {
throw std::runtime_error(::boost::histogram::detail::cat(
"cannot convert double to value_type ",
boost::typeindex::type_id<typename Axis::value_type>().pretty_name(),
@ -76,7 +92,8 @@ struct index_visitor : public static_visitor<int> {
struct lower_visitor : public static_visitor<double> {
int idx;
lower_visitor(int i) : idx(i) {}
template <typename Axis> double operator()(const Axis &a) const {
template <typename Axis>
double operator()(const Axis& a) const {
return impl(
std::integral_constant<
bool,
@ -85,10 +102,12 @@ struct lower_visitor : public static_visitor<double> {
interval_view<Axis>>::value)>(),
a);
}
template <typename Axis> double impl(std::true_type, const Axis &a) const {
template <typename Axis>
double impl(std::true_type, const Axis& a) const {
return a.lower(idx);
}
template <typename Axis> double impl(std::false_type, const Axis &) const {
template <typename Axis>
double impl(std::false_type, const Axis&) const {
throw std::runtime_error(::boost::histogram::detail::cat(
"cannot use ", boost::typeindex::type_id<Axis>().pretty_name(),
" with generic boost::histogram::axis::any interface, use"
@ -98,25 +117,32 @@ struct lower_visitor : public static_visitor<double> {
struct bicmp_visitor : public static_visitor<bool> {
template <typename T, typename U>
bool operator()(const T &, const U &) const {
bool operator()(const T&, const U&) const {
return false;
}
template <typename T> bool operator()(const T &a, const T &b) const {
template <typename T>
bool operator()(const T& a, const T& b) const {
return a == b;
}
};
template <typename T> struct assign_visitor : public static_visitor<void> {
T &t;
assign_visitor(T &tt) : t(tt) {}
template <typename U> void operator()(const U &u) const {
template <typename T>
struct assign_visitor : public static_visitor<void> {
T& t;
assign_visitor(T& tt) : t(tt) {}
template <typename U>
void operator()(const U& u) const {
impl(mp11::mp_contains<typename T::types, U>(), u);
}
template <typename U> void impl(mp11::mp_true, const U &u) const { t = u; }
template <typename U>
void impl(mp11::mp_true, const U& u) const {
t = u;
}
template <typename U> void impl(mp11::mp_false, const U &) const {
template <typename U>
void impl(mp11::mp_false, const U&) const {
throw std::invalid_argument(::boost::histogram::detail::cat(
"argument ", boost::typeindex::type_id<U>().pretty_name(),
" is not a bounded type of ",
@ -127,7 +153,8 @@ template <typename T> struct assign_visitor : public static_visitor<void> {
} // namespace detail
/// Polymorphic axis type
template <typename... Ts> class any : public ::boost::variant<Ts...> {
template <typename... Ts>
class any : public ::boost::variant<Ts...> {
using base_type = ::boost::variant<Ts...>;
public:
@ -140,29 +167,32 @@ public:
private:
template <typename T>
using requires_bounded_type = mp11::mp_if<
mp11::mp_contains<types, ::boost::histogram::detail::rm_cv_ref<T>>, void>;
mp11::mp_contains<types, ::boost::histogram::detail::rm_cv_ref<T>>,
void>;
public:
any() = default;
any(const any &) = default;
any &operator=(const any &) = default;
any(any &&) = default;
any &operator=(any &&) = default;
any(const any&) = default;
any& operator=(const any&) = default;
any(any&&) = default;
any& operator=(any&&) = default;
template <typename T, typename = requires_bounded_type<T>>
any(T &&t) : base_type(std::forward<T>(t)) {}
any(T&& t) : base_type(std::forward<T>(t)) {}
template <typename T, typename = requires_bounded_type<T>>
any &operator=(T &&t) {
any& operator=(T&& t) {
base_type::operator=(std::forward<T>(t));
return *this;
}
template <typename... Us> any(const any<Us...> &u) {
template <typename... Us>
any(const any<Us...>& u) {
::boost::apply_visitor(detail::assign_visitor<any>(*this), u);
}
template <typename... Us> any &operator=(const any<Us...> &u) {
template <typename... Us>
any& operator=(const any<Us...>& u) {
::boost::apply_visitor(detail::assign_visitor<any>(*this), u);
return *this;
}
@ -200,22 +230,24 @@ public:
bin_type operator[](const int idx) const { return bin_type(idx, *this); }
bool operator==(const any &rhs) const {
return base_type::operator==(static_cast<const base_type &>(rhs));
bool operator==(const any& rhs) const {
return base_type::operator==(static_cast<const base_type&>(rhs));
}
template <typename... Us> bool operator==(const any<Us...> &u) const {
template <typename... Us>
bool operator==(const any<Us...>& u) const {
return ::boost::apply_visitor(detail::bicmp_visitor(), *this, u);
}
template <typename T, typename = requires_bounded_type<T>>
bool operator==(const T &t) const {
bool operator==(const T& t) const {
// variant::operator==(T) is implemented, but only to fail, cannot use it
auto tp = ::boost::get<::boost::histogram::detail::rm_cv_ref<T>>(this);
return tp && *tp == t;
}
template <typename T> bool operator!=(T &&t) const {
template <typename T>
bool operator!=(T&& t) const {
return !operator==(std::forward<T>(t));
}
@ -230,34 +262,36 @@ public:
private:
friend class ::boost::serialization::access;
template <typename Archive> void serialize(Archive &, unsigned);
template <typename Archive>
void serialize(Archive&, unsigned);
};
// dynamic casts
template <typename T, typename... Ts>
typename std::add_lvalue_reference<T>::type cast(any<Ts...> &any) {
typename std::add_lvalue_reference<T>::type cast(any<Ts...>& any) {
return get<T>(any);
}
template <typename T, typename... Ts>
const typename std::add_lvalue_reference<T>::type cast(const any<Ts...> &any) {
const typename std::add_lvalue_reference<T>::type cast(
const any<Ts...>& any) {
return get<T>(any);
}
template <typename T, typename... Ts>
typename std::add_pointer<T>::type cast(any<Ts...> *any) {
typename std::add_pointer<T>::type cast(any<Ts...>* any) {
return get<T>(&any);
}
template <typename T, typename... Ts>
const typename std::add_pointer<T>::type cast(const any<Ts...> *any) {
const typename std::add_pointer<T>::type cast(const any<Ts...>* any) {
return get<T>(&any);
}
// pass-through for generic programming, to keep code workgin when
// you switch from dynamic to static histogram
template <typename, typename U>
auto cast(U &&u) -> decltype(std::forward<U>(u)) {
auto cast(U&& u) -> decltype(std::forward<U>(u)) {
return std::forward<U>(u);
}

View File

@ -14,29 +14,32 @@ namespace boost {
namespace histogram {
namespace axis {
template <typename Axis> class interval_view {
template <typename Axis>
class interval_view {
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 &operator=(const interval_view &) = default;
interval_view(interval_view &&) = default;
interval_view &operator=(interval_view &&) = default;
interval_view(const interval_view&) = default;
interval_view& operator=(const interval_view&) = default;
interval_view(interval_view&&) = default;
interval_view& operator=(interval_view&&) = default;
int idx() const noexcept { return idx_; }
auto lower() const noexcept -> decltype(std::declval<Axis &>().lower(0)) {
auto lower() const noexcept -> decltype(std::declval<Axis&>().lower(0)) {
return axis_.lower(idx_);
}
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);
}
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_;
}
bool operator!=(const interval_view &rhs) const noexcept {
bool operator!=(const interval_view& rhs) const noexcept {
return !operator==(rhs);
}
@ -44,7 +47,7 @@ public:
private:
const int idx_;
const Axis &axis_;
const Axis& axis_;
};
} // namespace axis

View File

@ -19,25 +19,26 @@ class iterator_over
random_access_traversal_tag,
typename Axis::bin_type> {
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 &operator=(const iterator_over &) = default;
iterator_over(const iterator_over&) = default;
iterator_over& operator=(const iterator_over&) = default;
protected:
void increment() noexcept { ++idx_; }
void decrement() noexcept { --idx_; }
void advance(int n) noexcept { idx_ += n; }
int distance_to(const iterator_over &other) const noexcept {
int distance_to(const iterator_over& other) const noexcept {
return other.idx_ - idx_;
}
bool equal(const iterator_over &other) const noexcept {
bool equal(const iterator_over& other) const noexcept {
return &axis_ == &other.axis_ && idx_ == other.idx_;
}
typename Axis::bin_type dereference() const { return axis_[idx_]; }
friend class ::boost::iterator_core_access;
const Axis &axis_;
const Axis& axis_;
int idx_;
};
@ -47,26 +48,26 @@ class reverse_iterator_over
reverse_iterator_over<Axis>, typename Axis::bin_type,
random_access_traversal_tag, typename Axis::bin_type> {
public:
explicit reverse_iterator_over(const Axis &axis, int idx)
explicit reverse_iterator_over(const Axis& axis, int idx)
: axis_(axis), idx_(idx) {}
reverse_iterator_over(const reverse_iterator_over &) = default;
reverse_iterator_over &operator=(const reverse_iterator_over &) = default;
reverse_iterator_over(const reverse_iterator_over&) = default;
reverse_iterator_over& operator=(const reverse_iterator_over&) = default;
protected:
void increment() noexcept { --idx_; }
void decrement() noexcept { ++idx_; }
void advance(int n) noexcept { idx_ -= n; }
int distance_to(const reverse_iterator_over &other) const noexcept {
int distance_to(const reverse_iterator_over& other) const noexcept {
return other.idx_ - idx_;
}
bool equal(const reverse_iterator_over &other) const noexcept {
bool equal(const reverse_iterator_over& other) const noexcept {
return &axis_ == &other.axis_ && idx_ == other.idx_;
}
typename Axis::bin_type dereference() const { return axis_[idx_ - 1]; }
friend class ::boost::iterator_core_access;
const Axis &axis_;
const Axis& axis_;
int idx_;
};

View File

@ -20,61 +20,56 @@ namespace histogram {
namespace axis {
namespace detail {
inline string_view to_string(const transform::identity &) { 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::identity&) { return {}; }
inline string_view to_string(const transform::log&) { return {"_log", 4}; }
inline string_view to_string(const transform::sqrt&) { return {"_sqrt", 5}; }
} // namespace detail
template <typename T>
inline std::ostream &operator<<(std::ostream &os, const interval_view<T> &i) {
inline std::ostream& operator<<(std::ostream& os, const interval_view<T>& i) {
os << "[" << i.lower() << ", " << i.upper() << ")";
return os;
}
template <typename T>
inline std::ostream &operator<<(std::ostream &os, const value_view<T> &i) {
inline std::ostream& operator<<(std::ostream& os, const value_view<T>& i) {
os << i.value();
return os;
}
template <typename RealType, typename Transform>
inline std::ostream &operator<<(std::ostream &os,
const regular<RealType, Transform> &a) {
inline std::ostream& operator<<(std::ostream& os,
const regular<RealType, Transform>& a) {
os << "regular" << detail::to_string(Transform()) << "(" << a.size() << ", "
<< a[0].lower() << ", " << a[a.size()].lower();
if (!a.label().empty()) {
os << ", label=";
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
}
if (!a.uoflow()) { os << ", uoflow=False"; }
os << ")";
return os;
}
template <typename RealType>
inline std::ostream &
operator<<(std::ostream &os, const regular<RealType, axis::transform::pow> &a) {
inline std::ostream& operator<<(
std::ostream& os, const regular<RealType, axis::transform::pow>& a) {
os << "regular_pow(" << a.size() << ", " << a[0].lower() << ", "
<< a[a.size()].lower() << ", " << a.transform().power;
if (!a.label().empty()) {
os << ", label=";
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
}
if (!a.uoflow()) { os << ", uoflow=False"; }
os << ")";
return os;
}
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();
if (a.phase() != 0.0) {
os << ", phase=" << a.phase();
}
if (a.phase() != 0.0) { os << ", phase=" << a.phase(); }
if (a.perimeter() != RealType(::boost::histogram::detail::two_pi)) {
os << ", perimeter=" << a.perimeter();
}
@ -87,38 +82,33 @@ inline std::ostream &operator<<(std::ostream &os, const circular<RealType> &a) {
}
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();
for (int i = 1; i <= a.size(); ++i) {
os << ", " << a[i].lower();
}
for (int i = 1; i <= a.size(); ++i) { os << ", " << a[i].lower(); }
if (!a.label().empty()) {
os << ", label=";
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
}
if (!a.uoflow()) { os << ", uoflow=False"; }
os << ")";
return os;
}
template <typename IntType>
inline std::ostream &operator<<(std::ostream &os, const integer<IntType> &a) {
inline std::ostream& operator<<(std::ostream& os, const integer<IntType>& a) {
os << "integer(" << a[0].lower() << ", " << a[a.size()].lower();
if (!a.label().empty()) {
os << ", label=";
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
}
if (!a.uoflow()) { os << ", uoflow=False"; }
os << ")";
return os;
}
template <typename T>
inline std::ostream &operator<<(std::ostream &os, const category<T> &a) {
inline std::ostream& operator<<(std::ostream& os, const category<T>& a) {
os << "category(";
for (int i = 0; i < a.size(); ++i) {
os << a[i] << (i == (a.size() - 1) ? "" : ", ");
@ -132,8 +122,8 @@ inline std::ostream &operator<<(std::ostream &os, const category<T> &a) {
}
template <>
inline std::ostream &operator<<(std::ostream &os,
const category<std::string> &a) {
inline std::ostream& operator<<(std::ostream& os,
const category<std::string>& a) {
os << "category(";
for (int i = 0; i < a.size(); ++i) {
::boost::histogram::detail::escape(os, a.value(i));

View File

@ -46,7 +46,8 @@ enum class uoflow { off = false, on = true };
#endif
/// Base class for all axes, uses CRTP to inject iterator logic.
template <typename Derived> class axis_base {
template <typename Derived>
class axis_base {
public:
using const_iterator = iterator_over<Derived>;
using const_reverse_iterator = reverse_iterator_over<Derived>;
@ -63,16 +64,16 @@ public:
void label(string_view label) { label_.assign(label.begin(), label.end()); }
const_iterator begin() const noexcept {
return const_iterator(*static_cast<const Derived *>(this), 0);
return const_iterator(*static_cast<const Derived*>(this), 0);
}
const_iterator end() const noexcept {
return const_iterator(*static_cast<const Derived *>(this), size());
return const_iterator(*static_cast<const Derived*>(this), size());
}
const_reverse_iterator rbegin() const noexcept {
return const_reverse_iterator(*static_cast<const Derived *>(this), size());
return const_reverse_iterator(*static_cast<const Derived*>(this), size());
}
const_reverse_iterator rend() const noexcept {
return const_reverse_iterator(*static_cast<const Derived *>(this), 0);
return const_reverse_iterator(*static_cast<const Derived*>(this), 0);
}
protected:
@ -86,12 +87,13 @@ protected:
}
axis_base() = default;
axis_base(const axis_base &) = default;
axis_base &operator=(const axis_base &) = default;
axis_base(axis_base &&rhs) : size_(rhs.size_), label_(std::move(rhs.label_)) {
axis_base(const axis_base&) = default;
axis_base& operator=(const axis_base&) = default;
axis_base(axis_base&& rhs)
: size_(rhs.size_), label_(std::move(rhs.label_)) {
rhs.size_ = 0;
}
axis_base &operator=(axis_base &&rhs) {
axis_base& operator=(axis_base&& rhs) {
if (this != &rhs) {
size_ = rhs.size_;
label_ = std::move(rhs.label_);
@ -100,7 +102,7 @@ protected:
return *this;
}
bool operator==(const axis_base &rhs) const noexcept {
bool operator==(const axis_base& rhs) const noexcept {
return size_ == rhs.size_ && label_ == rhs.label_;
}
@ -109,11 +111,13 @@ private:
std::string label_;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
/// Base class for axes with optional under-/overflow bins, uses CRTP.
template <typename Derived> class axis_base_uoflow : public axis_base<Derived> {
template <typename Derived>
class axis_base_uoflow : public axis_base<Derived> {
using base_type = axis_base<Derived>;
public:
@ -128,13 +132,13 @@ protected:
: base_type(n, label), shape_(n + 2 * static_cast<int>(uo)) {}
axis_base_uoflow() = default;
axis_base_uoflow(const axis_base_uoflow &) = default;
axis_base_uoflow &operator=(const axis_base_uoflow &) = default;
axis_base_uoflow(axis_base_uoflow &&rhs)
axis_base_uoflow(const axis_base_uoflow&) = default;
axis_base_uoflow& operator=(const axis_base_uoflow&) = default;
axis_base_uoflow(axis_base_uoflow&& rhs)
: base_type(std::move(rhs)), shape_(rhs.shape_) {
rhs.shape_ = 0;
}
axis_base_uoflow &operator=(axis_base_uoflow &&rhs) {
axis_base_uoflow& operator=(axis_base_uoflow&& rhs) {
if (this != &rhs) {
base_type::operator=(std::move(rhs));
shape_ = rhs.shape_;
@ -143,7 +147,7 @@ protected:
return *this;
}
bool operator==(const axis_base_uoflow &rhs) const noexcept {
bool operator==(const axis_base_uoflow& rhs) const noexcept {
return base_type::operator==(rhs) && shape_ == rhs.shape_;
}
@ -151,30 +155,50 @@ private:
int shape_ = 0;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
namespace transform {
namespace detail {
struct stateless {
bool operator==(const stateless &) const noexcept { return true; }
template <class Archive> void serialize(Archive &, unsigned) {}
bool operator==(const stateless&) const noexcept { return true; }
template <class Archive>
void serialize(Archive&, unsigned) {}
};
} // namespace detail
struct identity : public detail::stateless {
template <typename T> static T &&forward(T &&v) { return std::forward<T>(v); }
template <typename T> static T &&inverse(T &&v) { return std::forward<T>(v); }
template <typename T>
static T&& forward(T&& v) {
return std::forward<T>(v);
}
template <typename T>
static T&& inverse(T&& v) {
return std::forward<T>(v);
}
};
struct log : public detail::stateless {
template <typename T> static T forward(T v) { return std::log(v); }
template <typename T> static T inverse(T v) { return std::exp(v); }
template <typename T>
static T forward(T v) {
return std::log(v);
}
template <typename T>
static T inverse(T v) {
return std::exp(v);
}
};
struct sqrt : public detail::stateless {
template <typename T> static T forward(T v) { return std::sqrt(v); }
template <typename T> static T inverse(T v) { return v * v; }
template <typename T>
static T forward(T v) {
return std::sqrt(v);
}
template <typename T>
static T inverse(T v) {
return v * v;
}
};
// struct cos : public detail::stateless {
@ -187,17 +211,22 @@ struct pow {
pow() = default;
pow(double p) : power(p) {}
template <typename T> T forward(T v) const { return std::pow(v, power); }
template <typename T> T inverse(T v) const {
template <typename T>
T forward(T v) const {
return std::pow(v, power);
}
template <typename T>
T inverse(T v) const {
return std::pow(v, 1.0 / power);
}
bool operator==(const pow &other) const noexcept {
bool operator==(const pow& other) const noexcept {
return power == other.power;
}
private:
friend ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
} // namespace transform
@ -229,7 +258,9 @@ public:
string_view label = {}, BOOST_HISTOGRAM_ENUM_CLASS_ARG uoflow uo =
::boost::histogram::axis::uoflow::on,
Transform trans = Transform())
: base_type(n, label, uo), Transform(trans), min_(trans.forward(lower)),
: base_type(n, label, uo),
Transform(trans),
min_(trans.forward(lower)),
delta_((trans.forward(upper) - trans.forward(lower)) / n) {
if (lower < upper) {
BOOST_ASSERT(!std::isnan(min_));
@ -240,10 +271,10 @@ public:
}
regular() = default;
regular(const regular &) = default;
regular &operator=(const regular &) = default;
regular(regular &&) = default;
regular &operator=(regular &&) = default;
regular(const regular&) = default;
regular& operator=(const regular&) = default;
regular(regular&&) = default;
regular& operator=(regular&&) = default;
/// Returns the bin index for the passed argument.
int index(value_type x) const noexcept {
@ -271,21 +302,22 @@ public:
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_type::operator==(o) && Transform::operator==(o) &&
min_ == o.min_ && delta_ == o.delta_;
}
/// Access properties of the transform.
const Transform &transform() const noexcept {
return static_cast<const Transform &>(*this);
const Transform& transform() const noexcept {
return static_cast<const Transform&>(*this);
}
private:
value_type min_ = 0.0, delta_ = 1.0;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
/** Axis for real values on a circle.
@ -315,16 +347,16 @@ public:
: base_type(n, label), phase_(phase), perimeter_(perimeter) {}
circular() = default;
circular(const circular &) = default;
circular &operator=(const circular &) = default;
circular(circular &&) = default;
circular &operator=(circular &&) = default;
circular(const circular&) = default;
circular& operator=(const circular&) = default;
circular(circular&&) = default;
circular& operator=(circular&&) = default;
/// Returns the bin index for the passed argument.
int index(value_type x) const noexcept {
const value_type z = (x - phase_) / perimeter_;
const int i =
static_cast<int>(std::floor(z * base_type::size())) % base_type::size();
const int i = static_cast<int>(std::floor(z * base_type::size())) %
base_type::size();
return i + (i < 0) * base_type::size();
}
@ -334,11 +366,9 @@ public:
return z * perimeter_ + phase_;
}
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 circular &o) const noexcept {
bool operator==(const circular& o) const noexcept {
return base_type::operator==(o) && phase_ == o.phase_ &&
perimeter_ == o.perimeter_;
}
@ -350,7 +380,8 @@ private:
value_type phase_ = 0.0, perimeter_ = 1.0;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
/** Axis for non-equidistant bins on the real line.
@ -395,11 +426,11 @@ public:
}
variable() = default;
variable(const variable &o)
variable(const variable& o)
: base_type(o), x_(new value_type[base_type::size() + 1]) {
std::copy(o.x_.get(), o.x_.get() + base_type::size() + 1, x_.get());
}
variable &operator=(const variable &o) {
variable& operator=(const variable& o) {
if (this != &o) {
base_type::operator=(o);
x_.reset(new value_type[base_type::size() + 1]);
@ -407,8 +438,8 @@ public:
}
return *this;
}
variable(variable &&) = default;
variable &operator=(variable &&) = default;
variable(variable&&) = default;
variable& operator=(variable&&) = default;
/// Returns the bin index for the passed argument.
int index(value_type x) const noexcept {
@ -418,9 +449,7 @@ public:
/// Returns the starting edge of the bin.
value_type lower(int i) const noexcept {
if (i < 0) {
return -std::numeric_limits<value_type>::infinity();
}
if (i < 0) { return -std::numeric_limits<value_type>::infinity(); }
if (i > base_type::size()) {
return std::numeric_limits<value_type>::infinity();
}
@ -429,10 +458,8 @@ public:
bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); }
bool operator==(const variable &o) const noexcept {
if (!base_type::operator==(o)) {
return false;
}
bool operator==(const variable& o) const noexcept {
if (!base_type::operator==(o)) { return false; }
return std::equal(x_.get(), x_.get() + base_type::size() + 1, o.x_.get());
}
@ -440,7 +467,8 @@ private:
std::unique_ptr<value_type[]> x_; // smaller size compared to std::vector
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
/** Axis for an interval of integral values with unit steps.
@ -473,10 +501,10 @@ public:
}
integer() = default;
integer(const integer &) = default;
integer &operator=(const integer &) = default;
integer(integer &&) = default;
integer &operator=(integer &&) = default;
integer(const integer&) = default;
integer& operator=(const integer&) = default;
integer(integer&&) = default;
integer& operator=(integer&&) = default;
/// Returns the bin index for the passed argument.
int index(value_type x) const noexcept {
@ -486,9 +514,7 @@ public:
/// Returns lower edge of the integral bin.
value_type lower(int i) const noexcept {
if (i < 0) {
return -std::numeric_limits<value_type>::max();
}
if (i < 0) { return -std::numeric_limits<value_type>::max(); }
if (i > base_type::size()) {
return std::numeric_limits<value_type>::max();
}
@ -497,7 +523,7 @@ public:
bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); }
bool operator==(const integer &o) const noexcept {
bool operator==(const integer& o) const noexcept {
return base_type::operator==(o) && min_ == o.min_;
}
@ -505,7 +531,8 @@ private:
value_type min_ = 0;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
/** Axis which maps unique single values to bins (one on one).
@ -515,7 +542,8 @@ private:
* for this axis, which counts values that are not part of the set.
* Binning is a O(1) operation. The value type must be hashable.
*/
template <typename T> class category : public axis_base<category<T>> {
template <typename T>
class category : public axis_base<category<T>> {
using map_type = bimap<T, int>;
using base_type = axis_base<category<T>>;
@ -524,17 +552,17 @@ public:
using bin_type = value_view<category>;
category() = default;
category(const category &rhs)
category(const category& rhs)
: base_type(rhs), map_(new map_type(*rhs.map_)) {}
category &operator=(const category &rhs) {
category& operator=(const category& rhs) {
if (this != &rhs) {
base_type::operator=(rhs);
map_.reset(new map_type(*rhs.map_));
}
return *this;
}
category(category &&rhs) = default;
category &operator=(category &&rhs) = default;
category(category&& rhs) = default;
category& operator=(category&& rhs) = default;
/** Construct from an initializer list of strings.
*
@ -543,33 +571,29 @@ public:
category(std::initializer_list<value_type> seq, string_view label = {})
: base_type(seq.size(), label), map_(new map_type()) {
int index = 0;
for (const auto &x : seq)
map_->insert({x, index++});
if (index == 0)
throw std::invalid_argument("sequence is empty");
for (const auto& x : seq) map_->insert({x, index++});
if (index == 0) throw std::invalid_argument("sequence is empty");
}
template <typename Iterator,
typename = ::boost::histogram::detail::requires_iterator<Iterator>>
template <
typename Iterator,
typename = ::boost::histogram::detail::requires_iterator<Iterator>>
category(Iterator begin, Iterator end, string_view label = {})
: base_type(std::distance(begin, end), label), map_(new map_type()) {
int index = 0;
while (begin != end)
map_->insert({*begin++, index++});
if (index == 0)
throw std::invalid_argument("iterator range is empty");
while (begin != end) map_->insert({*begin++, index++});
if (index == 0) throw std::invalid_argument("iterator range is empty");
}
/// 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);
if (it == map_->left.end())
return base_type::size();
if (it == map_->left.end()) return base_type::size();
return it->second;
}
/// Returns the value for the bin index (performs a range check).
const value_type &value(int idx) const {
const value_type& value(int idx) const {
auto it = map_->right.find(idx);
if (it == map_->right.end())
throw std::out_of_range("category index out of range");
@ -578,7 +602,7 @@ public:
bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); }
bool operator==(const category &o) const noexcept {
bool operator==(const category& o) const noexcept {
return base_type::operator==(o) &&
std::equal(map_->begin(), map_->end(), o.map_->begin());
}
@ -587,7 +611,8 @@ private:
std::unique_ptr<map_type> map_;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
} // namespace axis
} // namespace histogram

View File

@ -14,25 +14,26 @@ namespace boost {
namespace histogram {
namespace axis {
template <typename Axis> class value_view {
template <typename Axis>
class value_view {
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 &operator=(const value_view &) = default;
value_view(value_view &&) = default;
value_view &operator=(value_view &&) = default;
value_view(const value_view&) = default;
value_view& operator=(const value_view&) = default;
value_view(value_view&&) = default;
value_view& operator=(value_view&&) = default;
int idx() const noexcept { return idx_; }
auto value() const -> decltype(std::declval<Axis &>().value(0)) {
auto value() const -> decltype(std::declval<Axis&>().value(0)) {
return axis_.value(idx_);
}
bool operator==(const value_view &rhs) const noexcept {
bool operator==(const value_view& rhs) const noexcept {
return idx_ == rhs.idx_ && axis_ == rhs.axis_;
}
bool operator!=(const value_view &rhs) const noexcept {
bool operator!=(const value_view& rhs) const noexcept {
return !operator==(rhs);
}
@ -40,7 +41,7 @@ public:
private:
const int idx_;
const Axis &axis_;
const Axis& axis_;
};
} // namespace axis

View File

@ -20,93 +20,102 @@ namespace detail {
namespace {
template <typename Tuple, typename VecVar> struct axes_equal_tuple_vecvar {
bool &equal;
const Tuple &t;
const VecVar &v;
axes_equal_tuple_vecvar(bool &eq, const Tuple &tt, const VecVar &vv)
template <typename Tuple, typename VecVar>
struct axes_equal_tuple_vecvar {
bool& equal;
const Tuple& t;
const VecVar& v;
axes_equal_tuple_vecvar(bool& eq, const Tuple& tt, const VecVar& vv)
: equal(eq), t(tt), v(vv) {}
template <typename Int> void operator()(Int) const {
template <typename Int>
void operator()(Int) const {
using T = mp11::mp_at<Tuple, Int>;
auto tp = ::boost::get<T>(&v[Int::value]);
equal &= (tp && *tp == std::get<Int::value>(t));
}
};
template <typename Tuple, typename VecVar> struct axes_assign_tuple_vecvar {
Tuple &t;
const VecVar &v;
axes_assign_tuple_vecvar(Tuple &tt, const VecVar &vv) : t(tt), v(vv) {}
template <typename Int> void operator()(Int) const {
template <typename Tuple, typename VecVar>
struct axes_assign_tuple_vecvar {
Tuple& t;
const VecVar& v;
axes_assign_tuple_vecvar(Tuple& tt, const VecVar& vv) : t(tt), v(vv) {}
template <typename Int>
void operator()(Int) const {
using T = mp11::mp_at<Tuple, Int>;
std::get<Int::value>(t) = ::boost::get<T>(v[Int::value]);
}
};
template <typename VecVar, typename Tuple> struct axes_assign_vecvar_tuple {
VecVar &v;
const Tuple &t;
axes_assign_vecvar_tuple(VecVar &vv, const Tuple &tt) : v(vv), t(tt) {}
template <typename Int> void operator()(Int) const {
template <typename VecVar, typename Tuple>
struct axes_assign_vecvar_tuple {
VecVar& v;
const Tuple& t;
axes_assign_vecvar_tuple(VecVar& vv, const Tuple& tt) : v(vv), t(tt) {}
template <typename Int>
void operator()(Int) const {
v[Int::value] = std::get<Int::value>(t);
}
};
template <typename... Ts>
inline bool axes_equal_impl(mp11::mp_true, const std::tuple<Ts...> &t,
const std::tuple<Ts...> &u) {
inline bool axes_equal_impl(mp11::mp_true, const std::tuple<Ts...>& t,
const std::tuple<Ts...>& u) {
return t == u;
}
template <typename... Ts, typename... Us>
inline bool axes_equal_impl(mp11::mp_false, const std::tuple<Ts...> &,
const std::tuple<Us...> &) {
inline bool axes_equal_impl(mp11::mp_false, const std::tuple<Ts...>&,
const std::tuple<Us...>&) {
return false;
}
} // namespace
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(
mp11::mp_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>(), t, u);
}
template <typename... Ts, typename... Us>
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,
"cannot assign incompatible axes");
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,
"cannot assign incompatible axes");
t = u;
}
template <typename... Ts, typename... Us>
inline bool axes_equal(const std::tuple<Ts...> &t,
const std::vector<axis::any<Us...>> &u) {
if (sizeof...(Ts) != u.size())
return false;
inline bool axes_equal(const std::tuple<Ts...>& t,
const std::vector<axis::any<Us...>>& u) {
if (sizeof...(Ts) != u.size()) return false;
bool equal = true;
auto fn =
axes_equal_tuple_vecvar<std::tuple<Ts...>, std::vector<axis::any<Us...>>>(
equal, t, u);
axes_equal_tuple_vecvar<std::tuple<Ts...>,
std::vector<axis::any<Us...>>>(equal, t, u);
mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>(fn);
return equal;
}
template <typename... Ts, typename... Us>
inline void axes_assign(std::tuple<Ts...> &t, const std::vector<axis::any<Us...>> &u) {
inline void axes_assign(std::tuple<Ts...>& t,
const std::vector<axis::any<Us...>>& u) {
auto fn = axes_assign_tuple_vecvar<std::tuple<Ts...>,
std::vector<axis::any<Us...>>>(t, u);
mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>(fn);
}
template <typename... Ts, typename... Us>
inline bool axes_equal(const std::vector<axis::any<Ts...>> &t,
const std::tuple<Us...> &u) {
inline bool axes_equal(const std::vector<axis::any<Ts...>>& t,
const std::tuple<Us...>& u) {
return axes_equal(u, t);
}
template <typename... Ts, typename... Us>
inline void axes_assign(std::vector<axis::any<Ts...>> &t, const std::tuple<Us...> &u) {
inline void axes_assign(std::vector<axis::any<Ts...>>& t,
const std::tuple<Us...>& u) {
t.resize(sizeof...(Us));
auto fn = axes_assign_vecvar_tuple<std::vector<axis::any<Ts...>>,
std::tuple<Us...>>(t, u);
@ -114,41 +123,45 @@ inline void axes_assign(std::vector<axis::any<Ts...>> &t, const std::tuple<Us...
}
template <typename... Ts, typename... Us>
inline bool axes_equal(const std::vector<axis::any<Ts...>> &t,
const std::vector<axis::any<Us...>> &u) {
if (t.size() != u.size())
return false;
inline bool axes_equal(const std::vector<axis::any<Ts...>>& t,
const std::vector<axis::any<Us...>>& u) {
if (t.size() != u.size()) return false;
for (std::size_t i = 0; i < t.size(); ++i) {
if (t[i] != u[i])
return false;
if (t[i] != u[i]) return false;
}
return true;
}
template <typename... Ts, typename... Us>
inline void axes_assign(std::vector<axis::any<Ts...>> &t,
const std::vector<axis::any<Us...>> &u) {
for (std::size_t i = 0; i < t.size(); ++i) {
t[i] = u[i];
}
inline void axes_assign(std::vector<axis::any<Ts...>>& t,
const std::vector<axis::any<Us...>>& u) {
for (std::size_t i = 0; i < t.size(); ++i) { t[i] = u[i]; }
}
struct field_count_visitor : public static_visitor<void> {
std::size_t value = 1;
template <typename T> void operator()(const T &t) { value *= t.shape(); }
template <typename T>
void operator()(const T& t) {
value *= t.shape();
}
};
template <typename Unary> struct unary_visitor : public static_visitor<void> {
Unary &unary;
unary_visitor(Unary &u) : unary(u) {}
template <typename Axis> void operator()(const Axis &a) const { unary(a); }
template <typename Unary>
struct unary_visitor : public static_visitor<void> {
Unary& unary;
unary_visitor(Unary& u) : unary(u) {}
template <typename Axis>
void operator()(const Axis& a) const {
unary(a);
}
};
struct shape_vector_visitor {
std::vector<unsigned> shapes;
std::vector<unsigned>::iterator iter;
shape_vector_visitor(unsigned n) : shapes(n) { iter = shapes.begin(); }
template <typename Axis> void operator()(const Axis &a) {
template <typename Axis>
void operator()(const Axis& a) {
*iter++ = a.shape();
}
};

View File

@ -17,16 +17,17 @@ namespace boost {
namespace histogram {
namespace detail {
namespace {
__attribute__((unused)) void cat_impl(std::ostringstream &) {}
__attribute__((unused)) void cat_impl(std::ostringstream&) {}
template <typename T, typename... Ts>
void cat_impl(std::ostringstream &os, const T &t, const Ts &... ts) {
void cat_impl(std::ostringstream& os, const T& t, const Ts&... ts) {
os << t;
cat_impl(os, ts...);
}
} // namespace
template <typename... Ts> std::string cat(const Ts &... args) {
template <typename... Ts>
std::string cat(const Ts&... args) {
std::ostringstream os;
cat_impl(os, args...);
return os.str();

View File

@ -20,29 +20,34 @@ namespace boost {
namespace histogram {
namespace detail {
#define BOOST_HISTOGRAM_MAKE_SFINAE(name, cond) \
template <typename U> struct name##_impl { \
template <typename T, typename = decltype(cond)> struct SFINAE {}; \
template <typename T> static std::true_type Test(SFINAE<T> *); \
template <typename T> static std::false_type Test(...); \
using type = decltype(Test<U>(nullptr)); \
}; \
template <typename T> using name = typename name##_impl<T>::type
#define BOOST_HISTOGRAM_MAKE_SFINAE(name, cond) \
template <typename U> \
struct name##_impl { \
template <typename T, typename = decltype(cond)> \
struct SFINAE {}; \
template <typename T> \
static std::true_type Test(SFINAE<T>*); \
template <typename T> \
static std::false_type Test(...); \
using type = decltype(Test<U>(nullptr)); \
}; \
template <typename T> \
using name = typename name##_impl<T>::type
BOOST_HISTOGRAM_MAKE_SFINAE(has_variance_support,
(std::declval<T &>().value(),
std::declval<T &>().variance()));
(std::declval<T&>().value(),
std::declval<T&>().variance()));
BOOST_HISTOGRAM_MAKE_SFINAE(has_method_lower, (std::declval<T &>().lower(0)));
BOOST_HISTOGRAM_MAKE_SFINAE(has_method_lower, (std::declval<T&>().lower(0)));
BOOST_HISTOGRAM_MAKE_SFINAE(is_dynamic_container,
(std::begin(std::declval<T &>())));
(std::begin(std::declval<T&>())));
BOOST_HISTOGRAM_MAKE_SFINAE(is_static_container,
(std::get<0>(std::declval<T &>())));
(std::get<0>(std::declval<T&>())));
BOOST_HISTOGRAM_MAKE_SFINAE(is_castable_to_int,
(static_cast<int>(std::declval<T &>())));
(static_cast<int>(std::declval<T&>())));
struct static_container_tag {};
struct dynamic_container_tag {};
@ -55,30 +60,34 @@ using classify_container = typename std::conditional<
dynamic_container_tag,
no_container_tag>::type>::type;
template <typename T, typename = decltype(std::declval<T &>().size(),
std::declval<T &>().increase(0),
std::declval<T &>()[0])>
template <typename T, typename = decltype(std::declval<T&>().size(),
std::declval<T&>().increase(0),
std::declval<T&>()[0])>
struct requires_storage {};
template <typename T,
typename = decltype(*std::declval<T &>(), ++std::declval<T &>())>
typename = decltype(*std::declval<T&>(), ++std::declval<T&>())>
struct requires_iterator {};
template <typename T>
using requires_axis =
decltype(std::declval<T &>().size(), std::declval<T &>().shape(),
std::declval<T &>().uoflow(), std::declval<T &>().label(),
std::declval<T &>()[0]);
decltype(std::declval<T&>().size(), std::declval<T&>().shape(),
std::declval<T&>().uoflow(), std::declval<T&>().label(),
std::declval<T&>()[0]);
namespace {
struct bool_mask_impl {
std::vector<bool> &b;
std::vector<bool>& b;
bool v;
template <typename Int> void operator()(Int) const { b[Int::value] = v; }
template <typename Int>
void operator()(Int) const {
b[Int::value] = v;
}
};
}
template <typename... Ns> std::vector<bool> bool_mask(unsigned n, bool v) {
template <typename... Ns>
std::vector<bool> bool_mask(unsigned n, bool v) {
std::vector<bool> b(n, !v);
mp11::mp_for_each<mp11::mp_list<Ns...>>(bool_mask_impl{b, v});
return b;
@ -88,7 +97,8 @@ template <class T>
using rm_cv_ref =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template <class T> using mp_size = mp11::mp_size<rm_cv_ref<T>>;
template <class T>
using mp_size = mp11::mp_size<rm_cv_ref<T>>;
template <typename T, unsigned D>
using mp_at_c = mp11::mp_at_c<rm_cv_ref<T>, D>;
@ -98,8 +108,10 @@ using mp_union =
mp11::mp_rename<mp11::mp_push_front<L2, L1>, mp11::mp_set_push_back>;
namespace {
template <typename L, typename... Ns> struct selection_impl {
template <typename Int> using at = mp11::mp_at<L, Int>;
template <typename L, typename... Ns>
struct selection_impl {
template <typename Int>
using at = mp11::mp_at<L, Int>;
using N = mp11::mp_list<Ns...>;
using LNs = mp11::mp_assign<L, N>;
using type = mp11::mp_transform<at, LNs>;
@ -113,17 +125,19 @@ template <typename Ns>
using unique_sorted = mp11::mp_unique<mp11::mp_sort<Ns, mp11::mp_less>>;
namespace {
template <typename Src, typename Dst> struct sub_tuple_assign_impl {
const Src &src;
Dst &dst;
template <typename I1, typename I2> void operator()(std::pair<I1, I2>) const {
template <typename Src, typename Dst>
struct sub_tuple_assign_impl {
const Src& src;
Dst& dst;
template <typename I1, typename I2>
void operator()(std::pair<I1, I2>) const {
std::get<I1::value>(dst) = std::get<I2::value>(src);
}
};
}
template <typename T, typename... Ns>
selection<T, Ns...> make_sub_tuple(const T &t) {
selection<T, Ns...> make_sub_tuple(const T& t) {
using U = selection<T, Ns...>;
U u;
using N1 = mp11::mp_list<Ns...>;

View File

@ -14,11 +14,11 @@
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/type_index.hpp>
#include <boost/utility/string_view.hpp>
#include <memory>
#include <ostream>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include <memory>
namespace boost {
namespace histogram {
@ -27,7 +27,7 @@ namespace detail {
// two_pi can be found in boost/math, but it is defined here to reduce deps
constexpr double two_pi = 6.283185307179586;
inline void escape(std::ostream &os, const string_view s) {
inline void escape(std::ostream& os, const string_view s) {
os << '\'';
for (auto sit = s.begin(); sit != s.end(); ++sit) {
if (*sit == '\'' && (sit == s.begin() || *(sit - 1) != '\\')) {
@ -41,7 +41,7 @@ inline void escape(std::ostream &os, const string_view s) {
// the following is highly optimized code that runs in a hot loop;
// please measure the performance impact of changes
inline void lin(std::size_t &out, std::size_t &stride, const int axis_size,
inline void lin(std::size_t& out, std::size_t& stride, const int axis_size,
const int axis_shape, int j) noexcept {
BOOST_ASSERT_MSG(stride == 0 || (-1 <= j && j <= axis_size),
"index must be in bounds for this algorithm");
@ -50,7 +50,8 @@ inline void lin(std::size_t &out, std::size_t &stride, const int axis_size,
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#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
}
struct index_cache {
@ -61,8 +62,9 @@ struct index_cache {
struct dim_visitor {
mutable std::size_t stride;
mutable dim_t *dims;
template <typename Axis> void operator()(const Axis &a) const noexcept {
mutable dim_t* dims;
template <typename Axis>
void operator()(const Axis& a) const noexcept {
*dims++ = dim_t{0, a.size(), stride};
stride *= a.shape();
}
@ -76,14 +78,11 @@ struct index_cache {
index_cache(index_cache&&) = default;
index_cache& operator=(index_cache&&) = default;
index_cache(const index_cache& o) :
dim_(o.dim_), dims_(new dim_t[o.dim_])
{
index_cache(const index_cache& o) : dim_(o.dim_), dims_(new dim_t[o.dim_]) {
std::copy(o.dims_.get(), o.dims_.get() + dim_, dims_.get());
}
index_cache& operator=(const index_cache& o)
{
index_cache& operator=(const index_cache& o) {
if (this != &o) {
if (o.dim_ != dim_) {
dim_ = o.dim_;
@ -124,12 +123,12 @@ struct index_cache {
struct index_mapper {
std::size_t first = 0, second = 0;
index_mapper(const std::vector<unsigned> &nvec,
const std::vector<bool> &bvec) {
index_mapper(const std::vector<unsigned>& nvec,
const std::vector<bool>& bvec) {
dims.reserve(nvec.size());
std::size_t s1 = 1, s2 = 1;
auto bi = bvec.begin();
for (const auto &ni : nvec) {
for (const auto& ni : nvec) {
if (*bi) {
dims.push_back({s1, s2});
s2 *= ni;
@ -139,8 +138,9 @@ struct index_mapper {
s1 *= ni;
++bi;
}
std::sort(dims.begin(), dims.end(),
[](const dim &a, const dim &b) { return a.stride1 > b.stride1; });
std::sort(dims.begin(), dims.end(), [](const dim& a, const dim& b) {
return a.stride1 > b.stride1;
});
nfirst = s1;
}
@ -148,7 +148,7 @@ struct index_mapper {
++first;
second = 0;
auto f = first;
for (const auto &d : dims) {
for (const auto& d : dims) {
auto i = f / d.stride1;
f -= i * d.stride1;
second += i * d.stride2;
@ -166,13 +166,13 @@ private:
template <typename T>
inline typename std::enable_if<(is_castable_to_int<T>::value), int>::type
indirect_int_cast(T &&t) noexcept {
indirect_int_cast(T&& t) noexcept {
return static_cast<int>(std::forward<T>(t));
}
template <typename T>
inline typename std::enable_if<!(is_castable_to_int<T>::value), int>::type
indirect_int_cast(T &&) noexcept {
indirect_int_cast(T&&) noexcept {
// Cannot use static_assert here, because this function is created as a
// side-effect of TMP. It must be valid at compile-time.
BOOST_ASSERT_MSG(false, "bin argument not convertible to int");
@ -180,19 +180,19 @@ indirect_int_cast(T &&) noexcept {
}
template <typename S, typename T>
inline void fill_storage(S &s, std::size_t idx, weight<T> &&w) {
inline void fill_storage(S& s, std::size_t idx, weight<T>&& w) {
s.add(idx, w);
}
template <typename S> inline void fill_storage(S &s, std::size_t idx) {
template <typename S>
inline void fill_storage(S& s, std::size_t idx) {
s.increase(idx);
}
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 {
if (error)
throw std::out_of_range("bin index out of range");
if (error) throw std::out_of_range("bin index out of range");
return s[idx];
}

View File

@ -62,22 +62,21 @@ public:
public:
histogram() = default;
histogram(const histogram &) = default;
histogram(histogram &&) = default;
histogram &operator=(const histogram &) = default;
histogram &operator=(histogram &&) = default;
histogram(const histogram&) = default;
histogram(histogram&&) = default;
histogram& operator=(const histogram&) = default;
histogram& operator=(histogram&&) = default;
template <typename Axis0, typename... Axis,
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)),
any_axis_type(std::forward<Axis>(axis))...}) {
storage_ = Storage(size_from_axes());
index_cache_.reset(*this);
}
explicit histogram(axes_type&& axes)
: axes_(std::move(axes)) {
explicit histogram(axes_type&& axes) : axes_(std::move(axes)) {
storage_ = Storage(size_from_axes());
index_cache_.reset(*this);
}
@ -90,14 +89,14 @@ public:
}
template <typename T, typename A, typename S>
explicit histogram(const histogram<T, A, S> &rhs) : storage_(rhs.storage_) {
explicit histogram(const histogram<T, A, S>& rhs) : storage_(rhs.storage_) {
detail::axes_assign(axes_, rhs.axes_);
index_cache_.reset(*this);
}
template <typename T, typename A, typename S>
histogram &operator=(const histogram<T, A, S> &rhs) {
if (static_cast<const void *>(this) != static_cast<const void *>(&rhs)) {
histogram& operator=(const histogram<T, A, S>& rhs) {
if (static_cast<const void*>(this) != static_cast<const void*>(&rhs)) {
detail::axes_assign(axes_, rhs.axes_);
storage_ = rhs.storage_;
index_cache_.reset(*this);
@ -106,13 +105,14 @@ public:
}
template <typename S>
explicit histogram(dynamic_histogram<Axes, S> &&rhs)
explicit histogram(dynamic_histogram<Axes, S>&& rhs)
: axes_(std::move(rhs.axes_)), storage_(std::move(rhs.storage_)) {
index_cache_.reset(*this);
}
template <typename S> histogram &operator=(dynamic_histogram<Axes, S> &&rhs) {
if (static_cast<const void *>(this) != static_cast<const void *>(&rhs)) {
template <typename S>
histogram& operator=(dynamic_histogram<Axes, S>&& rhs) {
if (static_cast<const void*>(this) != static_cast<const void*>(&rhs)) {
axes_ = std::move(rhs.axes_);
storage_ = std::move(rhs.storage_);
index_cache_.reset(*this);
@ -121,46 +121,48 @@ public:
}
template <typename T, typename A, typename S>
bool operator==(const histogram<T, A, S> &rhs) const noexcept {
bool operator==(const histogram<T, A, S>& rhs) const noexcept {
return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_;
}
template <typename T, typename A, typename S>
bool operator!=(const histogram<T, A, S> &rhs) const noexcept {
bool operator!=(const histogram<T, A, S>& rhs) const noexcept {
return !operator==(rhs);
}
template <typename T, typename A, typename S>
histogram &operator+=(const histogram<T, A, S> &rhs) {
histogram& operator+=(const histogram<T, A, S>& rhs) {
if (!detail::axes_equal(axes_, rhs.axes_))
throw std::invalid_argument("axes of histograms differ");
storage_ += rhs.storage_;
return *this;
}
template <typename T> histogram &operator*=(const T &rhs) {
template <typename T>
histogram& operator*=(const T& rhs) {
storage_ *= rhs;
return *this;
}
template <typename T> histogram &operator/=(const T &rhs) {
template <typename T>
histogram& operator/=(const T& rhs) {
storage_ *= 1.0 / rhs;
return *this;
}
template <typename... Ts> void operator()(Ts &&... ts) {
template <typename... Ts>
void operator()(Ts&&... ts) {
// case with one argument is ambiguous, is specialized below
BOOST_ASSERT_MSG(dim() == sizeof...(Ts),
"fill arguments does not match histogram dimension "
"(did you use weight() in the wrong place?)");
std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, std::forward<Ts>(ts)...);
if (stride) {
detail::fill_storage(storage_, idx);
}
if (stride) { detail::fill_storage(storage_, idx); }
}
template <typename T> void operator()(T &&t) {
template <typename T>
void operator()(T&& t) {
// check whether T is unpackable
if (dim() == 1) {
fill_impl(detail::no_container_tag(), std::forward<T>(t));
@ -170,19 +172,17 @@ public:
}
template <typename W, typename... Ts>
void operator()(detail::weight<W> &&w, Ts &&... ts) {
void operator()(detail::weight<W>&& w, Ts&&... ts) {
// case with one argument is ambiguous, is specialized below
BOOST_ASSERT_MSG(dim() == sizeof...(Ts),
"fill arguments does not match histogram dimension");
std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, std::forward<Ts>(ts)...);
if (stride) {
detail::fill_storage(storage_, idx, std::move(w));
}
if (stride) { detail::fill_storage(storage_, idx, std::move(w)); }
}
template <typename W, typename T>
void operator()(detail::weight<W> &&w, T &&t) {
void operator()(detail::weight<W>&& w, T&& t) {
// check whether T is unpackable
if (dim() == 1) {
fill_impl(detail::no_container_tag(), std::forward<T>(t), std::move(w));
@ -192,7 +192,8 @@ public:
}
}
template <typename... Ts> const_reference at(Ts &&... ts) const {
template <typename... Ts>
const_reference at(Ts&&... ts) const {
// case with one argument is ambiguous, is specialized below
BOOST_ASSERT_MSG(dim() == sizeof...(Ts),
"bin arguments does not match histogram dimension");
@ -201,12 +202,14 @@ public:
return detail::storage_get(storage_, idx, stride == 0);
}
template <typename T> const_reference at(T &&t) const {
template <typename T>
const_reference at(T&& t) const {
// check whether T is unpackable
return at_impl(detail::classify_container<T>(), std::forward<T>(t));
}
template <typename T> const_reference operator[](T &&t) const {
template <typename T>
const_reference operator[](T&& t) const {
// check whether T is unpackable
return at_impl(detail::classify_container<T>(), std::forward<T>(t));
}
@ -221,20 +224,21 @@ public:
void reset() { storage_ = Storage(size_from_axes()); }
/// Return axis \a i
any_axis_type &axis(unsigned i = 0) {
any_axis_type& axis(unsigned i = 0) {
BOOST_ASSERT_MSG(i < dim(), "axis index out of range");
return axes_[i];
}
/// Return axis \a i (const version)
const any_axis_type &axis(unsigned i = 0) const {
const any_axis_type& axis(unsigned i = 0) const {
BOOST_ASSERT_MSG(i < dim(), "axis index out of range");
return axes_[i];
}
/// Apply unary functor/function to each axis
template <typename Unary> void for_each_axis(Unary &&unary) const {
for (const auto &a : axes_) {
template <typename Unary>
void for_each_axis(Unary&& unary) const {
for (const auto& a : axes_) {
apply_visitor(detail::unary_visitor<Unary>(unary), a);
}
}
@ -247,10 +251,10 @@ public:
}
/// Return a lower dimensional histogram
template <typename... Ts> histogram reduce_to(int n, Ts... ts) const {
template <typename... Ts>
histogram reduce_to(int n, Ts... ts) const {
std::vector<bool> b(dim(), false);
for (const auto &i : {n, int(ts)...})
b[i] = true;
for (const auto& i : {n, int(ts)...}) b[i] = true;
return reduce_impl(b);
}
@ -258,14 +262,11 @@ public:
template <typename Iterator, typename = detail::requires_iterator<Iterator>>
histogram reduce_to(Iterator begin, Iterator end) const {
std::vector<bool> b(dim(), false);
for (; begin != end; ++begin)
b[*begin] = true;
for (; begin != end; ++begin) b[*begin] = true;
return reduce_impl(b);
}
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, storage_.size());
@ -283,7 +284,7 @@ private:
}
template <typename T, typename... Ts>
void fill_impl(detail::dynamic_container_tag, T &&t, Ts &&... ts) {
void fill_impl(detail::dynamic_container_tag, T&& t, Ts&&... ts) {
BOOST_ASSERT_MSG(dim() == std::distance(std::begin(t), std::end(t)),
"fill container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -294,7 +295,7 @@ private:
}
template <typename T, typename... Ts>
void fill_impl(detail::static_container_tag, T &&t, Ts &&... ts) {
void fill_impl(detail::static_container_tag, T&& t, Ts&&... ts) {
BOOST_ASSERT_MSG(dim() == detail::mp_size<T>::value,
"fill container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -306,7 +307,7 @@ private:
}
template <typename T, typename... Ts>
void fill_impl(detail::no_container_tag, T &&t, Ts &&... ts) {
void fill_impl(detail::no_container_tag, T&& t, Ts&&... ts) {
BOOST_ASSERT_MSG(dim() == 1,
"fill argument does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -317,7 +318,7 @@ private:
}
template <typename T>
const_reference at_impl(detail::dynamic_container_tag, T &&t) const {
const_reference at_impl(detail::dynamic_container_tag, T&& t) const {
BOOST_ASSERT_MSG(dim() == std::distance(std::begin(t), std::end(t)),
"bin container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -326,7 +327,7 @@ private:
}
template <typename T>
const_reference at_impl(detail::static_container_tag, T &&t) const {
const_reference at_impl(detail::static_container_tag, T&& t) const {
BOOST_ASSERT_MSG(dim() == detail::mp_size<T>::value,
"bin container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -336,7 +337,7 @@ private:
}
template <typename T>
const_reference at_impl(detail::no_container_tag, T &&t) const {
const_reference at_impl(detail::no_container_tag, T&& t) const {
BOOST_ASSERT_MSG(dim() == 1,
"bin argument does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -345,49 +346,55 @@ private:
}
struct lin_visitor : public static_visitor<void> {
std::size_t &idx;
std::size_t &stride;
std::size_t& idx;
std::size_t& stride;
const int j;
lin_visitor(std::size_t &i, std::size_t &s, const int x) noexcept
lin_visitor(std::size_t& i, std::size_t& s, const int x) noexcept
: idx(i),
stride(s),
j(x) {}
template <typename A> void operator()(const A &a) const noexcept {
template <typename A>
void operator()(const A& a) const noexcept {
const auto a_size = a.size();
const auto a_shape = a.shape();
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);
}
};
template <unsigned D>
void lin(std::size_t &, std::size_t &) const noexcept {}
void lin(std::size_t&, std::size_t&) const noexcept {}
template <unsigned D, typename... Ts>
void lin(std::size_t &idx, std::size_t &stride, int x, Ts... ts) const
void lin(std::size_t& idx, std::size_t& stride, int x, Ts... ts) const
noexcept {
apply_visitor(lin_visitor{idx, stride, x}, axes_[D]);
lin<D + 1>(idx, stride, ts...);
}
template <typename Value> struct xlin_visitor : public static_visitor<void> {
std::size_t &idx;
std::size_t &stride;
const Value &val;
xlin_visitor(std::size_t &i, std::size_t &s, const Value &v)
template <typename Value>
struct xlin_visitor : public static_visitor<void> {
std::size_t& idx;
std::size_t& stride;
const Value& val;
xlin_visitor(std::size_t& i, std::size_t& s, const Value& v)
: idx(i), stride(s), val(v) {}
template <typename Axis> void operator()(const Axis &a) const {
template <typename Axis>
void operator()(const Axis& a) const {
impl(std::is_convertible<Value, typename Axis::value_type>(), a);
}
template <typename Axis> void impl(std::true_type, const Axis &a) const {
template <typename Axis>
void impl(std::true_type, const Axis& a) const {
const auto a_size = a.size();
const auto a_shape = a.shape();
const auto j = a.index(val);
detail::lin(idx, stride, a_size, a_shape, j);
}
template <typename Axis> void impl(std::false_type, const Axis &) const {
template <typename Axis>
void impl(std::false_type, const Axis&) const {
throw std::invalid_argument(
detail::cat("fill argument not convertible to axis value type: ",
boost::typeindex::type_id<Axis>().pretty_name(), ", ",
@ -396,37 +403,36 @@ private:
};
template <unsigned D>
void xlin(std::size_t &, std::size_t &) const {}
void xlin(std::size_t&, std::size_t&) const {}
template <unsigned D, typename T, typename... Ts>
void xlin(std::size_t &idx, std::size_t &stride, T &&t,
Ts &&... ts) const {
void xlin(std::size_t& idx, std::size_t& stride, T&& t, Ts&&... ts) const {
apply_visitor(xlin_visitor<T>{idx, stride, t}, axes_[D]);
xlin<(D + 1)>(idx, stride, std::forward<Ts>(ts)...);
}
template <typename Iterator>
void lin_iter(std::size_t &idx, std::size_t &stride,
Iterator iter) const noexcept {
for (const auto &a : axes_) {
void lin_iter(std::size_t& idx, std::size_t& stride, Iterator iter) const
noexcept {
for (const auto& a : axes_) {
apply_visitor(lin_visitor(idx, stride, *iter++), a);
}
}
template <typename Iterator>
void xlin_iter(std::size_t &idx, std::size_t &stride, Iterator iter) const {
for (const auto &a : axes_) {
void xlin_iter(std::size_t& idx, std::size_t& stride, Iterator iter) const {
for (const auto& a : axes_) {
apply_visitor(xlin_visitor<decltype(*iter)>{idx, stride, *iter++}, a);
}
}
template <typename T>
void xlin_get(mp11::mp_int<0>, std::size_t &, std::size_t &, T &&) const
void xlin_get(mp11::mp_int<0>, std::size_t&, std::size_t&, T&&) const
noexcept {}
template <int N, typename T>
void xlin_get(mp11::mp_int<N>, std::size_t &idx, std::size_t &stride,
T &&t) const {
void xlin_get(mp11::mp_int<N>, std::size_t& idx, std::size_t& stride,
T&& t) const {
constexpr unsigned D = detail::mp_size<T>::value - N;
apply_visitor(
xlin_visitor<detail::mp_at_c<T, D>>{idx, stride, std::get<D>(t)},
@ -435,49 +441,49 @@ private:
}
template <typename T>
void lin_get(mp11::mp_int<0>, std::size_t &, std::size_t &, T &&) const
void lin_get(mp11::mp_int<0>, std::size_t&, std::size_t&, T&&) const
noexcept {}
template <int N, typename T>
void lin_get(mp11::mp_int<N>, std::size_t &idx, std::size_t &stride,
T &&t) const noexcept {
void lin_get(mp11::mp_int<N>, std::size_t& idx, std::size_t& stride,
T&& t) const noexcept {
constexpr unsigned D = detail::mp_size<T>::value - N;
apply_visitor(lin_visitor{idx, stride, static_cast<int>(std::get<D>(t))},
axes_[D]);
lin_get(mp11::mp_int<(N - 1)>(), idx, stride, std::forward<T>(t));
}
histogram reduce_impl(const std::vector<bool> &b) const {
histogram reduce_impl(const std::vector<bool>& b) const {
axes_type axes;
std::vector<unsigned> n(b.size());
auto axes_iter = axes_.begin();
auto n_iter = n.begin();
for (const auto &bi : b) {
if (bi)
axes.emplace_back(*axes_iter);
for (const auto& bi : b) {
if (bi) axes.emplace_back(*axes_iter);
*n_iter = axes_iter->shape();
++axes_iter;
++n_iter;
}
histogram h(std::move(axes));
detail::index_mapper m(n, b);
do {
h.storage_.add(m.second, storage_[m.first]);
} while (m.next());
do { h.storage_.add(m.second, storage_[m.first]); } while (m.next());
return h;
}
template <typename T, typename A, typename S> friend class histogram;
template <typename H> friend class iterator_over;
template <typename T, typename A, typename S>
friend class histogram;
template <typename H>
friend class iterator_over;
friend class ::boost::python::access;
friend class ::boost::serialization::access;
template <typename Archive> void serialize(Archive &, unsigned);
template <typename Archive>
void serialize(Archive&, unsigned);
};
template <typename... Axis>
dynamic_histogram<
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>>
make_dynamic_histogram(Axis &&... axis) {
make_dynamic_histogram(Axis&&... axis) {
return dynamic_histogram<
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>>(
std::forward<Axis>(axis)...);
@ -486,10 +492,10 @@ make_dynamic_histogram(Axis &&... axis) {
template <typename Storage, typename... Axis>
dynamic_histogram<
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>, Storage>
make_dynamic_histogram_with(Axis &&... axis) {
make_dynamic_histogram_with(Axis&&... axis) {
return dynamic_histogram<
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>, Storage>(
std::forward<Axis>(axis)...);
mp11::mp_set_push_back<axis::types, detail::rm_cv_ref<Axis>...>,
Storage>(std::forward<Axis>(axis)...);
}
template <typename Iterator, typename = detail::requires_iterator<Iterator>>

View File

@ -15,7 +15,8 @@ namespace boost {
namespace histogram {
class adaptive_storage;
template <typename T> class array_storage;
template <typename T>
class array_storage;
namespace axis {
@ -26,12 +27,17 @@ struct sqrt;
struct pow;
} // namespace transform
template <typename RealType = double, typename Transform = transform::identity>
template <typename RealType = double,
typename Transform = transform::identity>
class regular;
template <typename RealType = double> class circular;
template <typename RealType = double> class variable;
template <typename IntType = int> class integer;
template <typename T = int> class category;
template <typename RealType = double>
class circular;
template <typename RealType = double>
class variable;
template <typename IntType = int>
class integer;
template <typename T = int>
class category;
using types = mp11::mp_list<axis::regular<double, axis::transform::identity>,
axis::regular<double, axis::transform::log>,
@ -41,7 +47,8 @@ using types = mp11::mp_list<axis::regular<double, axis::transform::identity>,
axis::integer<int>, axis::category<int>,
axis::category<std::string>>;
template <typename... Ts> class any;
template <typename... Ts>
class any;
using any_std = mp11::mp_rename<types, any>;
} // namespace axis
@ -58,18 +65,30 @@ template <class Axes, class Storage = adaptive_storage>
using static_histogram = histogram<static_tag, Axes, Storage>;
namespace detail {
template <typename T> struct weight { T value; };
template <typename T>
struct weight {
T value;
};
// template <typename T> struct is_weight : std::false_type {};
// template <typename T> struct is_weight<weight_t<T>> : std::true_type {};
template <typename T> struct sample { T value; };
template <typename T>
struct sample {
T value;
};
// template <typename T> struct is_sample : std::false_type {};
// template <typename T> struct is_sample<sample_t<T>> : std::true_type {};
} // namespace detail
template <typename T> detail::weight<T> weight(T &&t) { return {t}; }
template <typename T>
detail::weight<T> weight(T&& t) {
return {t};
}
template <typename T> detail::sample<T> sample(T &&t) { return {t}; }
template <typename T>
detail::sample<T> sample(T&& t) {
return {t};
}
} // namespace histogram
} // namespace boost

View File

@ -8,8 +8,8 @@
#define _BOOST_HISTOGRAM_VALUE_ITERATOR_HPP_
#include <array>
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/histogram/detail/utility.hpp>
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/mp11.hpp>
#include <limits>
@ -22,16 +22,14 @@ namespace histogram {
template <typename Histogram>
class iterator_over
: public iterator_facade<
iterator_over<Histogram>,
typename Histogram::element_type,
random_access_traversal_tag,
typename Histogram::const_reference> {
iterator_over<Histogram>, typename Histogram::element_type,
random_access_traversal_tag, typename Histogram::const_reference> {
public:
iterator_over(const Histogram &h, std::size_t idx)
iterator_over(const Histogram& h, std::size_t idx)
: histogram_(h), idx_(idx) {}
iterator_over(const iterator_over &) = default;
iterator_over &operator=(const iterator_over &) = default;
iterator_over(const iterator_over&) = default;
iterator_over& operator=(const iterator_over&) = default;
unsigned dim() const noexcept { return histogram_.dim(); }
@ -41,23 +39,23 @@ public:
}
auto bin() const
-> decltype(std::declval<Histogram &>().axis(mp11::mp_int<0>())[0]) {
-> decltype(std::declval<Histogram&>().axis(mp11::mp_int<0>())[0]) {
return histogram_.axis(mp11::mp_int<0>())[idx(0)];
}
template <int Dim>
auto bin(mp11::mp_int<Dim>) const
-> decltype(std::declval<Histogram &>().axis(mp11::mp_int<Dim>())[0]) {
-> decltype(std::declval<Histogram&>().axis(mp11::mp_int<Dim>())[0]) {
return histogram_.axis(mp11::mp_int<Dim>())[idx(Dim)];
}
template <typename T = Histogram> // use SFINAE for this method
auto bin(unsigned dim) const -> decltype(std::declval<T &>().axis(dim)[0]) {
auto bin(unsigned dim) const -> decltype(std::declval<T&>().axis(dim)[0]) {
return histogram_.axis(dim)[idx(dim)];
}
private:
bool equal(const iterator_over &rhs) const noexcept {
bool equal(const iterator_over& rhs) const noexcept {
return &histogram_ == &rhs.histogram_ && idx_ == rhs.idx_;
}
@ -70,7 +68,7 @@ private:
return histogram_.storage_[idx_];
}
const Histogram &histogram_;
const Histogram& histogram_;
std::size_t idx_;
friend class ::boost::iterator_core_access;
};

View File

@ -13,21 +13,56 @@ namespace boost {
namespace histogram {
namespace literals {
namespace detail {
template <char C> struct char2int;
template <> struct char2int<'0'> { static constexpr int value = 0; };
template <> struct char2int<'1'> { static constexpr int value = 1; };
template <> struct char2int<'2'> { static constexpr int value = 2; };
template <> struct char2int<'3'> { static constexpr int value = 3; };
template <> struct char2int<'4'> { static constexpr int value = 4; };
template <> struct char2int<'5'> { static constexpr int value = 5; };
template <> struct char2int<'6'> { static constexpr int value = 6; };
template <> struct char2int<'7'> { static constexpr int value = 7; };
template <> struct char2int<'8'> { static constexpr int value = 8; };
template <> struct char2int<'9'> { static constexpr int value = 9; };
template <char C>
struct char2int;
template <>
struct char2int<'0'> {
static constexpr int value = 0;
};
template <>
struct char2int<'1'> {
static constexpr int value = 1;
};
template <>
struct char2int<'2'> {
static constexpr int value = 2;
};
template <>
struct char2int<'3'> {
static constexpr int value = 3;
};
template <>
struct char2int<'4'> {
static constexpr int value = 4;
};
template <>
struct char2int<'5'> {
static constexpr int value = 5;
};
template <>
struct char2int<'6'> {
static constexpr int value = 6;
};
template <>
struct char2int<'7'> {
static constexpr int value = 7;
};
template <>
struct char2int<'8'> {
static constexpr int value = 8;
};
template <>
struct char2int<'9'> {
static constexpr int value = 9;
};
template <int N> constexpr int parse() { return N; }
template <int N>
constexpr int parse() {
return N;
}
template <int N, char First, char... Rest> constexpr int parse() {
template <int N, char First, char... Rest>
constexpr int parse() {
return parse<N * 10 + char2int<First>::value, Rest...>();
}
} // namespace detail

View File

@ -16,16 +16,17 @@ namespace histogram {
namespace detail {
struct axis_ostream_visitor {
std::ostream &os_;
explicit axis_ostream_visitor(std::ostream &os) : os_(os) {}
template <typename Axis> void operator()(const Axis &a) const {
std::ostream& os_;
explicit axis_ostream_visitor(std::ostream& os) : os_(os) {}
template <typename Axis>
void operator()(const Axis& a) const {
os_ << "\n " << a << ",";
}
};
} // namespace detail
template <typename... Ts>
inline std::ostream &operator<<(std::ostream &os, const histogram<Ts...> &h) {
inline std::ostream& operator<<(std::ostream& os, const histogram<Ts...>& h) {
os << "histogram(";
h.for_each_axis(detail::axis_ostream_visitor(os));
os << (h.dim() ? "\n)" : ")");
@ -33,7 +34,8 @@ inline std::ostream &operator<<(std::ostream &os, const histogram<Ts...> &h) {
}
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() << ")";
return os;
}

View File

@ -28,89 +28,94 @@ namespace boost {
namespace histogram {
namespace detail {
template <typename Archive> struct serialize_helper {
Archive &ar_;
explicit serialize_helper(Archive &ar) : ar_(ar) {}
template <typename T> void operator()(T &t) const { ar_ &t; }
template <typename Archive>
struct serialize_helper {
Archive& ar_;
explicit serialize_helper(Archive& ar) : ar_(ar) {}
template <typename T>
void operator()(T& t) const {
ar_& t;
}
};
} // namespace detail
template <typename RealType>
template <class Archive>
void weight_counter<RealType>::serialize(Archive &ar, unsigned /* version */) {
ar &w;
ar &w2;
void weight_counter<RealType>::serialize(Archive& ar,
unsigned /* version */) {
ar& w;
ar& w2;
}
template <class Archive, typename Container>
void serialize(Archive &ar, array_storage<Container> &store,
void serialize(Archive& ar, array_storage<Container>& store,
unsigned /* version */) {
ar &store.array_;
ar& store.array_;
}
template <class Archive>
void adaptive_storage::serialize(Archive &ar, unsigned /* version */) {
void adaptive_storage::serialize(Archive& ar, unsigned /* version */) {
auto size = this->size();
ar &size;
ar& size;
if (Archive::is_loading::value) {
auto tid = 0u;
ar &tid;
ar& tid;
if (tid == 0u) {
buffer_ = detail::array<void>(size);
} else if (tid == 1u) {
detail::array<uint8_t> a(size);
ar &serialization::make_array(a.begin(), size);
ar& serialization::make_array(a.begin(), size);
buffer_ = std::move(a);
} else if (tid == 2u) {
detail::array<uint16_t> a(size);
ar &serialization::make_array(a.begin(), size);
ar& serialization::make_array(a.begin(), size);
buffer_ = std::move(a);
} else if (tid == 3u) {
detail::array<uint32_t> a(size);
ar &serialization::make_array(a.begin(), size);
ar& serialization::make_array(a.begin(), size);
buffer_ = std::move(a);
} else if (tid == 4u) {
detail::array<uint64_t> a(size);
ar &serialization::make_array(a.begin(), size);
ar& serialization::make_array(a.begin(), size);
buffer_ = std::move(a);
} else if (tid == 5u) {
detail::array<detail::mp_int> a(size);
ar &serialization::make_array(a.begin(), size);
ar& serialization::make_array(a.begin(), size);
buffer_ = std::move(a);
} else if (tid == 6u) {
detail::array<detail::wcount> a(size);
ar &serialization::make_array(a.begin(), size);
ar& serialization::make_array(a.begin(), size);
buffer_ = std::move(a);
}
} else {
auto tid = 0u;
if (get<detail::array<void>>(&buffer_)) {
tid = 0u;
ar &tid;
} else if (auto *a = get<detail::array<uint8_t>>(&buffer_)) {
ar& tid;
} else if (auto* a = get<detail::array<uint8_t>>(&buffer_)) {
tid = 1u;
ar &tid;
ar &serialization::make_array(a->begin(), size);
} else if (auto *a = get<detail::array<uint16_t>>(&buffer_)) {
ar& tid;
ar& serialization::make_array(a->begin(), size);
} else if (auto* a = get<detail::array<uint16_t>>(&buffer_)) {
tid = 2u;
ar &tid;
ar &serialization::make_array(a->begin(), size);
} else if (auto *a = get<detail::array<uint32_t>>(&buffer_)) {
ar& tid;
ar& serialization::make_array(a->begin(), size);
} else if (auto* a = get<detail::array<uint32_t>>(&buffer_)) {
tid = 3u;
ar &tid;
ar &serialization::make_array(a->begin(), size);
} else if (auto *a = get<detail::array<uint64_t>>(&buffer_)) {
ar& tid;
ar& serialization::make_array(a->begin(), size);
} else if (auto* a = get<detail::array<uint64_t>>(&buffer_)) {
tid = 4u;
ar &tid;
ar &serialization::make_array(a->begin(), size);
} else if (auto *a = get<detail::array<detail::mp_int>>(&buffer_)) {
ar& tid;
ar& serialization::make_array(a->begin(), size);
} else if (auto* a = get<detail::array<detail::mp_int>>(&buffer_)) {
tid = 5u;
ar &tid;
ar &serialization::make_array(a->begin(), size);
} else if (auto *a = get<detail::array<detail::wcount>>(&buffer_)) {
ar& tid;
ar& serialization::make_array(a->begin(), size);
} else if (auto* a = get<detail::array<detail::wcount>>(&buffer_)) {
tid = 6u;
ar &tid;
ar &serialization::make_array(a->begin(), size);
ar& tid;
ar& serialization::make_array(a->begin(), size);
}
}
}
@ -119,90 +124,91 @@ namespace axis {
template <typename Derived>
template <class Archive>
void axis_base<Derived>::serialize(Archive &ar, unsigned /* version */) {
ar &size_;
ar &label_;
void axis_base<Derived>::serialize(Archive& ar, unsigned /* version */) {
ar& size_;
ar& label_;
}
template <typename Derived>
template <class Archive>
void axis_base_uoflow<Derived>::serialize(Archive &ar, unsigned /* version */) {
ar &boost::serialization::base_object<axis_base<Derived>>(*this);
ar &shape_;
void axis_base_uoflow<Derived>::serialize(Archive& ar,
unsigned /* version */) {
ar& boost::serialization::base_object<axis_base<Derived>>(*this);
ar& shape_;
}
namespace transform {
template <class Archive>
void pow::serialize(Archive &ar, unsigned /* version */) {
ar &power;
void pow::serialize(Archive& ar, unsigned /* version */) {
ar& power;
}
} // namespace transform
template <typename RealType, typename Transform>
template <class Archive>
void regular<RealType, Transform>::serialize(Archive &ar,
void regular<RealType, Transform>::serialize(Archive& ar,
unsigned /* version */) {
ar &boost::serialization::base_object<base_type>(*this);
ar &boost::serialization::base_object<Transform>(*this);
ar &min_;
ar &delta_;
ar& boost::serialization::base_object<base_type>(*this);
ar& boost::serialization::base_object<Transform>(*this);
ar& min_;
ar& delta_;
}
template <typename RealType>
template <class Archive>
void circular<RealType>::serialize(Archive &ar, unsigned /* version */) {
ar &boost::serialization::base_object<base_type>(*this);
ar &phase_;
ar &perimeter_;
void circular<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& boost::serialization::base_object<base_type>(*this);
ar& phase_;
ar& perimeter_;
}
template <typename RealType>
template <class Archive>
void variable<RealType>::serialize(Archive &ar, unsigned /* version */) {
ar &boost::serialization::base_object<base_type>(*this);
void variable<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& boost::serialization::base_object<base_type>(*this);
if (Archive::is_loading::value) {
x_.reset(new RealType[base_type::size() + 1]);
}
ar &boost::serialization::make_array(x_.get(), base_type::size() + 1);
ar& boost::serialization::make_array(x_.get(), base_type::size() + 1);
}
template <typename IntType>
template <class Archive>
void integer<IntType>::serialize(Archive &ar, unsigned /* version */) {
ar &boost::serialization::base_object<base_type>(*this);
ar &min_;
void integer<IntType>::serialize(Archive& ar, unsigned /* version */) {
ar& boost::serialization::base_object<base_type>(*this);
ar& min_;
}
template <typename T>
template <class Archive>
void category<T>::serialize(Archive &ar, unsigned /* version */) {
ar &boost::serialization::base_object<base_type>(*this);
ar &map_;
void category<T>::serialize(Archive& ar, unsigned /* version */) {
ar& boost::serialization::base_object<base_type>(*this);
ar& map_;
}
template <typename... Ts>
template <class Archive>
void any<Ts...>::serialize(Archive &ar, unsigned /* version */) {
ar &boost::serialization::base_object<base_type>(*this);
void any<Ts...>::serialize(Archive& ar, unsigned /* version */) {
ar& boost::serialization::base_object<base_type>(*this);
}
} // namespace axis
template <class A, class S>
template <class Archive>
void histogram<static_tag, A, S>::serialize(Archive &ar,
void histogram<static_tag, A, S>::serialize(Archive& ar,
unsigned /* version */) {
detail::serialize_helper<Archive> sh(ar);
mp11::tuple_for_each(axes_, sh);
ar &storage_;
ar& storage_;
}
template <class A, class S>
template <class Archive>
void histogram<dynamic_tag, A, S>::serialize(Archive &ar,
void histogram<dynamic_tag, A, S>::serialize(Archive& ar,
unsigned /* version */) {
ar &axes_;
ar &storage_;
ar& axes_;
ar& storage_;
}
} // namespace histogram

View File

@ -45,33 +45,33 @@ public:
using iterator = const_iterator;
histogram() = default;
histogram(const histogram &rhs) = default;
histogram(histogram &&rhs) = default;
histogram &operator=(const histogram &rhs) = default;
histogram &operator=(histogram &&rhs) = default;
histogram(const histogram& rhs) = default;
histogram(histogram&& rhs) = default;
histogram& operator=(const histogram& rhs) = default;
histogram& operator=(histogram&& rhs) = default;
template <typename Axis0, typename... Axis,
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)...) {
storage_ = Storage(size_from_axes());
index_cache_.reset(*this);
}
explicit histogram(axes_type &&axes) : axes_(std::move(axes)) {
explicit histogram(axes_type&& axes) : axes_(std::move(axes)) {
storage_ = Storage(size_from_axes());
index_cache_.reset(*this);
}
template <typename S>
explicit histogram(const static_histogram<Axes, S> &rhs)
explicit histogram(const static_histogram<Axes, S>& rhs)
: axes_(rhs.axes_), storage_(rhs.storage_) {
index_cache_.reset(*this);
}
template <typename S>
histogram &operator=(const static_histogram<Axes, S> &rhs) {
if (static_cast<const void *>(this) != static_cast<const void *>(&rhs)) {
histogram& operator=(const static_histogram<Axes, S>& rhs) {
if (static_cast<const void*>(this) != static_cast<const void*>(&rhs)) {
axes_ = rhs.axes_;
storage_ = rhs.storage_;
}
@ -79,15 +79,15 @@ public:
}
template <typename A, typename S>
explicit histogram(const dynamic_histogram<A, S> &rhs)
explicit histogram(const dynamic_histogram<A, S>& rhs)
: storage_(rhs.storage_) {
detail::axes_assign(axes_, rhs.axes_);
index_cache_.reset(*this);
}
template <typename A, typename S>
histogram &operator=(const dynamic_histogram<A, S> &rhs) {
if (static_cast<const void *>(this) != static_cast<const void *>(&rhs)) {
histogram& operator=(const dynamic_histogram<A, S>& rhs) {
if (static_cast<const void*>(this) != static_cast<const void*>(&rhs)) {
detail::axes_assign(axes_, rhs.axes_);
storage_ = rhs.storage_;
index_cache_.reset(*this);
@ -96,27 +96,27 @@ public:
}
template <typename A, typename S>
bool operator==(const static_histogram<A, S> &) const noexcept {
bool operator==(const static_histogram<A, S>&) const noexcept {
return false;
}
template <typename S>
bool operator==(const static_histogram<Axes, S> &rhs) const noexcept {
bool operator==(const static_histogram<Axes, S>& rhs) const noexcept {
return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_;
}
template <typename A, typename S>
bool operator==(const dynamic_histogram<A, S> &rhs) const noexcept {
bool operator==(const dynamic_histogram<A, S>& rhs) const noexcept {
return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_;
}
template <typename T, typename A, typename S>
bool operator!=(const histogram<T, A, S> &rhs) const noexcept {
bool operator!=(const histogram<T, A, S>& rhs) const noexcept {
return !operator==(rhs);
}
template <typename S>
histogram &operator+=(const static_histogram<Axes, S> &rhs) {
histogram& operator+=(const static_histogram<Axes, S>& rhs) {
if (!detail::axes_equal(axes_, rhs.axes_))
throw std::invalid_argument("axes of histograms differ");
storage_ += rhs.storage_;
@ -124,34 +124,37 @@ public:
}
template <typename A, typename S>
histogram &operator+=(const dynamic_histogram<A, S> &rhs) {
histogram& operator+=(const dynamic_histogram<A, S>& rhs) {
if (!detail::axes_equal(axes_, rhs.axes_))
throw std::invalid_argument("axes of histograms differ");
storage_ += rhs.storage_;
return *this;
}
template <typename T> histogram &operator*=(const T &rhs) {
template <typename T>
histogram& operator*=(const T& rhs) {
storage_ *= rhs;
return *this;
}
template <typename T> histogram &operator/=(const T &rhs) {
template <typename T>
histogram& operator/=(const T& rhs) {
storage_ *= 1.0 / rhs;
return *this;
}
template <typename... Ts> void operator()(Ts &&... ts) {
template <typename... Ts>
void operator()(Ts&&... ts) {
// case with one argument is ambiguous, is specialized below
static_assert(sizeof...(Ts) == axes_size::value,
"fill arguments do not match histogram dimension");
std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, ts...);
if (stride)
detail::fill_storage(storage_, idx);
if (stride) detail::fill_storage(storage_, idx);
}
template <typename T> void operator()(T &&t) {
template <typename T>
void operator()(T&& t) {
// check whether we need to unpack argument
fill_impl(mp11::mp_if_c<(axes_size::value == 1), detail::no_container_tag,
detail::classify_container<T>>(),
@ -160,24 +163,24 @@ public:
// TODO: merge this with unpacking
template <typename W, typename... Ts>
void operator()(detail::weight<W> &&w, Ts &&... ts) {
void operator()(detail::weight<W>&& w, Ts&&... ts) {
// case with one argument is ambiguous, is specialized below
std::size_t idx = 0, stride = 1;
xlin<0>(idx, stride, ts...);
if (stride)
detail::fill_storage(storage_, idx, std::move(w));
if (stride) detail::fill_storage(storage_, idx, std::move(w));
}
// TODO: remove as obsolete
template <typename W, typename T>
void operator()(detail::weight<W> &&w, T &&t) {
void operator()(detail::weight<W>&& w, T&& t) {
// check whether we need to unpack argument
fill_impl(mp11::mp_if_c<(axes_size::value == 1), detail::no_container_tag,
detail::classify_container<T>>(),
std::forward<T>(t), std::move(w));
}
template <typename... Ts> const_reference at(Ts &&... ts) const {
template <typename... Ts>
const_reference at(Ts&&... ts) const {
// case with one argument is ambiguous, is specialized below
static_assert(sizeof...(ts) == axes_size::value,
"bin arguments do not match histogram dimension");
@ -186,12 +189,14 @@ public:
return detail::storage_get(storage_, idx, stride == 0);
}
template <typename T> const_reference operator[](T &&t) const {
template <typename T>
const_reference operator[](T&& t) const {
// check whether we need to unpack argument
return at_impl(detail::classify_container<T>(), std::forward<T>(t));
}
template <typename T> const_reference at(T &&t) const {
template <typename T>
const_reference at(T&& t) const {
// check whether we need to unpack argument
return at_impl(detail::classify_container<T>(), std::forward<T>(t));
}
@ -207,33 +212,34 @@ public:
/// Get N-th axis (const version)
template <int N>
typename std::add_const<typename std::tuple_element<N, axes_type>::type>::type
&axis(mp11::mp_int<N>) const {
typename std::add_const<typename std::tuple_element<N, axes_type>::type>::
type& axis(mp11::mp_int<N>) const {
static_assert(N < axes_size::value, "axis index out of range");
return std::get<N>(axes_);
}
/// Get N-th axis
template <int N>
typename std::tuple_element<N, axes_type>::type &axis(mp11::mp_int<N>) {
typename std::tuple_element<N, axes_type>::type& axis(mp11::mp_int<N>) {
static_assert(N < axes_size::value, "axis index out of range");
return std::get<N>(axes_);
}
// Get first axis (convenience for 1-d histograms, const version)
constexpr typename std::add_const<
typename std::tuple_element<0, axes_type>::type>::type &
typename std::tuple_element<0, axes_type>::type>::type&
axis() const {
return std::get<0>(axes_);
}
// Get first axis (convenience for 1-d histograms)
typename std::tuple_element<0, axes_type>::type &axis() {
typename std::tuple_element<0, axes_type>::type& axis() {
return std::get<0>(axes_);
}
/// Apply unary functor/function to each axis
template <typename Unary> void for_each_axis(Unary &&unary) const {
template <typename Unary>
void for_each_axis(Unary&& unary) const {
mp11::tuple_for_each(axes_, std::forward<Unary>(unary));
}
@ -242,8 +248,9 @@ public:
auto reduce_to(mp11::mp_int<N>, Ns...) const
-> static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>,
Storage> {
using HR = static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>,
Storage>;
using HR =
static_histogram<detail::selection<Axes, mp11::mp_int<N>, Ns...>,
Storage>;
auto hr =
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);
@ -251,9 +258,7 @@ public:
return hr;
}
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());
@ -271,10 +276,10 @@ private:
}
template <typename T, typename... Ts>
void fill_impl(detail::dynamic_container_tag, T &&t, Ts &&... ts) {
BOOST_ASSERT_MSG(std::distance(std::begin(t), std::end(t)) ==
axes_size::value,
"fill container does not match histogram dimension");
void fill_impl(detail::dynamic_container_tag, T&& t, Ts&&... ts) {
BOOST_ASSERT_MSG(
std::distance(std::begin(t), std::end(t)) == axes_size::value,
"fill container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
xlin_iter(axes_size(), idx, stride, std::begin(t));
if (stride) {
@ -283,7 +288,7 @@ private:
}
template <typename T, typename... Ts>
void fill_impl(detail::static_container_tag, T &&t, Ts &&... ts) {
void fill_impl(detail::static_container_tag, T&& t, Ts&&... ts) {
static_assert(detail::mp_size<T>::value == axes_size::value,
"fill container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -294,7 +299,7 @@ private:
}
template <typename T, typename... Ts>
void fill_impl(detail::no_container_tag, T &&t, Ts &&... ts) {
void fill_impl(detail::no_container_tag, T&& t, Ts&&... ts) {
static_assert(axes_size::value == 1,
"fill argument does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -305,17 +310,17 @@ private:
}
template <typename T>
const_reference at_impl(detail::dynamic_container_tag, T &&t) const {
BOOST_ASSERT_MSG(std::distance(std::begin(t), std::end(t)) ==
axes_size::value,
"bin container does not match histogram dimension");
const_reference at_impl(detail::dynamic_container_tag, T&& t) const {
BOOST_ASSERT_MSG(
std::distance(std::begin(t), std::end(t)) == axes_size::value,
"bin container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
lin_iter(axes_size(), idx, stride, std::begin(t));
return detail::storage_get(storage_, idx, stride == 0);
}
template <typename T>
const_reference at_impl(detail::static_container_tag, T &&t) const {
const_reference at_impl(detail::static_container_tag, T&& t) const {
static_assert(mp11::mp_size<T>::value == axes_size::value,
"bin container does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -324,18 +329,17 @@ private:
}
template <typename T>
const_reference at_impl(detail::no_container_tag, T &&t) const {
const_reference at_impl(detail::no_container_tag, T&& t) const {
std::size_t idx = 0, stride = 1;
lin<0>(idx, stride, detail::indirect_int_cast(t));
return detail::storage_get(storage_, idx, stride == 0);
}
template <unsigned D>
void xlin(std::size_t &, std::size_t &) const noexcept {}
void xlin(std::size_t&, std::size_t&) const noexcept {}
template <unsigned D, typename T, typename... Ts>
void xlin(std::size_t &idx, std::size_t &stride, T &&t,
Ts &&... ts) const {
void xlin(std::size_t& idx, std::size_t& stride, T&& t, Ts&&... ts) const {
const auto a_size = std::get<D>(axes_).size();
const auto a_shape = std::get<D>(axes_).shape();
const int j = std::get<D>(axes_).index(t);
@ -344,11 +348,11 @@ private:
}
template <typename Iterator>
void xlin_iter(mp11::mp_size_t<0>, std::size_t &, std::size_t &,
void xlin_iter(mp11::mp_size_t<0>, std::size_t&, std::size_t&,
Iterator) const noexcept {}
template <long unsigned int N, typename Iterator>
void xlin_iter(mp11::mp_size_t<N>, std::size_t &idx, std::size_t &stride,
void xlin_iter(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
Iterator iter) const {
constexpr unsigned D = axes_size::value - N;
const auto a_size = std::get<D>(axes_).size();
@ -359,10 +363,10 @@ private:
}
template <unsigned D>
void lin(std::size_t &, std::size_t &) const noexcept {}
void lin(std::size_t&, std::size_t&) const noexcept {}
template <unsigned D, typename... Ts>
void lin(std::size_t &idx, std::size_t &stride, int j, Ts... ts) const
void lin(std::size_t& idx, std::size_t& stride, int j, Ts... ts) const
noexcept {
const auto a_size = std::get<D>(axes_).size();
const auto a_shape = std::get<D>(axes_).shape();
@ -372,11 +376,11 @@ private:
}
template <typename Iterator>
void lin_iter(mp11::mp_size_t<0>, std::size_t &, std::size_t &,
void lin_iter(mp11::mp_size_t<0>, std::size_t&, std::size_t&,
Iterator) const noexcept {}
template <long unsigned int N, typename Iterator>
void lin_iter(mp11::mp_size_t<N>, std::size_t &idx, std::size_t &stride,
void lin_iter(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
Iterator iter) const noexcept {
constexpr unsigned D = axes_size::value - N;
const auto a_size = std::get<D>(axes_).size();
@ -388,12 +392,12 @@ private:
}
template <typename T>
void xlin_get(mp11::mp_size_t<0>, std::size_t &, std::size_t &, T &&) const
void xlin_get(mp11::mp_size_t<0>, std::size_t&, std::size_t&, T&&) const
noexcept {}
template <long unsigned int N, typename T>
void xlin_get(mp11::mp_size_t<N>, std::size_t &idx, std::size_t &stride,
T &&t) const {
void xlin_get(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
T&& t) const {
constexpr unsigned D = detail::mp_size<T>::value - N;
const auto a_size = std::get<D>(axes_).size();
const auto a_shape = std::get<D>(axes_).shape();
@ -403,12 +407,12 @@ private:
}
template <typename T>
void lin_get(mp11::mp_size_t<0>, std::size_t &, std::size_t &, T &&) const
void lin_get(mp11::mp_size_t<0>, std::size_t&, std::size_t&, T&&) const
noexcept {}
template <long unsigned int N, typename T>
void lin_get(mp11::mp_size_t<N>, std::size_t &idx, std::size_t &stride,
T &&t) const noexcept {
void lin_get(mp11::mp_size_t<N>, std::size_t& idx, std::size_t& stride,
T&& t) const noexcept {
constexpr unsigned D = detail::mp_size<T>::value - N;
const auto a_size = std::get<D>(axes_).size();
const auto a_shape = std::get<D>(axes_).shape();
@ -419,25 +423,26 @@ private:
}
template <typename H>
void reduce_impl(H &h, const std::vector<bool> &b) const {
void reduce_impl(H& h, const std::vector<bool>& b) const {
detail::shape_vector_visitor v(dim());
for_each_axis(v);
detail::index_mapper m(v.shapes, b);
do {
h.storage_.add(m.second, storage_[m.first]);
} while (m.next());
do { h.storage_.add(m.second, storage_[m.first]); } while (m.next());
}
template <typename T, typename A, typename S> friend class histogram;
template <typename H> friend class iterator_over;
template <typename T, typename A, typename S>
friend class histogram;
template <typename H>
friend class iterator_over;
friend class ::boost::serialization::access;
template <typename Archive> void serialize(Archive &, unsigned);
template <typename Archive>
void serialize(Archive&, unsigned);
};
/// default static type factory
template <typename... Axis>
static_histogram<mp11::mp_list<detail::rm_cv_ref<Axis>...>>
make_static_histogram(Axis &&... axis) {
make_static_histogram(Axis&&... axis) {
return static_histogram<mp11::mp_list<detail::rm_cv_ref<Axis>...>>(
std::forward<Axis>(axis)...);
}
@ -445,7 +450,7 @@ make_static_histogram(Axis &&... axis) {
/// static type factory with variable storage type
template <typename Storage, typename... Axis>
static_histogram<mp11::mp_list<detail::rm_cv_ref<Axis>...>, Storage>
make_static_histogram_with(Axis &&... axis) {
make_static_histogram_with(Axis&&... axis) {
return static_histogram<mp11::mp_list<detail::rm_cv_ref<Axis>...>, Storage>(
std::forward<Axis>(axis)...);
}

View File

@ -43,9 +43,10 @@ namespace detail {
using mp_int = ::boost::multiprecision::cpp_int;
using wcount = ::boost::histogram::weight_counter<double>;
template <typename T> inline T *alloc(std::size_t s) {
template <typename T>
inline T* alloc(std::size_t s) {
#ifdef BOOST_HISTOGRAM_TRACE_ALLOCS
boost::core::typeinfo const &ti = BOOST_CORE_TYPEID(T);
boost::core::typeinfo const& ti = BOOST_CORE_TYPEID(T);
std::cerr << "alloc " << boost::core::demangled_name(ti) << "[" << s << "]"
<< std::endl;
#endif
@ -56,10 +57,10 @@ class array_base {
public:
explicit array_base(const std::size_t s) : size(s) {}
array_base() = default;
array_base(const array_base &) = default;
array_base &operator=(const array_base &) = default;
array_base(array_base &&rhs) : size(rhs.size) { rhs.size = 0; }
array_base &operator=(array_base &&rhs) {
array_base(const array_base&) = default;
array_base& operator=(const array_base&) = default;
array_base(array_base&& rhs) : size(rhs.size) { rhs.size = 0; }
array_base& operator=(array_base&& rhs) {
if (this != &rhs) {
size = rhs.size;
rhs.size = 0;
@ -69,16 +70,17 @@ public:
std::size_t size = 0;
};
template <typename T> class array : public array_base {
template <typename T>
class array : public array_base {
public:
explicit array(const std::size_t s) : array_base(s), ptr(alloc<T>(s)) {
std::fill(begin(), end(), T(0));
}
array() = default;
array(const array &rhs) : array_base(rhs), ptr(alloc<T>(rhs.size)) {
array(const array& rhs) : array_base(rhs), ptr(alloc<T>(rhs.size)) {
std::copy(rhs.begin(), rhs.end(), begin());
}
array &operator=(const array &rhs) {
array& operator=(const array& rhs) {
if (this != &rhs) {
if (size != rhs.size) {
size = rhs.size;
@ -88,10 +90,10 @@ public:
}
return *this;
}
array(array &&rhs) : array_base(std::move(rhs)), ptr(std::move(rhs.ptr)) {
array(array&& rhs) : array_base(std::move(rhs)), ptr(std::move(rhs.ptr)) {
rhs.size = 0;
}
array &operator=(array &&rhs) {
array& operator=(array&& rhs) {
if (this != &rhs) {
size = rhs.size;
ptr = std::move(rhs.ptr);
@ -102,25 +104,26 @@ public:
// copy only up to nmax elements
template <typename U>
array(const array<U> &rhs,
array(const array<U>& rhs,
std::size_t nmax = std::numeric_limits<std::size_t>::max())
: array_base(rhs), ptr(alloc<T>(rhs.size)) {
std::copy(rhs.begin(), rhs.begin() + std::min(nmax, size), begin());
}
T &operator[](const std::size_t i) { return ptr[i]; }
const T &operator[](const std::size_t i) const { return ptr[i]; }
T& operator[](const std::size_t i) { return ptr[i]; }
const T& operator[](const std::size_t i) const { return ptr[i]; }
T *begin() { return ptr.get(); }
T *end() { return ptr.get() + size; }
const T *begin() const { return ptr.get(); }
const T *end() const { return ptr.get() + size; }
T* begin() { return ptr.get(); }
T* end() { return ptr.get() + size; }
const T* begin() const { return ptr.get(); }
const T* end() const { return ptr.get() + size; }
private:
std::unique_ptr<T[]> ptr;
};
template <> class array<void> : public array_base {
template <>
class array<void> : public array_base {
public:
using array_base::array_base;
};
@ -129,21 +132,36 @@ using any_array =
variant<array<void>, array<uint8_t>, array<uint16_t>, array<uint32_t>,
array<uint64_t>, array<mp_int>, array<wcount>>;
template <typename T> struct next_type;
template <> struct next_type<uint8_t> { using type = uint16_t; };
template <> struct next_type<uint16_t> { using type = uint32_t; };
template <> struct next_type<uint32_t> { using type = uint64_t; };
template <> struct next_type<uint64_t> { using type = mp_int; };
template <typename T> using next = typename next_type<T>::type;
template <typename T>
struct next_type;
template <>
struct next_type<uint8_t> {
using type = uint16_t;
};
template <>
struct next_type<uint16_t> {
using type = uint32_t;
};
template <>
struct next_type<uint32_t> {
using type = uint64_t;
};
template <>
struct next_type<uint64_t> {
using type = mp_int;
};
template <typename T>
using next = typename next_type<T>::type;
template <typename T> inline bool safe_increase(T &t) {
if (t == std::numeric_limits<T>::max())
return false;
template <typename T>
inline bool safe_increase(T& t) {
if (t == std::numeric_limits<T>::max()) return false;
++t;
return true;
}
template <typename T, typename U> inline bool safe_assign(T &t, const U &u) {
template <typename T, typename U>
inline bool safe_assign(T& t, const U& u) {
if (std::numeric_limits<T>::max() < std::numeric_limits<U>::max() &&
std::numeric_limits<T>::max() < u)
return false;
@ -151,57 +169,61 @@ template <typename T, typename U> inline bool safe_assign(T &t, const U &u) {
return true;
}
template <typename T, typename U> inline bool safe_radd(T &t, const U &u) {
if (static_cast<T>(std::numeric_limits<T>::max() - t) < u)
return false;
template <typename T, typename U>
inline bool safe_radd(T& t, const U& u) {
if (static_cast<T>(std::numeric_limits<T>::max() - t) < u) return false;
t += static_cast<T>(u);
return true;
}
// float rounding is a mess, the equal sign is necessary here
template <typename T> inline bool safe_radd(T &t, const double u) {
if ((std::numeric_limits<T>::max() - t) <= u)
return false;
template <typename T>
inline bool safe_radd(T& t, const double u) {
if ((std::numeric_limits<T>::max() - t) <= u) return false;
t += u;
return true;
}
struct size_visitor : public static_visitor<std::size_t> {
template <typename Array> std::size_t operator()(const Array &b) const {
template <typename Array>
std::size_t operator()(const Array& b) const {
return b.size;
}
};
template <typename RHS> struct assign_visitor : public static_visitor<void> {
any_array &lhs_any;
template <typename RHS>
struct assign_visitor : public static_visitor<void> {
any_array& lhs_any;
const std::size_t idx;
const RHS &rhs;
assign_visitor(any_array &a, const std::size_t i, const RHS &x)
const RHS& rhs;
assign_visitor(any_array& a, const std::size_t i, const RHS& x)
: lhs_any(a), idx(i), rhs(x) {}
template <typename T> void operator()(array<T> &lhs) const {
template <typename T>
void operator()(array<T>& lhs) const {
if (!safe_assign(lhs[idx], rhs)) {
lhs_any = array<next<T>>(lhs, idx);
operator()(get<array<next<T>>>(lhs_any));
}
}
void operator()(array<void> &lhs) const {
void operator()(array<void>& lhs) const {
lhs_any = array<uint8_t>(lhs.size);
operator()(get<array<uint8_t>>(lhs_any));
}
void operator()(array<mp_int> &lhs) const { lhs[idx].assign(rhs); }
void operator()(array<mp_int>& lhs) const { lhs[idx].assign(rhs); }
void operator()(array<wcount> &lhs) const { lhs[idx] = rhs; }
void operator()(array<wcount>& lhs) const { lhs[idx] = rhs; }
};
struct increase_visitor : public static_visitor<void> {
any_array &lhs_any;
any_array& lhs_any;
const std::size_t idx;
increase_visitor(any_array &a, const std::size_t i) : lhs_any(a), idx(i) {}
increase_visitor(any_array& a, const std::size_t i) : lhs_any(a), idx(i) {}
template <typename T> void operator()(array<T> &lhs) const {
template <typename T>
void operator()(array<T>& lhs) const {
if (!safe_increase(lhs[idx])) {
array<next<T>> a = lhs;
++a[idx];
@ -209,173 +231,182 @@ struct increase_visitor : public static_visitor<void> {
}
}
void operator()(array<void> &lhs) const {
void operator()(array<void>& lhs) const {
array<uint8_t> a(lhs.size);
++a[idx];
lhs_any = std::move(a);
}
void operator()(array<mp_int> &lhs) const { ++lhs[idx]; }
void operator()(array<mp_int>& lhs) const { ++lhs[idx]; }
void operator()(array<wcount> &lhs) const { ++lhs[idx]; }
void operator()(array<wcount>& lhs) const { ++lhs[idx]; }
};
struct bin_visitor : public static_visitor<wcount> {
const std::size_t idx;
bin_visitor(const std::size_t i) : idx(i) {}
template <typename Array> wcount operator()(const Array &b) const {
template <typename Array>
wcount operator()(const Array& b) const {
return wcount(static_cast<double>(b[idx]));
}
wcount operator()(const array<void> & /*b*/) const { return wcount(0.0); }
wcount operator()(const array<void>& /*b*/) const { return wcount(0.0); }
wcount operator()(const array<wcount> &b) const { return b[idx]; }
wcount operator()(const array<wcount>& b) const { return b[idx]; }
};
template <typename RHS> struct radd_visitor : public static_visitor<void> {
any_array &lhs_any;
template <typename RHS>
struct radd_visitor : public static_visitor<void> {
any_array& lhs_any;
const std::size_t idx;
const RHS &rhs;
radd_visitor(any_array &l, const std::size_t i, const RHS &r)
const RHS& rhs;
radd_visitor(any_array& l, const std::size_t i, const RHS& r)
: lhs_any(l), idx(i), rhs(r) {}
template <typename T> void operator()(array<T> &lhs) const {
template <typename T>
void operator()(array<T>& lhs) const {
if (!safe_radd(lhs[idx], rhs)) {
lhs_any = array<next<T>>(lhs);
operator()(get<array<next<T>>>(lhs_any));
}
}
void operator()(array<void> &lhs) const {
void operator()(array<void>& lhs) const {
if (rhs != 0) {
lhs_any = array<uint8_t>(lhs.size);
operator()(get<array<uint8_t>>(lhs_any));
}
}
void operator()(array<mp_int> &lhs) const {
void operator()(array<mp_int>& lhs) const {
lhs[idx] += static_cast<mp_int>(rhs);
}
void operator()(array<wcount> &lhs) const { lhs[idx] += rhs; }
void operator()(array<wcount>& lhs) const { lhs[idx] += rhs; }
};
template <> struct radd_visitor<mp_int> : public static_visitor<void> {
any_array &lhs_any;
template <>
struct radd_visitor<mp_int> : public static_visitor<void> {
any_array& lhs_any;
const std::size_t idx;
const mp_int &rhs;
radd_visitor(any_array &l, const std::size_t i, const mp_int &r)
const mp_int& rhs;
radd_visitor(any_array& l, const std::size_t i, const mp_int& r)
: lhs_any(l), idx(i), rhs(r) {}
template <typename T> void operator()(array<T> &lhs) const {
template <typename T>
void operator()(array<T>& lhs) const {
if (!safe_radd(lhs[idx], rhs)) {
lhs_any = array<next<T>>(lhs);
operator()(get<array<next<T>>>(lhs_any));
}
}
void operator()(array<void> &lhs) const {
void operator()(array<void>& lhs) const {
if (rhs != 0) {
lhs_any = array<uint8_t>(lhs.size);
operator()(get<array<uint8_t>>(lhs_any));
}
}
void operator()(array<mp_int> &lhs) const { lhs[idx] += rhs; }
void operator()(array<mp_int>& lhs) const { lhs[idx] += rhs; }
void operator()(array<wcount> &lhs) const {
void operator()(array<wcount>& lhs) const {
lhs[idx] += static_cast<double>(rhs);
}
};
template <> struct radd_visitor<wcount> : public static_visitor<void> {
any_array &lhs_any;
template <>
struct radd_visitor<wcount> : public static_visitor<void> {
any_array& lhs_any;
const std::size_t idx;
const wcount &rhs;
radd_visitor(any_array &l, const std::size_t i, const wcount &r)
const wcount& rhs;
radd_visitor(any_array& l, const std::size_t i, const wcount& r)
: lhs_any(l), idx(i), rhs(r) {}
template <typename T> void operator()(array<T> &lhs) const {
template <typename T>
void operator()(array<T>& lhs) const {
lhs_any = array<wcount>(lhs);
operator()(get<array<wcount>>(lhs_any));
}
void operator()(array<void> &lhs) const {
void operator()(array<void>& lhs) const {
lhs_any = array<wcount>(lhs.size);
operator()(get<array<wcount>>(lhs_any));
}
void operator()(array<wcount> &lhs) const { lhs[idx] += rhs; }
void operator()(array<wcount>& lhs) const { lhs[idx] += rhs; }
};
template <> struct radd_visitor<weight<double>> : public static_visitor<void> {
any_array &lhs_any;
template <>
struct radd_visitor<weight<double>> : public static_visitor<void> {
any_array& lhs_any;
const std::size_t idx;
const weight<double> rhs;
radd_visitor(any_array &l, const std::size_t i, const double w)
radd_visitor(any_array& l, const std::size_t i, const double w)
: lhs_any(l), idx(i), rhs{w} {}
template <typename T> void operator()(array<T> &lhs) const {
template <typename T>
void operator()(array<T>& lhs) const {
lhs_any = array<wcount>(lhs);
operator()(get<array<wcount>>(lhs_any));
}
void operator()(array<void> &lhs) const {
void operator()(array<void>& lhs) const {
lhs_any = array<wcount>(lhs.size);
operator()(get<array<wcount>>(lhs_any));
}
void operator()(array<wcount> &lhs) const { lhs[idx] += rhs; }
void operator()(array<wcount>& lhs) const { lhs[idx] += rhs; }
};
// precondition: both arrays must have same size and may not be identical
struct radd_array_visitor : public static_visitor<void> {
any_array &lhs_any;
radd_array_visitor(any_array &l) : lhs_any(l) {}
template <typename T> void operator()(const array<T> &rhs) const {
any_array& lhs_any;
radd_array_visitor(any_array& l) : lhs_any(l) {}
template <typename T>
void operator()(const array<T>& rhs) const {
for (std::size_t i = 0; i < rhs.size; ++i)
apply_visitor(radd_visitor<T>(lhs_any, i, rhs[i]), lhs_any);
}
void operator()(const array<void> &) const {}
void operator()(const array<void>&) const {}
};
struct rmul_visitor : public static_visitor<void> {
any_array &lhs_any;
any_array& lhs_any;
const double x;
rmul_visitor(any_array &l, const double v) : lhs_any(l), x(v) {}
template <typename T> void operator()(array<T> &lhs) const {
rmul_visitor(any_array& l, const double v) : lhs_any(l), x(v) {}
template <typename T>
void operator()(array<T>& lhs) const {
lhs_any = array<wcount>(lhs);
operator()(get<array<wcount>>(lhs_any));
}
void operator()(array<void> &) const {}
void operator()(array<wcount> &lhs) const {
for (std::size_t i = 0; i != lhs.size; ++i)
lhs[i] *= x;
void operator()(array<void>&) const {}
void operator()(array<wcount>& lhs) const {
for (std::size_t i = 0; i != lhs.size; ++i) lhs[i] *= x;
}
};
struct bicmp_visitor : public static_visitor<bool> {
template <typename T, typename U>
bool operator()(const array<T> &b1, const array<U> &b2) const {
if (b1.size != b2.size)
return false;
bool operator()(const array<T>& b1, const array<U>& b2) const {
if (b1.size != b2.size) return false;
return std::equal(b1.begin(), b1.end(), b2.begin());
}
template <typename T>
bool operator()(const array<T> &b1, const array<void> &b2) const {
if (b1.size != b2.size)
return false;
return std::all_of(b1.begin(), b1.end(), [](const T &t) { return t == 0; });
bool operator()(const array<T>& b1, const array<void>& b2) const {
if (b1.size != b2.size) return false;
return std::all_of(b1.begin(), b1.end(),
[](const T& t) { return t == 0; });
}
template <typename T>
bool operator()(const array<void> &b1, const array<T> &b2) const {
bool operator()(const array<void>& b1, const array<T>& b2) const {
return operator()(b2, b1);
}
bool operator()(const array<void> &b1, const array<void> &b2) const {
bool operator()(const array<void>& b1, const array<void>& b2) const {
return b1.size == b2.size;
}
};
@ -389,16 +420,17 @@ public:
using element_type = detail::wcount;
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(const adaptive_storage &) = default;
adaptive_storage &operator=(const adaptive_storage &) = default;
adaptive_storage(adaptive_storage &&) = default;
adaptive_storage &operator=(adaptive_storage &&) = default;
adaptive_storage(const adaptive_storage&) = default;
adaptive_storage& operator=(const adaptive_storage&) = default;
adaptive_storage(adaptive_storage&&) = default;
adaptive_storage& operator=(adaptive_storage&&) = default;
template <typename RHS>
explicit adaptive_storage(const RHS &rhs)
explicit adaptive_storage(const RHS& rhs)
: buffer_(detail::array<void>(rhs.size())) {
using T = typename RHS::element_type;
for (std::size_t i = 0, n = rhs.size(); i < n; ++i) {
@ -406,12 +438,11 @@ public:
}
}
template <typename RHS> adaptive_storage &operator=(const RHS &rhs) {
template <typename RHS>
adaptive_storage& operator=(const RHS& rhs) {
// no check for self-assign needed, default operator above is better match
const auto n = rhs.size();
if (size() != n) {
buffer_ = detail::array<void>(n);
}
if (size() != n) { buffer_ = detail::array<void>(n); }
using T = typename RHS::element_type;
for (std::size_t i = 0; i < n; ++i) {
apply_visitor(detail::assign_visitor<T>(buffer_, i, rhs[i]), buffer_);
@ -421,7 +452,7 @@ public:
// used in unit tests
template <typename T>
explicit adaptive_storage(const detail::array<T> &a) : buffer_(a) {}
explicit adaptive_storage(const detail::array<T>& a) : buffer_(a) {}
std::size_t size() const {
return apply_visitor(detail::size_visitor(), buffer_);
@ -431,20 +462,23 @@ public:
apply_visitor(detail::increase_visitor(buffer_, i), buffer_);
}
void add(std::size_t i, const element_type &x) {
void add(std::size_t i, const element_type& x) {
if (x.variance() == x.value()) {
apply_visitor(detail::radd_visitor<double>(buffer_, i, x.value()),
buffer_);
} else {
apply_visitor(detail::radd_visitor<element_type>(buffer_, i, x), buffer_);
apply_visitor(detail::radd_visitor<element_type>(buffer_, i, x),
buffer_);
}
}
template <typename T> void add(std::size_t i, const T &t) {
template <typename T>
void add(std::size_t i, const T& t) {
apply_visitor(detail::radd_visitor<T>(buffer_, i, t), buffer_);
}
template <typename T> void add(std::size_t i, const detail::weight<T> &w) {
template <typename T>
void add(std::size_t i, const detail::weight<T>& w) {
apply_visitor(
detail::radd_visitor<detail::weight<double>>(buffer_, i, w.value),
buffer_);
@ -454,12 +488,12 @@ public:
return apply_visitor(detail::bin_visitor(i), buffer_);
}
bool operator==(const adaptive_storage &rhs) const {
bool operator==(const adaptive_storage& rhs) const {
return apply_visitor(detail::bicmp_visitor(), buffer_, rhs.buffer_);
}
// precondition: storages have same size
adaptive_storage &operator+=(const adaptive_storage &rhs) {
adaptive_storage& operator+=(const adaptive_storage& rhs) {
if (this == &rhs) {
for (std::size_t i = 0, n = size(); i < n; ++i) {
add(i, rhs[i]); // may lose precision
@ -471,15 +505,17 @@ public:
}
// precondition: storages have same size
template <typename RHS> adaptive_storage &operator+=(const RHS &rhs) {
template <typename RHS>
adaptive_storage& operator+=(const RHS& rhs) {
for (std::size_t i = 0, n = size(); i < n; ++i)
apply_visitor(
detail::radd_visitor<typename RHS::element_type>(buffer_, i, rhs[i]),
buffer_);
apply_visitor(detail::radd_visitor<typename RHS::element_type>(
buffer_, i, rhs[i]),
buffer_);
return *this;
}
template <typename T> adaptive_storage &operator*=(const T &x) {
template <typename T>
adaptive_storage& operator*=(const T& x) {
apply_visitor(detail::rmul_visitor(buffer_, x), buffer_);
return *this;
}
@ -489,7 +525,8 @@ private:
friend class ::boost::python::access;
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned);
template <class Archive>
void serialize(Archive&, unsigned);
};
} // namespace histogram

View File

@ -22,10 +22,11 @@ class access;
namespace boost {
namespace histogram {
template <typename T> class array_storage {
template <typename T>
class array_storage {
public:
using element_type = T;
using const_reference = const T &;
using const_reference = const T&;
explicit array_storage(std::size_t s)
: size_(s), array_(new element_type[s]) {
@ -33,22 +34,22 @@ public:
}
array_storage() = default;
array_storage(const array_storage &other)
array_storage(const array_storage& other)
: size_(other.size()), array_(new element_type[other.size()]) {
std::copy(other.array_.get(), other.array_.get() + size_, array_.get());
}
array_storage &operator=(const array_storage &other) {
array_storage& operator=(const array_storage& other) {
if (this != &other) {
reset(other.size());
std::copy(other.array_.get(), other.array_.get() + size_, array_.get());
}
return *this;
}
array_storage(array_storage &&other) {
array_storage(array_storage&& other) {
std::swap(size_, other.size_);
std::swap(array_, other.array_);
}
array_storage &operator=(array_storage &&other) {
array_storage& operator=(array_storage&& other) {
if (this != &other) {
std::swap(size_, other.size_);
std::swap(array_, other.array_);
@ -57,14 +58,14 @@ public:
}
template <typename S, typename = detail::requires_storage<S>>
explicit array_storage(const S &other) {
explicit array_storage(const S& other) {
reset(other.size());
for (std::size_t i = 0; i < size_; ++i)
array_[i] = static_cast<element_type>(other[i]);
}
template <typename S, typename = detail::requires_storage<S>>
array_storage &operator=(const S &other) {
array_storage& operator=(const S& other) {
reset(other.size());
for (std::size_t i = 0; i < size_; ++i)
array_[i] = static_cast<element_type>(other[i]);
@ -75,28 +76,30 @@ public:
void increase(std::size_t i) noexcept { ++array_[i]; }
template <typename U> void add(std::size_t i, const U &x) noexcept {
template <typename U>
void add(std::size_t i, const U& x) noexcept {
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>
bool operator==(const array_storage<U> &rhs) const noexcept {
if (size_ != rhs.size_)
return false;
bool operator==(const array_storage<U>& rhs) const noexcept {
if (size_ != rhs.size_) return false;
return std::equal(array_.get(), array_.get() + size_, rhs.array_.get());
}
template <typename S> array_storage &operator+=(const S &rhs) noexcept {
for (std::size_t i = 0; i < size_; ++i)
add(i, rhs[i]);
template <typename S>
array_storage& operator+=(const S& rhs) noexcept {
for (std::size_t i = 0; i < size_; ++i) add(i, rhs[i]);
return *this;
}
template <typename U> array_storage &operator*=(const U &x) noexcept {
for (std::size_t i = 0; i < size_; ++i)
array_[i] *= x;
template <typename U>
array_storage& operator*=(const U& x) noexcept {
for (std::size_t i = 0; i < size_; ++i) array_[i] *= x;
return *this;
}
@ -109,10 +112,12 @@ private:
array_.reset(new element_type[size]);
}
template <typename U> friend class array_storage;
template <typename U>
friend class array_storage;
friend class ::boost::serialization::access;
template <typename Archive> void serialize(Archive &, unsigned);
template <typename Archive>
void serialize(Archive&, unsigned);
};
} // namespace histogram

View File

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

View File

@ -19,145 +19,152 @@ class access;
namespace histogram {
/// Double counter which holds a sum of weights and a sum of squared weights
template <typename RealType> class weight_counter {
template <typename RealType>
class weight_counter {
public:
/// Beware: For performance reasons counters are not initialized
weight_counter() = default;
weight_counter(const weight_counter &) = default;
weight_counter(weight_counter &&) = default;
weight_counter &operator=(const weight_counter &) = default;
weight_counter &operator=(weight_counter &&) = default;
weight_counter(const weight_counter&) = default;
weight_counter(weight_counter&&) = default;
weight_counter& operator=(const weight_counter&) = default;
weight_counter& operator=(weight_counter&&) = default;
weight_counter(const RealType &value, const RealType &variance) noexcept
weight_counter(const RealType& value, const RealType& variance) noexcept
: w(value),
w2(variance) {}
explicit weight_counter(const RealType &value) noexcept : w(value),
explicit weight_counter(const RealType& value) noexcept : w(value),
w2(value) {}
weight_counter &operator++() {
weight_counter& operator++() {
++w;
++w2;
return *this;
}
// TODO: explain why this is needed
weight_counter &operator+=(const RealType &x) {
weight_counter& operator+=(const RealType& x) {
w += x;
w2 += x;
return *this;
}
template <typename T>
weight_counter &operator+=(const weight_counter<T> &rhs) {
weight_counter& operator+=(const weight_counter<T>& rhs) {
w += static_cast<RealType>(rhs.w);
w2 += static_cast<RealType>(rhs.w2);
return *this;
}
template <typename T>
weight_counter &operator+=(const detail::weight<T> &rhs) {
weight_counter& operator+=(const detail::weight<T>& rhs) {
const auto x = static_cast<RealType>(rhs.value);
w += x;
w2 += x * x;
return *this;
}
weight_counter &operator*=(const RealType &x) {
weight_counter& operator*=(const RealType& x) {
w *= x;
w2 *= x * x;
return *this;
}
bool operator==(const weight_counter &rhs) const noexcept {
bool operator==(const weight_counter& rhs) const noexcept {
return w == rhs.w && w2 == rhs.w2;
}
bool operator!=(const weight_counter &rhs) const noexcept {
bool operator!=(const weight_counter& rhs) const noexcept {
return !operator==(rhs);
}
template <typename T>
bool operator==(const weight_counter<T> &rhs) const noexcept {
bool operator==(const weight_counter<T>& rhs) const noexcept {
return w == rhs.w && w2 == rhs.w2;
}
template <typename T>
bool operator!=(const weight_counter<T> &rhs) const noexcept {
bool operator!=(const weight_counter<T>& rhs) const noexcept {
return !operator==(rhs);
}
const RealType &value() const noexcept { return w; }
const RealType &variance() const noexcept { return w2; }
const RealType& value() const noexcept { return w; }
const RealType& variance() const noexcept { return w2; }
// conversion
template <typename T> explicit weight_counter(const T &t) { operator=(t); }
template <typename T> weight_counter &operator=(const T &x) {
template <typename T>
explicit weight_counter(const T& t) {
operator=(t);
}
template <typename T>
weight_counter& operator=(const T& x) {
w = w2 = static_cast<RealType>(x);
return *this;
}
// lossy conversion must be explicit
template <typename T> explicit operator T() const {
template <typename T>
explicit operator T() const {
return static_cast<T>(w);
}
private:
friend class ::boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned /* version */);
template <class Archive>
void serialize(Archive&, unsigned /* version */);
RealType w, w2;
};
template <typename T, typename U>
bool operator==(const weight_counter<T> &w, const U &u) {
bool operator==(const weight_counter<T>& w, const U& u) {
return w.value() == w.variance() && w.value() == static_cast<T>(u);
}
template <typename T, typename U>
bool operator==(const T &t, const weight_counter<U> &w) {
bool operator==(const T& t, const weight_counter<U>& w) {
return operator==(w, t);
}
template <typename T, typename U>
bool operator!=(const weight_counter<T> &w, const U &u) {
bool operator!=(const weight_counter<T>& w, const U& u) {
return !operator==(w, u);
}
template <typename T, typename U>
bool operator!=(const T &t, const weight_counter<U> &w) {
bool operator!=(const T& t, const weight_counter<U>& w) {
return operator!=(w, t);
}
template <typename T>
weight_counter<T> operator+(const weight_counter<T> &a,
const weight_counter<T> &b) noexcept {
weight_counter<T> operator+(const weight_counter<T>& a,
const weight_counter<T>& b) noexcept {
weight_counter<T> c = a;
return c += b;
}
template <typename T>
weight_counter<T> &&operator+(weight_counter<T> &&a,
const weight_counter<T> &b) noexcept {
weight_counter<T>&& operator+(weight_counter<T>&& a,
const weight_counter<T>& b) noexcept {
a += b;
return std::move(a);
}
template <typename T>
weight_counter<T> &&operator+(const weight_counter<T> &a,
weight_counter<T> &&b) noexcept {
weight_counter<T>&& operator+(const weight_counter<T>& a,
weight_counter<T>&& b) noexcept {
return operator+(std::move(b), a);
}
template <typename T>
weight_counter<T> operator+(const weight_counter<T> &a, const T &b) noexcept {
weight_counter<T> operator+(const weight_counter<T>& a, const T& b) noexcept {
auto r = a;
return r += b;
}
template <typename T>
weight_counter<T> operator+(const T &a, const weight_counter<T> &b) noexcept {
weight_counter<T> operator+(const T& a, const weight_counter<T>& b) noexcept {
auto r = b;
return r += a;
}

View File

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

View File

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

View File

@ -31,11 +31,11 @@ namespace detail {
class python_bytes_sink : public iostreams::sink {
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);
}
std::streamsize write(const char *s, std::streamsize n) {
std::streamsize write(const char* s, std::streamsize n) {
if (len_ == 0) {
*pstr_ = PyBytes_FromStringAndSize(s, n);
if (*pstr_ == 0) // no point trying to recover from allocation error
@ -47,7 +47,7 @@ public:
if (_PyBytes_Resize(pstr_, len_) == -1)
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_);
}
pos_ += n;
@ -55,17 +55,18 @@ public:
}
private:
PyObject **pstr_;
PyObject** pstr_;
std::streamsize len_, pos_;
};
} // 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) {
PyObject *pobj = 0;
PyObject* pobj = 0;
iostreams::stream<detail::python_bytes_sink> os(&pobj);
archive::text_oarchive oa(os);
oa << python::extract<const T &>(obj)();
oa << python::extract<const T&>(obj)();
os.flush();
return python::make_tuple(obj.attr("__dict__"),
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()),
PyBytes_Size(o.ptr()));
archive::text_iarchive ia(is);
ia >> python::extract<T &>(obj)();
ia >> python::extract<T&>(obj)();
}
static bool getstate_manages_dict() { return true; }

View File

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

View File

@ -18,18 +18,21 @@
using namespace boost::histogram;
template <typename T> adaptive_storage prepare(std::size_t n) {
template <typename T>
adaptive_storage prepare(std::size_t n) {
auto a = detail::array<T>(n);
return adaptive_storage(a);
}
template <typename T> adaptive_storage prepare(std::size_t n, const T x) {
template <typename T>
adaptive_storage prepare(std::size_t n, const T x) {
auto a = detail::array<T>(n);
a[0] = x;
return adaptive_storage(a);
}
template <typename T> void copy_impl() {
template <typename T>
void copy_impl() {
const auto b = prepare<T>(1);
auto a(b);
BOOST_TEST(a == b);
@ -47,7 +50,8 @@ template <typename T> void copy_impl() {
}
#ifdef HAVE_SERIALIZATION
template <typename T> void serialization_impl() {
template <typename T>
void serialization_impl() {
const auto a = prepare(1, T(1));
std::ostringstream os;
std::string buf;
@ -67,7 +71,8 @@ template <typename T> void serialization_impl() {
BOOST_TEST(a == b);
}
template <> void serialization_impl<void>() {
template <>
void serialization_impl<void>() {
adaptive_storage a(std::size_t(1));
std::ostringstream os;
std::string buf;
@ -88,7 +93,8 @@ template <> void serialization_impl<void>() {
}
#endif
template <typename T> void equal_impl() {
template <typename T>
void equal_impl() {
adaptive_storage a(std::size_t(1));
auto b = prepare(1, T(0));
BOOST_TEST_EQ(a[0].value(), 0.0);
@ -104,7 +110,8 @@ template <typename T> void equal_impl() {
BOOST_TEST(!(c == d));
}
template <> void equal_impl<void>() {
template <>
void equal_impl<void>() {
adaptive_storage a(std::size_t(1));
auto b = prepare<uint8_t>(1, 0);
auto c = prepare<uint8_t>(2, 0);
@ -125,7 +132,8 @@ template <> void equal_impl<void>() {
BOOST_TEST(!(d == a));
}
template <typename T> void increase_and_grow_impl() {
template <typename T>
void increase_and_grow_impl() {
auto tmax = std::numeric_limits<T>::max();
auto s = prepare(2, tmax);
auto n = s;
@ -145,7 +153,8 @@ template <typename T> void increase_and_grow_impl() {
BOOST_TEST_EQ(n2[1].value(), 0.0);
}
template <> void increase_and_grow_impl<void>() {
template <>
void increase_and_grow_impl<void>() {
adaptive_storage s(std::size_t(2));
BOOST_TEST_EQ(s[0].value(), 0);
BOOST_TEST_EQ(s[1].value(), 0);
@ -154,7 +163,8 @@ template <> void increase_and_grow_impl<void>() {
BOOST_TEST_EQ(s[1].value(), 0);
}
template <typename T> void convert_array_storage_impl() {
template <typename T>
void convert_array_storage_impl() {
const auto aref = prepare(1, T(0));
array_storage<uint8_t> s(std::size_t(1));
s.increase(0);
@ -180,8 +190,7 @@ template <typename T> void convert_array_storage_impl() {
array_storage<float> t(std::size_t(1));
t.increase(0);
while (t[0] < 1e20)
t.add(0, t[0]);
while (t[0] < 1e20) t.add(0, t[0]);
auto d = aref;
d = t;
BOOST_TEST(d == t);
@ -213,7 +222,8 @@ template <typename T> void convert_array_storage_impl() {
BOOST_TEST(h == u);
}
template <> void convert_array_storage_impl<void>() {
template <>
void convert_array_storage_impl<void>() {
const auto aref = adaptive_storage(std::size_t(1));
BOOST_TEST_EQ(aref[0].value(), 0.0);
array_storage<uint8_t> s(std::size_t(1));
@ -238,7 +248,8 @@ template <> void convert_array_storage_impl<void>() {
BOOST_TEST(!(d == t));
}
template <typename LHS, typename RHS> void add_impl() {
template <typename LHS, typename RHS>
void add_impl() {
auto a = prepare<LHS>(2);
auto b = prepare<RHS>(2);
if (std::is_same<RHS, void>::value) {
@ -255,7 +266,8 @@ template <typename LHS, typename RHS> void add_impl() {
}
}
template <typename LHS> void add_impl_all_rhs() {
template <typename LHS>
void add_impl_all_rhs() {
add_impl<LHS, void>();
add_impl<LHS, uint8_t>();
add_impl<LHS, uint16_t>();

View File

@ -21,7 +21,7 @@ using namespace boost::histogram;
#define BOOST_TEST_IS_CLOSE(a, b, eps) BOOST_TEST(std::abs(a - b) < eps)
template <typename Axis>
void test_axis_iterator(const Axis &a, int begin, int end) {
void test_axis_iterator(const Axis& a, int begin, int end) {
for (auto bin : a) {
BOOST_TEST_EQ(bin.idx(), begin);
BOOST_TEST_EQ(bin, a[begin]);
@ -62,7 +62,8 @@ int main() {
{
axis::regular<> a{4, -2, 2};
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;
BOOST_TEST_NOT(a == b);
b = a;
@ -160,7 +161,8 @@ int main() {
{
axis::variable<> a{-1, 0, 1};
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;
BOOST_TEST_NOT(a == b);
b = a;
@ -269,7 +271,8 @@ int main() {
a6 = a1;
BOOST_TEST_EQ(a6, a1);
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);
}
@ -299,14 +302,13 @@ int main() {
axes.push_back(axis::regular<double, axis::transform::pow>(
2, 1, 10, "regular4", axis::uoflow::off, -0.5));
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<std::string>({a, b}, "category2"));
axes.push_back(axis::integer<>(-1, 1, "integer", axis::uoflow::off));
std::ostringstream os;
for (const auto &a : axes) {
os << a << "\n";
}
for (const auto& a : axes) { os << a << "\n"; }
const std::string ref =
"regular(2, -1, 1, label='regular1')\n"
"regular_log(2, 1, 10, label='regular2', uoflow=False)\n"
@ -329,7 +331,7 @@ int main() {
axes.push_back(axis::variable<>{-1, 0, 1});
axes.push_back(axis::category<>{A, B, C});
axes.push_back(axis::integer<>{-1, 1});
for (const auto &a : axes) {
for (const auto& a : axes) {
BOOST_TEST(!(a == axis::any_std()));
BOOST_TEST_EQ(a, a);
}
@ -342,7 +344,7 @@ int main() {
std::string a = "A", b = "B";
axis::any_std x = axis::category<std::string>({a, b}, "category");
BOOST_TEST_THROWS(x.index(1.5), std::runtime_error);
const auto &cx = axis::cast<axis::category<std::string>>(x);
const auto& cx = axis::cast<axis::category<std::string>>(x);
BOOST_TEST_EQ(cx.index(b), 1);
}
@ -354,7 +356,8 @@ int main() {
std_vector1 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
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},
axis::category<>{{A, B, C}}};
@ -376,8 +379,8 @@ int main() {
std::make_tuple(axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
axis::category<>{{A, B}});
auto tuple3 =
std::make_tuple(axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1});
auto tuple3 = std::make_tuple(axis::regular<>{2, -1, 1},
axis::variable<>{-1, 0, 1});
BOOST_TEST(detail::axes_equal(std_vector1, tuple1));
BOOST_TEST(detail::axes_equal(tuple1, std_vector1));
@ -394,7 +397,8 @@ int main() {
std_vector1 = {axis::regular<>{2, -1, 1}, axis::variable<>{-1, 0, 1},
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},
axis::category<>{A, B}};

View File

@ -29,21 +29,24 @@ using i2 = mp11::mp_int<2>;
using i3 = mp11::mp_int<3>;
namespace std { // never add to std, we only do it to get ADL working
template <typename T> ostream &operator<<(ostream &os, const vector<T> &v) {
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
os << "[ ";
for (const auto &x : v)
os << x << " ";
for (const auto& x : v) os << x << " ";
os << "]";
return os;
}
struct ostreamer {
ostream &os;
template <typename T> void operator()(const T &t) const { os << t << " "; }
ostream& os;
template <typename T>
void operator()(const T& t) const {
os << t << " ";
}
};
template <typename... Ts>
ostream &operator<<(ostream &os, const tuple<Ts...> &t) {
ostream& operator<<(ostream& os, const tuple<Ts...>& t) {
os << "[ ";
::boost::mp11::tuple_for_each(t, ostreamer{os});
os << "]";
@ -135,16 +138,16 @@ int main() {
struct no_methods {};
struct value_method {
const double &value() const;
const double& value() const;
};
struct variance_method {
const double &variance() const;
const double& variance() const;
};
struct value_and_variance_methods {
const double &value() const;
const double &variance() const;
const double& value() const;
const double& variance() const;
};
BOOST_TEST_EQ(has_variance_support<no_methods>(), false);
@ -158,19 +161,19 @@ int main() {
using result1 = classify_container<int>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result1, no_container_tag>));
using result1a = classify_container<int &>;
using result1a = classify_container<int&>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result1a, no_container_tag>));
using result2 = classify_container<std::vector<int>>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result2, dynamic_container_tag>));
using result2a = classify_container<std::vector<int> &>;
using result2a = classify_container<std::vector<int>&>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result2a, dynamic_container_tag>));
using result3 = classify_container<std::pair<int, int>>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result3, static_container_tag>));
using result3a = classify_container<std::pair<int, int> &>;
using result3a = classify_container<std::pair<int, int>&>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result3a, static_container_tag>));
using result4 = classify_container<decltype("abc")>;
@ -190,10 +193,10 @@ int main() {
{
using T1 = int;
using T2 = const int;
using T3 = const int &;
using T3 = const int&;
using T4 = volatile int;
using T5 = volatile const int;
using T6 = volatile const int &;
using T6 = volatile const int&;
BOOST_TEST_TRAIT_TRUE((std::is_same<rm_cv_ref<T1>, int>));
BOOST_TEST_TRAIT_TRUE((std::is_same<rm_cv_ref<T2>, int>));
BOOST_TEST_TRAIT_TRUE((std::is_same<rm_cv_ref<T3>, int>));
@ -205,9 +208,9 @@ int main() {
// mp_union
{
using L1 = mp11::mp_list<int, char, long>;
using L2 = mp11::mp_list<char, char *>;
using L2 = mp11::mp_list<char, char*>;
using result = mp_union<L1, L2>;
using expected = mp11::mp_list<int, char, long, char *>;
using expected = mp11::mp_list<int, char, long, char*>;
BOOST_TEST_TRAIT_TRUE((std::is_same<result, expected>));
}

View File

@ -3,6 +3,7 @@
using namespace boost::histogram;
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));
}

View File

@ -3,6 +3,7 @@
using namespace boost::histogram;
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}));
}

View File

@ -3,6 +3,7 @@
using namespace boost::histogram;
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));
}

View File

@ -33,13 +33,13 @@ using namespace boost::histogram::literals; // to get _c suffix
namespace mp11 = boost::mp11;
template <typename S, typename... Axes>
auto make_histogram(static_tag, Axes &&... axes)
auto make_histogram(static_tag, Axes&&... axes)
-> decltype(make_static_histogram_with<S>(std::forward<Axes>(axes)...)) {
return make_static_histogram_with<S>(std::forward<Axes>(axes)...);
}
template <typename S, typename... Axes>
auto make_histogram(dynamic_tag, Axes &&... axes)
auto make_histogram(dynamic_tag, Axes&&... axes)
-> decltype(make_dynamic_histogram_with<S>(std::forward<Axes>(axes)...)) {
return make_dynamic_histogram_with<S>(std::forward<Axes>(axes)...);
}
@ -51,15 +51,16 @@ int expected_moved_from_dim(static_tag, int static_value) {
int expected_moved_from_dim(dynamic_tag, int) { return 0; }
template <typename Histogram>
typename Histogram::element_type sum(const Histogram &h) {
typename Histogram::element_type sum(const Histogram& h) {
return std::accumulate(h.begin(), h.end(),
typename Histogram::element_type(0));
}
template <typename... Ts>
void pass_histogram(boost::histogram::histogram<Ts...> &) {}
void pass_histogram(boost::histogram::histogram<Ts...>&) {}
template <typename Type> void run_tests() {
template <typename Type>
void run_tests() {
// init_1
{
@ -76,8 +77,8 @@ template <typename Type> void run_tests() {
// init_2
{
auto h = make_histogram<adaptive_storage>(Type(), axis::regular<>{3, -1, 1},
axis::integer<>{-1, 2});
auto h = make_histogram<adaptive_storage>(
Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2});
BOOST_TEST_EQ(h.dim(), 2);
BOOST_TEST_EQ(h.size(), 25);
BOOST_TEST_EQ(h.axis(0_c).shape(), 5);
@ -89,9 +90,9 @@ template <typename Type> void run_tests() {
// init_3
{
auto h = make_histogram<adaptive_storage>(Type(), axis::regular<>{3, -1, 1},
axis::integer<>{-1, 2},
axis::circular<>{3});
auto h = make_histogram<adaptive_storage>(
Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2},
axis::circular<>{3});
BOOST_TEST_EQ(h.dim(), 3);
BOOST_TEST_EQ(h.size(), 75);
auto h2 = make_histogram<array_storage<unsigned>>(
@ -136,8 +137,9 @@ template <typename Type> void run_tests() {
h(0, 0);
auto h2 = decltype(h)(h);
BOOST_TEST(h2 == h);
auto h3 = static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>,
array_storage<unsigned>>(h);
auto h3 =
static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>,
array_storage<unsigned>>(h);
BOOST_TEST_EQ(h3, h);
}
@ -153,8 +155,9 @@ template <typename Type> void run_tests() {
// test self-assign
h2 = h2;
BOOST_TEST_EQ(h, h2);
auto h3 = static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>,
array_storage<unsigned>>();
auto h3 =
static_histogram<mp11::mp_list<axis::integer<>, axis::integer<>>,
array_storage<unsigned>>();
h3 = h;
BOOST_TEST_EQ(h, h3);
}
@ -183,8 +186,8 @@ template <typename Type> void run_tests() {
// axis methods
{
enum { A = 3, B = 5 };
auto a = make_histogram<adaptive_storage>(Type(),
axis::regular<>(1, 1, 2, "foo"));
auto a = make_histogram<adaptive_storage>(
Type(), axis::regular<>(1, 1, 2, "foo"));
BOOST_TEST_EQ(a.axis().size(), 1);
BOOST_TEST_EQ(a.axis().shape(), 3);
BOOST_TEST_EQ(a.axis().index(1), 0);
@ -203,7 +206,8 @@ template <typename Type> void run_tests() {
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().shape(), 2);
BOOST_TEST_EQ(c.axis().index(A), 0);
@ -227,7 +231,8 @@ template <typename Type> void run_tests() {
BOOST_TEST(c != b);
BOOST_TEST(a == c);
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(d != c);
c(0);
@ -425,8 +430,8 @@ template <typename Type> void run_tests() {
// add_1
{
auto a = make_histogram<adaptive_storage>(Type(), axis::integer<>(0, 2));
auto b =
make_histogram<array_storage<unsigned>>(Type(), axis::integer<>(0, 2));
auto b = make_histogram<array_storage<unsigned>>(Type(),
axis::integer<>(0, 2));
a(0); // 1 0
b(1); // 0 1
auto a2 = a;
@ -477,8 +482,8 @@ template <typename Type> void run_tests() {
{
auto a =
make_histogram<array_storage<char>>(Type(), axis::integer<>(-1, 2));
auto b =
make_histogram<array_storage<unsigned>>(Type(), axis::integer<>(-1, 2));
auto b = make_histogram<array_storage<unsigned>>(Type(),
axis::integer<>(-1, 2));
a(-1);
b(1);
auto c = a;
@ -578,10 +583,11 @@ template <typename Type> void run_tests() {
Type(), axis::regular<>(3, -1, 1, "r"), axis::integer<>(0, 2, "i"));
std::ostringstream os;
os << a;
BOOST_TEST_EQ(os.str(), "histogram("
"\n regular(3, -1, 1, label='r'),"
"\n integer(0, 2, label='i'),"
"\n)");
BOOST_TEST_EQ(os.str(),
"histogram("
"\n regular(3, -1, 1, label='r'),"
"\n integer(0, 2, label='i'),"
"\n)");
}
// histogram_reset
@ -701,7 +707,7 @@ template <typename Type> void run_tests() {
// custom axis
{
struct custom_axis : public 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
@ -727,7 +733,7 @@ template <typename Type> void run_tests() {
// histogram iterator 1D
{
auto h = make_histogram<adaptive_storage>(Type(), axis::integer<>(0, 3));
const auto &a = h.axis();
const auto& a = h.axis();
h(weight(2), 0);
h(1);
h(1);
@ -763,8 +769,8 @@ template <typename Type> void run_tests() {
auto h = make_histogram<adaptive_storage>(
Type(), axis::integer<>(0, 1),
axis::integer<>(2, 4, "", axis::uoflow::off));
const auto &a0 = h.axis(0_c);
const auto &a1 = h.axis(1_c);
const auto& a0 = h.axis(0_c);
const auto& a1 = h.axis(1_c);
h(weight(2), 0, 2);
h(-1, 2);
h(1, 3);
@ -824,8 +830,7 @@ template <typename Type> void run_tests() {
// STL compatibility
{
auto h = make_histogram<adaptive_storage>(Type(), axis::integer<>(0, 3));
for (int i = 0; i < 3; ++i)
h(i);
for (int i = 0; i < 3; ++i) h(i);
auto a = std::vector<weight_counter<double>>();
std::partial_sum(h.begin(), h.end(), std::back_inserter(a));
BOOST_TEST_EQ(a[0].value(), 1);
@ -890,14 +895,15 @@ template <typename Type> void run_tests() {
}
}
template <typename T1, typename T2> void run_mixed_tests() {
template <typename T1, typename T2>
void run_mixed_tests() {
// compare
{
auto a = make_histogram<adaptive_storage>(T1{}, axis::regular<>{3, 0, 3},
axis::integer<>(0, 2));
auto b = make_histogram<array_storage<int>>(T2{}, axis::regular<>{3, 0, 3},
axis::integer<>(0, 2));
auto b = make_histogram<array_storage<int>>(
T2{}, axis::regular<>{3, 0, 3}, axis::integer<>(0, 2));
BOOST_TEST_EQ(a, b);
auto b2 = make_histogram<adaptive_storage>(T2{}, axis::integer<>{0, 3},
axis::integer<>(0, 2));
@ -926,8 +932,8 @@ template <typename T1, typename T2> void run_mixed_tests() {
{
auto a = make_histogram<adaptive_storage>(T1{}, axis::regular<>{3, 0, 3},
axis::integer<>(0, 2));
auto b = make_histogram<array_storage<int>>(T2{}, axis::regular<>{3, 0, 3},
axis::integer<>(0, 2));
auto b = make_histogram<array_storage<int>>(
T2{}, axis::regular<>{3, 0, 3}, axis::integer<>(0, 2));
a(1, 1);
BOOST_TEST_NE(a, b);
b = a;
@ -1000,7 +1006,7 @@ int main() {
// histogram iterator
{
auto h = make_dynamic_histogram(axis::integer<>(0, 3));
const auto &a = h.axis();
const auto& a = h.axis();
h(weight(2), 0);
h(1);
h(1);

View File

@ -6,12 +6,12 @@
#include <algorithm>
#include <boost/histogram.hpp>
#include <boost/mp11.hpp>
#include <cstdio>
#include <ctime>
#include <limits>
#include <random>
#include <memory>
#include <boost/mp11.hpp>
#include <random>
using namespace boost::histogram;
using boost::mp11::mp_list;
@ -21,17 +21,16 @@ std::unique_ptr<double[]> random_array(unsigned n, int type) {
std::default_random_engine gen(1);
if (type) { // type == 1
std::normal_distribution<> d(0.5, 0.3);
for (unsigned i = 0; i < n; ++i)
r[i] = d(gen);
for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
} else { // type == 0
std::uniform_real_distribution<> d(0.0, 1.0);
for (unsigned i = 0; i < n; ++i)
r[i] = d(gen);
for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
}
return r;
}
template<class T> void ignore( const T& ) { }
template <class T>
void ignore(const T&) {}
double baseline(unsigned n) {
auto r = random_array(n, 0);
@ -49,15 +48,15 @@ double baseline(unsigned n) {
return best;
}
template <typename Histogram> double compare_1d(unsigned n, int distrib) {
template <typename Histogram>
double compare_1d(unsigned n, int distrib) {
auto r = random_array(n, distrib);
auto best = std::numeric_limits<double>::max();
for (unsigned k = 0; k < 20; ++k) {
auto h = Histogram(axis::regular<>(100, 0, 1));
auto t = clock();
for (unsigned i = 0; i < n; ++i)
h(r[i]);
for (unsigned i = 0; i < n; ++i) h(r[i]);
t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC);
}
@ -65,15 +64,16 @@ template <typename Histogram> double compare_1d(unsigned n, int distrib) {
return best;
}
template <typename Histogram> double compare_2d(unsigned n, int distrib) {
template <typename Histogram>
double compare_2d(unsigned n, int distrib) {
auto r = random_array(n, distrib);
auto best = std::numeric_limits<double>::max();
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();
for (unsigned i = 0; i < n/2; ++i)
h(r[2 * i], r[2 * i + 1]);
for (unsigned i = 0; i < n / 2; ++i) h(r[2 * i], r[2 * i + 1]);
t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC);
}
@ -81,7 +81,8 @@ template <typename Histogram> double compare_2d(unsigned n, int distrib) {
return best;
}
template <typename Histogram> double compare_3d(unsigned n, int distrib) {
template <typename Histogram>
double compare_3d(unsigned n, int distrib) {
auto r = random_array(n, distrib);
auto best = std::numeric_limits<double>::max();
@ -89,7 +90,7 @@ template <typename Histogram> double compare_3d(unsigned n, int distrib) {
auto h = Histogram(axis::regular<>(100, 0, 1), axis::regular<>(100, 0, 1),
axis::regular<>(100, 0, 1));
auto t = clock();
for (unsigned i = 0; i < n/3; ++i)
for (unsigned i = 0; i < n / 3; ++i)
h(r[3 * i], r[3 * i + 1], r[3 * i + 2]);
t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC);
@ -98,7 +99,8 @@ template <typename Histogram> double compare_3d(unsigned n, int distrib) {
return best;
}
template <typename Histogram> double compare_6d(unsigned n, int distrib) {
template <typename Histogram>
double compare_6d(unsigned n, int distrib) {
auto r = random_array(n, distrib);
auto best = std::numeric_limits<double>::max();
@ -108,9 +110,9 @@ template <typename Histogram> double compare_6d(unsigned n, int distrib) {
axis::regular<>(10, 0, 1), axis::regular<>(10, 0, 1));
auto t = clock();
for (unsigned i = 0; i < n/6; ++i) {
h(r[6 * i], r[6 * i + 1], r[6 * i + 2],
r[6 * i + 3], r[6 * i + 4], r[6 * i + 5]);
for (unsigned i = 0; i < n / 6; ++i) {
h(r[6 * i], r[6 * i + 1], r[6 * i + 2], r[6 * i + 3], r[6 * i + 4],
r[6 * i + 5]);
}
t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC);
@ -132,14 +134,13 @@ int main() {
printf("normal distribution\n");
printf("hs_ss %.3f\n",
compare_1d<static_histogram<mp_list<axis::regular<>>,
array_storage<int>>>(
nfill, itype));
array_storage<int>>>(nfill, itype));
printf("hs_sd %.3f\n",
compare_1d<static_histogram<mp_list<axis::regular<>>,
adaptive_storage>>(nfill, itype));
compare_1d<
static_histogram<mp_list<axis::regular<>>, adaptive_storage>>(
nfill, itype));
printf("hd_ss %.3f\n",
compare_1d<dynamic_histogram<axis::types,
array_storage<int>>>(
compare_1d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype));
printf("hd_sd %.3f\n",
compare_1d<dynamic_histogram<axis::types, adaptive_storage>>(
@ -152,17 +153,16 @@ int main() {
printf("uniform distribution\n");
else
printf("normal distribution\n");
printf("hs_ss %.3f\n",
compare_2d<static_histogram<
mp_list<axis::regular<>, axis::regular<>>,
array_storage<int>>>(nfill, itype));
printf("hs_sd %.3f\n",
compare_2d<static_histogram<
mp_list<axis::regular<>, axis::regular<>>,
adaptive_storage>>(nfill, itype));
printf(
"hs_ss %.3f\n",
compare_2d<static_histogram<mp_list<axis::regular<>, axis::regular<>>,
array_storage<int>>>(nfill, itype));
printf(
"hs_sd %.3f\n",
compare_2d<static_histogram<mp_list<axis::regular<>, axis::regular<>>,
adaptive_storage>>(nfill, itype));
printf("hd_ss %.3f\n",
compare_2d<dynamic_histogram<axis::types,
array_storage<int>>>(
compare_2d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype));
printf("hd_sd %.3f\n",
compare_2d<dynamic_histogram<axis::types, adaptive_storage>>(
@ -184,8 +184,7 @@ int main() {
mp_list<axis::regular<>, axis::regular<>, axis::regular<>>,
adaptive_storage>>(nfill, itype));
printf("hd_ss %.3f\n",
compare_3d<dynamic_histogram<axis::types,
array_storage<int>>>(
compare_3d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype));
printf("hd_sd %.3f\n",
compare_3d<dynamic_histogram<axis::types, adaptive_storage>>(
@ -201,16 +200,15 @@ int main() {
printf("hs_ss %.3f\n",
compare_6d<static_histogram<
mp_list<axis::regular<>, axis::regular<>, axis::regular<>,
axis::regular<>, axis::regular<>, axis::regular<>>,
axis::regular<>, axis::regular<>, axis::regular<>>,
array_storage<int>>>(nfill, itype));
printf("hs_sd %.3f\n",
compare_6d<static_histogram<
mp_list<axis::regular<>, axis::regular<>, axis::regular<>,
axis::regular<>, axis::regular<>, axis::regular<>>,
axis::regular<>, axis::regular<>, axis::regular<>>,
adaptive_storage>>(nfill, itype));
printf("hd_ss %.3f\n",
compare_6d<dynamic_histogram<axis::types,
array_storage<int>>>(
compare_6d<dynamic_histogram<axis::types, array_storage<int>>>(
nfill, itype));
printf("hd_sd %.3f\n",
compare_6d<dynamic_histogram<axis::types, adaptive_storage>>(

View File

@ -11,20 +11,18 @@
#include <cstdio>
#include <ctime>
#include <limits>
#include <random>
#include <memory>
#include <random>
std::unique_ptr<double[]> random_array(unsigned n, int type) {
std::unique_ptr<double[]> r(new double[n]);
std::default_random_engine gen(1);
if (type) { // type == 1
std::normal_distribution<> d(0.5, 0.3);
for (unsigned i = 0; i < n; ++i)
r[i] = d(gen);
for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
} else { // type == 0
std::uniform_real_distribution<> d(0.0, 1.0);
for (unsigned i = 0; i < n; ++i)
r[i] = d(gen);
for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
}
return r;
}
@ -34,11 +32,10 @@ void compare_1d(unsigned n, int distrib) {
double best = std::numeric_limits<double>::max();
for (unsigned k = 0; k < 20; ++k) {
gsl_histogram *h = gsl_histogram_alloc(100);
gsl_histogram* h = gsl_histogram_alloc(100);
gsl_histogram_set_ranges_uniform(h, 0, 1);
auto t = clock();
for (unsigned i = 0; i < n; ++i)
gsl_histogram_increment(h, r[i]);
for (unsigned i = 0; i < n; ++i) gsl_histogram_increment(h, r[i]);
t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC);
gsl_histogram_free(h);
@ -51,10 +48,10 @@ void compare_2d(unsigned n, int distrib) {
double best = std::numeric_limits<double>::max();
for (unsigned k = 0; k < 20; ++k) {
gsl_histogram2d *h = gsl_histogram2d_alloc(100, 100);
gsl_histogram2d* h = gsl_histogram2d_alloc(100, 100);
gsl_histogram2d_set_ranges_uniform(h, 0, 1, 0, 1);
auto t = clock();
for (unsigned i = 0; i < n/2; ++i)
for (unsigned i = 0; i < n / 2; ++i)
gsl_histogram2d_increment(h, r[2 * i], r[2 * i + 1]);
t = clock() - t;
best = std::min(best, double(t) / CLOCKS_PER_SEC);
@ -63,7 +60,7 @@ void compare_2d(unsigned n, int distrib) {
printf("gsl %.3f\n", best);
}
int main(int argc, char **argv) {
int main(int argc, char** argv) {
constexpr unsigned nfill = 6000000;
printf("1D\n");
printf("uniform distribution\n");

View File

@ -13,20 +13,18 @@
#include <cstdio>
#include <ctime>
#include <limits>
#include <random>
#include <memory>
#include <random>
std::unique_ptr<double[]> random_array(unsigned n, int type) {
std::unique_ptr<double[]> r(new double[n]);
std::default_random_engine gen(1);
if (type) { // type == 1
std::normal_distribution<> d(0.5, 0.3);
for (unsigned i = 0; i < n; ++i)
r[i] = d(gen);
for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
} else { // type == 0
std::uniform_real_distribution<> d(0.0, 1.0);
for (unsigned i = 0; i < n; ++i)
r[i] = d(gen);
for (unsigned i = 0; i < n; ++i) r[i] = d(gen);
}
return r;
}
@ -38,8 +36,7 @@ void compare_1d(unsigned n, int distrib) {
for (unsigned k = 0; k < 20; ++k) {
TH1I hroot("", "", 100, 0, 1);
auto t = clock();
for (unsigned i = 0; i < n; ++i)
hroot.Fill(r[i]);
for (unsigned i = 0; i < n; ++i) hroot.Fill(r[i]);
t = clock() - t;
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) {
TH2I hroot("", "", 100, 0, 1, 100, 0, 1);
auto t = clock();
for (unsigned i = 0; i < n/2; ++i)
hroot.Fill(r[2 * i], r[2 * i + 1]);
for (unsigned i = 0; i < n / 2; ++i) hroot.Fill(r[2 * i], r[2 * i + 1]);
t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
}
@ -68,7 +64,7 @@ void compare_3d(unsigned n, int distrib) {
for (unsigned k = 0; k < 20; ++k) {
TH3I hroot("", "", 100, 0, 1, 100, 0, 1, 100, 0, 1);
auto t = clock();
for (unsigned i = 0; i < n/3; ++i)
for (unsigned i = 0; i < n / 3; ++i)
hroot.Fill(r[3 * i], r[3 * i + 1], r[3 * i + 2]);
t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
@ -87,16 +83,14 @@ void compare_6d(unsigned n, int distrib) {
THnI hroot("", "", 6, &bin.front(), &min.front(), &max.front());
auto t = clock();
for (unsigned i = 0; i < n/6; ++i) {
hroot.Fill(r.get() + 6 * i);
}
for (unsigned i = 0; i < n / 6; ++i) { hroot.Fill(r.get() + 6 * i); }
t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
}
printf("root %.3f\n", best_root);
}
int main(int argc, char **argv) {
int main(int argc, char** argv) {
constexpr unsigned nfill = 6000000;
printf("1D\n");