SOPT
Sparse OPTimisation
innards.impl.h
Go to the documentation of this file.
1 #ifndef SOPT_WAVELETS_INNARDS_H
2 #define SOPT_WAVELETS_INNARDS_H
3 
4 #include "sopt/config.h"
5 #include <algorithm> // for std::copy<>
6 #include <Eigen/Core>
7 
8 // Function inside anonymouns namespace won't appear in library
9 namespace sopt::wavelets {
10 namespace {
14 template <typename T0>
15 auto copy(Eigen::ArrayBase<T0> const &a) ->
16  typename std::remove_const<typename std::remove_reference<decltype(a.eval())>::type>::type {
17  return a.eval();
18 }
19 
25 template <typename T0, typename T2>
26 typename T0::Scalar periodic_scalar_product(Eigen::ArrayBase<T0> const &a,
27  Eigen::ArrayBase<T2> const &b,
28  typename T0::Index offset) {
29  auto const Na = static_cast<typename T0::Index>(a.size());
30  auto const Nb = static_cast<typename T0::Index>(b.size());
31  // offset in [0, a.size()[
32  offset %= Na;
33  if (offset < 0) offset += Na;
34  // Simple case, just do it
35  if (Na > Nb + offset) {
36  return (a.segment(offset, Nb) * b).sum();
37  }
38  // Wrap around, do it, but carefully
39  typename T0::Scalar result(0);
40  for (typename T0::Index i(0), j(offset); i < Nb; ++i, ++j) result += a(j % Na) * b(i);
41  return result;
42 }
43 
46 template <typename T0, typename T1, typename T2>
47 void convolve(Eigen::ArrayBase<T0> &result, Eigen::ArrayBase<T1> const &signal,
48  Eigen::ArrayBase<T2> const &filter) {
49  assert(result.size() == signal.size());
50  for (typename T0::Index i(0); i < t_int(signal.size()); ++i)
51  result(i) = periodic_scalar_product(signal, filter, i);
52 }
54 template <typename T0, typename T1, typename T2>
55 void convolve(Eigen::VectorBlock<T0> &&result, Eigen::ArrayBase<T1> const &signal,
56  Eigen::ArrayBase<T2> const &filter) {
57  return convolve(result, signal, filter);
58 }
59 
62 template <typename T0, typename T1, typename T2>
63 void down_convolve(Eigen::ArrayBase<T0> &result, Eigen::ArrayBase<T1> const &signal,
64  Eigen::ArrayBase<T2> const &filter) {
65  assert(result.size() * 2 <= signal.size());
66  if (signal.rows() == 1) {
67 #ifdef SOPT_OPENMP
68 #pragma omp parallel for
69 #endif
70  for (typename T0::Index i = 0; i < result.size(); ++i)
71  result(i) = periodic_scalar_product(signal.transpose(), filter, 2 * i);
72  } else {
73 #ifdef SOPT_OPENMP
74 #pragma omp parallel for
75 #endif
76  for (typename T0::Index i = 0; i < result.size(); ++i)
77  result(i) = periodic_scalar_product(signal, filter, 2 * i);
78  }
79 }
81 template <typename T0, typename T1, typename T2>
82 void down_convolve(Eigen::VectorBlock<T0> &&result, Eigen::ArrayBase<T1> const &signal,
83  Eigen::ArrayBase<T2> const &filter) {
84  down_convolve(result, signal, filter);
85 }
86 
88 template <typename T0, typename T1, typename T2, typename T3, typename T4>
89 void convolve_sum(Eigen::ArrayBase<T0> &result, Eigen::ArrayBase<T1> const &low_pass_signal,
90  Eigen::ArrayBase<T2> const &low_pass,
91  Eigen::ArrayBase<T3> const &high_pass_signal,
92  Eigen::ArrayBase<T4> const &high_pass) {
93  assert(result.size() == low_pass_signal.size());
94  assert(result.size() == high_pass_signal.size());
95  assert(low_pass.size() == high_pass.size());
96  static_assert(std::is_signed<typename T0::Index>::value, "loffset, hoffset expect signed values");
97  auto const loffset = 1 - static_cast<typename T0::Index>(low_pass.size());
98  auto const hoffset = 1 - static_cast<typename T0::Index>(high_pass.size());
99  for (typename T0::Index i(0); i < result.size(); ++i) {
100  result(i) = periodic_scalar_product(low_pass_signal, low_pass, i + loffset) +
101  periodic_scalar_product(high_pass_signal, high_pass, i + hoffset);
102  }
103 }
104 
112 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
113 void up_convolve_sum(Eigen::ArrayBase<T0> &result, Eigen::ArrayBase<T1> const &coeffs,
114  Eigen::ArrayBase<T2> const &low_even, Eigen::ArrayBase<T3> const &low_odd,
115  Eigen::ArrayBase<T4> const &high_even, Eigen::ArrayBase<T5> const &high_odd) {
116  assert(result.size() <= coeffs.size());
117  assert(result.size() % 2 == 0);
118  assert(low_even.size() == high_even.size());
119  assert(low_odd.size() == high_odd.size());
120  auto const Nlow = (coeffs.size() + 1) / 2;
121  auto const Nhigh = coeffs.size() / 2;
122  auto const size = low_even.size() + low_odd.size();
123  auto const is_even = size % 2 == 0;
124  auto const even_offset = (1 - size) / 2;
125  auto const odd_offset = (1 - size) / 2 + (is_even ? 0 : 1);
126  auto const index_place_even = (is_even ? 1 : 0);
127  auto const index_place_odd = (is_even ? 0 : 1);
128 #ifdef SOPT_OPENMP
129 #pragma omp parallel for
130 #endif
131  for (typename T0::Index i = 0; i < result.size() / 2; i++) {
132  result(2 * i + index_place_even) =
133  periodic_scalar_product(coeffs.head(Nlow), low_even, i + even_offset) +
134  periodic_scalar_product(coeffs.tail(Nhigh), high_even, i + even_offset);
135  result(2 * i + index_place_odd) =
136  periodic_scalar_product(coeffs.head(Nlow), low_odd, i + odd_offset) +
137  periodic_scalar_product(coeffs.tail(Nhigh), high_odd, i + odd_offset);
138  }
139 }
140 } // namespace
141 } // namespace sopt::wavelets
142 #endif
constexpr Scalar b
sopt::t_real Scalar
constexpr Scalar a
int t_int
Root of the type hierarchy for signed integers.
Definition: types.h:13