accessor [] to index and indices

This commit is contained in:
Hans Dembinski 2019-01-17 21:56:02 +01:00
parent 07b91f013f
commit f8ebf85a05
14 changed files with 72 additions and 68 deletions

View File

@ -56,7 +56,7 @@ int main() {
Passing `coverage::all` as the optional second argument iterates over all bins.
- Access the value with the dereference operator. The proxy acts like a pointer to it.
- Access the current index with operator[] of the accessor, passing the dimension d.
- Access the current index with `index(d)` of the accessor, passing the dimension d.
- Access the corresponding bin interval view with `bin(d)`. Use a compile-time number
like 1_c instead of a normal number like 1, if possible, to make this call more
efficent. The return type depends on the axis type (see the axis reference for
@ -68,8 +68,8 @@ int main() {
std::ostringstream os;
for (auto x : indexed(h, coverage::all)) {
os << boost::format("bin %2i [%4.1f, %4.1f): %i\n") % x[0] % x.bin(0_c).lower() %
x.bin(0_c).upper() % *x;
os << boost::format("bin %2i [%4.1f, %4.1f): %i\n") % x.index() % x.bin().lower() %
x.bin().upper() % *x;
}
std::cout << os.str() << std::flush;

View File

@ -47,9 +47,10 @@ int main() {
const auto& cat_axis = bh::axis::get<cat>(h.axis(0)); // get reference to category axis
std::ostringstream os;
for (auto x : bh::indexed(h)) {
os << boost::format("(%i, %i, %i) %4s [%3.1f, %3.1f) [%3.1f, %3.1f) %3.0f\n") % x[0] %
x[1] % x[2] % cat_axis[x[0]] % x.bin(1).lower() % x.bin(1).upper() %
x.bin(2).lower() % x.bin(2).upper() % *x;
os << boost::format("(%i, %i, %i) %4s [%3.1f, %3.1f) [%3.1f, %3.1f) %3.0f\n") %
x.index(0) % x.index(1) % x.index(2) % cat_axis[x.index(0)] %
x.bin(1).lower() % x.bin(1).upper() % x.bin(2).lower() % x.bin(2).upper() %
*x;
}
std::cout << os.str() << std::flush;

View File

@ -35,8 +35,8 @@ int main() {
*/
std::ostringstream os;
for (auto x : bh::indexed(p)) {
os << boost::format("bin %i [%3.1f, %3.1f) count %i mean %g\n") % x[0] %
x.bin(0).lower() % x.bin(0).upper() % x->count() % x->value();
os << boost::format("bin %i [%3.1f, %3.1f) count %i mean %g\n") % x.index() %
x.bin().lower() % x.bin().upper() % x->count() % x->value();
}
std::cout << os.str() << std::flush;

View File

@ -42,11 +42,11 @@ int main() {
std::ostringstream os;
for (auto x : indexed(h)) {
// x is a special accessor object
const auto i = x[0]; // current index along first axis
const auto j = x[1]; // current index along second axis
const auto b0 = x.bin(0); // current bin interval along first axis
const auto b1 = x.bin(1); // current bin interval along second axis
const auto v = *x; // "dereference" to get the bin value
const auto i = x.index(0); // current index along first axis
const auto j = x.index(1); // current index along second axis
const auto b0 = x.bin(0); // current bin interval along first axis
const auto b1 = x.bin(1); // current bin interval along second axis
const auto v = *x; // "dereference" to get the bin value
os << boost::format("%i %i [%2i, %i) [%2i, %i): %i\n") % i % j % b0.lower() %
b0.upper() % b1.lower() % b1.upper() % v;
}
@ -62,7 +62,7 @@ int main() {
// second argument `coverage::all` to walk over all bins
std::ostringstream os2;
for (auto x : indexed(h, coverage::all)) {
os2 << boost::format("%2i %2i: %i\n") % x[0] % x[1] % *x;
os2 << boost::format("%2i %2i: %i\n") % x.index(0) % x.index(1) % *x;
}
std::cout << os2.str() << std::flush;

View File

@ -33,7 +33,7 @@ int main() {
std::ostringstream os;
for (auto&& b : bh::indexed(h)) {
os << "bin " << b[0] << " [" << b.bin(0) << "] " << *b << "\n";
os << "bin " << b.index() << " [" << b.bin() << "] " << *b << "\n";
}
std::cout << os.str() << std::endl;

View File

@ -40,7 +40,8 @@ int main() {
assert(sum(h) == 3 && sum(hr0) == 3 && sum(hr1) == 3);
std::ostringstream os1;
for (auto x : bh::indexed(h)) os1 << "(" << x[0] << ", " << x[1] << "): " << *x << "\n";
for (auto x : bh::indexed(h))
os1 << "(" << x.index(0) << ", " << x.index(1) << "): " << *x << "\n";
std::cout << os1.str() << std::flush;
assert(os1.str() == "(0, 0): 1\n"
"(1, 0): 1\n"
@ -50,14 +51,14 @@ int main() {
"(2, 1): 1\n");
std::ostringstream os2;
for (auto x : bh::indexed(hr0)) os2 << "(" << x[0] << ", -): " << *x << "\n";
for (auto x : bh::indexed(hr0)) os2 << "(" << x.index(0) << ", -): " << *x << "\n";
std::cout << os2.str() << std::flush;
assert(os2.str() == "(0, -): 1\n"
"(1, -): 1\n"
"(2, -): 1\n");
std::ostringstream os3;
for (auto x : bh::indexed(hr1)) os3 << "(- ," << x[0] << "): " << *x << "\n";
for (auto x : bh::indexed(hr1)) os3 << "(- ," << x.index(0) << "): " << *x << "\n";
std::cout << os3.str() << std::flush;
assert(os3.str() == "(- ,0): 2\n"
"(- ,1): 1\n");

View File

@ -51,7 +51,7 @@ auto project(const histogram<A, S>& h, std::integral_constant<unsigned, N>, Ns..
auto idx = detail::make_stack_buffer<int>(unsafe_access::axes(result));
for (auto x : indexed(h, coverage::all)) {
auto i = idx.begin();
mp11::mp_for_each<LN>([&i, &x](auto J) { *i++ = x[J]; });
mp11::mp_for_each<LN>([&i, &x](auto J) { *i++ = x.index(J); });
result.at(idx) += *x;
}
return result;
@ -83,7 +83,7 @@ auto project(const histogram<A, S>& h, const Iterable& c) {
auto idx = detail::make_stack_buffer<int>(unsafe_access::axes(result));
for (auto x : indexed(h, coverage::all)) {
auto i = idx.begin();
for (auto d : c) *i++ = x[d];
for (auto d : c) *i++ = x.index(d);
result.at(idx) += *x;
}

View File

@ -130,7 +130,7 @@ decltype(auto) reduce(const Histogram& h, const C& options) {
for (auto x : indexed(h, coverage::all)) {
auto i = idx.begin();
auto o = opts.begin();
for (auto j : x) {
for (auto j : x.indices()) {
*i = (j - o->begin);
if (*i <= -1)
*i = -1;

View File

@ -84,25 +84,19 @@ public:
void reset() { storage_.reset(storage_.size()); }
/// Get N-th axis
template <unsigned N>
decltype(auto) axis(std::integral_constant<unsigned, N>) {
template <unsigned N = 0>
decltype(auto) axis(std::integral_constant<unsigned, N> = {}) {
detail::axis_index_is_valid(axes_, N);
return detail::axis_get<N>(axes_);
}
/// Get N-th axis (const version)
template <unsigned N>
decltype(auto) axis(std::integral_constant<unsigned, N>) const {
template <unsigned N = 0>
decltype(auto) axis(std::integral_constant<unsigned, N> = {}) const {
detail::axis_index_is_valid(axes_, N);
return detail::axis_get<N>(axes_);
}
/// Get first axis (convenience for 1-d histograms)
decltype(auto) axis() { return axis(std::integral_constant<unsigned, 0>()); }
/// Get first axis (convenience for 1-d histograms, const version)
decltype(auto) axis() const { return axis(std::integral_constant<unsigned, 0>()); }
/// Get N-th axis with runtime index
decltype(auto) axis(unsigned i) {
detail::axis_index_is_valid(axes_, i);

View File

@ -36,13 +36,27 @@ class BOOST_HISTOGRAM_NODISCARD indexed_range {
public:
class accessor {
public:
class index_iterator
: public boost::iterator_adaptor<index_iterator,
typename cache_type::const_iterator> {
class indices_view {
public:
index_iterator(typename cache_type::const_iterator i)
: index_iterator::iterator_adaptor_(i) {}
decltype(auto) operator*() const noexcept { return index_iterator::base()->idx; }
class index_iterator
: public boost::iterator_adaptor<index_iterator,
typename cache_type::const_iterator> {
public:
index_iterator(typename cache_type::const_iterator i)
: index_iterator::iterator_adaptor_(i) {}
decltype(auto) operator*() const noexcept { return index_iterator::base()->idx; }
};
auto begin() const { return index_iterator(cache_.begin()); }
auto end() const { return index_iterator(cache_.end()); }
auto size() const { return cache_.size(); }
int operator[](unsigned d) const { return cache_[d].idx; }
int at(unsigned d) const { return cache_.at(d).idx; }
private:
indices_view(const cache_type& c) : cache_(c) {}
const cache_type& cache_;
friend class accessor;
};
// pointer interface for value
@ -50,26 +64,22 @@ public:
decltype(auto) get() const noexcept { return *iter_; }
decltype(auto) operator-> () const noexcept { return iter_; }
// array interface for ND index
int operator[](unsigned d) const { return parent_->cache_[d].idx; }
int at(unsigned d) const { return parent_->cache_.at(d).idx; }
auto begin() const { return index_iterator(parent_->cache_.begin()); }
auto end() const { return index_iterator(parent_->cache_.end()); }
auto size() const { return parent_->cache_.size(); }
// convenience interface
template <unsigned N>
decltype(auto) bin(std::integral_constant<unsigned, N>) const {
return parent_->hist_.axis(std::integral_constant<unsigned, N>())[(*this)[N]];
int index(unsigned d = 0) const { return parent_->cache_[d].idx; }
auto indices() const { return indices_view(parent_->cache_); }
template <unsigned N = 0>
decltype(auto) bin(std::integral_constant<unsigned, N> = {}) const {
return parent_->hist_.axis(std::integral_constant<unsigned, N>())[index(N)];
}
decltype(auto) bin(unsigned d) const { return parent_->hist_.axis(d)[(*this)[d]]; }
decltype(auto) bin(unsigned d) const { return parent_->hist_.axis(d)[index(d)]; }
double density() const {
double x = 1;
auto it = begin();
auto it = parent_->cache_.begin();
parent_->hist_.for_each_axis([&](const auto& a) {
const auto w = axis::traits::width_as<double>(a, *it++);
const auto w = axis::traits::width_as<double>(a, it++->idx);
x *= w ? w : 1;
});
return *iter_ / x;
@ -77,10 +87,8 @@ public:
private:
accessor(indexed_range* parent, histogram_iterator i) : parent_(parent), iter_(i) {}
indexed_range* parent_;
histogram_iterator iter_;
friend class indexed_range;
};

View File

@ -59,7 +59,7 @@ void run_tests() {
BOOST_TEST_EQ(hr.axis(0)[3].upper(), 5);
BOOST_TEST_EQ(hr.axis(1)[0].lower(), -1);
BOOST_TEST_EQ(hr.axis(1)[2].upper(), 2);
for (auto x : indexed(h, coverage::all)) BOOST_TEST_EQ(hr.at(x), *x);
for (auto x : indexed(h, coverage::all)) BOOST_TEST_EQ(hr.at(x.indices()), *x);
BOOST_TEST_EQ(hr, h);
hr = reduce(h, shrink(0, 2, 4));

View File

@ -59,8 +59,8 @@ int main() {
BOOST_TEST_EQ(h.at(0, 0), 1);
for (auto&& x : indexed(h)) {
BOOST_TEST_THROWS(x.density(), std::runtime_error); // cannot use density method
BOOST_TEST_EQ(x[0], 2.0 * x.bin(0_c).lower() / si::meter);
BOOST_TEST_EQ(x[1], 2.0 * x.bin(1_c).lower());
BOOST_TEST_EQ(x.index(0), 2.0 * x.bin(0_c).lower() / si::meter);
BOOST_TEST_EQ(x.index(1), 2.0 * x.bin(1_c).lower());
}
}

View File

@ -32,28 +32,28 @@ void run_1d_tests(mp_list<IsDynamic, Coverage>) {
auto ind = indexed(h, Coverage());
auto it = ind.begin();
BOOST_TEST_EQ(it->size(), 1);
BOOST_TEST_EQ(it->indices().size(), 1);
if (Coverage() == coverage::all) {
BOOST_TEST_EQ(it->operator[](0), -1);
BOOST_TEST_EQ(it->index(0), -1);
BOOST_TEST_EQ(**it, 1);
BOOST_TEST_EQ(it->bin(0), h.axis()[-1]);
++it;
}
BOOST_TEST_EQ(it->operator[](0), 0);
BOOST_TEST_EQ(it->index(0), 0);
BOOST_TEST_EQ(**it, 2);
BOOST_TEST_EQ(it->bin(0), h.axis()[0]);
++it;
BOOST_TEST_EQ(it->operator[](0), 1);
BOOST_TEST_EQ(it->index(0), 1);
BOOST_TEST_EQ(**it, 3);
BOOST_TEST_EQ(it->bin(0), h.axis()[1]);
++it;
BOOST_TEST_EQ(it->operator[](0), 2);
BOOST_TEST_EQ(it->index(0), 2);
BOOST_TEST_EQ(**it, 4);
BOOST_TEST_EQ(it->bin(0), h.axis()[2]);
++it;
if (Coverage() == coverage::all) {
BOOST_TEST_EQ(it->operator[](0), 3);
BOOST_TEST_EQ(it->index(0), 3);
BOOST_TEST_EQ(**it, 5);
BOOST_TEST_EQ(it->bin(0), h.axis()[3]);
++it;
@ -78,7 +78,7 @@ void run_3d_tests(mp_list<IsDynamic, Coverage>) {
auto ind = indexed(h, Coverage());
auto it = ind.begin();
BOOST_TEST_EQ(it->size(), 3);
BOOST_TEST_EQ(it->indices().size(), 3);
const int d = Coverage() == coverage::all;
@ -86,9 +86,9 @@ void run_3d_tests(mp_list<IsDynamic, Coverage>) {
for (int k = 0; k < 4 + d; ++k)
for (int j = 0; j < 3; ++j)
for (int i = -d; i < 2 + d; ++i) {
BOOST_TEST_EQ(it->operator[](0), i);
BOOST_TEST_EQ(it->operator[](1), j);
BOOST_TEST_EQ(it->operator[](2), k);
BOOST_TEST_EQ(it->index(0), i);
BOOST_TEST_EQ(it->index(1), j);
BOOST_TEST_EQ(it->index(2), k);
BOOST_TEST_EQ(it->bin(0_c), h.axis(0_c)[i]);
BOOST_TEST_EQ(it->bin(1_c), h.axis(1_c)[j]);
BOOST_TEST_EQ(it->bin(2_c), h.axis(2_c)[k]);

View File

@ -62,9 +62,9 @@ static void IndexedLoop(benchmark::State& state) {
for (auto _ : state) {
for (auto x : boost::histogram::indexed(h, cov)) {
benchmark::DoNotOptimize(*x);
benchmark::DoNotOptimize(x[0]);
benchmark::DoNotOptimize(x[1]);
benchmark::DoNotOptimize(x[2]);
benchmark::DoNotOptimize(x.index(0));
benchmark::DoNotOptimize(x.index(1));
benchmark::DoNotOptimize(x.index(2));
}
}
}