Commit c206bb3e authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Merge branch 'development/border-management' into 'development/ranges'

New border management system

See merge request !65
parents e04a9fc8 69d0bd8d
{
"files.associations": {
"tuple": "cpp",
"slist": "cpp",
"cstdint": "cpp",
"__config": "cpp",
"__nullptr": "cpp",
"cstddef": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"new": "cpp",
"stdexcept": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"__locale": "cpp",
"algorithm": "cpp",
"array": "cpp",
"fstream": "cpp",
"functional": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"locale": "cpp",
"map": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"string": "cpp",
"utility": "cpp",
"vector": "cpp",
"__bit_reference": "cpp",
"__hash_table": "cpp",
"__split_buffer": "cpp",
"__tree": "cpp",
"deque": "cpp",
"iterator": "cpp",
"regex": "cpp",
"set": "cpp",
"string_view": "cpp",
"unordered_set": "cpp",
"bitset": "cpp",
"memory": "cpp",
"optional": "cpp",
"variant": "cpp",
"random": "cpp",
"__debug": "cpp",
"__functional_03": "cpp",
"__functional_base": "cpp",
"__functional_base_03": "cpp",
"__string": "cpp",
"__tuple": "cpp",
"atomic": "cpp",
"limits": "cpp",
"complex": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"valarray": "cpp",
"chrono": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"thread": "cpp",
"queue": "cpp",
"stack": "cpp"
},
"python.pythonPath": "/usr/bin/python3",
"C_Cpp.configurationWarnings": "Disabled",
"git.ignoreLimitWarning": true,
"cquery.misc.compilationDatabaseDirectory": "${workspaceRoot}/build-gcc"
}
\ No newline at end of file
{}
\ No newline at end of file
......@@ -2,6 +2,7 @@
#include <mln/core/image/image.hpp>
#include <mln/core/rangev3/rows.hpp>
#include <mln/core/rangev3/view/reverse.hpp>
#include <mln/core/rangev3/view/zip.hpp>
#include <mln/io/imprint.hpp>
......@@ -27,7 +28,10 @@ namespace fixtures::ImageCompare
{
template <class ImageLhs, class ImageRhs>
bool compare(ImageLhs f, ImageRhs g);
}
template <class ImageLhs, class ImageRhs>
bool compare_with_border(ImageLhs f, ImageRhs g, std::size_t default_border = 3);
} // namespace experimental
/******************************************/
/**** Implementation ****/
......@@ -52,10 +56,13 @@ namespace fixtures::ImageCompare
namespace impl
{
template <class I, class J>
std::string err_compare_msg(const mln::Image<I>& reference, const mln::Image<J>& input)
std::string err_compare_msg(const mln::Image<I>& reference, const mln::Image<J>& input, bool eq = true)
{
std::stringstream msg;
msg << "The following images differs:\n";
if (eq)
msg << "The following images differ:\n";
else
msg << "The following images are identical:\n";
mln::io::imprint(reference, msg);
msg << " and\n:";
mln::io::imprint(input, msg);
......@@ -72,44 +79,143 @@ namespace fixtures::ImageCompare
static_assert(mln::is_a<ImageLhs, mln::experimental::Image>());
static_assert(mln::is_a<ImageRhs, mln::experimental::Image>());
auto f_dom = f.domain();
auto g_dom = g.domain();
using f_domain_t = typename ImageLhs::domain_type;
using g_domain_t = typename ImageRhs::domain_type;
constexpr auto f_dim = f_domain_t::ndim;
constexpr auto g_dim = g_domain_t::ndim;
static_assert(f_dim == g_dim);
{
auto f_dom = f.domain();
auto g_dom = g.domain();
auto f_dom_b = ::ranges::begin(f_dom);
auto g_dom_b = ::ranges::begin(g_dom);
auto f_dom_e = ::ranges::end(f_dom);
auto g_dom_e = ::ranges::end(g_dom);
for (; (f_dom_b != f_dom_e) || (g_dom_b != g_dom_e); ++f_dom_b, ++g_dom_b)
if (*f_dom_b != *g_dom_b)
return false;
auto f_dom_b = ::ranges::begin(f_dom);
auto g_dom_b = ::ranges::begin(g_dom);
auto f_dom_e = ::ranges::end(f_dom);
auto g_dom_e = ::ranges::end(g_dom);
for (; (f_dom_b != f_dom_e) || (g_dom_b != g_dom_e); ++f_dom_b, ++g_dom_b)
if (*f_dom_b != *g_dom_b)
if ((f_dom_b != f_dom_e) || (g_dom_b != g_dom_e))
return false;
}
if ((f_dom_b != f_dom_e) || (g_dom_b != g_dom_e))
return false;
{
auto zipped_vals = mln::ranges::view::zip(f.new_values(), g.new_values());
for (auto&& r : mln::ranges::rows(zipped_vals))
for (auto&& [f_v, g_v] : r)
if (f_v != g_v)
return false;
}
return true;
}
namespace detail
{
template <typename Pnt, typename S, std::size_t... I>
Pnt shift_pnt_impl(const Pnt& p, S shift, std::index_sequence<I...>)
{
return Pnt((p[I] + shift)...);
}
template <std::size_t D, typename Pnt, typename S>
Pnt shift_pnt(const Pnt& p, S shift)
{
return shift_pnt_impl(p, shift, std::make_index_sequence<D>{});
}
} // namespace detail
template <class ImageLhs, class ImageRhs>
bool compare_with_border(ImageLhs f, ImageRhs g, std::size_t default_border)
{
static_assert(mln::is_a<ImageLhs, mln::experimental::Image>());
static_assert(mln::is_a<ImageRhs, mln::experimental::Image>());
using f_domain_t = typename ImageLhs::domain_type;
using g_domain_t = typename ImageRhs::domain_type;
constexpr auto f_dim = f_domain_t::ndim;
constexpr auto g_dim = g_domain_t::ndim;
static_assert(f_dim == g_dim);
auto zipped_vals = mln::ranges::view::zip(f.new_values(), g.new_values());
for (auto&& r : mln::ranges::rows(zipped_vals))
for (auto&& [f_v, g_v] : r)
if (f_v != g_v)
auto pmin = typename f_domain_t::point_type{};
auto pmax = typename f_domain_t::point_type{};
{
auto f_dom = f.domain();
auto g_dom = g.domain();
pmin = *::ranges::begin(f_dom);
auto f_dom_r = mln::ranges::view::reverse(f_dom);
pmax = *::ranges::begin(f_dom_r);
auto f_dom_b = ::ranges::begin(f_dom);
auto g_dom_b = ::ranges::begin(g_dom);
auto f_dom_e = ::ranges::end(f_dom);
auto g_dom_e = ::ranges::end(g_dom);
for (; (f_dom_b != f_dom_e) || (g_dom_b != g_dom_e); ++f_dom_b, ++g_dom_b)
if (*f_dom_b != *g_dom_b)
return false;
if ((f_dom_b != f_dom_e) || (g_dom_b != g_dom_e))
return false;
}
{
int border = 0;
auto f_ext = f.extension();
auto g_ext = g.extension();
border = std::min(std::min(f_ext.extent(), g_ext.extent()), static_cast<int>(default_border));
auto extended_dom =
f_domain_t{detail::shift_pnt<f_dim>(pmin, -border), detail::shift_pnt<f_dim>(pmax, +border)};
for (auto&& p : extended_dom)
if (f.at(p) != g.at(p))
return false;
}
return true;
}
} // namespace experimental
namespace impl
{
template <class ImageLhs, class ImageRhs>
std::string err_compare_msg(ImageLhs f, ImageRhs g)
std::string err_compare_msg(ImageLhs f, ImageRhs g, bool eq = true)
{
static_assert(mln::is_a<ImageLhs, mln::experimental::Image>());
static_assert(mln::is_a<ImageRhs, mln::experimental::Image>());
std::stringstream msg;
msg << "The following images differs:\n";
if (eq)
msg << "The following images differ:\n";
else
msg << "The following images are identical:\n";
mln::io::experimental::imprint(f, msg);
msg << " and\n:";
mln::io::experimental::imprint(g, msg);
return msg.str();
}
template <class ImageLhs, class ImageRhs>
std::string err_compare_with_border_msg(ImageLhs f, ImageRhs g, bool eq = true, std::size_t default_border = 3)
{
static_assert(mln::is_a<ImageLhs, mln::experimental::Image>());
static_assert(mln::is_a<ImageRhs, mln::experimental::Image>());
std::stringstream msg;
if (eq)
msg << "The following images differ:\n";
else
msg << "The following images are identical:\n";
mln::io::experimental::imprint_with_border(f, msg, default_border);
msg << " and\n:";
mln::io::experimental::imprint_with_border(g, msg, default_border);
return msg.str();
}
} // namespace impl
} // namespace experimental
......@@ -120,6 +226,21 @@ namespace fixtures::ImageCompare
#define ASSERT_IMAGES_EQ(f, g) \
ASSERT_TRUE(::fixtures::ImageCompare::compare(f, g)) << ::fixtures::ImageCompare::impl::err_compare_msg(f, g)
#define ASSERT_IMAGES_NE(f, g) \
ASSERT_FALSE(::fixtures::ImageCompare::compare(f, g)) << ::fixtures::ImageCompare::impl::err_compare_msg(f, g, false)
#define ASSERT_IMAGES_EQ_EXP(f, g) \
ASSERT_TRUE(::fixtures::ImageCompare::experimental::compare(f, g)) \
<< ::fixtures::ImageCompare::experimental::impl::err_compare_msg(f, g)
#define ASSERT_IMAGES_NE_EXP(f, g) \
ASSERT_FALSE(::fixtures::ImageCompare::experimental::compare(f, g)) \
<< ::fixtures::ImageCompare::experimental::impl::err_compare_msg(f, g, false)
#define ASSERT_IMAGES_WITH_BORDER_EQ_EXP(f, g) \
ASSERT_TRUE(::fixtures::ImageCompare::experimental::compare_with_border(f, g)) \
<< ::fixtures::ImageCompare::experimental::impl::err_compare_with_border_msg(f, g)
#define ASSERT_IMAGES_WITH_BORDER_NE_EXP(f, g) \
ASSERT_FALSE(::fixtures::ImageCompare::experimental::compare_with_border(f, g)) \
<< ::fixtures::ImageCompare::experimental::impl::err_compare_with_border_msg(f, g, false)
......@@ -104,6 +104,6 @@ install(FILES
DESTINATION lib/cmake/pylene)
# GCC8 has enoying random compilation failures
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
target_compile_definitions(Pylene PUBLIC PYLENE_GCC8_WORKAROUND)
endif()
......@@ -2,7 +2,7 @@ include(CMakeFindDependencyMacro)
find_dependency(Boost 1.58)
find_dependency(range-v3 0.5.0)
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.2)
if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.2)
find_dependency(cmcstl2)
endif()
......
#pragma once
#include <mln/accu/accumulator.hpp>
#include <mln/core/canvas/local_accumulation.hpp>
#include <mln/core/concept/new/structuring_elements.hpp>
#include <mln/core/extension/border_management.hpp>
#include <mln/core/extension/extension.hpp>
#include <mln/core/image/image.hpp>
#include <variant>
namespace mln
{
template <class A, class I, class J, class SE, extension::BorderManagementMethod bmm>
void accumulate_local(I f, const experimental::StructuringElement<SE>& se, const AccumulatorLike<A>& accu,
extension::border_manager<bmm> bm, J g);
template <class A, class I, class SE, extension::BorderManagementMethod bmm>
ch_value_t<I, accu::result_of_t<A, image_value_t<I>>>
accumulate_local(I f, const experimental::StructuringElement<SE>& se, const AccumulatorLike<A>& accu,
extension::border_manager<bmm> bm);
/******************************************/
/**** Implementation ****/
/******************************************/
template <class A, class I, class J, class SE, extension::BorderManagementMethod bmm>
void accumulate_local(I f, const experimental::StructuringElement<SE>& se_, const AccumulatorLike<A>& accu_,
extension::border_manager<bmm> bm, J g)
{
static_assert(mln::is_a<I, experimental::Image>());
static_assert(mln::is_a<J, experimental::Image>());
const SE& se = static_cast<const SE&>(se_);
auto accu = accu::make_accumulator(mln::exact(accu_), image_value_t<I>());
auto [managed_ima, managed_se] = bm.manage(f, se);
std::visit(
[&accu, &g](auto ima, auto s) {
auto algo = canvas::make_LocalAccumulation(accu, s, ima, g);
// canvas::LocalAccumulation algo(accu, se, *extended, g);
algo.Execute();
},
managed_ima, managed_se);
}
template <class A, class I, class SE, extension::BorderManagementMethod bmm>
image_ch_value_t<I, accu::result_of_t<A, image_value_t<I>>>
accumulate_local(I f, const experimental::StructuringElement<SE>& se, const AccumulatorLike<A>& accu,
extension::border_manager<bmm> bm)
{
using V = accu::result_of_t<A, image_value_t<I>>;
image_ch_value_t<I, V> g = imchvalue<V>(f);
accumulate_local(std::move(f), se, accu, bm, g);
return g;
}
} // namespace mln
#pragma once
#include <mln/core/rangev3/multi_indices.hpp>
#include <mln/core/experimental/point.hpp>
#include <mln/core/rangev3/multi_indices.hpp>
#include <array>
#include <type_traits>
#ifdef PYLENE_CONCEPT_TS_ENABLED
#include <stl2/type_traits.hpp>
#endif
......@@ -21,7 +24,7 @@ namespace mln::experimental
template <int D, class T>
struct _bref;
};
}; // namespace impl
/******************************************/
/**** Box Types and Types Aliases ****/
......@@ -36,9 +39,9 @@ namespace mln::experimental
using ndboxref = _box<impl::_bref<dim, const int>>;
using box1d = ndbox<1>;
using box2d = ndbox<2>;
using box3d = ndbox<3>;
using box1d = ndbox<1>;
using box2d = ndbox<2>;
using box3d = ndbox<3>;
using const_box1d_ref = ndboxref<1>;
using const_box2d_ref = ndboxref<2>;
using const_box3d_ref = ndboxref<3>;
......@@ -63,9 +66,9 @@ namespace mln::experimental
friend struct impl::_bref;
using typename Impl::coord_type;
using Impl::Impl;
using Impl::ndim;
using typename Impl::coord_type;
/// Observers
......@@ -134,9 +137,15 @@ namespace mln::experimental
/// \brief Returns the bottom-right (past-the-end) corner point
using Impl::br;
/// \brief Returns the shape of the domain
using Impl::shape;
/// \brief Returns the number of dimensions
using Impl::dim;
/// \brief Returns the size of each dimension
using Impl::extents;
/// \brief Returns a pointer to the coordinate array
using Impl::data;
/// \}
......@@ -202,7 +211,6 @@ namespace mln::experimental
};
/******************************************/
/**** Implementation ****/
/******************************************/
......@@ -351,6 +359,17 @@ namespace mln::experimental
constexpr point_type br() const noexcept { return m_end; }
constexpr point_type& br() noexcept { return m_end; }
constexpr auto shape() const noexcept { return tl() - br(); }
constexpr auto extents() const noexcept
{
auto pmin = tl();
auto pmax = br();
auto ret = std::array<std::size_t, D>{};
for (int i = 0; i < D; i++)
ret[i] = pmax[i] - pmin[i];
return ret;
}
constexpr point_type __from() const noexcept { return m_begin; }
constexpr point_type __to() const noexcept { return m_end; }
......@@ -472,6 +491,17 @@ namespace mln::experimental
constexpr ConstPointRef br() const noexcept { return {m_dim, m_coords + m_dim}; }
constexpr PointRef br() noexcept { return {m_dim, m_coords + m_dim}; }
constexpr auto shape() const noexcept { return tl() - br(); }
auto extents() const noexcept
{
auto pmin = tl();
auto pmax = br();
auto ret = std::vector<std::size_t>{m_dim, 0};
for (int i = 0; i < m_dim; i++)
ret[i] = pmax[i] - pmin[i];
return ret;
}
constexpr int begin() const noexcept { return 0; }
constexpr int end() const noexcept { return 1; }
......@@ -499,8 +529,21 @@ namespace mln::experimental
constexpr T& __begin(int k) const noexcept { return assert(k < D), m_coords[k]; }
constexpr T& __end(int k) const noexcept { return assert(k < D), m_coords[D + k]; }
constexpr ndpointref<D, T> tl() const noexcept { return {m_coords}; }
constexpr ndpointref<D, T> br() const noexcept { return {m_coords + D}; }
constexpr ndpointref<D, T> tl() const noexcept { return {m_coords}; }
constexpr ndpointref<D, T> br() const noexcept { return {m_coords + D}; }
constexpr auto shape() const noexcept { return tl() - br(); }
constexpr auto extents() const noexcept
{
auto pmin = tl();
auto pmax = br();
auto ret = std::array<std::size_t, D>{};
for (int i = 0; i < D; i++)
ret[i] = pmax[i] - pmin[i];
return ret;
}
constexpr ndpoint<D, std::remove_const_t<T>> __from() const noexcept { return tl(); }
constexpr ndpoint<D, std::remove_const_t<T>> __to() const noexcept { return br(); }
......@@ -537,6 +580,17 @@ namespace mln::experimental
constexpr ConstPointRef tl() const noexcept { return {m_dim, m_coords}; }
constexpr ConstPointRef br() const noexcept { return {m_dim, m_coords + m_dim}; }
constexpr auto shape() const noexcept { return tl() - br(); }
auto extents() const noexcept
{
auto pmin = tl();
auto pmax = br();
auto ret = std::vector<std::size_t>{m_dim, 0};
for (int i = 0; i < m_dim; i++)
ret[i] = pmax[i] - pmin[i];
return ret;
}
int begin() const { return 0; }
int end() const { return 1; }
......@@ -692,4 +746,3 @@ STL2_OPEN_NAMESPACE
}
STL2_CLOSE_NAMESPACE
#endif
#pragma once
#include <mln/core/canvas/local_algorithm.hpp>
namespace mln::canvas
{
template <class Accu, class SE, class I, class J,
bool __incremental__ = SE::incremental::value&& Accu::has_untake::value>
class LocalAccumulation;
template <class Accu, class SE, class I, class J>
class LocalAccumulation<Accu, SE, I, J, false> : public LocalAlgorithm<SE, I, J>
{
private:
using base_t = LocalAlgorithm<SE, I, J>;
Accu m_accu;
public:
LocalAccumulation(Accu accu, SE se, I& f, J& g)
: base_t{std::move(se), f, g}
, m_accu{std::move(accu)}
{
}
private:
void ExecuteAtLineStart() final { m_accu.init(); }
void EvalBeforeLocalLoop(image_reference_t<I> /*pval_i*/, image_reference_t<J> /*pval_j*/) final { m_accu.init(); }
void EvalAfterLocalLoop(image_reference_t<I> /* pval_i */, image_reference_t<J> pval_j) final
{
pval_j = m_accu.to_result();
}
void EvalInLocalLoop(image_reference_t<I> nval_i, image_reference_t<I> /* pval_i */,
image_reference_t<J> /*pval_j*/) final
{
m_accu.take(nval_i);
}
};
template <class Accu, class SE, class I, class J>
class LocalAccumulation<Accu, SE, I, J, true> : public IncrementalLocalAlgorithm<SE, I, J>
{
private:
using base_t = IncrementalLocalAlgorithm<SE, I, J>;
Accu m_accu;
public:
LocalAccumulation(Accu accu, SE se, I& f, J& g)
: base_t{std::move(se), f, g}
, m_accu{std::move(accu)}
{
}
private:
void ExecuteAtLineStart() final { m_accu.init(); }
void EvalBeforeLocalLoop(image_reference_t<I> /* pval_i */, image_reference_t<J> /* pval_j */) final