mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-11 13:14:06 +00:00
clang-format
This commit is contained in:
parent
699bb519c5
commit
bfc437b7bd
88
.clang-format
Normal file
88
.clang-format
Normal 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
|
||||
...
|
@ -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
|
||||
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
*/
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
*/
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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),
|
||||
)
|
||||
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
//]
|
||||
|
@ -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); }
|
||||
|
||||
//]
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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...>;
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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>>
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)...);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<>>());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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>();
|
||||
|
@ -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}};
|
||||
|
||||
|
@ -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>));
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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}));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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>>(
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user