Commit 119a8b87 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Add new accumulators: max/min elements + moment of inertia and fix

accu_as_it and variance accus.

	*  mln/accu/accumulators/accu_as_it.hpp,
	*  mln/accu/accumulators/max_elements.hpp,
	*  mln/accu/accumulators/min_elements.hpp,
	*  mln/accu/accumulators/moment_of_inertia.hpp: New
	*  mln/accu/accumulators/variance.hpp: Add mean extraction.
	*  tests/accu/CMakeLists.txt,
	*  tests/accu/max_elements.cpp,
	*  tests/accu/min_elements.cpp,
	*  tests/accu/moment_of_inertia.cpp: New.
parent 1c818d5e
......@@ -43,9 +43,13 @@ namespace mln
void take(const Accu& x)
{
m_accu.take(x.m_accu);
m_accu.take(x);
}
void take(const accu_as_it& x)
{
m_accu.take(x.m_accu);
}
void untake(const argument_type& x)
{
......
#ifndef MLN_ACCU_ACCUMULATORS_MAX_ELEMENTS_HPP
# define MLN_ACCU_ACCUMULATORS_MAX_ELEMENTS_HPP
/// \file
/// \brief Header file for the maximum accumulator
# include <mln/accu/accumulator.hpp>
# include <mln/accu/accumulator_base.hpp>
# include <mln/core/value/value_traits.hpp>
# include <utility>
# include <vector>
namespace mln
{
namespace accu
{
namespace accumulators
{
/// \brief Maximal elements accumulator.
///
/// Given a set (V,≺) where ≺ denotes a partial order.
/// x is a maximal element of a subset S ⊆ V if there is no
/// other y ∈ S that is greater than x. More formally:
/// ∀ y ∈ S, ¬(x ≺ y).
///
/// Note that the returned set may contain doublons.
/// \tparam T The type of elements to accumulate
/// \tparam Compare The comparison function ≼ (non-strict).
template <typename T, typename Compare = productorder_less_equal<T> >
struct maximal_elements;
}
namespace features
{
/// \brief Maximal elements accumulator.
/// \tparam T The argument type.
/// \tparam Compare The comparison function (`void` results in productorder_less by default).
template <typename Compare = void>
struct maximal_elements;
}
namespace extractor
{
template <typename A>
auto
maximal_elements(const Accumulator<A>& acc)
-> decltype( extract(exact(acc), features::maximal_elements<> ()) )
{
return extract(exact(acc), features::maximal_elements<> ());
}
}
namespace features
{
template <typename Compare>
struct maximal_elements : simple_feature< maximal_elements<Compare> >
{
maximal_elements(const Compare& cmp = Compare())
: m_cmp(cmp)
{
}
template <typename T>
struct apply
{
typedef accumulators::maximal_elements<T, Compare> type;
};
template <typename T>
accumulators::maximal_elements<T, Compare>
make() const
{
return accumulators::maximal_elements<T, Compare> (m_cmp);
}
private: // dynamic parameter.
Compare m_cmp;
};
namespace internal
{
template <typename T>
using meta_maximal_elements = accumulators::maximal_elements<T>;
}
template <>
struct maximal_elements<void>
: simple_feature_facade< maximal_elements<void>, internal::meta_maximal_elements>
{
};
}
namespace accumulators
{
template <typename T, typename Compare>
struct maximal_elements : accumulator_base< maximal_elements<T, Compare>, T, T,
features::maximal_elements<> >
{
typedef T argument_type;
typedef std::vector<T> return_type;
//typedef features::max<> feature;
maximal_elements(const Compare& cmp = Compare())
: m_cmp( cmp )
{
}
void init()
{
m_val.clear();
}
void take(const T& v)
{
bool inserted = false;
for (T& x: m_val)
if (m_cmp(v, x))
return;
else if (m_cmp(x, v)) // new maximal element
{
x = v;
inserted = true;
}
if (not inserted)
m_val.push_back(v);
}
template <typename Other>
void take(const Accumulator<Other>& other)
{
std::vector<T> vec = extractor::maximal_elements(other);
for (T v: vec)
this->take(v);
}
friend
std::vector<T>
extract(const maximal_elements& accu, features::maximal_elements<> )
{
return accu.m_val;
}
private:
std::vector<T> m_val;
Compare m_cmp;
};
}
}
}
#endif // ! MLN_ACCU_ACCUMULATORS_MAX_ELEMENTS_HPP
#ifndef MLN_ACCU_ACCUMULATORS_MIN_ELEMENTS_HPP
# define MLN_ACCU_ACCUMULATORS_MIN_ELEMENTS_HPP
/// \file
/// \brief Header file for the minimum accumulator
# include <mln/accu/accumulator.hpp>
# include <mln/accu/accumulator_base.hpp>
# include <mln/core/value/value_traits.hpp>
# include <utility>
# include <vector>
namespace mln
{
namespace accu
{
namespace accumulators
{
/// \brief Minimal elements accumulator.
/// \tparam T The argument.
/// \tparam Compare The comparison function (non strict partial or total order).
template <typename T, typename Compare = productorder_less_equal<T> >
struct minimal_elements;
}
namespace features
{
/// \brief Minimal elements accumulator.
/// \tparam T The argument type.
/// \tparam Compare The comparison function (`void` results in productorder_less by default).
template <typename Compare = void>
struct minimal_elements;
}
namespace extractor
{
template <typename A>
auto
minimal_elements(const Accumulator<A>& acc)
-> decltype( extract(exact(acc), features::minimal_elements<> ()) )
{
return extract(exact(acc), features::minimal_elements<> ());
}
}
namespace features
{
template <typename Compare>
struct minimal_elements : simple_feature< minimal_elements<Compare> >
{
minimal_elements(const Compare& cmp = Compare())
: m_cmp(cmp)
{
}
template <typename T>
struct apply
{
typedef accumulators::minimal_elements<T, Compare> type;
};
template <typename T>
accumulators::minimal_elements<T, Compare>
make() const
{
return accumulators::minimal_elements<T, Compare> (m_cmp);
}
private: // dynamic parameter.
Compare m_cmp;
};
namespace internal
{
template <typename T>
using meta_minimal_elements = accumulators::minimal_elements<T>;
}
template <>
struct minimal_elements<void>
: simple_feature_facade< minimal_elements<void>, internal::meta_minimal_elements>
{
};
}
namespace accumulators
{
template <typename T, typename Compare>
struct minimal_elements : accumulator_base< minimal_elements<T, Compare>, T, T, features::minimal_elements<> >
{
typedef T argument_type;
typedef std::vector<T> return_type;
//typedef features::min<> feature;
minimal_elements(const Compare& cmp = Compare())
: m_cmp( cmp )
{
}
void init()
{
m_val.clear();
}
void take(const T& v)
{
bool inserted = false;
for (T& x: m_val)
if (m_cmp(x, v))
return;
else if (m_cmp(v, x)) // new minimal element
{
x = v;
inserted = true;
}
if (not inserted)
m_val.push_back(v);
}
template <typename Other>
void take(const Accumulator<Other>& other)
{
std::vector<T> vec = extractor::minimal_elements(other);
for (T v: vec)
this->take(v);
}
friend
std::vector<T>
extract(const minimal_elements& accu, features::minimal_elements<> )
{
return accu.m_val;
}
private:
std::vector<T> m_val;
Compare m_cmp;
};
}
}
}
#endif // ! MLN_ACCU_ACCUMULATORS_MIN_ELEMENTS_HPP
#ifndef MLN_ACCU_ACCUMULATORS_MOMENT_OF_INERTIA_HPP
# define MLN_ACCU_ACCUMULATORS_MOMENT_OF_INERTIA_HPP
# include <mln/core/math_ops.hpp>
# include <mln/accu/accumulators/sum.hpp>
# include <mln/accu/accumulators/count.hpp>
# include <mln/accu/accumulators/mean.hpp>
# include <mln/accu/composite_accumulator.hpp>
# include <boost/type_traits/promote.hpp>
/// \file
/// \brief Moment of inertia accumulator.
namespace mln
{
namespace accu
{
namespace accumulators
{
/// \brief Accumulator for the scale invariant moment of inertia
///
/// The moment of inertia is the 1st hu moment, i.e., in the 2D
/// case:
///
/// \f$ \frac{1}{n^(1+2/d)} \mu_{(2,0)} + \mu_{(0,2)} \f$
/// with:
/// \f[
/// \mu_{pq} = \sum_{x} \sum_{y} (x - \bar{x})^p(y -
/// \bar{y})^q
/// \f]
template <typename T,
typename SumType = typename boost::promote<T>::type,
typename SumSqrType = SumType>
struct moment_of_inertia;
}
namespace features
{
template <typename SumType = void,
typename SumSqrType = SumType>
struct moment_of_inertia;
}
namespace extractor
{
template <typename A>
inline
auto
moment_of_inertia(const Accumulator<A>& acc)
-> decltype(extract(exact(acc), features::moment_of_inertia<> ()))
{
return extract(exact(acc), features::moment_of_inertia<> ());
}
}
namespace features
{
namespace internal
{
template <typename SumType, typename SumSqrType>
struct meta_moment_of_inertia
{
template <typename T>
using type = accu::accumulators::moment_of_inertia<T, SumType, SumSqrType>;
};
template <>
struct meta_moment_of_inertia<void, void>
{
template <typename T>
using type = accu::accumulators::moment_of_inertia<T>;
};
}
template <typename SumType,
typename SumSqrType>
struct moment_of_inertia : simple_feature_facade<
moment_of_inertia<SumType, SumSqrType>,
internal::meta_moment_of_inertia<SumType, SumSqrType>::template type
>
{
};
}
namespace accumulators
{
template <typename T, typename SumType, typename SumSqrType>
struct moment_of_inertia : accumulator_base< moment_of_inertia<T, SumType, SumSqrType>,
T,
double,
features::moment_of_inertia<> >
{
typedef T argument_type;
typedef double result_type;
moment_of_inertia()
: m_count {0},
m_sum {},
m_sum_sqr {}
{
}
void init()
{
m_count = 0;
m_sum = SumType ();
m_sum_sqr = SumSqrType ();
}
void take(const argument_type& arg)
{
SumSqrType x(arg);
m_count += 1;
m_sum += SumType(arg);
m_sum_sqr += x * x;
}
void untake(const argument_type& arg)
{
SumSqrType x(arg);
m_count -= 1;
m_sum -= SumType(arg);
m_sum_sqr -= x * x;
}
void take(const moment_of_inertia& other)
{
m_count += other.m_count;
m_sum += other.m_sum;
m_sum_sqr += other.m_sum_sqr;
}
void untake(const moment_of_inertia& other)
{
m_count -= other.m_count;
m_sum -= other.m_sum;
m_sum_sqr -= other.m_sum_sqr;
}
template <class ST1, class ST2>
friend
result_type extract(const moment_of_inertia& accu, features::moment_of_inertia<ST1, ST2> )
{
using mln::sum;
if (accu.m_count == 0)
return 0;
result_type n = accu.m_count;
result_type inertia = sum(accu.m_sum_sqr - sqr(accu.m_sum) / n);
constexpr unsigned dim = value_traits<typename moment_of_inertia::argument_type>::ndim;
if (dim == 2)
return inertia / sqr(n);
else
return inertia / std::pow(n, 1.0 + 2.0 / value_traits<typename moment_of_inertia::argument_type>::ndim);
}
friend
unsigned extract(const moment_of_inertia& accu, features::count<> )
{
return accu.m_count;
}
friend
SumType
extract(const moment_of_inertia& accu, features::mean<> )
{
return accu.m_sum / accu.m_count;
}
private:
unsigned m_count;
SumType m_sum;
SumSqrType m_sum_sqr;
};
}
}
}
#endif // ! MLN_ACCU_ACCUMULATORS_MOMENT_OF_INERTIA_HPP
......@@ -3,6 +3,7 @@
# include <mln/accu/accumulators/sum.hpp>
# include <mln/accu/accumulators/count.hpp>
# include <mln/accu/accumulators/mean.hpp>
# include <mln/accu/composite_accumulator.hpp>
# include <boost/type_traits/promote.hpp>
......@@ -149,6 +150,13 @@ namespace mln
return accu.m_count;
}
friend
SumType
extract(const variance& accu, features::mean<> )
{
return accu.m_sum / accu.m_count;
}
private:
unsigned m_count;
SumType m_sum;
......
......@@ -3,9 +3,15 @@ add_executable(count count.cpp)
add_executable(mean mean.cpp)
add_executable(infsup infsup.cpp)
add_executable(composite_accumulator composite_accumulator.cpp)
add_executable(min_elements min_elements.cpp)
add_executable(max_elements max_elements.cpp)
add_executable(moment_of_inertia moment_of_inertia.cpp)
add_core_test(sum sum)
add_core_test(infsup infsup)
add_core_test(count count)
add_core_test(mean mean)
add_core_test(min_elements min_elements)
add_core_test(max_elements max_elements)
add_core_test(composite_accumulator composite_accumulator)
add_core_test(moment_of_inertia moment_of_inertia)
#include <mln/accu/accumulators/max_elements.hpp>
#include <mln/core/colors.hpp>
#define BOOST_TEST_MODULE Accu
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(Max_elements)
{
using namespace mln::accu;
accumulators::maximal_elements<unsigned> acc;
acc.take(5);
acc.take(15);
acc.take(2);
{
auto res = extractor::maximal_elements(acc);
BOOST_CHECK_EQUAL(res.size(), 1u);
BOOST_CHECK_EQUAL(res[0], 15u);
}
acc.take(15);
acc.take(2);
{
auto res = extractor::maximal_elements(acc);
BOOST_CHECK_EQUAL(res.size(), 1u);
BOOST_CHECK_EQUAL(res[0], 15u);
}
}
BOOST_AUTO_TEST_CASE(Max_elements_vec)
{
using namespace mln;
using namespace mln::accu;
accumulators::maximal_elements<rgb8> acc;
acc.take(rgb8 {(uint8)5, (uint8)5, (uint8)255});
acc.take(rgb8 {(uint8)255, (uint8)5, (uint8)255});
acc.take(rgb8 {(uint8)2, (uint8)2, (uint8)25});
{
auto res = extractor::maximal_elements(acc);
BOOST_CHECK_EQUAL(res.size(), 1u);
BOOST_CHECK_EQUAL(res[0], (rgb8 {(uint8)255, (uint8)5, (uint8)255}));
}