better reference docu

This commit is contained in:
Hans Dembinski 2019-01-22 22:14:38 +01:00
parent 1bd67c780e
commit fd0b7dea8d
9 changed files with 121 additions and 92 deletions

View File

@ -31,36 +31,41 @@ template <typename RealType>
class sum {
public:
sum() = default;
explicit sum(const RealType& value) noexcept : sum_(value), cor_(0) {}
/// Initialize sum to value
explicit sum(const RealType& value) noexcept : large_(value) {}
/// Set sum to value
sum& operator=(const RealType& value) noexcept {
sum_ = value;
cor_ = 0;
large_ = value;
small_ = 0;
return *this;
}
void operator()() { operator+=(1); }
/// Increment sum by one
sum& operator++() { return operator+=(1); }
void operator()(const RealType& x) { operator+=(x); }
sum& operator+=(const RealType& x) {
auto temp = sum_ + x; // prevent optimization
if (std::abs(sum_) >= std::abs(x))
cor_ += (sum_ - temp) + x;
/// Increment sum by value
sum& operator+=(const RealType& value) {
auto temp = large_ + value; // prevent optimization
if (std::abs(large_) >= std::abs(value))
small_ += (large_ - temp) + value;
else
cor_ += (x - temp) + sum_;
sum_ = temp;
small_ += (value - temp) + large_;
large_ = temp;
return *this;
}
sum& operator*=(const RealType& x) {
sum_ *= x;
cor_ *= x;
/// Scale by value
sum& operator*=(const RealType& value) {
large_ *= value;
small_ *= value;
return *this;
}
template <typename T>
bool operator==(const sum<T>& rhs) const noexcept {
return sum_ == rhs.sum_ && cor_ == rhs.cor_;
return large_ == rhs.large_ && small_ == rhs.small_;
}
template <typename T>
@ -68,17 +73,21 @@ public:
return !operator==(rhs);
}
const RealType& large() const noexcept { return sum_; }
const RealType& small() const noexcept { return cor_; }
/// Return large part of the sum.
const RealType& large() const { return large_; }
/// Return small part of the sum.
const RealType& small() const { return small_; }
// allow implicit conversion to RealType
operator RealType() const { return sum_ + cor_; }
operator RealType() const { return large_ + small_; }
template <class Archive>
void serialize(Archive&, unsigned /* version */);
private:
RealType sum_ = 0, cor_ = 0;
RealType large_ = RealType();
RealType small_ = RealType();
};
} // namespace accumulators

View File

@ -19,49 +19,45 @@ template <typename RealType>
class weighted_sum {
public:
weighted_sum() = default;
explicit weighted_sum(const RealType& value) noexcept : sum_(value), sum2_(value) {}
explicit weighted_sum(const RealType& value) noexcept
: sum_of_weights_(value), sum_of_weights_squared_(value) {}
weighted_sum(const RealType& value, const RealType& variance) noexcept
: sum_(value), sum2_(variance) {}
: sum_of_weights_(value), sum_of_weights_squared_(variance) {}
void operator()() {
sum_ += 1;
sum2_ += 1;
}
/// Increment by one.
weighted_sum& operator++() { return operator+=(1); }
/// Increment by value.
template <typename T>
void operator()(const T& w) {
sum_ += w;
sum2_ += w * w;
}
// used when adding non-weighted histogram to weighted histogram
template <typename T>
weighted_sum& operator+=(const T& x) {
sum_ += x;
sum2_ += x;
weighted_sum& operator+=(const T& value) {
sum_of_weights_ += value;
sum_of_weights_squared_ += value * value;
return *this;
}
/// Added another weighted sum.
template <typename T>
weighted_sum& operator+=(const weighted_sum<T>& rhs) {
sum_ += static_cast<RealType>(rhs.sum_);
sum2_ += static_cast<RealType>(rhs.sum2_);
sum_of_weights_ += static_cast<RealType>(rhs.sum_of_weights_);
sum_of_weights_squared_ += static_cast<RealType>(rhs.sum_of_weights_squared_);
return *this;
}
/// Scale by value.
weighted_sum& operator*=(const RealType& x) {
sum_ *= x;
sum2_ *= x * x;
sum_of_weights_ *= x;
sum_of_weights_squared_ *= x * x;
return *this;
}
bool operator==(const RealType& rhs) const noexcept {
return sum_ == rhs && sum2_ == rhs;
return sum_of_weights_ == rhs && sum_of_weights_squared_ == rhs;
}
template <typename T>
bool operator==(const weighted_sum<T>& rhs) const noexcept {
return sum_ == rhs.sum_ && sum2_ == rhs.sum2_;
return sum_of_weights_ == rhs.sum_of_weights_ &&
sum_of_weights_squared_ == rhs.sum_of_weights_squared_;
}
template <typename T>
@ -69,20 +65,24 @@ public:
return !operator==(rhs);
}
const RealType& value() const noexcept { return sum_; }
const RealType& variance() const noexcept { return sum2_; }
/// Return value of the sum.
const RealType& value() const noexcept { return sum_of_weights_; }
/// Return estimated variance of the sum.
const RealType& variance() const noexcept { return sum_of_weights_squared_; }
// lossy conversion must be explicit
template <typename T>
template <class T>
explicit operator T() const {
return static_cast<T>(sum_);
return static_cast<T>(sum_of_weights_);
}
template <class Archive>
void serialize(Archive&, unsigned /* version */);
private:
RealType sum_ = RealType(), sum2_ = RealType();
RealType sum_of_weights_ = RealType();
RealType sum_of_weights_squared_ = RealType();
};
} // namespace accumulators

View File

@ -46,16 +46,23 @@ public:
using const_iterator = iterator<Derived>;
using const_reverse_iterator = boost::reverse_iterator<const_iterator>;
/// Bin iterator to beginning of the axis (read-only).
const_iterator begin() const noexcept {
return const_iterator(*static_cast<const Derived*>(this), 0);
}
/// Bin iterator to the end of the axis (read-only).
const_iterator end() const noexcept {
return const_iterator(*static_cast<const Derived*>(this),
static_cast<const Derived*>(this)->size());
}
/// Reverse bin iterator to the last entry of the axis (read-only).
const_reverse_iterator rbegin() const noexcept {
return boost::make_reverse_iterator(end());
}
/// Reverse bin iterator to the end (read-only).
const_reverse_iterator rend() const noexcept {
return boost::make_reverse_iterator(begin());
}

View File

@ -110,7 +110,7 @@ struct sqrt {
/// Pow transform for equidistant bins in pow-space.
struct pow {
double power = 1;
double power = 1; /**< power index */
explicit pow(double p) : power(p) {}
pow() = default;

View File

@ -162,11 +162,11 @@ public:
return visit([&u](const auto& a) { return traits::index(a, u); }, *this);
}
// Throws invalid_argument exception if axis has incompatible call signature
template <class U>
std::pair<int, int> update(const U& u) {
return visit([&u](auto& a) { return traits::update(a, u); }, *this);
}
// // Throws invalid_argument exception if axis has incompatible call signature
// template <class U>
// std::pair<int, int> update(const U& u) {
// return visit([&u](auto& a) { return traits::update(a, u); }, *this);
// }
// Only works for axes with value method that returns something convertible to
// double and will throw a runtime_error otherwise, see axis::traits::value
@ -212,9 +212,9 @@ public:
template <class Archive>
void serialize(Archive& ar, unsigned);
template <class Functor, class Variant>
friend auto visit(Functor&&, Variant &&)
-> detail::visitor_return_type<Functor, Variant>;
template <class Visitor, class Variant>
friend auto visit(Visitor&&, Variant &&)
-> detail::visitor_return_type<Visitor, Variant>;
template <class T, class... Us>
friend T& get(variant<Us...>& v);
@ -232,43 +232,52 @@ public:
friend const T* get_if(const variant<Us...>* v);
};
template <class Functor, class Variant>
auto visit(Functor&& f, Variant&& v) -> detail::visitor_return_type<Functor, Variant> {
using R = detail::visitor_return_type<Functor, Variant>;
/// Apply visitor to variant
template <class Visitor, class Variant>
auto visit(Visitor&& vis, Variant&& var)
-> detail::visitor_return_type<Visitor, Variant> {
using R = detail::visitor_return_type<Visitor, Variant>;
using B = detail::copy_qualifiers<Variant, typename detail::naked<Variant>::base_type>;
return boost::apply_visitor(detail::functor_wrapper<Functor, R>(f), static_cast<B>(v));
return boost::apply_visitor(detail::functor_wrapper<Visitor, R>(vis),
static_cast<B>(var));
}
/// Return lvalue reference to T, throws unspecified exception if type does not match
template <class T, class... Us>
T& get(variant<Us...>& v) {
using B = typename variant<Us...>::base_type;
return boost::get<T>(static_cast<B&>(v));
}
/// Return rvalue reference to T, throws unspecified exception if type does not match
template <class T, class... Us>
T&& get(variant<Us...>&& v) {
using B = typename variant<Us...>::base_type;
return boost::get<T>(static_cast<B&&>(v));
}
/// Return const reference to T, throws unspecified exception if type does not match
template <class T, class... Us>
const T& get(const variant<Us...>& v) {
using B = typename variant<Us...>::base_type;
return boost::get<T>(static_cast<const B&>(v));
}
/// Returns pointer to T in variant or null pointer if type does not match
template <class T, class... Us>
T* get_if(variant<Us...>* v) {
using B = typename variant<Us...>::base_type;
return boost::relaxed_get<T>(static_cast<B*>(v));
}
/// Returns pointer to const T in variant or null pointer if type does not match
template <class T, class... Us>
const T* get_if(const variant<Us...>* v) {
using B = typename variant<Us...>::base_type;
return boost::relaxed_get<T>(static_cast<const B*>(v));
}
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
// pass-through version for generic programming, if U is axis instead of variant
template <class T, class U>
decltype(auto) get(U&& u) {
@ -287,6 +296,8 @@ const T* get_if(const U* u) {
return std::is_same<T, detail::naked<U>>::value ? reinterpret_cast<const T*>(u)
: nullptr;
}
#endif
} // namespace axis
} // namespace histogram
} // namespace boost

View File

@ -81,8 +81,7 @@ public:
}
template <class A, class S>
explicit histogram(A&& a, S&& s)
: axes_(std::forward<A>(a)), storage_(std::forward<S>(s)) {
histogram(A&& a, S&& s) : axes_(std::forward<A>(a)), storage_(std::forward<S>(s)) {
storage_.reset(detail::bincount(axes_));
}
@ -125,34 +124,33 @@ public:
not convertible to the value type accepted by the axis or passing the wrong number
of arguments causes a throw of std::invalid_argument.
# Axis with multiple arguments
**Axis with multiple arguments**
If the histogram contains an axis which accepts a std::tuple of arguments, the
arguments for that axis need to passed as a std::tuple, for example,
std::make_tuple(1.2, 2.3). If the histogram contains only this axis and no other,
the arguments can be passed directly.
# Weights
**Weights**
An optional weight can be passed as the first or last argument with the weight
helper function. Compilation fails if the storage elements do not support weights.
# Samples
**Samples**
If the storage elements accept samples, pass them with the sample helper function
in addition to the axis arguments, which can be the first or last argument. The
sample helper function can pass one or more arguments to the storage element. If
samples and weights are used together, they can be passed in any order at the beginning
or end of the argument list.
*/
//@{
template <class... Ts>
auto operator()(const Ts&... ts) {
return operator()(std::forward_as_tuple(ts...));
}
/// Fill histogram with values and optional weight or sample from a tuple.
template <class... Ts>
auto operator()(const std::tuple<Ts...>& t) {
return detail::fill(storage_, axes_, t);
}
//@}
/// Add values of another histogram.
template <class A, class S>
@ -190,7 +188,6 @@ public:
decltype(auto) at(int t, Ts... ts) const {
return at(std::forward_as_tuple(t, ts...));
}
//@}
/// Access cell value at integral indices stored in std::tuple.
/// @copydoc at(int t, Ts... ts)
@ -252,12 +249,24 @@ public:
return !operator==(rhs);
}
/// Return value iterator to the beginning of the histogram.
iterator begin() noexcept { return storage_.begin(); }
/// Return value iterator to the end in the histogram.
iterator end() noexcept { return storage_.end(); }
/// Return value iterator to the beginning of the histogram (read-only).
const_iterator begin() const noexcept { return storage_.begin(); }
/// Return value iterator to the end in the histogram (read-only).
const_iterator end() const noexcept { return storage_.end(); }
/// Return value iterator to the beginning of the histogram (read-only).
const_iterator cbegin() const noexcept { return storage_.begin(); }
/// Return value iterator to the end in the histogram (read-only).
const_iterator cend() const noexcept { return storage_.end(); }
private:
axes_type axes_;
storage_type storage_;

View File

@ -81,15 +81,15 @@ namespace accumulators {
template <class RealType>
template <class Archive>
void sum<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& sum_;
ar& cor_;
ar& large_;
ar& small_;
}
template <class RealType>
template <class Archive>
void weighted_sum<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& sum_;
ar& sum2_;
ar& sum_of_weights_;
ar& sum_of_weights_squared_;
}
template <class RealType>

View File

@ -31,7 +31,7 @@ int main() {
BOOST_TEST_EQ(w, 1);
BOOST_TEST_NE(w, 2);
w(2);
w += 2;
BOOST_TEST_EQ(w.value(), 3);
BOOST_TEST_EQ(w.variance(), 5);
BOOST_TEST_EQ(w, w_t(3, 5));
@ -44,20 +44,14 @@ int main() {
// consistency: a weighted counter increased by weight 1 multiplied
// by 2 must be the same as a weighted counter increased by weight 2
w_t u(0);
u(1);
++u;
u *= 2;
BOOST_TEST_EQ(u, w_t(2, 4));
w_t v(0);
v(2);
v += 2;
BOOST_TEST_EQ(u, v);
// consistency : a weight counter increased by a real number x
// is the same was adding x times weight(1)
w_t x(0);
x += 2;
BOOST_TEST_EQ(x, w_t(2, 2));
// conversion to RealType
w_t y(1, 2);
BOOST_TEST_NE(y, 1);
@ -134,9 +128,9 @@ int main() {
BOOST_TEST_EQ(bad_sum, 0); // instead of 2
accumulators::sum<double> sum;
sum(); // equivalent to sum += 1
sum(1e100); // equivalent to sum += 1e100
sum += 1;
++sum;
sum += 1e100;
++sum;
sum += -1e100;
BOOST_TEST_EQ(sum, 2);
}
@ -144,10 +138,10 @@ int main() {
{
accumulators::weighted_sum<accumulators::sum<double>> w;
w();
w(1e100);
w();
w(-1e100);
++w;
w += 1e100;
++w;
w += -1e100;
BOOST_TEST_EQ(w.value(), 2);
BOOST_TEST_EQ(w.variance(), 2e200);

View File

@ -158,10 +158,9 @@ int main() {
{
auto a = storage_adaptor<std::vector<accumulators::weighted_sum<double>>>();
a.reset(1);
a[0]();
a[0](1); // rvalue weight
const auto weight = 2;
a[0](weight); // lvalue weight
++a[0];
a[0] += 1;
a[0] += 2;
a[0] += accumulators::weighted_sum<double>(1, 0);
BOOST_TEST_EQ(a[0].value(), 5);
BOOST_TEST_EQ(a[0].variance(), 6);