CppNCorr
C++ ncorr Digital Image Correlation engine
Loading...
Searching...
No Matches
Array2D.h
Go to the documentation of this file.
1/*
2 * File: Array2D.h
3 * Author: justin
4 *
5 * Created on December 30, 2014, 4:55 PM
6 */
7
8#ifndef ARRAY2D_H
9#define ARRAY2D_H
10
11#include <cstddef>
12#include <memory>
13#include <iostream>
14#include <fstream>
15#include <utility>
16#include <mutex>
17#include <cmath>
18#include <algorithm>
19#include <limits>
20#include <string>
21
22#include "ncorr/log.h"
23
24// Non standard libraries
25extern "C" { // Blas - for matrix multiplication
26 void dgemm_(char*, char*, int*, int*, int*, double*, double*, int*, double*, int*, double*, double*, int*);
27}
28#include "fftw3.h" // For convolution and deconvolution
29#include "opencv2/opencv.hpp" // For imshow()
30#include "suitesparse/SuiteSparseQR.hpp" // for in-paint
31
32namespace ncorr {
33
34namespace details {
35 class last_index { };
36 class all_range { };
37
38 template <typename> class base_iterator;
39 template <typename> class simple_iterator;
40 template <typename> class sub_iterator;
41 template <typename> class bool_iterator;
42 template <typename> class interface_iterator;
43
44 template <typename> class base_region;
45 template <typename> class simple_region;
46 template <typename> class sub_region;
47 template <typename> class bool_region;
48 template <typename> class interface_region;
49
50 template <typename> class base_interp;
51 template <typename> class nearest_interp;
52 template <typename> class linear_interp;
53 template <typename> class cubic_interp;
54 template <typename> class cubic_interp_precompute;
55 template <typename> class quintic_interp;
56 template <typename> class quintic_interp_precompute;
57 template <typename> class interface_interp;
58
59 template <typename> class base_linsolver;
60 template <typename> class LU_linsolver;
61 template <typename> class QR_linsolver;
62 template <typename> class CHOL_linsolver;
63 template <typename> class interface_linsolver;
64}
65
66// These can be passed as arguments in Array2D indexing operations -----------//
67// "last" is used instead of "end" because end() is the function call for the
68// end iterator and results in a name collision when used in Array2D methods.
71
72// Define enums for functions that take them ---------------------------------//
73enum class PAD { ZEROS, EXPAND_EDGES };
74// Make sure ordering of INTERP depends on polynomial order, as some functions
75// only work for higher order interpolation and use relational operators on
76// input INTERP to test for this.
78enum class LINSOLVER { LU, QR, CHOL };
79
80template <typename T, typename T_alloc = std::allocator<T>>
81class Array2D final {
82// -------------------------------------------------------------------------- //
83// -------------------------------------------------------------------------- //
84// Note: This container only works with stateless, default-constructed //
85// allocators. Allocators are not passed around; they are created when //
86// Array2Ds are created, using their default constructor. //
87// -------------------------------------------------------------------------- //
88// -------------------------------------------------------------------------- //
89 public:
90 typedef T value_type;
91 typedef T* pointer;
92 typedef const T* const_pointer;
93 typedef T& reference;
94 typedef const T& const_reference;
95 typedef std::size_t size_type;
96 typedef std::ptrdiff_t difference_type;
97 typedef std::pair<difference_type,difference_type> coords;
104 typedef T_alloc allocator_type;
107 typedef typename allocator_type::template rebind<bool>::other bool_allocator;
109
110 template <typename T2, typename T_alloc2>
111 friend class Array2D;
112
113 // Rule of 5 and destructor ------------------------------------------//
114 // Array2D has value-like semantics
115 Array2D() noexcept : h(), w(), s(), ptr(nullptr) { }
116 Array2D(const Array2D &A) : h(A.h), w(A.w), s(A.s), ptr(allocate_and_copy(A.s, A.ptr)) { }
117 Array2D(Array2D &&A) noexcept : h(A.h), w(A.w), s(A.s), ptr(A.ptr) { A.make_null(); }
119 Array2D& operator=(Array2D&&) noexcept;
120 ~Array2D() noexcept { destroy_and_deallocate(); }
121
122 // Additional Constructors -------------------------------------------//
124 Array2D(std::initializer_list<value_type>);
125 Array2D(std::initializer_list<std::initializer_list<value_type>>);
126 // Allow conversions from other array types only explicitly
127 template <typename T2, typename T_alloc2>
128 explicit Array2D(const Array2D<T2,T_alloc2> &A) : h(A.h), w(A.w), s(A.s), ptr(allocate_and_copy(A.s, A.ptr)) { }
129 // Allow implicit conversions from regions - overloads for region and
130 // const_region are both needed because implicit conversions do not chain.
131 Array2D(const const_region &reg) : h(reg.region_height()), w(reg.region_width()), s(reg.region_size()), ptr(allocate_and_copy(reg.region_size(), reg.begin())) { }
132 Array2D(const region &reg) : h(reg.region_height()), w(reg.region_width()), s(reg.region_size()), ptr(allocate_and_copy(reg.region_size(), reg.begin())) { }
133
134 // Static factory methods --------------------------------------------//
135 // Allow Array2Ds to be formed from binary filename or a stream. Only
136 // allow for arithmetic types.
137 template <typename T_output = Array2D>
138 static typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type load(const std::string&);
139 template <typename T_output = Array2D>
140 static typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type load(std::ifstream&);
141
142 // Conversion --------------------------------------------------------//
143 // Only allow conversions explicitly when array is 1x1
144 explicit operator value_type();
145
146 //--------------------------------------------------------------------//
147 // Single element indexing -------------------------------------------//
148 //--------------------------------------------------------------------//
149
150 // Linear indexing
152 reference operator()(difference_type p) { return const_cast<reference>((*const_cast<const Array2D*>(this))(p)); }
153 // "last" overload
154 const_reference operator()(const details::last_index&) const { return (*this)(s - 1); }
155 reference operator()(const details::last_index &last) { return const_cast<reference>((*const_cast<const Array2D*>(this))(last)); }
156
157 // 2D indexing
159 reference operator()(difference_type p1, difference_type p2) { return const_cast<reference>((*const_cast<const Array2D*>(this))(p1,p2)); }
160 // "last" overloads
161 const_reference operator()(difference_type p1, const details::last_index&) const { return (*this)(p1,w - 1); }
162 reference operator()(difference_type p1, const details::last_index &last) { return const_cast<reference>((*const_cast<const Array2D*>(this))(p1,last)); }
163 const_reference operator()(const details::last_index&, difference_type p2) const { return (*this)(h - 1,p2); }
164 reference operator()(const details::last_index &last, difference_type p2) { return const_cast<reference>((*const_cast<const Array2D*>(this))(last,p2)); }
165 const_reference operator()(const details::last_index&, const details::last_index&) const { return (*this)(h - 1,w - 1); }
166 reference operator()(const details::last_index &last1, const details::last_index &last2) { return const_cast<reference>((*const_cast<const Array2D*>(this))(last1,last2)); }
167
168 //--------------------------------------------------------------------//
169 // Regions -----------------------------------------------------------//
170 //--------------------------------------------------------------------//
171 // Note that regions that use "ranges" use inclusive bounds ONLY in the
172 // interface. Empty ranges are supported by having the second index less
173 // than the first index. These ranges are converted by get_range() such
174 // that the end range is non-inclusive for computation. In this case
175 // an empty range is denoted by two indices of the same value.
176 private:
177 struct r_convert {
178 // Five overall supported conversions to range:
179 enum class RANGE { SINGLE, LAST, COORDS, LAST_COORDS, ALL } range_type;
180 r_convert(RANGE range_type, difference_type p1 = 0, difference_type p2 = 0) : range_type(range_type), p1(p1), p2(p2) { }
183 };
184 // Derived classes of r_convert allows get_range() function to determine
185 // which value to substitute "last" and "all" with - either s, h, or w.
186 struct r_convert_1D final : r_convert {
187 // Three types of conversions for 1D
188 r_convert_1D(difference_type p1, difference_type p2) : r_convert(r_convert::RANGE::COORDS, p1, p2) { }
189 r_convert_1D(difference_type p1, const details::last_index&) : r_convert(r_convert::RANGE::LAST_COORDS, p1) { }
190 r_convert_1D(const details::all_range&) : r_convert(r_convert::RANGE::ALL) { }
191 };
192 struct r_convert_2D_1 final : r_convert {
193 // Five types of conversions for 2D first argument
194 r_convert_2D_1(difference_type p) : r_convert(r_convert::RANGE::SINGLE,p) { }
195 r_convert_2D_1(const details::last_index&) : r_convert(r_convert::RANGE::LAST) { }
196 r_convert_2D_1(difference_type p1, difference_type p2) : r_convert(r_convert::RANGE::COORDS, p1, p2) { }
197 r_convert_2D_1(difference_type p1, const details::last_index&) : r_convert(r_convert::RANGE::LAST_COORDS, p1) { }
198 r_convert_2D_1(const details::all_range&) : r_convert(r_convert::RANGE::ALL) { }
199 };
200 struct r_convert_2D_2 final : r_convert {
201 // Five types of conversions for 2D second argument
202 r_convert_2D_2(difference_type p) : r_convert(r_convert::RANGE::SINGLE,p) { }
203 r_convert_2D_2(const details::last_index&) : r_convert(r_convert::RANGE::LAST) { }
204 r_convert_2D_2(difference_type p1, difference_type p2) : r_convert(r_convert::RANGE::COORDS, p1, p2) { }
205 r_convert_2D_2(difference_type p1, const details::last_index&) : r_convert(r_convert::RANGE::LAST_COORDS, p1) { }
206 r_convert_2D_2(const details::all_range&) : r_convert(r_convert::RANGE::ALL) { }
207 };
208
209 public:
210 // 1D Sub Array Indexing ---------------------------------------------//
211 // Special empty index (i.e. A()) will get all elements and treat it
212 // like a 1D range over the entire array.
215
216 const_region operator()(const r_convert_1D &r_sub_1D) const { return const_region(new details::simple_region<const Array2D>(*this,get_range(r_sub_1D))); }
217 region operator()(const r_convert_1D &r_sub_1D) { return region(new details::simple_region<Array2D>(*this,get_range(r_sub_1D))); }
218
219 // 2D Sub Array Indexing ---------------------------------------------//
220 const_region operator()(const r_convert_2D_1 &r_sub1_2D,const r_convert_2D_2 &r_sub2_2D) const { return const_region(new details::sub_region<const Array2D>(*this,get_range(r_sub1_2D),get_range(r_sub2_2D))); }
221 region operator()(const r_convert_2D_1 &r_sub1_2D, const r_convert_2D_2 &r_sub2_2D) { return region(new details::sub_region<Array2D>(*this,get_range(r_sub1_2D),get_range(r_sub2_2D))); }
222
223 // Logical indexing --------------------------------------------------//
224 // Note that region will form a copy of the input bool_container. This is
225 // templated to prevent ambiguous function calls with 1D range indexing
226 // since Array2D has a constructor which takes two integers; this
227 // result in an ambiguous function call when using the {,} notation.
228 template <typename T_container>
229 typename std::enable_if<std::is_same<typename T_container::container,bool_container>::value, const_region>::type operator()(T_container A) const { return const_region(new details::bool_region<const Array2D>(*this,std::move(A))); }
230 template <typename T_container>
231 typename std::enable_if<std::is_same<typename T_container::container,bool_container>::value, region>::type operator()(T_container A) { return region(new details::bool_region<Array2D>(*this,std::move(A))); }
232
233 // Provide overload for regions since implicit conversions cant be done
234 // with template methods.
235 template <typename T_container>
236 typename std::enable_if<std::is_same<typename T_container::container,bool_container>::value, const_region>::type operator()(const details::interface_region<details::base_region<T_container>> &reg) const { return const_region(new details::bool_region<const Array2D>(*this,reg)); }
237 template <typename T_container>
238 typename std::enable_if<std::is_same<typename T_container::container,bool_container>::value, region>::type operator()(const details::interface_region<details::base_region<T_container>> &reg) { return region(new details::bool_region<Array2D>(*this,reg)); }
239
240 // Iterators ---------------------------------------------------------//
241 // Use simple iterators; these will iterate over the entire array.
248
249 // Interpolator ------------------------------------------------------//
250 template<typename T_output = interpolator>
251 typename std::enable_if<std::is_floating_point<value_type>::value, T_output>::type get_interpolator(INTERP interp_type) const {
252 interpolator interp;
253 switch (interp_type) {
254 case INTERP::NEAREST : interp = interpolator(new details::nearest_interp<Array2D>(*this)); break;
255 case INTERP::LINEAR : interp = interpolator(new details::linear_interp<Array2D>(*this)); break;
256 case INTERP::CUBIC_KEYS : interp = interpolator(new details::cubic_interp<Array2D>(*this)); break;
260 }
261
262 return interp;
263 }
264
265 // Linsolvers --------------------------------------------------------//
266 template<typename T_output = linsolver>
267 typename std::enable_if<std::is_floating_point<value_type>::value, T_output>::type get_linsolver(LINSOLVER linsolver_type) const {
269 switch (linsolver_type) {
273 }
274
275 return linsolve;
276 }
277
278 //--------------------------------------------------------------------//
279 // Operations interface ----------------------------------------------//
280 //--------------------------------------------------------------------//
281 // These operations are special in that they allow for implicit //
282 // conversions with Array2D, so they can be used with regions (look //
283 // at item 46 in effective C++). //
284 // Overloads are only provided for R-value types to provide some //
285 // performance improvements. If regions are passed, they will trigger //
286 // the R-value overload if one exists. //
287 // These functions call private template member functions that use //
288 // SFINAE to allow some operations for only some types (i.e. imshow() //
289 // can only be called for arithmetic types). //
290 // -------------------------------------------------------------------//
291
292 // General operations ------------------------------------------------//
293 template <typename T2>
295 friend cv::Mat get_cv_img(const Array2D &A, value_type min, value_type max) { return A.this_cv_img(min, max); }
296 friend void imshow(const Array2D &A, difference_type delay) { A.this_imshow(delay); }
297 friend std::ostream& operator<<(std::ostream &os, const Array2D &A) { return A.this_stream(os); }
298 friend Array2D repmat(const Array2D &A, difference_type rows, difference_type cols) { return A.this_repmat(rows,cols); }
299 friend Array2D pad(const Array2D &A, difference_type padding, PAD pad_type = PAD::ZEROS) { return A.this_pad(padding,pad_type); }
300 friend Array2D t(const Array2D &A) { return A.this_t(); }
301 friend void save(const Array2D &A, const std::string &filename) { A.this_save(filename); }
302 friend void save(const Array2D &A, std::ofstream &os) { A.this_save(os); }
303
304 // Logical operators -------------------------------------------------//
305 friend bool isequal(const Array2D &A, const Array2D &B) { return A.this_isequal(B); }
306 friend bool_container operator==(const Array2D &A, const Array2D &B) { return A.this_equals(B); }
307 friend bool_container operator==(const Array2D &A, const_reference val) { return A.this_equals(val); }
308 friend bool_container operator==(const_reference val, const Array2D &A) { return A.this_equals(val); }
309 friend bool_container operator!=(const Array2D &A, const Array2D &B) { return A.this_notequals(B); }
310 friend bool_container operator!=(const Array2D &A, const_reference val) { return A.this_notequals(val); }
311 friend bool_container operator!=(const_reference val, const Array2D &A) { return A.this_notequals(val); }
312 friend bool_container operator&(const Array2D &A, const Array2D &B) { return A.this_and(B); }
313 friend bool_container operator|(const Array2D &A, const Array2D &B) { return A.this_or(B); }
314 friend bool_container operator~(const Array2D &A) { return A.this_negate(); }
315 friend bool any_true(const Array2D &A) { return A.this_any_true(); }
316 friend bool all_true(const Array2D &A) { return A.this_all_true(); }
317 friend difference_type find(const Array2D &A, difference_type start = 0) { return A.this_find(start); }
318
319 // Relational Operators ----------------------------------------------//
320 friend bool_container operator>(const Array2D &A, const Array2D &B) { return A.this_greaterthan(B); }
321 friend bool_container operator>(const Array2D &A, const_reference val) { return A.this_greaterthan(val); }
322 friend bool_container operator>=(const Array2D &A, const Array2D &B) { return A.this_greaterthanorequalto(B); }
323 friend bool_container operator>=(const Array2D &A, const_reference val) { return A.this_greaterthanorequalto(val); }
324 friend bool_container operator<(const Array2D &A, const Array2D &B) { return A.this_lessthan(B); }
325 friend bool_container operator<(const Array2D &A, const_reference val) { return A.this_lessthan(val); }
326 friend bool_container operator<=(const Array2D &A, const Array2D &B) { return A.this_lessthanorequalto(B); }
327 friend bool_container operator<=(const Array2D &A, const_reference val) { return A.this_lessthanorequalto(val); }
328
329 // Arithmetic operators ----------------------------------------------//
330 friend Array2D operator+(const Array2D &A, const Array2D &B) { Array2D C(A); return C += B; }
331 friend Array2D operator+(const Array2D &A, Array2D &&B) { return B += A; }
332 friend Array2D operator+(Array2D &&A, const Array2D &B) { return A += B; }
333 friend Array2D operator+(Array2D &&A, Array2D &&B) { return A += B; }
334
335 friend Array2D operator+(const Array2D &A, const_reference val) { Array2D B(A); return B += val; }
336 friend Array2D operator+(Array2D &&A, const_reference val) { return A += val; }
337 friend Array2D operator+(const_reference val, const Array2D &A) { Array2D B(A); return B += val; }
338 friend Array2D operator+(const_reference val, Array2D &&A) { return A += val; }
339
340 // Subtraction is not commutative- so some wrangling is required for
341 // dealing with r-values
342 friend Array2D operator-(const Array2D &A, const Array2D &B) { Array2D C(A); return C -= B; }
343 friend Array2D operator-(const Array2D &A, Array2D &&B) { return B.this_flipsubassign(A); } // Cannot use -=
344 friend Array2D operator-(Array2D &&A, const Array2D &B) { return A -= B; }
345 friend Array2D operator-(Array2D &&A, Array2D &&B) { return A -= B; }
346
347 friend Array2D operator-(const Array2D &A, const_reference val) { Array2D B(A); return B -= val; }
348 friend Array2D operator-(Array2D &&A, const_reference val) { return A -= val; }
349 friend Array2D operator-(const_reference val, const Array2D &A) { Array2D B(A); return B.this_flipsubassign(val); }
350 friend Array2D operator-(const_reference val, Array2D &&A) { return A.this_flipsubassign(val); }
351
352 // For element-wise multiplication of two arrays, use "mult" instead of
353 // operator* - this is reserved for matrix multiplication
354 friend Array2D mult(const Array2D &A, const Array2D &B) { Array2D C(A); return C *= B; }
355 friend Array2D mult(const Array2D &A, Array2D &&B) { return B *= A; }
356 friend Array2D mult(Array2D &&A, const Array2D &B) { return A *= B; }
357 friend Array2D mult(Array2D &&A, Array2D &&B) { return A *= B; }
358
359 friend Array2D operator*(const Array2D &A, const_reference val) { Array2D B(A); return B *= val; }
360 friend Array2D operator*(Array2D &&A, const_reference val) { return A *= val; }
361 friend Array2D operator*(const_reference val, const Array2D &A) { Array2D B(A); return B *= val; }
362 friend Array2D operator*(const_reference val, Array2D &&A) { return A *= val; }
363
364 // Division is not commutative- so some wrangling is required for
365 // dealing with r-values
366 friend Array2D operator/(const Array2D &A, const Array2D &B) { Array2D C(A); return C /= B; }
367 friend Array2D operator/(const Array2D &A, Array2D &&B) { return B.this_flipdivassign(A); }
368 friend Array2D operator/(Array2D &&A, const Array2D &B) { return A /= B; }
369 friend Array2D operator/(Array2D &&A, Array2D &&B) { return A /= B; }
370
371 friend Array2D operator/(const Array2D &A, const_reference val) { Array2D B(A); return B /= val; }
372 friend Array2D operator/(Array2D &&A, const_reference val) { return A /= val; }
373 friend Array2D operator/(const_reference val, const Array2D &A) { Array2D B(A); return B.this_flipdivassign(val); }
374 friend Array2D operator/(const_reference val, Array2D &&A) { return A.this_flipdivassign(val); }
375
376 friend Array2D sort(Array2D A) { return A.this_sort(); } // by-value
377
378 friend value_type sum(const Array2D &A) { return A.this_sum(); }
379
380 friend value_type max(const Array2D &A) { return A.this_max(); }
381 friend value_type min(const Array2D &A) { return A.this_min(); }
382
383 friend value_type prctile(Array2D A, double percent) { return A.this_prctile(percent); } // by-value
384
385 friend value_type median(Array2D A) { return prctile(std::move(A),0.5); } // by-value
386
387 // Element-wise
388 friend Array2D sqrt(Array2D A) { return A.this_sqrt(); } // by-value
389
390 friend Array2D pow(Array2D A, double n) { return A.this_pow(n); } // by-value
391
392 // Matrix multiplication and convolution operations ------------------//
393 // These have special overloads for double type
394 friend Array2D operator*(const Array2D &A, const Array2D &B) { return A.this_mat_mult(B); }
395 friend Array2D conv(const Array2D &A, const Array2D &B) { return A.this_conv(B); }
396 friend Array2D deconv(const Array2D &A, const Array2D &B) { return A.this_deconv(B); }
397 friend Array2D xcorr(const Array2D &A, const Array2D &B) { return A.this_xcorr(B); }
398
399 // Additional arithmetic operations ----------------------------------//
400 friend value_type dot(const Array2D &x, const Array2D &y) { return x.this_dot(y); }
401 friend Array2D normalize(Array2D A) { return A.this_normalize(); } // by-value
402 friend Array2D linsolve(const Array2D &A, const Array2D &b) { return A.this_linsolve(b); }
403
404 //--------------------------------------------------------------------//
405 // End of operations interface ---------------------------------------//
406 //--------------------------------------------------------------------//
407
408 // Access ------------------------------------------------------------//
409 difference_type height() const { return h; }
410 difference_type width() const { return w; }
411 difference_type size() const { return s; }
412 pointer get_pointer() const { return ptr; }
413
414 // Utility -----------------------------------------------------------//
415 bool empty() const { return s == 0; }
416 template <typename T_container>
417 bool same_size(const T_container &A) const { return h == A.h && w == A.w; }
418 difference_type sub2ind(difference_type p1, difference_type p2) const { return p1 + p2*h; }
419 coords ind2sub(difference_type p) const { return {p % h, p / h}; }
420 bool in_bounds(difference_type p) const { return p >= 0 && p < s; }
421 bool in_bounds(difference_type p1, difference_type p2) const { return p1 >= 0 && p1 < h && p2 >= 0 && p2 < w; }
422 std::string size_string() const { return std::to_string(s); }
423 std::string size_2D_string() const { return "(" + std::to_string(h) + "," + std::to_string(w) + ")"; }
424
425 private:
426 // -------------------------------------------------------------------//
427 // These operations are private because the interface for operators //
428 // does not involve member functions. This is because all operators //
429 // are meant to work with Array2D AND regions, so operators need to //
430 // use implicit conversions on possibly all their arguments which is //
431 // not possible with member functions. Furthermore, these functions //
432 // can modify the array in-place, whereas interface functions never //
433 // modify in-place. //
434 // -------------------------------------------------------------------//
435
436 // General operation -------------------------------------------------//
437 template<typename T_output = cv::Mat>
438 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_cv_img(value_type, value_type) const;
439 template<typename T_output = void>
440 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_imshow(difference_type) const;
441 template<typename T_output = std::ostream&>
442 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_stream(std::ostream&) const;
443 Array2D this_repmat(difference_type, difference_type) const;
444 Array2D this_pad(difference_type, PAD) const;
445 Array2D this_t() const;
446 template<typename T_output = void>
447 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_save(const std::string&) const;
448 template<typename T_output = void>
449 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_save(std::ofstream&) const;
450
451 // Logical operations ------------------------------------------------//
452 bool this_isequal(const Array2D&) const;
453 bool_container this_equals(const Array2D&) const;
454 bool_container this_equals(const value_type&) const;
455 bool_container this_notequals(const Array2D&) const;
456 bool_container this_notequals(const value_type&) const;
457 bool_container this_and(const Array2D&) const;
458 bool_container this_or(const Array2D&) const;
459 bool_container this_negate() const;
460 bool this_any_true() const;
461 bool this_all_true() const;
462 difference_type this_find(difference_type start) const;
463
464 // Relational operations ---------------------------------------------//
465 bool_container this_greaterthan(const Array2D&) const;
466 bool_container this_greaterthan(const value_type&) const;
467 bool_container this_greaterthanorequalto(const Array2D&) const;
468 bool_container this_greaterthanorequalto(const value_type&) const;
469 bool_container this_lessthan(const Array2D&) const;
470 bool_container this_lessthan(const value_type&) const;
471 bool_container this_lessthanorequalto(const Array2D&) const;
472 bool_container this_lessthanorequalto(const value_type&) const;
473
474 // Arithmetic operations ---------------------------------------------//
475 Array2D& operator+=(const Array2D&);
476 Array2D& operator+=(const_reference);
477
478 Array2D& operator-=(const Array2D&);
479 Array2D& this_flipsubassign(const Array2D&);
480 Array2D& operator-=(const_reference);
481 Array2D& this_flipsubassign(const_reference);
482
483 Array2D& operator*=(const Array2D&);
484 Array2D& operator*=(const_reference);
485
486 Array2D& operator/=(const Array2D&);
487 Array2D& this_flipdivassign(const Array2D&);
488 Array2D& operator/=(const_reference);
489 Array2D& this_flipdivassign(const_reference);
490
493
494 Array2D& this_sort();
495 value_type this_sum() const;
496 value_type this_max() const;
497 value_type this_min() const;
498 value_type this_prctile(double);
499
500 // sqrt and pow use std::sqrt and std::pow which are only defined for arithmetic types
501 template<typename T_output = Array2D&>
502 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_sqrt();
503 template<typename T_output = Array2D&>
504 typename std::enable_if<std::is_arithmetic<value_type>::value, T_output>::type this_pow(double);
505
506 // Provide specific overload for double
507 template<typename T_output = Array2D>
508 typename std::enable_if<std::is_same<value_type,double>::value, T_output>::type this_mat_mult(const Array2D&) const;
509 template<typename T_output = Array2D>
510 typename std::enable_if<!std::is_same<value_type,double>::value, T_output>::type this_mat_mult(const Array2D&) const;
511
512 // Provide specific overload for double
513 template<typename T_output = Array2D>
514 typename std::enable_if<std::is_same<value_type,double>::value, T_output>::type this_conv(const Array2D&) const;
515 template<typename T_output = Array2D>
516 typename std::enable_if<std::is_same<value_type,double>::value, T_output>::type this_deconv(const Array2D&) const;
517 template<typename T_output = Array2D>
518 typename std::enable_if<std::is_same<value_type,double>::value, T_output>::type this_xcorr(const Array2D&) const;
519 enum class FFTW { CONV, DECONV, XCORR };
520 Array2D this_conv_base(const Array2D&, FFTW) const;
521
522 // Additional arithmetic operations ----------------------------------//
523 template<typename T_output = value_type>
524 typename std::enable_if<std::is_floating_point<value_type>::value, T_output>::type this_dot(const Array2D&) const;
525 template<typename T_output = Array2D>
526 typename std::enable_if<std::is_floating_point<value_type>::value, T_output>::type this_normalize();
527 template<typename T_output = Array2D>
528 typename std::enable_if<std::is_floating_point<value_type>::value, T_output>::type this_linsolve(const Array2D&) const;
529
530 // Utility -----------------------------------------------------------//
531 coords get_range(const r_convert_1D&) const;
532 coords get_range(const r_convert_2D_1&) const;
533 coords get_range(const r_convert_2D_2&) const;
534
535 pointer allocate(difference_type);
536 pointer allocate_and_init(difference_type, const_reference);
537 template <typename T_it>
538 pointer allocate_and_copy(difference_type, T_it);
539 void destroy_and_deallocate();
540 void make_null() { ptr = nullptr; h = w = s = 0; }
541
542 void chk_size_op(difference_type, difference_type, const std::string&) const;
543 void chk_samesize_op(const Array2D&, const std::string&) const;
544 void chk_minsize_op(difference_type, difference_type, const std::string&) const;
545 void chk_column_op(const std::string&) const;
546 void chk_square_op(const std::string&) const;
547 void chk_in_bounds_op(difference_type, const std::string&) const;
548 void chk_in_bounds_op(difference_type, difference_type, const std::string&) const;
549 void chk_mult_size(const Array2D&) const;
550 void chk_kernel_size(const Array2D&) const;
551
555 pointer ptr;
556 allocator_type alloc;
557};
558
559namespace details {
560 // Container traits will cause pointer, reference, iterator, region, etc to
561 // be const if the T_container is const. Also includes const and nonconst
562 // versions for convenience.
563 template<typename T_container>
564 struct container_traits {
565 typedef typename T_container::pointer nonconst_pointer;
566 typedef typename T_container::reference nonconst_reference;
567 typedef typename T_container::iterator nonconst_iterator;
568 typedef typename T_container::region nonconst_region;
569 typedef typename T_container::container nonconst_container;
570
571 typedef typename T_container::pointer pointer;
572 typedef typename T_container::reference reference;
573 typedef typename T_container::iterator iterator;
574 typedef typename T_container::region region;
575 typedef typename T_container::container container;
576
577 typedef typename T_container::const_pointer const_pointer;
578 typedef typename T_container::const_reference const_reference;
579 typedef typename T_container::const_iterator const_iterator;
580 typedef typename T_container::const_region const_region;
581 typedef typename T_container::const_container const_container;
582 };
583
584 template<typename T_container>
585 struct container_traits<const T_container> { // Specialization for const container
586 typedef typename T_container::pointer nonconst_pointer;
587 typedef typename T_container::reference nonconst_reference;
588 typedef typename T_container::iterator nonconst_iterator;
589 typedef typename T_container::region nonconst_region;
590 typedef typename T_container::container nonconst_container;
591
592 typedef typename T_container::const_pointer pointer;
593 typedef typename T_container::const_reference reference;
594 typedef typename T_container::const_iterator iterator;
595 typedef typename T_container::const_region region;
596 typedef typename T_container::const_container container;
597
598 typedef typename T_container::const_pointer const_pointer;
599 typedef typename T_container::const_reference const_reference;
600 typedef typename T_container::const_iterator const_iterator;
601 typedef typename T_container::const_region const_region;
602 typedef typename T_container::const_container const_container;
603 };
604
605 // Iterator --------------------------------------------------------------//
606 template <typename T_container>
608 // Base class for 2D iterators
609 public:
610 typedef std::bidirectional_iterator_tag iterator_category;
611 typedef typename T_container::value_type value_type;
612 typedef typename T_container::size_type size_type;
613 typedef typename T_container::difference_type difference_type;
614 typedef typename T_container::coords coords;
615 typedef typename container_traits<T_container>::pointer pointer; // Can be const or non-const
616 typedef typename container_traits<T_container>::reference reference; // Can be const or non-const
617 typedef typename container_traits<T_container>::nonconst_container nonconst_container;
618 typedef typename container_traits<T_container>::container container; // Can be const or non-const
619 typedef typename container_traits<T_container>::const_container const_container;
620
621 template <typename T_container2>
622 friend class base_iterator;
623 friend container;
624
625 // Rule of 5 and destructor --------------------------------------//
626 base_iterator() noexcept : A_ptr(nullptr), p() { }
627 base_iterator(const base_iterator&) noexcept = default;
628 base_iterator(base_iterator&&) noexcept = default;
629 base_iterator& operator=(const base_iterator&) = default;
630 base_iterator& operator=(base_iterator&&) = default;
631 virtual ~base_iterator() noexcept = default;
632
633 // Additional Constructors ---------------------------------------//
635 // Allow conversions from non const to const
636 template<typename T_container2>
637 base_iterator(const base_iterator<T_container2> &it, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) : A_ptr(it.A_ptr), p(it.p) { }
638
639 // Access methods ------------------------------------------------//
640 difference_type pos() const { return p; }
641 coords pos_2D() const { return A_ptr->ind2sub(p); }
642 reference operator*() const;
643
644 // Arithmetic methods --------------------------------------------//
645 virtual base_iterator& operator++() = 0;
646 virtual base_iterator& operator--() = 0;
647
648 template <typename T_container2>
649 typename std::enable_if<std::is_same<typename container_traits<T_container2>::nonconst_container, nonconst_container>::value, bool>::type operator==(const base_iterator<T_container2> &it) const {
650 return A_ptr == it.A_ptr && p == it.p; // enable if containers are the same
651 }
652 template <typename T_container2>
653 typename std::enable_if<std::is_same<typename container_traits<T_container2>::nonconst_container, nonconst_container>::value, bool>::type operator!=(const base_iterator<T_container2> &it) const {
654 return !((*this) == it); // enable if containers are the same
655 }
656
657 // Clone ---------------------------------------------------------//
658 virtual base_iterator* clone() const = 0;
660
661 protected:
662 // Utility -------------------------------------------------------//
663 void chk_valid_increment() const;
664 void chk_valid_decrement() const;
665 void chk_in_range() const;
666
669 };
670
671 template <typename T_container>
672 class simple_iterator final : public base_iterator<T_container> {
673 // Simplest iterator
674 public:
685
686 template <typename T_container2>
687 friend class simple_iterator;
688
689 // Rule of 5 and destructor --------------------------------------//
690 simple_iterator() noexcept = default;
691 simple_iterator(const simple_iterator&) noexcept = default;
692 simple_iterator(simple_iterator&&) noexcept = default;
693 simple_iterator& operator=(const simple_iterator&) = default;
694 simple_iterator& operator=(simple_iterator&&) = default;
695 ~simple_iterator() noexcept override = default;
696
697 // Additional Constructors ---------------------------------------//
699 // Allow conversions from non const to const
700 template<typename T_container2>
701 simple_iterator(const simple_iterator<T_container2> &it, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
702 base_iterator<container>(it) { }
703
704 // Arithmetic methods --------------------------------------------//
705 simple_iterator& operator++() override;
706 simple_iterator& operator--() override;
707
708 // Clone ---------------------------------------------------------//
709 simple_iterator* clone() const override { return new simple_iterator(*this); }
711 };
712
713 template <typename T_container>
714 class sub_iterator final : public base_iterator<T_container> {
715 // Iterator for subarray
716 public:
727
728 template <typename T_container2>
729 friend class sub_iterator;
730 friend container;
731
732 // Rule of 5 and destructor --------------------------------------//
733 sub_iterator() noexcept : sub_p(), sub_h(), sub_w(), sub_s() { }
734 sub_iterator(const sub_iterator&) noexcept = default;
735 sub_iterator(sub_iterator&&) noexcept = default;
736 sub_iterator& operator=(const sub_iterator&) = default;
737 sub_iterator& operator=(sub_iterator&&) = default;
738 ~sub_iterator() noexcept override = default;
739
740 // Additional Constructors ---------------------------------------//
741 sub_iterator(container&, const coords&, const coords&, const coords&);
742 // Allow conversions from non const to const
743 template <typename T_container2>
744 sub_iterator(const sub_iterator<T_container2> &it, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
745 base_iterator<container>(it), r_sub1_2D(it.r_sub1_2D), r_sub2_2D(it.r_sub2_2D), sub_p(it.sub_p), sub_h(it.sub_h), sub_w(it.sub_w), sub_s(it.sub_s) { }
746
747 // Arithmetic methods --------------------------------------------//
748 sub_iterator& operator++() override;
749 sub_iterator& operator--() override;
750
751 // Clone ---------------------------------------------------------//
752 sub_iterator* clone() const override { return new sub_iterator(*this); }
754
755 private:
756 void chk_valid_ranges() const;
757
758 coords r_sub1_2D;
759 coords r_sub2_2D;
760 difference_type sub_p;
761 difference_type sub_h;
762 difference_type sub_w;
763 difference_type sub_s;
764 };
765
766 template <typename T_container>
767 class bool_iterator final : public base_iterator<T_container> {
768 // Iterator for boolean array
769 public:
780 typedef typename T_container::bool_container bool_container;
781
782 template <typename T_container2>
783 friend class bool_iterator;
784 friend container;
785
786 // Rule of 5 and destructor --------------------------------------//
787 bool_iterator() noexcept : A_bool_ptr(nullptr) { }
788 bool_iterator(const bool_iterator&) noexcept = default;
789 bool_iterator(bool_iterator&&) noexcept = default;
790 bool_iterator& operator=(const bool_iterator&) = default;
791 bool_iterator& operator=(bool_iterator&&) = default;
792 ~bool_iterator() noexcept override = default;
793
794 // Additional Constructors ---------------------------------------//
796 // Allow conversions from non const to const
797 template <typename T_container2>
798 bool_iterator(const bool_iterator<T_container2> &it, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
799 base_iterator<container>(it), A_bool_ptr(it.A_bool_ptr) { }
800
801 // Arithmetic methods --------------------------------------------//
802 bool_iterator& operator++() override;
803 bool_iterator& operator--() override;
804
805 // Clone ---------------------------------------------------------//
806 bool_iterator* clone() const override { return new bool_iterator(*this); }
808
809 private:
810 // Utility -------------------------------------------------------//
811 void chk_same_size() const;
812
813 const bool_container *A_bool_ptr;
814 };
815
816 template <typename T_iterator>
817 class interface_iterator final {
818 // This is a container for the base iterator class to hide the
819 // inheritance tree.
820 public:
821 typedef typename T_iterator::iterator_category iterator_category;
822 typedef typename T_iterator::value_type value_type;
823 typedef typename T_iterator::size_type size_type;
824 typedef typename T_iterator::difference_type difference_type;
825 typedef typename T_iterator::coords coords;
826 typedef typename T_iterator::pointer pointer;
827 typedef typename T_iterator::reference reference;
828 typedef typename T_iterator::nonconst_container nonconst_container;
829 typedef typename T_iterator::container container;
830 typedef typename T_iterator::const_container const_container;
831
832 template <typename T_iterator2>
833 friend class interface_iterator;
834 friend container;
835
836 // Rule of 5 and destructor --------------------------------------//
837 interface_iterator() noexcept = default;
838 interface_iterator(const interface_iterator &it) : ptr(it.ptr ? it.ptr->clone() : nullptr) { }
839 interface_iterator(interface_iterator &&it) : ptr(std::move(it.ptr)) { }
840 interface_iterator& operator=(const interface_iterator &it) { this->ptr.reset(it.ptr ? it.ptr->clone() : nullptr); return *this; }
841 interface_iterator& operator=(interface_iterator &&it) { this->ptr = std::move(it.ptr); return *this; }
842 ~interface_iterator() noexcept = default;
843
844 // Additional Constructors ---------------------------------------//
845 // explicit is important since ptr is wrapped in shared_ptr, which
846 // will call delete on ptr when this object goes out of scope.
847 explicit interface_iterator(T_iterator *ptr) : ptr(ptr) { }
848 // Allow conversions from non const to const
849 template <typename T_iterator2>
850 interface_iterator(const interface_iterator<T_iterator2> &it, typename std::enable_if<std::is_same<typename T_iterator2::container, nonconst_container>::value, int>::type = 0) :
851 ptr(it.ptr ? it.ptr->const_clone() : nullptr) { }
852
853 // Access methods ------------------------------------------------//
854 difference_type pos() const { return ptr->pos(); }
855 coords pos_2D() const { return ptr->pos_2D(); }
856 reference operator*() const { return *(*ptr); }
857
858 // Arithmetic methods --------------------------------------------//
859 interface_iterator& operator++() { ++(*ptr); return *this; }
860 interface_iterator& operator--() { --(*ptr); return *this; }
861 template <typename T_iterator2>
862 typename std::enable_if<std::is_same<typename T_iterator2::nonconst_container, nonconst_container>::value, bool>::type operator==(const interface_iterator<T_iterator2> &it) const {
863 return *(it.ptr) == *(ptr); // enable if containers are the same
864 }
865 template <typename T_iterator2>
866 typename std::enable_if<std::is_same<typename T_iterator2::nonconst_container, nonconst_container>::value, bool>::type operator!=(const interface_iterator<T_iterator2> &it) const {
867 return *(it.ptr) != *(ptr); // enable if containers are the same
868 }
869
870 private:
871 std::shared_ptr<T_iterator> ptr;
872 };
873
874 // Region ----------------------------------------------------------------//
875 template <typename T_container>
876 class base_region {
877 // Base class for regions.
878 public:
879 typedef typename T_container::value_type value_type;
880 typedef typename T_container::size_type size_type;
881 typedef typename T_container::difference_type difference_type;
882 typedef typename T_container::coords coords;
883 typedef typename container_traits<T_container>::pointer pointer; // Can be const or non-const
884 typedef typename container_traits<T_container>::const_pointer const_pointer;
885 typedef typename container_traits<T_container>::reference reference; // Can be const or non-const
886 typedef typename container_traits<T_container>::const_reference const_reference;
887 typedef typename container_traits<T_container>::iterator iterator; // Can be const or non-const
888 typedef typename container_traits<T_container>::const_iterator const_iterator;
889 typedef typename container_traits<T_container>::nonconst_container nonconst_container;
890 typedef typename container_traits<T_container>::container container; // Can be const or non-const
891 typedef typename container_traits<T_container>::const_container const_container;
892
893 template <typename T_container2>
894 friend class base_region;
895 friend container;
896
897 // Rule of 5 and destructor --------------------------------------//
898 base_region() noexcept : A_ptr(nullptr), region_h(), region_w(), region_s() { }
899 base_region(const base_region&) noexcept = default;
900 base_region(base_region&&) noexcept = default;
901 base_region& operator=(const base_region&);
902 base_region& operator=(base_region &&reg) { return operator=(reg); }
903 virtual ~base_region() noexcept = default;
904
905 // Additional Constructors ---------------------------------------//
907 // Allow conversions from non const to const
908 template<typename T_container2>
909 base_region(const base_region<T_container2> &reg, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
910 A_ptr(reg.A_ptr), region_h(reg.region_h), region_w(reg.region_w), region_s(reg.region_s) { }
911
912 // Assignment methods --------------------------------------------//
913 // Allow assignments from const_regions to region. Since this
914 // conversion doesnt exist, make assignment operator a template
915 // function
916 template<typename T_container2>
917 typename std::enable_if<std::is_same<typename container_traits<T_container2>::nonconst_container, nonconst_container>::value, base_region&>::type operator=(const base_region<T_container2>&);
920
921 // Access methods ------------------------------------------------//
925
926 // Clone ---------------------------------------------------------//
927 virtual base_region* clone() const = 0;
929
930 // Iterators -----------------------------------------------------//
931 // Note that iterators have a dependence on both the container and
932 // region they are called from. If region OR Array2D is destroyed,
933 // iterators may become invalid.
934 virtual iterator begin() const = 0;
935 virtual iterator end() const = 0;
936 virtual const_iterator cbegin() const = 0;
937 virtual const_iterator cend() const = 0;
938
939 // Utility -------------------------------------------------------//
940 std::string region_size_string() const { return std::to_string(region_s); }
941 std::string region_size_2D_string() const { return "(" + std::to_string(region_h) + "," + std::to_string(region_w) + ")"; }
942
943 protected:
948 };
949
950 template <typename T_container>
951 class simple_region final : public base_region<T_container> {
952 // Simplest region
953 public:
967
968 template <typename T_container2>
969 friend class simple_region;
970 friend container;
971
972 // Rule of 5 and destructor --------------------------------------//
973 simple_region() = default;
974 simple_region(const simple_region&) noexcept = default;
975 simple_region(simple_region&&) noexcept = default;
976 simple_region& operator=(const simple_region &reg) { base_region<container>::operator=(reg); return *this; }
978 ~simple_region() noexcept override = default;
979
980 // Additional Constructors ---------------------------------------//
981 simple_region(container&, const coords&);
982 // Allow conversions from non const to const
983 template<typename T_container2>
984 simple_region(const simple_region<T_container2> &reg, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
985 base_region<container>(reg), r(reg.r) { }
986
987 // Clone ---------------------------------------------------------//
988 simple_region* clone() const override { return new simple_region(*this); }
990
991 // Iterators -----------------------------------------------------//
992 iterator begin() const override { return iterator(new simple_iterator<container>(*this->A_ptr,r.first)); }
993 iterator end() const override { return iterator(new simple_iterator<container>(*this->A_ptr,r.second)); }
994 const_iterator cbegin() const override { return const_iterator(new simple_iterator<const_container>(*this->A_ptr,r.first)); }
995 const_iterator cend() const override { return const_iterator(new simple_iterator<const_container>(*this->A_ptr,r.second)); }
996
997 private:
998 // Utility -------------------------------------------------------//
999 void chk_valid_range() const;
1000
1001 coords r;
1002 };
1003
1004 template <typename T_container>
1005 class sub_region final : public base_region<T_container> {
1006 // Region for subarray
1007 public:
1021
1022 template <typename T_container2>
1023 friend class sub_region;
1025
1026 // Rule of 5 and destructor --------------------------------------//
1027 sub_region() noexcept : sub_h(), sub_w(), sub_s() { }
1028 sub_region(const sub_region&) noexcept = default;
1029 sub_region(sub_region&&) noexcept = default;
1030 sub_region& operator=(const sub_region &reg) { base_region<container>::operator=(reg); return *this; }
1031 sub_region& operator=(sub_region &&reg) { return operator=(reg); }
1032 ~sub_region() noexcept override = default;
1033
1034 // Additional Constructors ---------------------------------------//
1035 sub_region(container&, const coords&, const coords&);
1036 // Allow conversions from non const to const
1037 template<typename T_container2>
1038 sub_region(const sub_region<T_container2> &reg, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
1039 base_region<container>(reg), r_sub1_2D(reg.r_sub1_2D), r_sub2_2D(reg.r_sub2_2D), sub_h(reg.sub_h), sub_w(reg.sub_w), sub_s(reg.sub_s) { }
1040
1041 // Clone ---------------------------------------------------------//
1042 sub_region* clone() const override { return new sub_region(*this); }
1044
1045 // Iterators -----------------------------------------------------//
1046 // Check sub_s equals to zero for empty sub regions because sub height
1047 // can be zero with a nonzero sub width and vice versa.
1048 iterator begin() const override { return iterator(new sub_iterator<container>(*this->A_ptr,{r_sub1_2D.first, r_sub2_2D.first},r_sub1_2D,r_sub2_2D)); }
1049 iterator end() const override { return sub_s == 0 ? begin() : iterator(new sub_iterator<container>(*this->A_ptr,{r_sub1_2D.first, r_sub2_2D.second},r_sub1_2D,r_sub2_2D)); }
1050 const_iterator cbegin() const override { return const_iterator(new sub_iterator<const_container>(*this->A_ptr,{r_sub1_2D.first, r_sub2_2D.first},r_sub1_2D,r_sub2_2D)); }
1051 const_iterator cend() const override { return sub_s == 0 ? cbegin() : const_iterator(new sub_iterator<const_container>(*this->A_ptr,{r_sub1_2D.first, r_sub2_2D.second},r_sub1_2D,r_sub2_2D)); }
1052
1053 private:
1054 // Utility -------------------------------------------------------//
1055 void chk_valid_ranges() const;
1056
1057 coords r_sub1_2D;
1058 coords r_sub2_2D;
1059 difference_type sub_h;
1060 difference_type sub_w;
1061 difference_type sub_s;
1062 };
1063
1064 template <typename T_container>
1065 class bool_region final : public base_region<T_container> {
1066 // Region for logical indexing
1067 public:
1081 typedef typename T_container::bool_container bool_container;
1082
1083 template <typename T_container2>
1084 friend class bool_region;
1086
1087 // Rule of 5 and destructor --------------------------------------//
1088 bool_region() noexcept = default;
1089 bool_region(const bool_region&) = default;
1090 bool_region(bool_region&&) noexcept = default;
1091 bool_region& operator=(const bool_region &reg) { base_region<container>::operator=(reg); return *this; }
1092 bool_region& operator=(bool_region &&reg) { return operator=(reg); }
1093 ~bool_region() noexcept override = default;
1094
1095 // Additional Constructors ---------------------------------------//
1096 bool_region(container&, bool_container); // by-value
1097 // Allow conversions from non const to const
1098 template<typename T_container2>
1099 bool_region(const bool_region<T_container2> &reg, typename std::enable_if<std::is_same<T_container2, nonconst_container>::value, int>::type = 0) :
1100 base_region<container>(reg), A_bool_ptr(reg.A_bool_ptr) { }
1101
1102 // Clone ---------------------------------------------------------//
1103 bool_region* clone() const override { return new bool_region(*this); }
1105
1106 // Iterators -----------------------------------------------------//
1107 iterator begin() const override { return iterator(new bool_iterator<container>(*this->A_ptr,0,A_bool_ptr.get())); }
1108 iterator end() const override { return iterator(new bool_iterator<container>(*this->A_ptr,this->A_ptr->size(),A_bool_ptr.get())); }
1109 const_iterator cbegin() const override { return const_iterator(new bool_iterator<const_container>(*this->A_ptr,0,A_bool_ptr.get())); }
1110 const_iterator cend() const override { return const_iterator(new bool_iterator<const_container>(*this->A_ptr,this->A_ptr->size(),A_bool_ptr.get())); }
1111
1112 private:
1113 // Utility -------------------------------------------------------//
1114 void chk_same_size() const;
1115
1116 std::shared_ptr<bool_container> A_bool_ptr;
1117 };
1118
1119 template <typename T_region>
1120 class interface_region final {
1121 // This is a container for the base region class to hide the inheritance
1122 // tree.
1123 public:
1124 typedef typename T_region::value_type value_type;
1125 typedef typename T_region::size_type size_type;
1126 typedef typename T_region::difference_type difference_type;
1127 typedef typename T_region::coords coords;
1128 typedef typename T_region::pointer pointer;
1129 typedef typename T_region::const_pointer const_pointer;
1130 typedef typename T_region::reference reference;
1131 typedef typename T_region::const_reference const_reference;
1132 typedef typename T_region::iterator iterator;
1133 typedef typename T_region::const_iterator const_iterator;
1134 typedef typename T_region::nonconst_container nonconst_container;
1135 typedef typename T_region::container container;
1136 typedef typename T_region::const_container const_container;
1137
1138 template <typename T_region2>
1139 friend class interface_region;
1141
1142 // Rule of 5 and destructor --------------------------------------//
1143 interface_region() noexcept = default;
1144 interface_region(const interface_region &reg) : ptr(reg.ptr ? reg.ptr->clone() : nullptr) { }
1145 interface_region(interface_region &&reg) : ptr(std::move(reg.ptr)) { }
1146 // Note that region is special in that the assignment operator
1147 // is overwritten. Do not store regions as members of objects - as
1148 // default assignment will not work properly.
1149 interface_region& operator=(const interface_region &reg) { (*this->ptr) = *(reg.ptr); return *this; }
1151 ~interface_region() noexcept = default;
1152
1153 // Additional Constructors ---------------------------------------//
1154 // explicit is important since ptr is wrapped in shared_ptr, which
1155 // will call delete on ptr when this object goes out of scope.
1156 explicit interface_region(T_region *ptr) : ptr(ptr) { }
1157 // Allow conversions from non const to const
1158 template <typename T_region2>
1159 interface_region(const interface_region<T_region2> &reg, typename std::enable_if<std::is_same<typename T_region2::container, nonconst_container>::value, int>::type = 0) :
1160 ptr(reg.ptr ? reg.ptr->const_clone() : nullptr) { }
1161
1162 // Assignment methods --------------------------------------------//
1163 template <typename T_region2>
1164 typename std::enable_if<std::is_same<typename T_region2::nonconst_container, nonconst_container>::value, interface_region&>::type operator=(const T_region2 &reg) { *(ptr) = *(reg.ptr); return *this; }
1165 interface_region& operator=(const_container &A) { *(ptr) = A; return *this; }
1166 interface_region& operator=(const_reference val) { *(ptr) = val; return *this; }
1167
1168 // Access methods ------------------------------------------------//
1169 difference_type region_height() const { return ptr->region_height(); }
1170 difference_type region_width() const { return ptr->region_width(); }
1171 difference_type region_size() const { return ptr->region_size(); }
1172
1173 // Iterators -----------------------------------------------------//
1174 iterator begin() const { return ptr->begin(); }
1175 iterator end() const { return ptr->end(); }
1176 const_iterator cbegin() const { return ptr->cbegin(); }
1177 const_iterator cend() const { return ptr->cend(); }
1178
1179 // Utility -------------------------------------------------------//
1180 std::string region_size_string() const { return ptr->region_size_string(); }
1181 std::string region_size_2D_string() const { return ptr->region_size_2D_string(); }
1182
1183 private:
1184 std::shared_ptr<T_region> ptr;
1185 };
1186
1187 // Interpolator ----------------------------------------------------------//
1188 template <typename T_container>
1190 // Base class for interpolator. Note that this class does not take into
1191 // account if caller Array2D is const or not.
1192 public:
1193 typedef typename T_container::value_type value_type;
1194 typedef typename T_container::reference reference;
1195 typedef typename T_container::size_type size_type;
1196 typedef typename T_container::difference_type difference_type;
1197 typedef typename T_container::coords coords;
1198 typedef typename container_traits<T_container>::nonconst_container container;
1199 typedef typename container_traits<T_container>::const_container const_container;
1200
1202
1203 // Rule of 5 and destructor --------------------------------------//
1204 base_interp() : A_ptr(nullptr) { }
1205 base_interp(const base_interp&) = default;
1206 base_interp(base_interp&&) noexcept = default;
1207 base_interp& operator=(const base_interp&) = default;
1208 base_interp& operator=(base_interp&&) = default;
1209 virtual ~base_interp() noexcept = default;
1210
1211 // Additional Constructors ---------------------------------------//
1213
1214 // Arithmetic methods --------------------------------------------//
1215 virtual value_type operator()(double, double) const = 0;
1216 // first_order returns interpolation value along with it's first
1217 // order gradients. Interpolation value is provided with them
1218 // because often times calculations are reused when calculating
1219 // gradients along with the interpolation value, and also all three
1220 // values are usually needed together anyway.
1221 virtual const_container& first_order(double, double) const = 0;
1222
1223 // Clone ---------------------------------------------------------//
1224 virtual base_interp* clone() const = 0;
1225
1226 protected:
1227 // Utility -------------------------------------------------------//
1228 virtual bool out_of_bounds(double, double) const = 0;
1229
1232 };
1233
1234 template <typename T_container>
1235 class nearest_interp final : public base_interp<T_container> {
1236 // Nearest neighbor interpolation
1237 public:
1245
1247
1248 // Rule of 5 and destructor --------------------------------------//
1249 nearest_interp() = default;
1251 nearest_interp(nearest_interp&&) noexcept = default;
1252 nearest_interp& operator=(const nearest_interp&) = default;
1253 nearest_interp& operator=(nearest_interp&&) = default;
1254 ~nearest_interp() noexcept = default;
1255
1256 // Additional Constructors ---------------------------------------//
1258
1259 // Arithmetic methods --------------------------------------------//
1260 value_type operator()(double, double) const override;
1261 const_container& first_order(double, double) const override;
1262
1263 // Clone ---------------------------------------------------------//
1264 nearest_interp* clone() const override { return new nearest_interp(*this); }
1265
1266 protected:
1267 // Utility -------------------------------------------------------//
1268 // Since nearest neighbor rounds, the bounds can be extended by 0.5
1269 bool out_of_bounds(double p1, double p2) const override { return p1 <= -0.5 || p2 <= -0.5 || p1 >= this->A_ptr->height() - 0.5 || p2 >= this->A_ptr->width() - 0.5; }
1270 };
1271
1272 template <typename T_container>
1273 class linear_interp final : public base_interp<T_container> {
1274 // Bilinear interpolation - not implemented as coefficient matrix
1275 // interpolation since it's simple and fast.
1276 public:
1284
1286
1287 // Rule of 5 and destructor --------------------------------------//
1288 linear_interp() = default;
1289 linear_interp(const linear_interp&) = default;
1290 linear_interp(linear_interp&&) noexcept = default;
1291 linear_interp& operator=(const linear_interp&) = default;
1292 linear_interp& operator=(linear_interp&&) = default;
1293 ~linear_interp() noexcept = default;
1294
1295 // Additional Constructors ---------------------------------------//
1297
1298 // Arithmetic methods --------------------------------------------//
1299 value_type operator()(double, double) const override;
1300 const_container& first_order(double, double) const override;
1301
1302 // Clone ---------------------------------------------------------//
1303 linear_interp* clone() const override { return new linear_interp(*this); }
1304
1305 private:
1306 // Utility -------------------------------------------------------//
1307 // Uses four points around floored point. Possibly add scheme to
1308 // interpolation points on the right and bottom edges of the image
1309 // later.
1310 bool out_of_bounds(double p1, double p2) const override { return p1 < 0 || p1 >= this->A_ptr->height() - 1 || p2 < 0 || p2 >= this->A_ptr->width() - 1; }
1311 };
1312
1313 template <typename T_container>
1314 class coef_mat_interp_base : public base_interp<T_container> {
1315 // The is the base class for interpolation schemes which use a coefficient
1316 // matrix
1317 public:
1318 typedef typename base_interp<T_container>::value_type value_type;
1319 typedef typename base_interp<T_container>::reference reference;
1320 typedef typename base_interp<T_container>::size_type size_type;
1321 typedef typename base_interp<T_container>::difference_type difference_type;
1322 typedef typename base_interp<T_container>::coords coords;
1323 typedef typename base_interp<T_container>::container container;
1324 typedef typename base_interp<T_container>::const_container const_container;
1325
1326 friend container;
1327
1328 // Rule of 5 and destructor --------------------------------------//
1329 coef_mat_interp_base() : order() { }
1330 coef_mat_interp_base(const coef_mat_interp_base&) = default;
1331 coef_mat_interp_base(coef_mat_interp_base&&) noexcept = default;
1332 coef_mat_interp_base& operator=(const coef_mat_interp_base&) = default;
1333 coef_mat_interp_base& operator=(coef_mat_interp_base&&) = default;
1334 virtual ~coef_mat_interp_base() noexcept = default;
1335
1336 // Additional Constructors ---------------------------------------//
1337 coef_mat_interp_base(const_container &A, difference_type order) :
1338 base_interp<container>(A), order(order), p1_pow_buf(order+1,1), p2_pow_buf(order+1,1), p1_pow_dp1_buf(order+1,1), p2_pow_dp2_buf(order+1,1) {
1339 if (order < 1) {
1340 // This is purely a programmer error since this class is abstract
1341 throw std::invalid_argument("Attempted to form coef_mat_interp_base with order of: " + std::to_string(order) + " order must be 1 or greater.");
1342 }
1343 }
1344
1345 // Arithmetic methods --------------------------------------------//
1346 value_type operator()(double, double) const override;
1347 const_container& first_order(double, double) const override;
1348
1349 protected:
1350 // Arithmetic methods --------------------------------------------//
1351 virtual container& get_p_pow(container&, double) const;
1352 virtual container& get_dp_pow(container&, const_container&) const;
1353 virtual value_type t_vec_mat_vec(const_container&, const_container&, const_container&) const;
1354 virtual const_container& calc_coef_mat(container&, const_container&, difference_type, difference_type) const = 0;
1355 virtual const_container& get_coef_mat(difference_type, difference_type) const = 0;
1356
1357 difference_type order;
1358 mutable container p1_pow_buf;
1359 mutable container p2_pow_buf;
1360 mutable container p1_pow_dp1_buf;
1361 mutable container p2_pow_dp2_buf;
1362 };
1363
1364 template <typename T_container>
1365 class cubic_interp_base : public coef_mat_interp_base<T_container> {
1366 // Cubic interpolation base class
1367 public:
1368 typedef typename coef_mat_interp_base<T_container>::value_type value_type;
1369 typedef typename coef_mat_interp_base<T_container>::reference reference;
1370 typedef typename coef_mat_interp_base<T_container>::size_type size_type;
1371 typedef typename coef_mat_interp_base<T_container>::difference_type difference_type;
1372 typedef typename coef_mat_interp_base<T_container>::coords coords;
1373 typedef typename coef_mat_interp_base<T_container>::container container;
1374 typedef typename coef_mat_interp_base<T_container>::const_container const_container;
1375
1376 friend container;
1377
1378 // Rule of 5 and destructor --------------------------------------//
1379 cubic_interp_base() = default;
1380 cubic_interp_base(const cubic_interp_base&) = default;
1381 cubic_interp_base(cubic_interp_base&&) noexcept = default;
1382 cubic_interp_base& operator=(const cubic_interp_base&) = default;
1383 cubic_interp_base& operator=(cubic_interp_base&&) = default;
1384 virtual ~cubic_interp_base() noexcept = default;
1385
1386 // Additional Constructors ---------------------------------------//
1387 cubic_interp_base(const_container &A) : coef_mat_interp_base<container>(A,3) { }
1388
1389 // Arithmetic methods --------------------------------------------//
1390 value_type operator()(double, double) const override;
1391 const_container& first_order(double, double) const override;
1392
1393 protected:
1394 // Arithmetic methods --------------------------------------------//
1395 const_container& calc_coef_mat(container&, const_container&, difference_type, difference_type) const override;
1396
1397 // Utility -------------------------------------------------------//
1398 // Uses 16 points around floored point. Possibly add scheme to
1399 // interpolate points within the image near the border that can't
1400 // be interpolated later.
1401 bool out_of_bounds(double p1, double p2) const override { return p1 < 1 || p1 >= this->A_ptr->height() - 2 || p2 < 1 || p2 >= this->A_ptr->width() - 2; }
1402 };
1403
1404 template <typename T_container>
1405 class cubic_interp final : public cubic_interp_base<T_container> {
1406 // Bicubic interpolation
1407 public:
1408 typedef typename cubic_interp_base<T_container>::value_type value_type;
1409 typedef typename cubic_interp_base<T_container>::reference reference;
1410 typedef typename cubic_interp_base<T_container>::size_type size_type;
1411 typedef typename cubic_interp_base<T_container>::difference_type difference_type;
1412 typedef typename cubic_interp_base<T_container>::coords coords;
1413 typedef typename cubic_interp_base<T_container>::container container;
1414 typedef typename cubic_interp_base<T_container>::const_container const_container;
1415
1417
1418 // Rule of 5 and destructor --------------------------------------//
1419 cubic_interp() = default;
1420 cubic_interp(const cubic_interp&) = default;
1421 cubic_interp(cubic_interp&&) noexcept = default;
1422 cubic_interp& operator=(const cubic_interp&) = default;
1423 cubic_interp& operator=(cubic_interp&&) = default;
1424 ~cubic_interp() noexcept = default;
1425
1426 // Additional Constructors ---------------------------------------//
1427 cubic_interp(const_container &A) : cubic_interp_base<container>(A), coef_mat_buf(4,4) { }
1428
1429 // Clone ---------------------------------------------------------//
1430 cubic_interp* clone() const override { return new cubic_interp(*this); }
1431
1432 private:
1433 // Arithmetic methods --------------------------------------------//
1434 // This will compute the coefficient matrix
1435 const_container& get_coef_mat(difference_type p1, difference_type p2) const override {
1436 return this->calc_coef_mat(coef_mat_buf, *this->A_ptr, p1 - 1, p2 - 1);
1437 }
1438
1439 mutable container coef_mat_buf;
1440 };
1441
1442 template <typename T_container>
1443 class cubic_interp_precompute final : public cubic_interp_base<T_container> {
1444 // Bicubic interpolation with a precomputed coefficient table
1445 // Note that this requires a LOT of memory (approx 16 x the original image), so
1446 // only use this if the same image is interpolated many times.
1447 public:
1448 typedef typename cubic_interp_base<T_container>::value_type value_type;
1449 typedef typename cubic_interp_base<T_container>::reference reference;
1450 typedef typename cubic_interp_base<T_container>::size_type size_type;
1451 typedef typename cubic_interp_base<T_container>::difference_type difference_type;
1452 typedef typename cubic_interp_base<T_container>::coords coords;
1453 typedef typename cubic_interp_base<T_container>::container container;
1454 typedef typename cubic_interp_base<T_container>::const_container const_container;
1455
1457
1458 // Rule of 5 and destructor --------------------------------------//
1464 ~cubic_interp_precompute() noexcept = default;
1465
1466 // Additional Constructors ---------------------------------------//
1468
1469 // Clone ---------------------------------------------------------//
1470 cubic_interp_precompute* clone() const override { return new cubic_interp_precompute(*this); }
1471
1472 private:
1473 // Arithmetic methods --------------------------------------------//
1474 // This returns precomputed coef matrix instead of calculating it
1475 const_container& get_coef_mat(difference_type p1, difference_type p2) const override { return (*coef_mat_precompute_ptr)(p1,p2); }
1476
1477 std::shared_ptr<Array2D<container>> coef_mat_precompute_ptr; // immutable
1478 };
1479
1480 template <typename T_container>
1481 class quintic_interp_base : public coef_mat_interp_base<T_container> {
1482 // Biquintic B-spline base class
1483 public:
1484 typedef typename coef_mat_interp_base<T_container>::value_type value_type;
1485 typedef typename coef_mat_interp_base<T_container>::reference reference;
1486 typedef typename coef_mat_interp_base<T_container>::size_type size_type;
1487 typedef typename coef_mat_interp_base<T_container>::difference_type difference_type;
1488 typedef typename coef_mat_interp_base<T_container>::coords coords;
1489 typedef typename coef_mat_interp_base<T_container>::container container;
1490 typedef typename coef_mat_interp_base<T_container>::const_container const_container;
1491
1492 friend container;
1493
1494 // Rule of 5 and destructor --------------------------------------//
1495 quintic_interp_base() = default;
1496 quintic_interp_base(const quintic_interp_base&) = default;
1497 quintic_interp_base(quintic_interp_base&&) noexcept = default;
1498 quintic_interp_base& operator=(const quintic_interp_base&) = default;
1499 quintic_interp_base& operator=(quintic_interp_base&&) = default;
1500 virtual ~quintic_interp_base() noexcept = default;
1501
1502 // Additional Constructors ---------------------------------------//
1503 quintic_interp_base(const_container &A) : coef_mat_interp_base<container>(A,5) { }
1504
1505 // Arithmetic methods --------------------------------------------//
1506 value_type operator()(double, double) const override;
1507 const_container& first_order(double, double) const override;
1508
1509 protected:
1510 // Arithmetic methods --------------------------------------------//
1511 std::shared_ptr<container> get_bspline_mat_ptr(const_container&) const;
1512 const_container& calc_coef_mat(container&, const_container&, difference_type, difference_type) const override;
1513
1514 // Utility -------------------------------------------------------//
1515 // Uses 36 points around floored point. Allow interpolation within
1516 // entire image bounds since padding is used for the b-coefficient
1517 // array; this padding must be 3 or greater.
1518 bool out_of_bounds(double p1, double p2) const override { return p1 < 0 || p1 > this->A_ptr->height() - 1 || p2 < 0 || p2 > this->A_ptr->width() - 1; }
1519
1520 // Must be greater than or equal to 3 in order to interpolate entire
1521 // image for any input size. Large borders mitigate ringing errors.
1522 difference_type bcoef_border = 20;
1523 };
1524
1525 template <typename T_container>
1526 class quintic_interp final : public quintic_interp_base<T_container> {
1527 // Biquintic B-spline interpolation
1528 public:
1529 typedef typename quintic_interp_base<T_container>::value_type value_type;
1530 typedef typename quintic_interp_base<T_container>::reference reference;
1531 typedef typename quintic_interp_base<T_container>::size_type size_type;
1532 typedef typename quintic_interp_base<T_container>::difference_type difference_type;
1533 typedef typename quintic_interp_base<T_container>::coords coords;
1534 typedef typename quintic_interp_base<T_container>::container container;
1535 typedef typename quintic_interp_base<T_container>::const_container const_container;
1536
1538
1539 // Rule of 5 and destructor --------------------------------------//
1540 quintic_interp() = default;
1542 quintic_interp(quintic_interp&&) noexcept = default;
1543 quintic_interp& operator=(const quintic_interp&) = default;
1544 quintic_interp& operator=(quintic_interp&&) = default;
1545 ~quintic_interp() noexcept = default;
1546
1547 // Additional Constructors ---------------------------------------//
1548 quintic_interp(const_container &A) : quintic_interp_base<container>(A), coef_mat_buf(6,6), bcoef_ptr(this->get_bspline_mat_ptr(A)) { }
1549
1550 // Clone ---------------------------------------------------------//
1551 quintic_interp* clone() const override { return new quintic_interp(*this); }
1552
1553 private:
1554 // Arithmetic methods --------------------------------------------//
1555 // The will compute the coefficient matrix
1556 const_container& get_coef_mat(difference_type p1, difference_type p2) const override {
1557 return this->calc_coef_mat(coef_mat_buf, *bcoef_ptr, p1 + this->bcoef_border - 2, p2 + this->bcoef_border - 2);
1558 }
1559
1560 mutable container coef_mat_buf;
1561 std::shared_ptr<container> bcoef_ptr; // immutable
1562 };
1563
1564 template <typename T_container>
1565 class quintic_interp_precompute final : public quintic_interp_base<T_container> {
1566 // Biquintic B-spline interpolation with a precomputed coefficient table
1567 // Note that this requires a LOT of memory (36 x the original image), so
1568 // only use this if the same image is interpolated many times.
1569 public:
1570 typedef typename quintic_interp_base<T_container>::value_type value_type;
1571 typedef typename quintic_interp_base<T_container>::reference reference;
1572 typedef typename quintic_interp_base<T_container>::size_type size_type;
1573 typedef typename quintic_interp_base<T_container>::difference_type difference_type;
1574 typedef typename quintic_interp_base<T_container>::coords coords;
1575 typedef typename quintic_interp_base<T_container>::container container;
1576 typedef typename quintic_interp_base<T_container>::const_container const_container;
1577
1579
1580 // Rule of 5 and destructor --------------------------------------//
1586 ~quintic_interp_precompute() noexcept = default;
1587
1588 // Additional Constructors ---------------------------------------//
1590
1591 // Clone ---------------------------------------------------------//
1592 quintic_interp_precompute* clone() const override { return new quintic_interp_precompute(*this); }
1593
1594 private:
1595 // Arithmetic methods --------------------------------------------//
1596 // This returns precomputed coef matrix instead of calculating it
1597 const_container& get_coef_mat(difference_type p1, difference_type p2) const override { return (*coef_mat_precompute_ptr)(p1,p2); }
1598
1599 std::shared_ptr<Array2D<container>> coef_mat_precompute_ptr; // immutable
1600 };
1601
1602 template <typename T_interp>
1603 class interface_interp final {
1604 // This is a container for the base interp class to hide the inheritance
1605 // tree.
1606 public:
1607 typedef typename T_interp::value_type value_type;
1608 typedef typename T_interp::reference reference;
1609 typedef typename T_interp::size_type size_type;
1610 typedef typename T_interp::difference_type difference_type;
1611 typedef typename T_interp::coords coords;
1612 typedef typename T_interp::container container;
1613 typedef typename T_interp::const_container const_container;
1614
1615 template <typename T_interp2>
1616 friend class interface_interp;
1618
1619 // Part of rule of 5 ---------------------------------------------//
1620 interface_interp() noexcept : ptr(nullptr) { }
1621 interface_interp(const interface_interp &interp) : ptr(interp.ptr ? interp.ptr->clone() : nullptr) { }
1622 interface_interp(interface_interp &&interp) : ptr(std::move(interp.ptr)) { }
1623 interface_interp& operator=(const interface_interp &interp) { ptr.reset(interp.ptr ? interp.ptr->clone() : nullptr); return *this; }
1624 interface_interp& operator=(interface_interp &&interp) { ptr = std::move(interp.ptr); return *this; }
1625 ~interface_interp() noexcept = default;
1626
1627 // Additional Constructors ---------------------------------------//
1628 // explicit is important since ptr is wrapped in shared_ptr, which
1629 // will call delete on ptr when this object goes out of scope.
1630 explicit interface_interp(T_interp *ptr) : ptr(ptr) { }
1631
1632 // Access methods ------------------------------------------------//
1633 value_type operator()(double p1, double p2) const { return (*ptr)(p1,p2); }
1634 const_container& first_order(double p1, double p2) const { return ptr->first_order(p1,p2); }
1635
1636 private:
1637 std::shared_ptr<T_interp> ptr;
1638 };
1639
1640 // Linsolver -------------------------------------------------------------//
1641 template <typename T_container>
1643 // Base class for linsolver. Note that this class does not take into
1644 // account if caller Array2D is const or not.
1645 public:
1646 typedef typename T_container::value_type value_type;
1647 typedef typename T_container::reference reference;
1648 typedef typename T_container::size_type size_type;
1649 typedef typename T_container::difference_type difference_type;
1650 typedef typename T_container::coords coords;
1651 typedef typename container_traits<T_container>::nonconst_container container;
1652 typedef typename container_traits<T_container>::const_container const_container;
1653
1655
1656 // Rule of 5 and destructor --------------------------------------//
1657 base_linsolver() noexcept = default;
1659 base_linsolver(base_linsolver&&) noexcept = default;
1660 base_linsolver& operator=(const base_linsolver&) = default;
1661 base_linsolver& operator=(base_linsolver&&) = default;
1662 virtual ~base_linsolver() noexcept = default;
1663
1664 // Additional Constructors ---------------------------------------//
1665 // Copy input Array2D, and then perform in-place decomposition
1666 base_linsolver(const_container &A) : x_buf(A.width(),1), A_factored_ptr(std::make_shared<container>(A)) { }
1667
1668 // Conversion ----------------------------------------------------//
1669 // This allows tests to see if factorization was successful
1670 virtual operator bool() = 0;
1671
1672 // Arithmetic methods --------------------------------------------//
1676
1677 // Clone ---------------------------------------------------------//
1678 virtual base_linsolver* clone() const = 0;
1679
1680 protected:
1681 mutable container x_buf; // have a copy per
1682 std::shared_ptr<container> A_factored_ptr; // the factored matrix - immutable
1683 };
1684
1685 template <typename T_container>
1686 class LU_linsolver final : public base_linsolver<T_container> {
1687 // Class for the LU solver
1688 public:
1696
1698
1699 // Rule of 5 and destructor --------------------------------------//
1700 LU_linsolver() : full_rank() { }
1701 LU_linsolver(const LU_linsolver&) = default;
1702 LU_linsolver(LU_linsolver&&) noexcept = default;
1703 LU_linsolver& operator=(const LU_linsolver&) = default;
1704 LU_linsolver& operator=(LU_linsolver&&) = default;
1705 ~LU_linsolver() noexcept = default;
1706
1707 // Additional Constructors ---------------------------------------//
1709
1710 // Conversion ----------------------------------------------------//
1711 // Tests whether system is nonsingular
1712 operator bool() override { return full_rank; }
1713
1714 // Arithmetic methods --------------------------------------------//
1715 const_container& solve(const_container&) const override;
1716
1717 // Clone ---------------------------------------------------------//
1718 LU_linsolver* clone() const override { return new LU_linsolver(*this); }
1719
1720 private:
1721 std::shared_ptr<container> piv_ptr; // pivots - immutable
1722 bool full_rank;
1723 };
1724
1725 template <typename T_container>
1726 class QR_linsolver final : public base_linsolver<T_container> {
1727 // Class for QR solver
1728 public:
1736
1738
1739 // Rule of 5 and destructor --------------------------------------//
1740 QR_linsolver() : full_rank(), rank() { }
1741 QR_linsolver(const QR_linsolver&) = default;
1742 QR_linsolver(QR_linsolver&&) noexcept = default;
1743 QR_linsolver& operator=(const QR_linsolver&) = default;
1744 QR_linsolver& operator=(QR_linsolver&&) = default;
1745 ~QR_linsolver() noexcept = default;
1746
1747 // Additional Constructors ---------------------------------------//
1749
1750 // Conversion ----------------------------------------------------//
1751 // Tests whether system is nonsingular
1752 operator bool() override { return full_rank; }
1753
1754 // Arithmetic methods --------------------------------------------//
1755 std::pair<container, value_type> house(const_container&) const;
1756 const_container& solve(const_container&) const override;
1757
1758 // Clone ---------------------------------------------------------//
1759 QR_linsolver* clone() const override { return new QR_linsolver(*this); }
1760
1761 private:
1762 std::shared_ptr<container> piv_ptr; // pivots - immutable
1763 std::shared_ptr<container> beta_ptr; // beta - immutable
1764 bool full_rank;
1765 difference_type rank;
1766 };
1767
1768 template <typename T_container>
1769 class CHOL_linsolver final : public base_linsolver<T_container> {
1770 // Class for cholesky solver
1771 public:
1779
1781
1782 // Rule of 5 and destructor --------------------------------------//
1783 CHOL_linsolver() : pos_def() { }
1785 CHOL_linsolver(CHOL_linsolver&&) noexcept = default;
1786 CHOL_linsolver& operator=(const CHOL_linsolver&) = default;
1787 CHOL_linsolver& operator=(CHOL_linsolver&&) = default;
1788 ~CHOL_linsolver() noexcept = default;
1789
1790 // Additional Constructors ---------------------------------------//
1792
1793 // Conversion ----------------------------------------------------//
1794 // Tests whether system is positive definite
1795 operator bool() override { return pos_def; }
1796
1797 // Solve method --------------------------------------------------//
1798 const_container& solve(const_container&) const override;
1799
1800 // Clone ---------------------------------------------------------//
1801 CHOL_linsolver* clone() const override { return new CHOL_linsolver(*this); }
1802
1803 private:
1804 bool pos_def;
1805 };
1806
1807 template <typename T_linsolver>
1808 class interface_linsolver final {
1809 // This is a container for the base linsolver class to hide the inheritance
1810 // tree.
1811 public:
1812 typedef typename T_linsolver::value_type value_type;
1813 typedef typename T_linsolver::reference reference;
1814 typedef typename T_linsolver::size_type size_type;
1815 typedef typename T_linsolver::difference_type difference_type;
1816 typedef typename T_linsolver::coords coords;
1817 typedef typename T_linsolver::container container;
1818 typedef typename T_linsolver::const_container const_container;
1819
1820 template <typename T_linsolver2>
1823
1824 // Part of rule of 5 ---------------------------------------------//
1825 interface_linsolver() noexcept : ptr(nullptr) { }
1826 interface_linsolver(const interface_linsolver &linsolver) : ptr(linsolver.ptr ? linsolver.ptr->clone() : nullptr) { }
1827 interface_linsolver(interface_linsolver &&linsolver) : ptr(std::move(linsolver.ptr)) { }
1828 interface_linsolver& operator=(const interface_linsolver &linsolver) { ptr.reset(linsolver.ptr ? linsolver.ptr->clone() : nullptr); return *this; }
1829 interface_linsolver& operator=(interface_linsolver &&linsolver) { ptr = std::move(linsolver.ptr); return *this; }
1830 ~interface_linsolver() noexcept = default;
1831
1832 // Additional Constructors ---------------------------------------//
1833 // explicit is important since ptr is wrapped in shared_ptr, which
1834 // will call delete on ptr when this object goes out of scope.
1835 explicit interface_linsolver(T_linsolver *ptr) : ptr(ptr) { }
1836
1837 // Conversion ----------------------------------------------------//
1838 // Allow implicit conversions to bool to test whether system is "valid"
1839 // (i.e. nonsingular for LU decomposition, positive definite for
1840 // cholesky decomposition, etc)
1841 operator bool() { return (*ptr); }
1842
1843 // Solve method --------------------------------------------------//
1844 const_container& solve(const_container &b) const { return ptr->solve(b); }
1845
1846 private:
1847 std::shared_ptr<T_linsolver> ptr;
1848 };
1849}
1850
1851// ---------------------------------------------------------------------------//
1852// Definitions ---------------------------------------------------------------//
1853// ---------------------------------------------------------------------------//
1854
1855// Array2D -------------------------------------------------------------------//
1856template <typename T, typename T_alloc>
1858 // Must copy before freeing in the case "this" is self-assigned
1859 auto new_ptr = allocate_and_copy(A.s,A.ptr);
1860 destroy_and_deallocate();
1861 // Copy size of A and assign new pointer
1862 this->h = A.h;
1863 this->w = A.w;
1864 this->s = A.s;
1865 this->ptr = new_ptr;
1866
1867 return *this;
1868}
1869
1870template <typename T, typename T_alloc>
1872 // Test to make sure this is not self-assigned
1873 if (this != &A) {
1874 destroy_and_deallocate();
1875 // Pointer is directly copied; make r-value A null so that its destructor
1876 // does not free this pointer while also remaining valid
1877 this->h = A.h;
1878 this->w = A.w;
1879 this->s = A.s;
1880 this->ptr = A.ptr;
1881 A.make_null();
1882 }
1883
1884 return *this;
1885}
1886
1887// Additional Constructors ---------------------------------------------------//
1888template <typename T, typename T_alloc>
1889Array2D<T,T_alloc>::Array2D(difference_type h, difference_type w, const_reference val) : h(h), w(w), s(h*w), ptr(nullptr) {
1890 chk_minsize_op(0,0,"Array2D construction");
1891
1892 this->ptr = allocate_and_init(this->h*this->w, val);
1893}
1894
1895template <typename T, typename T_alloc>
1896Array2D<T,T_alloc>::Array2D(std::initializer_list<value_type> il) : h(il.size()), w(1), s(h*w), ptr(allocate_and_init(s, value_type())) {
1897 // Regular initializer_list is initialized as a column; copy values.
1898 std::copy(il.begin(), il.end(), this->ptr);
1899}
1900
1901template <typename T, typename T_alloc>
1902Array2D<T,T_alloc>::Array2D(std::initializer_list<std::initializer_list<value_type>> il_row) : h(il_row.size()), w(il_row.begin()->size()), s(h*w), ptr(allocate_and_init(s, value_type())) {
1903 // Assign width based on first inner list; must check for consistency among
1904 // every inner list and throw exception if initializer list is jagged.
1905 difference_type p1 = 0;
1906 for (auto it_row = il_row.begin(); it_row != il_row.end(); ++it_row) {
1907 // Get inner list
1908 auto il_col = *it_row;
1909 // Must insure consistent width
1910 if (il_col.size() != this->w) {
1911 // This is a programmer error. Call destructor before throwing
1912 // exception since memory was already allocated. Destructor call is
1913 // safe because all elements are initialized as default elements.
1914 this->~Array2D();
1915
1916 throw std::invalid_argument("Initializer list for Array2D must not be jagged.");
1917 }
1918
1919 difference_type p2 = 0;
1920 for (auto it_col = il_col.begin(); it_col != il_col.end(); ++it_col) {
1921 (*this)(p1,p2) = *it_col;
1922 ++p2;
1923 }
1924 ++p1;
1925 }
1926}
1927
1928// Static factory methods ----------------------------------------------------//
1929template <typename T, typename T_alloc>
1930template <typename T_output>
1931typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T, T_alloc>::load(const std::string &filename) {
1932 // Form stream
1933 std::ifstream is(filename.c_str(), std::ios::in | std::ios::binary);
1934 if (!is.is_open()) {
1935 throw std::invalid_argument("Could not open " + filename + " for loading Array2D.");
1936 }
1937
1938 // Form Array using stream static factory method
1939 auto A = Array2D::load(is);
1940
1941 // Close stream
1942 is.close();
1943
1944 return A;
1945}
1946
1947template <typename T, typename T_alloc>
1948template <typename T_output>
1949typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T, T_alloc>::load(std::ifstream &is) {
1950 // Form empty A and then fill in values in accordance to how they are saved
1951 Array2D A;
1952
1953 // Load height -> width
1954 is.read(reinterpret_cast<char*>(&A.h), std::streamsize(sizeof(difference_type)));
1955 is.read(reinterpret_cast<char*>(&A.w), std::streamsize(sizeof(difference_type)));
1956 A.s = A.h*A.w; // Set s
1957
1958 // Allocate memory
1959 A.ptr = A.allocate_and_init(A.s, value_type());
1960
1961 // Read data
1962 is.read(reinterpret_cast<char*>(A.ptr), std::streamsize(sizeof(value_type) * A.s));
1963
1964 return A;
1965}
1966
1967// Conversion ----------------------------------------------------------------//
1968template <typename T, typename T_alloc>
1970 chk_size_op(1,1,"value_type conversion");
1971
1972 return (*this)(0);
1973}
1974
1975// Indexing ------------------------------------------------------------------//
1976template <typename T, typename T_alloc>
1978 #ifndef NDEBUG
1979 // Checks make indexing slow, so only do so in debug mode
1980 chk_minsize_op(1,1,"1D single-element indexing");
1981 chk_in_bounds_op(p,"1D single-element indexing");
1982 #endif
1983
1984 return ptr[p];
1985}
1986
1987template <typename T, typename T_alloc>
1989 #ifndef NDEBUG
1990 // Checks make indexing slow, so only do so in debug mode
1991 chk_minsize_op(1,1,"2D single-element indexing");
1992 chk_in_bounds_op(p1,p2,"2D single-element indexing");
1993 #endif
1994
1995 return ptr[sub2ind(p1,p2)];
1996}
1997
1998// General operations --------------------------------------------------------//
1999template <typename T, typename T_alloc>
2000template <typename T_output>
2001typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T,T_alloc>::this_cv_img(value_type min, value_type max) const {
2002 // Returns opencv style matrix in unsigned char format so it can be displayed
2003 // as an image
2004
2005 // Convert to cv::Mat using unsigned char type
2006 cv::Mat cv_img(h, w, cv::DataType<uchar>::type);
2007 double conversion = (std::abs(max - min) > std::numeric_limits<double>::epsilon()) ? std::numeric_limits<uchar>::max() / (max - min) : 0;
2008 for (difference_type p2 = 0; p2 < w; ++p2) {
2009 for (difference_type p1 = 0; p1 < h; ++p1) {
2010 // Mat is row-major, so must convert from column major.
2011 double val = ((*this)(p1,p2) - min) * conversion;
2012 if (val < 0) {
2013 cv_img.at<uchar>(p1,p2) = 0;
2014 } else if (val > 255) {
2015 cv_img.at<uchar>(p1,p2) = 255;
2016 } else {
2017 cv_img.at<uchar>(p1,p2) = val;
2018 }
2019 }
2020 }
2021
2022 return cv_img;
2023}
2024
2025// imshow is only supported for arithmetic types
2026template <typename T, typename T_alloc>
2027template <typename T_output>
2028typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T,T_alloc>::this_imshow(difference_type delay) const {
2029 // opencv's imshow function doesnt work for empty arrays
2030 chk_minsize_op(1,1,"imshow");
2031
2032 // Get cv style matrix and show it
2033 cv::Mat cv_img = this_cv_img(this_min(), this_max());
2034 cv::imshow("Array2D", cv_img);
2035 delay == -1 ? cv::waitKey() : cv::waitKey(delay);
2036}
2037
2038template <typename T, typename T_alloc>
2039template <typename T_output>
2040typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T,T_alloc>::this_stream(std::ostream &os) const {
2041 // Note this prints in row-major order
2042 for (difference_type p1 = 0; p1 < h; ++p1) {
2043 for (difference_type p2 = 0; p2 < w; ++p2) {
2044 os << (*this)(p1,p2) << ((p2 < w - 1) ? '\t' : '\0');
2045 }
2046 os << '\n';
2047 }
2048
2049 return os;
2050}
2051
2052template <typename T, typename T_alloc>
2053Array2D<T, T_alloc> Array2D<T, T_alloc>::this_repmat(difference_type rows, difference_type cols) const {
2054 Array2D B(h * rows, w * cols);
2055 for (difference_type p2 = 0; p2 < cols; ++p2) {
2056 for (difference_type p1 = 0; p1 < rows; ++p1) {
2057 B({p1*h, (p1+1)*h-1},{p2*w, (p2+1)*w-1}) = (*this);
2058 }
2059 }
2060
2061 return B;
2062}
2063
2064template <typename T, typename T_alloc>
2065Array2D<T, T_alloc> Array2D<T, T_alloc>::this_pad(difference_type padding, PAD type) const {
2066 Array2D A(h + 2*padding, w + 2*padding);
2067 A({padding, h + padding - 1},{padding, w + padding - 1}) = *this;
2068 switch (type) {
2069 case PAD::EXPAND_EDGES :
2070 // fills in padding with edge values - check to make sure this array
2071 // is not empty first
2072 if (!empty()) {
2073 // Fill corners:
2074 A({0,padding-1},{0,padding-1}) = (*this)(0,0);
2075 A({0,padding-1},{w+padding,w+2*padding-1}) = (*this)(0,last);
2076 A({h+padding,last},{0,padding-1}) = (*this)(last,0);
2077 A({h+padding,last},{w+padding,w+2*padding-1}) = (*this)(last,last);
2078 // Fill sides:
2079 A({0,padding-1},{padding,w+padding-1}) = repmat((*this)(0,all),padding,1);
2080 A({padding,h+padding-1},{0,padding-1}) = repmat((*this)(all,0),1,padding);
2081 A({padding,h+padding-1},{w+padding,last}) = repmat((*this)(all,last),1,padding);
2082 A({h+padding,last},{padding,w+padding-1}) = repmat((*this)(last,all),padding,1);
2083 }
2084 break;
2085 case PAD::ZEROS :
2086 break;
2087 }
2088
2089 return A;
2090}
2091
2092template <typename T, typename T_alloc>
2093Array2D<T, T_alloc> Array2D<T, T_alloc>::this_t() const {
2094 Array2D A(w, h);
2095 for (difference_type p2 = 0; p2 < w; ++p2) {
2096 for (difference_type p1 = 0; p1 < h; ++p1) {
2097 A(p2,p1) = (*this)(p1,p2);
2098 }
2099 }
2100
2101 return A;
2102}
2103
2104template <typename T, typename T_alloc>
2105template <typename T_output>
2106typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T, T_alloc>::this_save(const std::string &filename) const {
2107 // Form stream
2108 std::ofstream os(filename.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
2109 if (!os.is_open()) {
2110 throw std::invalid_argument("Could not open " + filename + " for saving Array2D.");
2111 }
2112
2113 // Save data into stream
2114 this_save(os);
2115
2116 // Close stream
2117 os.close();
2118}
2119
2120template <typename T, typename T_alloc>
2121template <typename T_output>
2122typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T, T_alloc>::this_save(std::ofstream &os) const {
2123 // Save height -> width -> data
2124 os.write(reinterpret_cast<const char*>(&h), std::streamsize(sizeof(difference_type)));
2125 os.write(reinterpret_cast<const char*>(&w), std::streamsize(sizeof(difference_type)));
2126 os.write(reinterpret_cast<const char*>(ptr), std::streamsize(sizeof(value_type) * s));
2127}
2128
2129
2130// Logical operations --------------------------------------------------------//
2131template <typename T, typename T_alloc>
2132bool Array2D<T, T_alloc>::this_isequal(const Array2D &A) const {
2133 if (h != A.h || w != A.w) {
2134 return false;
2135 }
2136
2137 for (difference_type p = 0; p < s; ++p) {
2138 if ((*this)(p) != A(p)) {
2139 return false;
2140 }
2141 }
2142
2143 return true;
2144}
2145
2146template <typename T, typename T_alloc>
2147typename Array2D<T,T_alloc>::bool_container Array2D<T, T_alloc>::this_equals(const Array2D &A) const {
2148 chk_samesize_op(A,"element-wise equality");
2149
2150 bool_container B(h,w);
2151 for (difference_type p = 0; p < s; ++p) {
2152 B(p) = (*this)(p) == A(p);
2153 }
2154
2155 return B;
2156}
2157
2158template <typename T, typename T_alloc>
2159typename Array2D<T,T_alloc>::bool_container Array2D<T, T_alloc>::this_equals(const_reference val) const {
2160 bool_container B(h,w);
2161 for (difference_type p = 0; p < s; ++p) {
2162 B(p) = (*this)(p) == val;
2163 }
2164
2165 return B;
2166}
2167
2168template <typename T, typename T_alloc>
2169typename Array2D<T,T_alloc>::bool_container Array2D<T, T_alloc>::this_notequals(const Array2D &A) const {
2170 chk_samesize_op(A,"element-wise inequality");
2171
2172 bool_container B(h,w);
2173 for (difference_type p = 0; p < s; ++p) {
2174 B(p) = (*this)(p) != A(p);
2175 }
2176
2177 return B;
2178}
2179
2180template <typename T, typename T_alloc>
2181typename Array2D<T,T_alloc>::bool_container Array2D<T, T_alloc>::this_notequals(const_reference val) const {
2182 bool_container B(h,w);
2183 for (difference_type p = 0; p < s; ++p) {
2184 B(p) = (*this)(p) != val;
2185 }
2186
2187 return B;
2188}
2189
2190template <typename T, typename T_alloc>
2191typename Array2D<T,T_alloc>::bool_container Array2D<T, T_alloc>::this_and(const Array2D &A) const {
2192 chk_samesize_op(A,"element-wise 'and'");
2193
2194 bool_container B(h,w);
2195 for (difference_type p = 0; p < s; ++p) {
2196 B(p) = (*this)(p) && A(p);
2197 }
2198
2199 return B;
2200}
2201
2202template <typename T, typename T_alloc>
2203typename Array2D<T,T_alloc>::bool_container Array2D<T, T_alloc>::this_or(const Array2D &A) const {
2204 chk_samesize_op(A,"element-wise 'or'");
2205
2206 bool_container B(h,w);
2207 for (difference_type p = 0; p < s; ++p) {
2208 B(p) = (*this)(p) || A(p);
2209 }
2210
2211 return B;
2212}
2213
2214template <typename T, typename T_alloc>
2215typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_negate() const {
2216 bool_container B(h,w);
2217 for (difference_type p = 0; p < s; ++p) {
2218 B(p) = !(*this)(p);
2219 }
2220
2221 return B;
2222}
2223
2224template <typename T, typename T_alloc>
2225bool Array2D<T,T_alloc>::this_any_true() const {
2226 for (difference_type p = 0; p < s; ++p) {
2227 if ((*this)(p)) {
2228 return true;
2229 }
2230 }
2231 // returns false for empty arrays
2232 return false;
2233}
2234
2235template <typename T, typename T_alloc>
2236bool Array2D<T,T_alloc>::this_all_true() const {
2237 for (difference_type p = 0; p < s; ++p) {
2238 if (!(*this)(p)) {
2239 return false;
2240 }
2241 }
2242 // returns true for empty arrays
2243 return true;
2244}
2245
2246template <typename T, typename T_alloc>
2247typename Array2D<T,T_alloc>::difference_type Array2D<T,T_alloc>::this_find(difference_type start) const {
2248 // Returns index of first true element starting from "start"
2249 for (difference_type p = start; p < s; ++p) {
2250 if ((*this)(p)) {
2251 return p;
2252 }
2253 }
2254 // Returns -1 if value wasnt found
2255 return -1;
2256}
2257
2258// Relational operations -----------------------------------------------------//
2259template <typename T, typename T_alloc>
2260typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_greaterthan(const Array2D &A) const {
2261 chk_samesize_op(A,"element-wise greater-than");
2262
2263 bool_container B(h,w);
2264 for (difference_type p = 0; p < s; ++p) {
2265 B(p) = (*this)(p) > A(p);
2266 }
2267
2268 return B;
2269}
2270
2271template <typename T, typename T_alloc>
2272typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_greaterthan(const_reference val) const {
2273 bool_container B(h,w);
2274 for (difference_type p = 0; p < s; ++p) {
2275 B(p) = (*this)(p) > val;
2276 }
2277
2278 return B;
2279}
2280
2281template <typename T, typename T_alloc>
2282typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_greaterthanorequalto(const Array2D &A) const {
2283 chk_samesize_op(A,"element-wise greater-than or equal to");
2284
2285 bool_container B(h,w);
2286 for (difference_type p = 0; p < s; ++p) {
2287 B(p) = (*this)(p) >= A(p);
2288 }
2289
2290 return B;
2291}
2292
2293template <typename T, typename T_alloc>
2294typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_greaterthanorequalto(const_reference val) const {
2295 bool_container B(h,w);
2296 for (difference_type p = 0; p < s; ++p) {
2297 B(p) = (*this)(p) >= val;
2298 }
2299
2300 return B;
2301}
2302
2303template <typename T, typename T_alloc>
2304typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_lessthan(const Array2D &A) const {
2305 chk_samesize_op(A,"element-wise less-than");
2306
2307 bool_container B(h,w);
2308 for (difference_type p = 0; p < s; ++p) {
2309 B(p) = (*this)(p) < A(p);
2310 }
2311
2312 return B;
2313}
2314
2315template <typename T, typename T_alloc>
2316typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_lessthan(const_reference val) const {
2317 bool_container B(h,w);
2318 for (difference_type p = 0; p < s; ++p) {
2319 B(p) = (*this)(p) < val;
2320 }
2321
2322 return B;
2323}
2324
2325template <typename T, typename T_alloc>
2326typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_lessthanorequalto(const Array2D &A) const {
2327 chk_samesize_op(A,"element-wise less-than or equal to");
2328
2329 bool_container B(h,w);
2330 for (difference_type p = 0; p < s; ++p) {
2331 B(p) = (*this)(p) <= A(p);
2332 }
2333
2334 return B;
2335}
2336
2337template <typename T, typename T_alloc>
2338typename Array2D<T,T_alloc>::bool_container Array2D<T,T_alloc>::this_lessthanorequalto(const_reference val) const {
2339 bool_container B(h,w);
2340 for (difference_type p = 0; p < s; ++p) {
2341 B(p) = (*this)(p) <= val;
2342 }
2343
2344 return B;
2345}
2346
2347// Arithmetic operations -----------------------------------------------------//
2348template <typename T, typename T_alloc>
2349Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator+=(const Array2D &A) {
2350 chk_samesize_op(A,"element-wise addition");
2351
2352 for (difference_type p = 0; p < s; ++p) {
2353 (*this)(p) += A(p);
2354 }
2355
2356 return *this;
2357}
2358
2359template <typename T, typename T_alloc>
2360Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator+=(const_reference val) {
2361 for (difference_type p = 0; p < s; ++p) {
2362 (*this)(p) += val;
2363 }
2364
2365 return *this;
2366}
2367
2368template <typename T, typename T_alloc>
2369Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator-=(const Array2D &A) {
2370 chk_samesize_op(A,"element-wise subtraction");
2371
2372 for (difference_type p = 0; p < s; ++p) {
2373 (*this)(p) -= A(p);
2374 }
2375
2376 return *this;
2377}
2378
2379template <typename T, typename T_alloc>
2380Array2D<T,T_alloc>& Array2D<T,T_alloc>::this_flipsubassign(const Array2D &A) {
2381 chk_samesize_op(A,"element-wise subtraction");
2382
2383 for (difference_type p = 0; p < s; ++p) {
2384 (*this)(p) = A(p)-(*this)(p);
2385 }
2386
2387 return *this;
2388}
2389
2390template <typename T, typename T_alloc>
2391Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator-=(const_reference val) {
2392 for (difference_type p = 0; p < s; ++p) {
2393 (*this)(p) -= val;
2394 }
2395
2396 return *this;
2397}
2398
2399template <typename T, typename T_alloc>
2400Array2D<T,T_alloc>& Array2D<T,T_alloc>::this_flipsubassign(const_reference val) {
2401 for (difference_type p = 0; p < s; ++p) {
2402 (*this)(p) = val-(*this)(p);
2403 }
2404
2405 return *this;
2406}
2407
2408template <typename T, typename T_alloc>
2409Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator*=(const Array2D &A) {
2410 chk_samesize_op(A,"element-wise multiplication");
2411
2412 for (difference_type p = 0; p < s; ++p) {
2413 (*this)(p) *= A(p);
2414 }
2415
2416 return *this;
2417}
2418
2419template <typename T, typename T_alloc>
2420Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator*=(const_reference val) {
2421 for (difference_type p = 0; p < s; ++p) {
2422 (*this)(p) *= val;
2423 }
2424
2425 return *this;
2426}
2427
2428template <typename T, typename T_alloc>
2429Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator/=(const Array2D &A) {
2430 chk_samesize_op(A,"element-wise division");
2431
2432 for (difference_type p = 0; p < s; ++p) {
2433 (*this)(p) /= A(p);
2434 }
2435
2436 return *this;
2437}
2438
2439template <typename T, typename T_alloc>
2440Array2D<T,T_alloc>& Array2D<T,T_alloc>::this_flipdivassign(const Array2D &A) {
2441 chk_samesize_op(A,"element-wise division");
2442
2443 for (difference_type p = 0; p < s; ++p) {
2444 (*this)(p) = A(p)/(*this)(p);
2445 }
2446
2447 return *this;
2448}
2449
2450template <typename T, typename T_alloc>
2451Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator/=(const_reference val) {
2452 for (difference_type p = 0; p < s; ++p) {
2453 (*this)(p) /= val;
2454 }
2455
2456 return *this;
2457}
2458
2459template <typename T, typename T_alloc>
2460Array2D<T,T_alloc>& Array2D<T,T_alloc>::this_flipdivassign(const_reference val) {
2461 for (difference_type p = 0; p < s; ++p) {
2462 (*this)(p) = val/(*this)(p);
2463 }
2464
2465 return *this;
2466}
2467
2468template <typename T, typename T_alloc>
2469Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator+() {
2470 return *this;
2471}
2472
2473template <typename T, typename T_alloc>
2474Array2D<T,T_alloc>& Array2D<T,T_alloc>::operator-() {
2475 for (difference_type p = 0; p < s; ++p) {
2476 (*this)(p) = -(*this)(p);
2477 }
2478
2479 return *this;
2480}
2481
2482template <typename T, typename T_alloc>
2483Array2D<T, T_alloc>& Array2D<T,T_alloc>::this_sort() {
2484 std::sort(ptr, ptr + s);
2485
2486 return *this;
2487}
2488
2489template <typename T, typename T_alloc>
2490T Array2D<T,T_alloc>::this_sum() const {
2491 value_type sum = value_type();
2492 for (difference_type p = 0; p < s; ++p) {
2493 sum += (*this)(p);
2494 }
2495
2496 return sum;
2497}
2498
2499template <typename T, typename T_alloc>
2500T Array2D<T,T_alloc>::this_max() const {
2501 chk_minsize_op(1,1,"max");
2502
2503 return *std::max_element(ptr, ptr + s);
2504}
2505
2506template <typename T, typename T_alloc>
2507T Array2D<T,T_alloc>::this_min() const {
2508 chk_minsize_op(1,1,"min");
2509
2510 return *std::min_element(ptr, ptr + s);
2511}
2512
2513template <typename T, typename T_alloc>
2514T Array2D<T,T_alloc>::this_prctile(double percent) {
2515 chk_minsize_op(1,1,"prctile");
2516 if (percent < 0 || percent > 1) {
2517 throw std::invalid_argument("Input percent of: " + std::to_string(percent) + " provided to prctile operator. Value must be between (inclusive) 0 and 1.");
2518 }
2519
2520 // Sort, then return floored element closest to percent. No interpolation is
2521 // done.
2522 std::sort(ptr, ptr + s);
2523
2524 return (*this)((s-1) * percent);
2525}
2526
2527template <typename T, typename T_alloc>
2528template<typename T_output>
2529typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T,T_alloc>::this_sqrt() {
2530 for (difference_type p = 0; p < s; ++p) {
2531 (*this)(p) = std::sqrt((*this)(p));
2532 }
2533
2534 return *this;
2535}
2536
2537template <typename T, typename T_alloc>
2538template<typename T_output>
2539typename std::enable_if<std::is_arithmetic<T>::value, T_output>::type Array2D<T,T_alloc>::this_pow(double n) {
2540 for (difference_type p = 0; p < s; ++p) {
2541 (*this)(p) = std::pow((*this)(p),n);
2542 }
2543
2544 return *this;
2545}
2546
2547template <typename T, typename T_alloc>
2548template <typename T_output>
2549typename std::enable_if<!std::is_same<T,double>::value, T_output>::type Array2D<T,T_alloc>::this_mat_mult(const Array2D<T,T_alloc> &A) const {
2550 chk_mult_size(A);
2551
2552 // Note this algorithm performs C = AB+C. Must ensure C is initialized
2553 // to zero which is true when C is value initialized for numeric types.
2554 Array2D B(h, A.w);
2555 for (difference_type p = 0; p < A.w; ++p) {
2556 for (difference_type p2 = 0; p2 < w; ++p2) {
2557 for (difference_type p1 = 0; p1 < h; ++p1) {
2558 B(p1,p) += (*this)(p1,p2) * A(p2,p);
2559 }
2560 }
2561 }
2562
2563 return B;
2564}
2565
2566template <typename T, typename T_alloc>
2567template <typename T_output>
2568typename std::enable_if<std::is_same<T,double>::value, T_output>::type Array2D<T,T_alloc>::this_mat_mult(const Array2D<T,T_alloc> &A) const {
2569 chk_mult_size(A);
2570
2571 // Note this algorithm performs C = ALPHA*A*B + BETA*C. C will be value
2572 // initialized to 0.
2573 Array2D B(h, A.w);
2574
2575 // Call blas routine for double precision matrix-matrix multiplication -
2576 // note that there might be some narrowing conversion from difference_type
2577 // to int.
2578 char TRANS = 'N';
2579 int M = h;
2580 int N = A.w;
2581 int K = w;
2582 double ALPHA = 1.0;
2583 double BETA = 0.0;
2584 dgemm_(&TRANS, &TRANS, &M, &N, &K, &ALPHA, ptr, &M, A.ptr, &K, &BETA, B.ptr, &M);
2585
2586 return B;
2587}
2588
2589namespace details {
2590 // -----------------------------------------------------------------------//
2591 // FFTW allocator for conv function --------------------------------------//
2592 // -----------------------------------------------------------------------//
2593 template <typename T>
2594 class fftw_allocator final {
2595 public:
2596 typedef T value_type;
2597 typedef T* pointer;
2598 typedef const T* const_pointer;
2599 typedef T& reference;
2600 typedef const T& const_reference;
2601 typedef std::size_t size_type;
2602 typedef std::ptrdiff_t difference_type;
2603
2604 // Rule of 5 and destructor --------------------------------------//
2605 fftw_allocator() noexcept = default;
2606 fftw_allocator(const fftw_allocator&) noexcept = default;
2607 fftw_allocator(fftw_allocator&&) noexcept = default;
2608 fftw_allocator& operator=(const fftw_allocator&) = default;
2609 fftw_allocator& operator=(fftw_allocator&&) = default;
2610 ~fftw_allocator() noexcept = default;
2611
2612 // Other functions -----------------------------------------------//
2613 // Note that fftw_malloc and fftw_free allocate aligned double
2614 // precision arrays.
2615 pointer allocate(difference_type s, const void * = 0) {
2616 pointer ptr = static_cast<pointer>(malloc_function(s * sizeof(value_type)));
2617 if (!ptr) {
2618 NLOG_ERROR << "Failed to allocate memory using allocate in fftw_allocator.";
2619 throw std::bad_alloc();
2620 }
2621
2622 return ptr;
2623 }
2624 void deallocate(pointer ptr, difference_type) { free_function(ptr); }
2625 void construct(pointer ptr, const_reference val = value_type()) { ::new((void *)ptr) value_type(val); }
2626 void destroy(pointer ptr) { ptr->~value_type(); }
2627 template<typename T2>
2628 struct rebind { typedef fftw_allocator<T2> other; };
2629
2630 private:
2631 // These are specialized based on the type. Input is already
2632 // converted to bytes by allocate().
2633 void* malloc_function(difference_type s) { return malloc(s); }
2634 void free_function(pointer ptr) { return free(ptr); }
2635 };
2636 // Specialize malloc_function and free_function for double. These will use
2637 // fftw_malloc so SIMD instructions can be used. Input is already converted
2638 // to bytes by allocate().
2639 template<>
2640 inline void* fftw_allocator<double>::malloc_function(difference_type s) { return fftw_malloc(s); }
2641 template<>
2642 inline void fftw_allocator<double>::free_function(pointer ptr) { fftw_free(ptr); }
2643 // -----------------------------------------------------------------------//
2644 // -----------------------------------------------------------------------//
2645 // -----------------------------------------------------------------------//
2646}
2647
2648template <typename T, typename T_alloc>
2649template <typename T_output>
2650typename std::enable_if<std::is_same<T,double>::value, T_output>::type Array2D<T,T_alloc>::this_conv(const Array2D &A) const { return this_conv_base(A, FFTW::CONV); }
2651
2652template <typename T, typename T_alloc>
2653template <typename T_output>
2654typename std::enable_if<std::is_same<T,double>::value, T_output>::type Array2D<T,T_alloc>::this_deconv(const Array2D &A) const { return this_conv_base(A, FFTW::DECONV); }
2655
2656template <typename T, typename T_alloc>
2657template <typename T_output>
2658typename std::enable_if<std::is_same<T,double>::value, T_output>::type Array2D<T,T_alloc>::this_xcorr(const Array2D &A) const { return this_conv_base(A, FFTW::XCORR); }
2659
2660namespace details {
2661 extern std::mutex fftw_mutex; // Declare fftw_mutex
2662}
2663template <typename T, typename T_alloc>
2664Array2D<T,T_alloc> Array2D<T,T_alloc>::this_conv_base(const Array2D &kernel, FFTW fftw_type) const {
2665 using details::fftw_allocator;
2666
2667 chk_kernel_size(kernel);
2668
2669 // According to FFTW documentation, the only thread safe function is
2670 // fftw_execute
2671 std::unique_lock<std::mutex> fftw_lock(details::fftw_mutex);
2672
2673 // Allocate row-major temporary buffers for FFTW simple API
2674 const difference_type H = h;
2675 const difference_type W = w;
2676 const difference_type halfWplus1 = (W/2) + 1;
2677
2678 double* A_rm = static_cast<double*>(fftw_malloc(sizeof(double) * H * W));
2679 double* K_rm = static_cast<double*>(fftw_malloc(sizeof(double) * H * W));
2680 if (!A_rm || !K_rm) {
2681 if (A_rm) fftw_free(A_rm);
2682 if (K_rm) fftw_free(K_rm);
2683 throw std::bad_alloc();
2684 }
2685 // Zero initialize
2686 std::fill(A_rm, A_rm + H*W, 0.0);
2687 std::fill(K_rm, K_rm + H*W, 0.0);
2688
2689 // Copy input array (*this) to row-major buffer
2690 for (difference_type r = 0; r < H; ++r) {
2691 for (difference_type c = 0; c < W; ++c) {
2692 A_rm[r*W + c] = (*this)(r, c);
2693 }
2694 }
2695
2696 // Wrap kernel center to top-left into K_rm using (H,W)
2697 const difference_type KH = kernel.h;
2698 const difference_type KW = kernel.w;
2699 const difference_type c_kh = (KH - 1) / 2;
2700 const difference_type c_kw = (KW - 1) / 2;
2701
2702 // Q4 → top-left: kernel[c_kh: , c_kw: ] → K_rm[0:c_kh+1, 0:c_kw+1]
2703 for (difference_type r = 0; r <= c_kh; ++r) {
2704 for (difference_type c = 0; c <= c_kw; ++c) {
2705 K_rm[r*W + c] = kernel(c_kh + r, c_kw + c);
2706 }
2707 }
2708 // Q3 → top-right: kernel[c_kh: , :c_kw] → K_rm[0:c_kh+1, W-c_kw:W]
2709 if (c_kw > 0) {
2710 for (difference_type r = 0; r <= c_kh; ++r) {
2711 for (difference_type c = 0; c < c_kw; ++c) {
2712 K_rm[r*W + (W - c_kw + c)] = kernel(c_kh + r, c);
2713 }
2714 }
2715 }
2716 // Q1 → bottom-left: kernel[:c_kh, c_kw:] → K_rm[H-c_kh:H, 0:c_kw+1]
2717 if (c_kh > 0) {
2718 for (difference_type r = 0; r < c_kh; ++r) {
2719 for (difference_type c = 0; c <= c_kw; ++c) {
2720 K_rm[(H - c_kh + r)*W + c] = kernel(r, c_kh + c);
2721 }
2722 }
2723 }
2724 // Q2 → bottom-right: kernel[:c_kh, :c_kw] → K_rm[H-c_kh:H, W-c_kw:W]
2725 if (c_kh > 0 && c_kw > 0) {
2726 for (difference_type r = 0; r < c_kh; ++r) {
2727 for (difference_type c = 0; c < c_kw; ++c) {
2728 K_rm[(H - c_kh + r)*W + (W - c_kw + c)] = kernel(r, c);
2729 }
2730 }
2731 }
2732
2733 // Allocate complex spectra
2734 fftw_complex* A_fft = reinterpret_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * H * halfWplus1));
2735 fftw_complex* K_fft = reinterpret_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * H * halfWplus1));
2736 if (!A_fft || !K_fft) {
2737 if (A_fft) fftw_free(A_fft);
2738 if (K_fft) fftw_free(K_fft);
2739 fftw_free(A_rm);
2740 fftw_free(K_rm);
2741 throw std::bad_alloc();
2742 }
2743
2744 // Create plans (row-major simple API uses (h,w))
2745 fftw_plan plan_A = fftw_plan_dft_r2c_2d(static_cast<int>(H), static_cast<int>(W), A_rm, A_fft, FFTW_ESTIMATE);
2746 fftw_plan plan_kernel = fftw_plan_dft_r2c_2d(static_cast<int>(H), static_cast<int>(W), K_rm, K_fft, FFTW_ESTIMATE);
2747 fftw_plan plan_output = fftw_plan_dft_c2r_2d(static_cast<int>(H), static_cast<int>(W), A_fft, A_rm, FFTW_ESTIMATE);
2748
2749 // Ensure plans are destroyed on scope exit
2750 auto plan_deleter = [](fftw_plan *p) { return fftw_destroy_plan(*p); };
2751 std::unique_ptr<fftw_plan,decltype(plan_deleter)> plan_A_delete(&plan_A, plan_deleter);
2752 std::unique_ptr<fftw_plan,decltype(plan_deleter)> plan_kernel_delete(&plan_kernel, plan_deleter);
2753 std::unique_ptr<fftw_plan,decltype(plan_deleter)> plan_output_delete(&plan_output, plan_deleter);
2754
2755 // Unlock before executing
2756 fftw_lock.unlock();
2757
2758 // Execute forward FFTs
2759 fftw_execute(plan_A);
2760 fftw_execute(plan_kernel);
2761
2762 // Complex-domain operation over valid half-spectrum (H x (W/2+1))
2763 for (difference_type r = 0; r < H; ++r) {
2764 difference_type row_off = r * halfWplus1;
2765 for (difference_type c = 0; c < halfWplus1; ++c) {
2766 difference_type idx = row_off + c;
2767 double ar = A_fft[idx][0];
2768 double ai = A_fft[idx][1];
2769 double kr = K_fft[idx][0];
2770 double ki = K_fft[idx][1];
2771 switch (fftw_type) {
2772 case FFTW::CONV: {
2773 double nr = ar*kr - ai*ki;
2774 double ni = ar*ki + ai*kr;
2775 A_fft[idx][0] = nr;
2776 A_fft[idx][1] = ni;
2777 break;
2778 }
2779 case FFTW::DECONV: {
2780 double den = kr*kr + ki*ki;
2781 if (den == 0.0) {
2782 A_fft[idx][0] = 0.0;
2783 A_fft[idx][1] = 0.0;
2784 } else {
2785 double nr = (ar*kr + ai*ki)/den;
2786 double ni = (ai*kr - ar*ki)/den;
2787 A_fft[idx][0] = nr;
2788 A_fft[idx][1] = ni;
2789 }
2790 break;
2791 }
2792 case FFTW::XCORR: {
2793 // multiply by conj(kernel): (ar+iai)*(kr-iki)
2794 double nr = ar*kr + ai*ki;
2795 double ni = -ar*ki + ai*kr;
2796 A_fft[idx][0] = nr;
2797 A_fft[idx][1] = ni;
2798 break;
2799 }
2800 }
2801 }
2802 }
2803
2804 // Inverse FFT back to real row-major buffer
2805 fftw_execute(plan_output);
2806
2807 // Relock before cleanup
2808 fftw_lock.lock();
2809
2810 // Form output Array2D from A_rm and scale by 1/(h*w)
2811 Array2D C(H, W);
2812 const double scale = 1.0 / static_cast<double>(H * W);
2813 for (difference_type r = 0; r < H; ++r) {
2814 for (difference_type c = 0; c < W; ++c) {
2815 C(r, c) = A_rm[r*W + c] * scale;
2816 }
2817 }
2818
2819 // Free temp buffers
2820 fftw_free(A_rm);
2821 fftw_free(K_rm);
2822 fftw_free(A_fft);
2823 fftw_free(K_fft);
2824
2825 return C;
2826}
2827
2828// Additional arithmetic operations ------------------------------------------//
2829template <typename T, typename T_alloc>
2830template <typename T_output>
2831typename std::enable_if<std::is_floating_point<T>::value, T_output>::type Array2D<T,T_alloc>::this_dot(const Array2D &x) const {
2832 chk_samesize_op(x,"dot product");
2833
2834 value_type sum = value_type();
2835 for (difference_type p = 0; p < s; ++p) {
2836 sum += (*this)(p)*x(p);
2837 }
2838
2839 return sum;
2840}
2841
2842template <typename T, typename T_alloc>
2843template <typename T_output>
2844typename std::enable_if<std::is_floating_point<T>::value, T_output>::type Array2D<T,T_alloc>::this_normalize() {
2845 value_type norm = value_type();
2846 for (difference_type p = 0; p < s; ++p) {
2847 norm += std::pow((*this)(p),2.0);
2848 }
2849 norm = std::sqrt(norm);
2850
2851 return (*this) /= norm;
2852}
2853
2854template <typename T, typename T_alloc>
2855template <typename T_output>
2856typename std::enable_if<std::is_floating_point<T>::value, T_output>::type Array2D<T,T_alloc>::this_linsolve(const Array2D &b) const {
2857 // Use LU with partial pivoting for a square matrix, and QR with column
2858 // pivoting for rectangular matrices. This supports b with more than one
2859 // column; it solves one column at a time and stores a copy in x.
2860 auto linsolver = ((h == w) ? get_linsolver(LINSOLVER::LU) : get_linsolver(LINSOLVER::QR));
2861
2862 container x(w, b.width());
2863 for (difference_type p2 = 0; p2 < b.width(); ++p2) {
2864 x(all,p2) = linsolver.solve(b(all,p2));
2865 }
2866
2867 return x;
2868}
2869
2870// Utility Methods -----------------------------------------------------------//
2871template <typename T, typename T_alloc>
2872typename Array2D<T,T_alloc>::coords Array2D<T,T_alloc>::get_range(const r_convert_1D &r) const {
2873 // Get input inclusive range
2874 difference_type p1 = -1;
2875 difference_type p2 = -1;
2876 switch (r.range_type) {
2877 case r_convert::RANGE::SINGLE :
2878 // Programmer error
2879 throw std::invalid_argument("Attempted to use 'single' element range for 1D range");
2880 case r_convert::RANGE::LAST :
2881 // Programmer error
2882 throw std::invalid_argument("Attempted to use 'last' element range for 1D range");
2883 case r_convert::RANGE::COORDS :
2884 p1 = r.p1;
2885 p2 = r.p2;
2886 break;
2887 case r_convert::RANGE::LAST_COORDS :
2888 p1 = r.p1;
2889 p2 = s-1;
2890 break;
2891 case r_convert::RANGE::ALL :
2892 p1 = 0;
2893 p2 = s-1;
2894 break;
2895 }
2896
2897 // Test validity of coords and set them to "one past the end" range
2898 if (p2 < p1) {
2899 // Zero range - return {0,0} by default
2900 return {0,0};
2901 } else {
2902 // Positive range - test for validity
2903 if (p1 < 0 || p2 >= s) {
2904 throw std::invalid_argument("Attempted to perform 1D range type indexing using: ({" + std::to_string(p1) + "," + std::to_string(p2) +
2905 "}) which is beyond the size of the array: " + size_string());
2906 } else {
2907 // valid range
2908 return {p1,p2+1};
2909 }
2910 }
2911}
2912
2913template <typename T, typename T_alloc>
2914typename Array2D<T,T_alloc>::coords Array2D<T,T_alloc>::get_range(const r_convert_2D_1 &r) const {
2915 // Get input inclusive range
2916 difference_type p1 = -1;
2917 difference_type p2 = -1;
2918 switch (r.range_type) {
2919 case r_convert::RANGE::SINGLE :
2920 p1 = r.p1;
2921 p2 = r.p1;
2922 break;
2923 case r_convert::RANGE::LAST :
2924 p1 = h-1;
2925 p2 = h-1;
2926 break;
2927 case r_convert::RANGE::COORDS :
2928 p1 = r.p1;
2929 p2 = r.p2;
2930 break;
2931 case r_convert::RANGE::LAST_COORDS :
2932 p1 = r.p1;
2933 p2 = h-1;
2934 break;
2935 case r_convert::RANGE::ALL :
2936 p1 = 0;
2937 p2 = h-1;
2938 break;
2939 }
2940
2941 // Test validity of coords and set them to "one past the end" range
2942 if (p2 < p1) {
2943 // Zero range - return {0,0} by default
2944 return {0,0};
2945 } else {
2946 // Positive range - test for validity
2947 if (p1 < 0 || p2 >= h) {
2948 throw std::invalid_argument("Attempted to perform 2D range type indexing using: ({" + std::to_string(p1) + "," + std::to_string(p2) +
2949 "},) which is beyond the size of the Array: " + size_2D_string() + ".");
2950 } else {
2951 // valid range
2952 return {p1,p2+1};
2953 }
2954 }
2955}
2956
2957template <typename T, typename T_alloc>
2958typename Array2D<T,T_alloc>::coords Array2D<T,T_alloc>::get_range(const r_convert_2D_2 &r) const {
2959 // Get input inclusive range
2960 difference_type p1 = -1;
2961 difference_type p2 = -1;
2962 switch (r.range_type) {
2963 case r_convert::RANGE::SINGLE :
2964 p1 = r.p1;
2965 p2 = r.p1;
2966 break;
2967 case r_convert::RANGE::LAST :
2968 p1 = w-1;
2969 p2 = w-1;
2970 break;
2971 case r_convert::RANGE::COORDS :
2972 p1 = r.p1;
2973 p2 = r.p2;
2974 break;
2975 case r_convert::RANGE::LAST_COORDS :
2976 p1 = r.p1;
2977 p2 = w-1;
2978 break;
2979 case r_convert::RANGE::ALL :
2980 p1 = 0;
2981 p2 = w-1;
2982 break;
2983 }
2984
2985 // Test validity of coords and set them to "one past the end" range
2986 if (p2 < p1) {
2987 // Zero range - return {0,0} by default
2988 return {0,0};
2989 } else {
2990 // Positive range - test for validity
2991 if (p1 < 0 || p2 >= w) {
2992 throw std::invalid_argument("Attempted to perform 2D range type indexing using: (,{" + std::to_string(p1) + "," + std::to_string(p2) +
2993 "}) which is beyond the size of the Array: " + size_2D_string() + ".");
2994 } else {
2995 // valid range
2996 return {p1,p2+1};
2997 }
2998 }
2999}
3000
3001template <typename T, typename T_alloc>
3002typename Array2D<T,T_alloc>::pointer Array2D<T,T_alloc>::allocate(difference_type s_init) {
3003 pointer ptr_new;
3004 try {
3005 ptr_new = alloc.allocate(s_init);
3006 } catch (std::bad_alloc &e) {
3007 // Bad alloc doesn't have a what() message, so just add one to terminal
3008 NLOG_ERROR << "Error: failed to allocate memory for Array2D.";
3009 throw;
3010 }
3011
3012 return ptr_new;
3013}
3014
3015template <typename T, typename T_alloc>
3016typename Array2D<T,T_alloc>::pointer Array2D<T,T_alloc>::allocate_and_init(difference_type s_init, const_reference val) {
3017 pointer ptr_new = allocate(s_init);
3018 std::uninitialized_fill_n(ptr_new, s_init, val);
3019
3020 return ptr_new;
3021}
3022
3023template <typename T, typename T_alloc>
3024template <typename T_it>
3025typename Array2D<T,T_alloc>::pointer Array2D<T,T_alloc>::allocate_and_copy(difference_type s_init, T_it it) {
3026 pointer ptr_new = allocate(s_init);
3027 std::uninitialized_copy_n(it, s_init, ptr_new);
3028
3029 return ptr_new;
3030}
3031
3032template <typename T, typename T_alloc>
3033void Array2D<T,T_alloc>::destroy_and_deallocate() {
3034 // Unlike free, cannot pass a null pointer to allocator, so test for it.
3035 // Note that r-values, after they are copied, are nullified through "make_null()"
3036 // method, which sets ptr to nullptr.
3037 if (ptr) {
3038 // Must destroy objects first before deallocating memory
3039 for (pointer ptr_delete = ptr + s; ptr_delete != ptr; /* empty */) {
3040 alloc.destroy(--ptr_delete);
3041 }
3042 alloc.deallocate(ptr, s);
3043 }
3044}
3045
3046template <typename T, typename T_alloc>
3047void Array2D<T,T_alloc>::chk_size_op(difference_type h, difference_type w, const std::string &op) const {
3048 if (this->h != h || this->w != w) {
3049 throw std::invalid_argument("Attempted to use " + op + " operator on array of size " + size_2D_string() +
3050 ". Array must have size of (" + std::to_string(h) + "," + std::to_string(w) + ").");
3051 }
3052}
3053
3054template <typename T, typename T_alloc>
3055void Array2D<T,T_alloc>::chk_samesize_op(const Array2D &A, const std::string &op) const {
3056 if (!same_size(A)) {
3057 throw std::invalid_argument("Attempted to use " + op + " operator on array of size " + size_2D_string() +
3058 " with array of size " + A.size_2D_string() + ". Arrays must have the same size.");
3059 }
3060}
3061
3062template <typename T, typename T_alloc>
3063void Array2D<T,T_alloc>::chk_minsize_op(difference_type h, difference_type w, const std::string &op) const {
3064 if (this->h < h || this->w < w) {
3065 throw std::invalid_argument("Attempted to use " + op + " operator on array of size " + size_2D_string() +
3066 ". Array must be of size (" + std::to_string(h) + "," + std::to_string(w) + ") or greater.");
3067 }
3068}
3069
3070template <typename T, typename T_alloc>
3071void Array2D<T,T_alloc>::chk_column_op(const std::string &op) const {
3072 if (this->w != 1) {
3073 throw std::invalid_argument("Attempted to use " + op + " operator on array of size " + size_2D_string() +
3074 ". Array must be a column.");
3075 }
3076}
3077
3078template <typename T, typename T_alloc>
3079void Array2D<T,T_alloc>::chk_square_op(const std::string &op) const {
3080 if (this->h != this->w) {
3081 throw std::invalid_argument("Attempted to use " + op + " operator on array of size " + size_2D_string() +
3082 ". Array must be square.");
3083 }
3084}
3085
3086template <typename T, typename T_alloc>
3087void Array2D<T,T_alloc>::chk_in_bounds_op(difference_type p, const std::string &op) const {
3088 if (!in_bounds(p)) {
3089 throw std::invalid_argument("Attempted to use " + op + " with input of " + std::to_string(p) + " on array of size " +
3090 size_string() + ".");
3091 }
3092}
3093
3094template <typename T, typename T_alloc>
3095void Array2D<T,T_alloc>::chk_in_bounds_op(difference_type p1, difference_type p2, const std::string &op) const {
3096 if (!in_bounds(p1,p2)) {
3097 throw std::invalid_argument("Attempted to use " + op + " with input of (" + std::to_string(p1) + "," + std::to_string(p2) + ") on array of size " +
3098 size_2D_string() + ".");
3099 }
3100}
3101
3102template <typename T, typename T_alloc>
3103void Array2D<T,T_alloc>::chk_mult_size(const Array2D &A) const {
3104 if (this->w != A.h) {
3105 throw std::invalid_argument("Attempted to multiply matrix of size " + size_2D_string() + " with " + A.size_2D_string() +
3106 ". These sizes are incompatible for matrix multiplication.");
3107 }
3108}
3109
3110template <typename T, typename T_alloc>
3111void Array2D<T,T_alloc>::chk_kernel_size(const Array2D &kernel) const {
3112 // Kernel must have odd dimensions and be smaller than or equal to A
3113 if (!(kernel.h % 2) || !(kernel.w % 2) || kernel.w > this->w || kernel.h > this->h) {
3114 throw std::invalid_argument("Attempted to convolve matrix of size " + size_2D_string() + " with kernel of size " + kernel.size_2D_string() +
3115 ". Kernel must have odd dimensions and be equal to or smaller than matrix.");
3116 }
3117}
3118
3119namespace details {
3120 // Base Iterator ---------------------------------------------------------//
3121 template <typename T_container>
3123 chk_in_range();
3124
3125 return (*A_ptr)(p);
3126 }
3127
3128 template <typename T_container>
3130 if (p >= A_ptr->size()) {
3131 throw std::invalid_argument("Attempted to increment Array2D iterator beyond last element.");
3132 }
3133 }
3134
3135 template <typename T_container>
3137 if (p <= 0) {
3138 throw std::invalid_argument("Attempted to decrement Array2D iterator beyond first element.");
3139 }
3140 }
3141
3142 template <typename T_container>
3144 if (!A_ptr->in_bounds(p)) {
3145 throw std::invalid_argument("Attempted to dereference Array2D iterator out of range.");
3146 }
3147 }
3148
3149 // Simple Iterator -------------------------------------------------------//
3150 template <typename T_container>
3152 this->chk_valid_increment();
3153
3154 ++this->p;
3155
3156 return *this;
3157 }
3158
3159 template <typename T_container>
3161 this->chk_valid_decrement();
3162
3163 --this->p;
3164
3165 return *this;
3166 }
3167
3168 // Sub Iterator ----------------------------------------------------------//
3169 template <typename T_container>
3170 sub_iterator<T_container>::sub_iterator(container &A, const coords &p_2D, const coords &r_sub1_2D, const coords &r_sub2_2D) :
3171 base_iterator<container>(A,A.sub2ind(p_2D.first,p_2D.second)),
3172 r_sub1_2D(r_sub1_2D),
3173 r_sub2_2D(r_sub2_2D),
3174 sub_p(p_2D.first-r_sub1_2D.first + (p_2D.second-r_sub2_2D.first)*(r_sub1_2D.second-r_sub1_2D.first)),
3175 sub_h(r_sub1_2D.second-r_sub1_2D.first),
3176 sub_w(r_sub2_2D.second-r_sub2_2D.first),
3177 sub_s((r_sub1_2D.second-r_sub1_2D.first) * (r_sub2_2D.second-r_sub2_2D.first)) {
3178 // Input ranges must be valid (check the criterion in the function))
3179 chk_valid_ranges();
3180 }
3181
3182 template <typename T_container>
3184 this->chk_valid_increment();
3185
3186 // increment sub_p, then determine position from it
3187 ++sub_p;
3188 this->p = this->A_ptr->sub2ind(sub_p % sub_h + r_sub1_2D.first, sub_p / sub_h + r_sub2_2D.first);
3189
3190 return *this;
3191 }
3192
3193 template <typename T_container>
3195 this->chk_valid_decrement();
3196
3197 // decrement sub_p, then determine position from it
3198 --sub_p;
3199 this->p = this->A_ptr->sub2ind(sub_p % sub_h + r_sub1_2D.first, sub_p / sub_h + r_sub2_2D.first);
3200
3201 return *this;
3202 }
3203
3204 template <typename T_container>
3206 if (r_sub1_2D.first > r_sub1_2D.second || r_sub1_2D.first < 0 || r_sub1_2D.second > this->A_ptr->height() ||
3207 r_sub2_2D.first > r_sub2_2D.second || r_sub2_2D.first < 0 || r_sub2_2D.second > this->A_ptr->width()) {
3208 throw std::invalid_argument("Range of ({" + std::to_string(r_sub1_2D.first) + "," + std::to_string(r_sub1_2D.second-1) + "},{" +
3209 std::to_string(r_sub2_2D.first) + "," + std::to_string(r_sub2_2D.second-1) + "}) is not valid for sub iterator with size of: " +
3210 this->A_ptr->size_2D_string() + ".");
3211 }
3212 }
3213
3214 // Bool Iterator ---------------------------------------------------------//
3215 template <typename T_container>
3217 base_iterator<container>(A,p), A_bool_ptr(A_bool_ptr) {
3218 chk_same_size();
3219 // If the initial position is (0,0), check to see if it is true; if not,
3220 // iterate until the first true position is found. This is done for
3221 // convenience so the begin() iterator can be set with a position of 0
3222 // by the caller.
3223 if (this->p == 0 && !this->A_ptr->empty() && !(*this->A_bool_ptr)(0)) {
3224 ++(*this);
3225 }
3226 }
3227
3228 template <typename T_container>
3230 this->chk_valid_increment();
3231
3232 // increment p until true value is found
3233 while (++this->p < this->A_ptr->size()) {
3234 if ((*A_bool_ptr)(this->p)) {
3235 return *this;
3236 }
3237 }
3238 return *this;
3239 }
3240
3241 template <typename T_container>
3243 this->chk_valid_decrement();
3244
3245 // decrement p until true value is found
3246 while (this->p > 0) {
3247 if ((*A_bool_ptr)(--this->p)) {
3248 return *this;
3249 }
3250 }
3251
3252 return *this;
3253 }
3254
3255 template <typename T_container>
3257 if (!this->A_ptr->same_size(*A_bool_ptr)) {
3258 throw std::invalid_argument("Attempted to use boolean Array of size: " + A_bool_ptr->size_2D_string() +
3259 " to form iterator for Array2D of size: " + this->A_ptr->size_2D_string() + ".");
3260 }
3261 }
3262
3263 // Base Region -----------------------------------------------------------//
3264 template <typename T_container>
3266 if (this->region_h != reg.region_h || this->region_w != reg.region_w) {
3267 throw std::invalid_argument("Attempted to assign region of size: " + reg.region_size_2D_string() +
3268 " to region of size: " + region_size_2D_string() + ".");
3269 }
3270
3271 std::copy(reg.begin(), reg.end(), this->begin());
3272
3273 return *this;
3274 }
3275
3276 template <typename T_container>
3277 template <typename T_container2>
3278 typename std::enable_if<std::is_same<typename container_traits<T_container2>::nonconst_container, typename base_region<T_container>::nonconst_container>::value, base_region<T_container>&>::type base_region<T_container>::operator=(const base_region<T_container2> &reg) {
3279 if (this->region_h != reg.region_h || this->region_w != reg.region_w) {
3280 throw std::invalid_argument("Attempted to assign region of size: " + reg.region_size_2D_string() +
3281 " to region of size: " + region_size_2D_string() + ".");
3282 }
3283
3284 std::copy(reg.begin(), reg.end(), this->begin());
3285
3286 return *this;
3287 }
3288
3289 template <typename T_container>
3291 if (this->region_h != A.height() || this->region_w != A.width()) {
3292 throw std::invalid_argument("Attempted to assign Array2D of size: " + A.size_2D_string() +
3293 " to region of size: " + region_size_2D_string() + ".");
3294 }
3295
3296 std::copy(A.begin(), A.end(), this->begin());
3297
3298 return *this;
3299 }
3300
3301 template <typename T_container>
3303 std::fill(this->begin(), this->end(), val);
3304
3305 return *this;
3306 }
3307
3308 // Simple Region ---------------------------------------------------------//
3309 template <typename T_container>
3311 // Input ranges must be valid (check the criterion in the function))
3312 chk_valid_range();
3313 }
3314
3315 template <typename T_container>
3317 if (r.first > r.second || r.first < 0 || r.second > this->A_ptr->size()) {
3318 throw std::invalid_argument("Range of: ({" + std::to_string(r.first) + "," + std::to_string(r.second-1) +
3319 "}) is not valid for region with max size of: " + this->A_ptr->size_string() + ".");
3320 }
3321 }
3322
3323 // Sub Region ------------------------------------------------------------//
3324 template <typename T_container>
3325 sub_region<T_container>::sub_region(container &A, const coords &r_sub1_2D, const coords &r_sub2_2D) :
3326 base_region<container>(A,r_sub1_2D.second-r_sub1_2D.first,r_sub2_2D.second-r_sub2_2D.first),
3327 r_sub1_2D(r_sub1_2D),
3328 r_sub2_2D(r_sub2_2D),
3329 sub_h(r_sub1_2D.second-r_sub1_2D.first),
3330 sub_w(r_sub2_2D.second-r_sub2_2D.first),
3331 sub_s((r_sub1_2D.second-r_sub1_2D.first) * (r_sub2_2D.second-r_sub2_2D.first)) {
3332 // Input ranges must be valid (check the criterion in the function))
3333 chk_valid_ranges();
3334 }
3335
3336 template <typename T_container>
3338 if (r_sub1_2D.first > r_sub1_2D.second || r_sub1_2D.first < 0 || r_sub1_2D.second > this->A_ptr->height() ||
3339 r_sub2_2D.first > r_sub2_2D.second || r_sub2_2D.first < 0 || r_sub2_2D.second > this->A_ptr->width()) {
3340 throw std::invalid_argument("Range of ({" + std::to_string(r_sub1_2D.first) + "," + std::to_string(r_sub1_2D.second-1) + "},{" +
3341 std::to_string(r_sub2_2D.first) + "," + std::to_string(r_sub2_2D.second-1) + "}) is not valid for sub region with max size of: " +
3342 this->A_ptr->size_2D_string() + ".");
3343 }
3344 }
3345
3346 // Bool Region -----------------------------------------------------------//
3347 template <typename T_container>
3349 base_region<container>(A,sum(convert(A_bool,difference_type())),1), A_bool_ptr(std::make_shared<bool_container>(std::move(A_bool))) {
3350 chk_same_size();
3351 }
3352
3353 template <typename T_container>
3355 if (!this->A_ptr->same_size(*A_bool_ptr)) {
3356 throw std::invalid_argument("Attempted to use boolean Array of size: " + A_bool_ptr->size_2D_string() +
3357 " to index Array2D of size: " + this->A_ptr->size_2D_string() + ".");
3358 }
3359 }
3360
3361 // Nearest Interpolator --------------------------------------------------//
3362 template <typename T_container>
3364 if (out_of_bounds(p1, p2)) {
3365 return std::numeric_limits<value_type>::quiet_NaN();
3366 }
3367
3368 return (*this->A_ptr)(std::round(p1),std::round(p2));
3369 }
3370
3371 template <typename T_container>
3373 if (out_of_bounds(p1, p2)) {
3374 this->first_order_buf(0) = this->first_order_buf(1) = this->first_order_buf(2) = std::numeric_limits<value_type>::quiet_NaN();
3375 return this->first_order_buf;
3376 }
3377
3378 this->first_order_buf(0) = (*this->A_ptr)(std::round(p1),std::round(p2));
3379 this->first_order_buf(1) = this->first_order_buf(2) = 0; // Gradients are zero
3380
3381 return this->first_order_buf;
3382 }
3383
3384 // Bilinear Interpolator -------------------------------------------------//
3385 template <typename T_container>
3387 if (out_of_bounds(p1,p2)) {
3388 return std::numeric_limits<value_type>::quiet_NaN();
3389 }
3390
3391 double delta_p1 = p1 - std::floor(p1);
3392 double delta_p2 = p2 - std::floor(p2);
3393
3394 return (*this->A_ptr)(p1,p2) * (1-delta_p1) * (1-delta_p2) +
3395 (*this->A_ptr)(p1+1,p2) * delta_p1 * (1-delta_p2) +
3396 (*this->A_ptr)(p1,p2+1) * (1-delta_p1) * delta_p2 +
3397 (*this->A_ptr)(p1+1,p2+1) * delta_p1 * delta_p2;
3398 }
3399
3400 template <typename T_container>
3402 if (out_of_bounds(p1,p2)) {
3403 this->first_order_buf(0) = this->first_order_buf(1) = this->first_order_buf(2) = std::numeric_limits<value_type>::quiet_NaN();
3404 return this->first_order_buf;
3405 }
3406
3407 double delta_p1 = p1 - std::floor(p1);
3408 double delta_p2 = p2 - std::floor(p2);
3409
3410 this->first_order_buf(0) = (*this->A_ptr)(p1,p2) * (1-delta_p1) * (1-delta_p2) +
3411 (*this->A_ptr)(p1+1,p2) * delta_p1 * (1-delta_p2) +
3412 (*this->A_ptr)(p1,p2+1) * (1-delta_p1) * delta_p2 +
3413 (*this->A_ptr)(p1+1,p2+1) * delta_p1 * delta_p2;
3414
3415 this->first_order_buf(1) = (*this->A_ptr)(p1,p2) * (-1) * (1-delta_p2) +
3416 (*this->A_ptr)(p1+1,p2) * 1 * (1-delta_p2) +
3417 (*this->A_ptr)(p1,p2+1) * (-1) * delta_p2 +
3418 (*this->A_ptr)(p1+1,p2+1) * 1 * delta_p2;
3419
3420 this->first_order_buf(2) = (*this->A_ptr)(p1,p2) * (1-delta_p1) * (-1) +
3421 (*this->A_ptr)(p1+1,p2) * delta_p1 * (-1) +
3422 (*this->A_ptr)(p1,p2+1) * (1-delta_p1) * 1 +
3423 (*this->A_ptr)(p1+1,p2+1) * delta_p1 * 1;
3424
3425 return this->first_order_buf;
3426 }
3427
3428 // Coefficient Matrix Interpolator ---------------------------------------//
3429 template <typename T_container>
3430 inline typename coef_mat_interp_base<T_container>::value_type coef_mat_interp_base<T_container>::operator()(double p1, double p2) const {
3431 // This is the general interpolation scheme for interpolators that use
3432 // a coefficient matrix. Can be overridden in child classes to increase
3433 // speed.
3434 if (this->out_of_bounds(p1,p2)) {
3435 return std::numeric_limits<value_type>::quiet_NaN();
3436 }
3437
3438 // Get powers of delta_p1
3439 p1_pow_buf = get_p_pow(p1_pow_buf, p1 - std::floor(p1));
3440
3441 // Get powers of delta_p2
3442 p2_pow_buf = get_p_pow(p2_pow_buf, p2 - std::floor(p2));
3443
3444 // Get coefficient matrix
3445 const auto &coef_mat = this->get_coef_mat(p1, p2);
3446
3447 // Interpolate value
3448 return t_vec_mat_vec(p1_pow_buf, coef_mat, p2_pow_buf);
3449 }
3450
3451 template <typename T_container>
3452 inline typename coef_mat_interp_base<T_container>::const_container& coef_mat_interp_base<T_container>::first_order(double p1, double p2) const {
3453 // This is the general first-order interpolation scheme for interpolators
3454 // that use a coefficient matrix. Can be overridden in child classes to
3455 // increase speed.
3456 if (this->out_of_bounds(p1,p2)) {
3457 this->first_order_buf(0) = this->first_order_buf(1) = this->first_order_buf(2) = std::numeric_limits<value_type>::quiet_NaN();
3458 return this->first_order_buf;
3459 }
3460
3461 // Get powers of delta_p1
3462 p1_pow_buf = get_p_pow(p1_pow_buf, p1 - std::floor(p1));
3463
3464 // Get derivatives of p1
3465 p1_pow_dp1_buf = get_dp_pow(p1_pow_dp1_buf, p1_pow_buf);
3466
3467 // Get powers of delta_p2
3468 p2_pow_buf = get_p_pow(p2_pow_buf, p2 - std::floor(p2));
3469
3470 // Get derivatives of p2
3471 p2_pow_dp2_buf = get_dp_pow(p2_pow_dp2_buf, p2_pow_buf);
3472
3473 // Get coefficient matrix
3474 const auto &coef_mat = this->get_coef_mat(p1, p2);
3475
3476 // Interpolate values
3477 this->first_order_buf(0) = t_vec_mat_vec(p1_pow_buf, coef_mat, p2_pow_buf);
3478 this->first_order_buf(1) = t_vec_mat_vec(p1_pow_dp1_buf, coef_mat, p2_pow_buf);
3479 this->first_order_buf(2) = t_vec_mat_vec(p1_pow_buf, coef_mat, p2_pow_dp2_buf);
3480
3481 return this->first_order_buf;
3482 }
3483
3484 template <typename T_container>
3485 inline typename coef_mat_interp_base<T_container>::container& coef_mat_interp_base<T_container>::get_p_pow(container &p_pow, double delta_p) const {
3486 // Order must be 1 or greater - note this is already checked for in the
3487 // base interpolator's constructor.
3488 p_pow(0) = 1.0;
3489 p_pow(1) = delta_p;
3490 for (difference_type i = 2; i <= this->order; ++i) {
3491 p_pow(i) = p_pow(i-1) * delta_p;
3492 }
3493
3494 return p_pow;
3495 }
3496
3497 template <typename T_container>
3498 inline typename coef_mat_interp_base<T_container>::container& coef_mat_interp_base<T_container>::get_dp_pow(container &p_pow_dp, const_container &p_pow) const {
3499 // Order must be 1 or greater - note this is already checked for in the
3500 // base interpolator's constructor.
3501 p_pow_dp(0) = 0.0;
3502 p_pow_dp(1) = 1.0;
3503 for (difference_type i = 2; i <= this->order; ++i) {
3504 p_pow_dp(i) = p_pow(i-1) * i;
3505 }
3506
3507 return p_pow_dp;
3508 }
3509
3510 template <typename T_container>
3511 inline typename coef_mat_interp_base<T_container>::value_type coef_mat_interp_base<T_container>::t_vec_mat_vec(const_container &vec1, const_container &mat, const_container &vec2) const {
3512 return value_type( t( vec1 ) * mat * vec2 );
3513 }
3514
3515 // Bicubic Interpolator --------------------------------------------------//
3516 template <typename T_container>
3517 inline typename cubic_interp_base<T_container>::value_type cubic_interp_base<T_container>::operator()(double p1, double p2) const {
3518 if (out_of_bounds(p1,p2)) {
3519 return std::numeric_limits<value_type>::quiet_NaN();
3520 }
3521
3522 double delta_p1 = p1 - std::floor(p1);
3523 double delta_p2 = p2 - std::floor(p2);
3524
3525 this->p1_pow_buf(0) = 1.0;
3526 this->p1_pow_buf(1) = delta_p1;
3527 this->p1_pow_buf(2) = this->p1_pow_buf(1)*delta_p1;
3528 this->p1_pow_buf(3) = this->p1_pow_buf(2)*delta_p1;
3529
3530 this->p2_pow_buf(0) = 1.0;
3531 this->p2_pow_buf(1) = delta_p2;
3532 this->p2_pow_buf(2) = this->p2_pow_buf(1)*delta_p2;
3533 this->p2_pow_buf(3) = this->p2_pow_buf(2)*delta_p2;
3534
3535 const auto &coef_mat = this->get_coef_mat(p1, p2);
3536
3537 return (this->p2_pow_buf(0)*coef_mat(0,0)+this->p2_pow_buf(1)*coef_mat(0,1)+this->p2_pow_buf(2)*coef_mat(0,2)+this->p2_pow_buf(3)*coef_mat(0,3))*this->p1_pow_buf(0)+
3538 (this->p2_pow_buf(0)*coef_mat(1,0)+this->p2_pow_buf(1)*coef_mat(1,1)+this->p2_pow_buf(2)*coef_mat(1,2)+this->p2_pow_buf(3)*coef_mat(1,3))*this->p1_pow_buf(1)+
3539 (this->p2_pow_buf(0)*coef_mat(2,0)+this->p2_pow_buf(1)*coef_mat(2,1)+this->p2_pow_buf(2)*coef_mat(2,2)+this->p2_pow_buf(3)*coef_mat(2,3))*this->p1_pow_buf(2)+
3540 (this->p2_pow_buf(0)*coef_mat(3,0)+this->p2_pow_buf(1)*coef_mat(3,1)+this->p2_pow_buf(2)*coef_mat(3,2)+this->p2_pow_buf(3)*coef_mat(3,3))*this->p1_pow_buf(3);
3541 }
3542
3543 template <typename T_container>
3544 inline typename cubic_interp_base<T_container>::const_container& cubic_interp_base<T_container>::first_order(double p1, double p2) const {
3545 if (out_of_bounds(p1,p2)) {
3546 this->first_order_buf(0) = this->first_order_buf(1) = this->first_order_buf(2) = std::numeric_limits<value_type>::quiet_NaN();
3547 return this->first_order_buf;
3548 }
3549
3550 double delta_p1 = p1 - std::floor(p1);
3551 double delta_p2 = p2 - std::floor(p2);
3552
3553 this->p1_pow_buf(0) = 1.0;
3554 this->p1_pow_buf(1) = delta_p1;
3555 this->p1_pow_buf(2) = this->p1_pow_buf(1) * delta_p1;
3556 this->p1_pow_buf(3) = this->p1_pow_buf(2) * delta_p1;
3557
3558 this->p1_pow_dp1_buf(0) = 0.0;
3559 this->p1_pow_dp1_buf(1) = 1.0;
3560 this->p1_pow_dp1_buf(2) = 2.0 * this->p1_pow_buf(1);
3561 this->p1_pow_dp1_buf(3) = 3.0 * this->p1_pow_buf(2);
3562
3563 this->p2_pow_buf(0) = 1.0;
3564 this->p2_pow_buf(1) = delta_p2;
3565 this->p2_pow_buf(2) = this->p2_pow_buf(1) * delta_p2;
3566 this->p2_pow_buf(3) = this->p2_pow_buf(2) * delta_p2;
3567
3568 this->p2_pow_dp2_buf(0) = 0.0;
3569 this->p2_pow_dp2_buf(1) = 1.0;
3570 this->p2_pow_dp2_buf(2) = 2.0 * this->p2_pow_buf(1);
3571 this->p2_pow_dp2_buf(3) = 3.0 * this->p2_pow_buf(2);
3572
3573 const auto &coef_mat = this->get_coef_mat(p1, p2);
3574
3575 this->first_order_buf(0) = (this->p2_pow_buf(0)*coef_mat(0,0)+this->p2_pow_buf(1)*coef_mat(0,1)+this->p2_pow_buf(2)*coef_mat(0,2)+this->p2_pow_buf(3)*coef_mat(0,3))*this->p1_pow_buf(0)+
3576 (this->p2_pow_buf(0)*coef_mat(1,0)+this->p2_pow_buf(1)*coef_mat(1,1)+this->p2_pow_buf(2)*coef_mat(1,2)+this->p2_pow_buf(3)*coef_mat(1,3))*this->p1_pow_buf(1)+
3577 (this->p2_pow_buf(0)*coef_mat(2,0)+this->p2_pow_buf(1)*coef_mat(2,1)+this->p2_pow_buf(2)*coef_mat(2,2)+this->p2_pow_buf(3)*coef_mat(2,3))*this->p1_pow_buf(2)+
3578 (this->p2_pow_buf(0)*coef_mat(3,0)+this->p2_pow_buf(1)*coef_mat(3,1)+this->p2_pow_buf(2)*coef_mat(3,2)+this->p2_pow_buf(3)*coef_mat(3,3))*this->p1_pow_buf(3);
3579
3580 this->first_order_buf(1) = (this->p2_pow_buf(0)*coef_mat(0,0)+this->p2_pow_buf(1)*coef_mat(0,1)+this->p2_pow_buf(2)*coef_mat(0,2)+this->p2_pow_buf(3)*coef_mat(0,3))*this->p1_pow_dp1_buf(0)+
3581 (this->p2_pow_buf(0)*coef_mat(1,0)+this->p2_pow_buf(1)*coef_mat(1,1)+this->p2_pow_buf(2)*coef_mat(1,2)+this->p2_pow_buf(3)*coef_mat(1,3))*this->p1_pow_dp1_buf(1)+
3582 (this->p2_pow_buf(0)*coef_mat(2,0)+this->p2_pow_buf(1)*coef_mat(2,1)+this->p2_pow_buf(2)*coef_mat(2,2)+this->p2_pow_buf(3)*coef_mat(2,3))*this->p1_pow_dp1_buf(2)+
3583 (this->p2_pow_buf(0)*coef_mat(3,0)+this->p2_pow_buf(1)*coef_mat(3,1)+this->p2_pow_buf(2)*coef_mat(3,2)+this->p2_pow_buf(3)*coef_mat(3,3))*this->p1_pow_dp1_buf(3);
3584
3585 this->first_order_buf(2) = (this->p2_pow_dp2_buf(0)*coef_mat(0,0)+this->p2_pow_dp2_buf(1)*coef_mat(0,1)+this->p2_pow_dp2_buf(2)*coef_mat(0,2)+this->p2_pow_dp2_buf(3)*coef_mat(0,3))*this->p1_pow_buf(0)+
3586 (this->p2_pow_dp2_buf(0)*coef_mat(1,0)+this->p2_pow_dp2_buf(1)*coef_mat(1,1)+this->p2_pow_dp2_buf(2)*coef_mat(1,2)+this->p2_pow_dp2_buf(3)*coef_mat(1,3))*this->p1_pow_buf(1)+
3587 (this->p2_pow_dp2_buf(0)*coef_mat(2,0)+this->p2_pow_dp2_buf(1)*coef_mat(2,1)+this->p2_pow_dp2_buf(2)*coef_mat(2,2)+this->p2_pow_dp2_buf(3)*coef_mat(2,3))*this->p1_pow_buf(2)+
3588 (this->p2_pow_dp2_buf(0)*coef_mat(3,0)+this->p2_pow_dp2_buf(1)*coef_mat(3,1)+this->p2_pow_dp2_buf(2)*coef_mat(3,2)+this->p2_pow_dp2_buf(3)*coef_mat(3,3))*this->p1_pow_buf(3);
3589
3590 return this->first_order_buf;
3591 }
3592
3593 template <typename T_container>
3594 inline typename cubic_interp_base<T_container>::const_container& cubic_interp_base<T_container>::calc_coef_mat(container &coef_mat_buf, const_container &A, difference_type p1, difference_type p2) const {
3595 // p1 and p2 refer to the top-left corner of the desired coefficient matrix
3596 #ifndef NDEBUG
3597 if (p1 < 0 || p1 + 3 >= A.height() || p2 < 0 || p2 + 3 >= A.width()) {
3598 throw std::invalid_argument("p1 and p2 are outside range of array for calc_coef_mat() with cubic interpolation - this is a programmer error.");
3599 }
3600 #endif
3601
3602 coef_mat_buf(0,0) = 1.0*A(p1+1,p2+1);
3603 coef_mat_buf(1,0) = 0.5*A(p1+2,p2+1)-0.5*A(p1,p2+1);
3604 coef_mat_buf(2,0) = 1.0*A(p1,p2+1)-2.5*A(p1+1,p2+1)+2.0*A(p1+2,p2+1)-0.5*A(p1+3,p2+1);
3605 coef_mat_buf(3,0) = 1.5*A(p1+1,p2+1)-0.5*A(p1,p2+1)-1.5*A(p1+2,p2+1)+0.5*A(p1+3,p2+1);
3606 coef_mat_buf(0,1) = 0.5*A(p1+1,p2+2)-0.5*A(p1+1,p2);
3607 coef_mat_buf(1,1) = 0.25*A(p1,p2)-0.25*A(p1,p2+2)-0.25*A(p1+2,p2)+0.25*A(p1+2,p2+2);
3608 coef_mat_buf(2,1) = 0.5*A(p1,p2+2)-0.5*A(p1,p2)+1.25*A(p1+1,p2)-1.25*A(p1+1,p2+2)-1.0*A(p1+2,p2)+1.0*A(p1+2,p2+2)+0.25*A(p1+3,p2)-0.25*A(p1+3,p2+2);
3609 coef_mat_buf(3,1) = 0.25*A(p1,p2)-0.25*A(p1,p2+2)-0.75*A(p1+1,p2)+0.75*A(p1+1,p2+2)+0.75*A(p1+2,p2)-0.75*A(p1+2,p2+2)-0.25*A(p1+3,p2)+0.25*A(p1+3,p2+2);
3610 coef_mat_buf(0,2) = 1.0*A(p1+1,p2)-2.5*A(p1+1,p2+1)+2.0*A(p1+1,p2+2)-0.5*A(p1+1,p2+3);
3611 coef_mat_buf(1,2) = 1.25*A(p1,p2+1)-0.5*A(p1,p2)-1.0*A(p1,p2+2)+0.25*A(p1,p2+3)+0.5*A(p1+2,p2)-1.25*A(p1+2,p2+1)+1.0*A(p1+2,p2+2)-0.25*A(p1+2,p2+3);
3612 coef_mat_buf(2,2) = 1.0*A(p1,p2)-2.5*A(p1,p2+1)+2.0*A(p1,p2+2)-0.5*A(p1,p2+3)-2.5*A(p1+1,p2)+6.25*A(p1+1,p2+1)-5.0*A(p1+1,p2+2)+1.25*A(p1+1,p2+3)+2.0*A(p1+2,p2)-5.0*A(p1+2,p2+1)+4.0*A(p1+2,p2+2)-1.0*A(p1+2,p2+3)-0.5*A(p1+3,p2)+1.25*A(p1+3,p2+1)-1.0*A(p1+3,p2+2)+0.25*A(p1+3,p2+3);
3613 coef_mat_buf(3,2) = 1.25*A(p1,p2+1)-0.5*A(p1,p2)-1.0*A(p1,p2+2)+0.25*A(p1,p2+3)+1.5*A(p1+1,p2)-3.75*A(p1+1,p2+1)+3.0*A(p1+1,p2+2)-0.75*A(p1+1,p2+3)-1.5*A(p1+2,p2)+3.75*A(p1+2,p2+1)-3.0*A(p1+2,p2+2)+0.75*A(p1+2,p2+3)+0.5*A(p1+3,p2)-1.25*A(p1+3,p2+1)+1.0*A(p1+3,p2+2)-0.25*A(p1+3,p2+3);
3614 coef_mat_buf(0,3) = 1.5*A(p1+1,p2+1)-0.5*A(p1+1,p2)-1.5*A(p1+1,p2+2)+0.5*A(p1+1,p2+3);
3615 coef_mat_buf(1,3) = 0.25*A(p1,p2)-0.75*A(p1,p2+1)+0.75*A(p1,p2+2)-0.25*A(p1,p2+3)-0.25*A(p1+2,p2)+0.75*A(p1+2,p2+1)-0.75*A(p1+2,p2+2)+0.25*A(p1+2,p2+3);
3616 coef_mat_buf(2,3) = 1.5*A(p1,p2+1)-0.5*A(p1,p2)-1.5*A(p1,p2+2)+0.5*A(p1,p2+3)+1.25*A(p1+1,p2)-3.75*A(p1+1,p2+1)+3.75*A(p1+1,p2+2)-1.25*A(p1+1,p2+3)-1.0*A(p1+2,p2)+3.0*A(p1+2,p2+1)-3.0*A(p1+2,p2+2)+1.0*A(p1+2,p2+3)+0.25*A(p1+3,p2)-0.75*A(p1+3,p2+1)+0.75*A(p1+3,p2+2)-0.25*A(p1+3,p2+3);
3617 coef_mat_buf(3,3) = 0.25*A(p1,p2)-0.75*A(p1,p2+1)+0.75*A(p1,p2+2)-0.25*A(p1,p2+3)-0.75*A(p1+1,p2)+2.25*A(p1+1,p2+1)-2.25*A(p1+1,p2+2)+0.75*A(p1+1,p2+3)+0.75*A(p1+2,p2)-2.25*A(p1+2,p2+1)+2.25*A(p1+2,p2+2)-0.75*A(p1+2,p2+3)-0.25*A(p1+3,p2)+0.75*A(p1+3,p2+1)-0.75*A(p1+3,p2+2)+0.25*A(p1+3,p2+3);
3618
3619 return coef_mat_buf;
3620 }
3621
3622 // Precomputed Bicubic Interpolator --------------------------------------//
3623 template <typename T_container>
3625 // pre-allocate memory for entire coefficient array - note that this will
3626 // be a lot of memory - 16 times the size of the original array.
3627 coef_mat_precompute_ptr = std::make_shared<Array2D<container>>(this->A_ptr->height(), this->A_ptr->width(), container(4,4));
3628
3629 for (difference_type p2 = 1; p2 < this->A_ptr->width() - 2; ++p2) {
3630 for (difference_type p1 = 1; p1 < this->A_ptr->height() - 2; ++p1) {
3631 this->calc_coef_mat((*coef_mat_precompute_ptr)(p1,p2), *this->A_ptr, p1 - 1, p2 - 1);
3632 }
3633 }
3634 }
3635
3636 // Biquintic B-spline base class -----------------------------------------//
3637 template <typename T_container>
3638 inline typename quintic_interp_base<T_container>::value_type quintic_interp_base<T_container>::operator()(double p1, double p2) const {
3639 if (out_of_bounds(p1,p2)) {
3640 return std::numeric_limits<value_type>::quiet_NaN();
3641 }
3642
3643 double delta_p1 = p1 - std::floor(p1);
3644 double delta_p2 = p2 - std::floor(p2);
3645
3646 this->p1_pow_buf(0) = 1.0;
3647 this->p1_pow_buf(1) = delta_p1;
3648 this->p1_pow_buf(2) = this->p1_pow_buf(1)*delta_p1;
3649 this->p1_pow_buf(3) = this->p1_pow_buf(2)*delta_p1;
3650 this->p1_pow_buf(4) = this->p1_pow_buf(3)*delta_p1;
3651 this->p1_pow_buf(5) = this->p1_pow_buf(4)*delta_p1;
3652
3653 this->p2_pow_buf(0) = 1.0;
3654 this->p2_pow_buf(1) = delta_p2;
3655 this->p2_pow_buf(2) = this->p2_pow_buf(1)*delta_p2;
3656 this->p2_pow_buf(3) = this->p2_pow_buf(2)*delta_p2;
3657 this->p2_pow_buf(4) = this->p2_pow_buf(3)*delta_p2;
3658 this->p2_pow_buf(5) = this->p2_pow_buf(4)*delta_p2;
3659
3660 const auto &coef_mat = this->get_coef_mat(p1, p2);
3661
3662 return (this->p2_pow_buf(0)*coef_mat(0,0)+this->p2_pow_buf(1)*coef_mat(0,1)+this->p2_pow_buf(2)*coef_mat(0,2)+this->p2_pow_buf(3)*coef_mat(0,3)+this->p2_pow_buf(4)*coef_mat(0,4)+this->p2_pow_buf(5)*coef_mat(0,5))*this->p1_pow_buf(0)+
3663 (this->p2_pow_buf(0)*coef_mat(1,0)+this->p2_pow_buf(1)*coef_mat(1,1)+this->p2_pow_buf(2)*coef_mat(1,2)+this->p2_pow_buf(3)*coef_mat(1,3)+this->p2_pow_buf(4)*coef_mat(1,4)+this->p2_pow_buf(5)*coef_mat(1,5))*this->p1_pow_buf(1)+
3664 (this->p2_pow_buf(0)*coef_mat(2,0)+this->p2_pow_buf(1)*coef_mat(2,1)+this->p2_pow_buf(2)*coef_mat(2,2)+this->p2_pow_buf(3)*coef_mat(2,3)+this->p2_pow_buf(4)*coef_mat(2,4)+this->p2_pow_buf(5)*coef_mat(2,5))*this->p1_pow_buf(2)+
3665 (this->p2_pow_buf(0)*coef_mat(3,0)+this->p2_pow_buf(1)*coef_mat(3,1)+this->p2_pow_buf(2)*coef_mat(3,2)+this->p2_pow_buf(3)*coef_mat(3,3)+this->p2_pow_buf(4)*coef_mat(3,4)+this->p2_pow_buf(5)*coef_mat(3,5))*this->p1_pow_buf(3)+
3666 (this->p2_pow_buf(0)*coef_mat(4,0)+this->p2_pow_buf(1)*coef_mat(4,1)+this->p2_pow_buf(2)*coef_mat(4,2)+this->p2_pow_buf(3)*coef_mat(4,3)+this->p2_pow_buf(4)*coef_mat(4,4)+this->p2_pow_buf(5)*coef_mat(4,5))*this->p1_pow_buf(4)+
3667 (this->p2_pow_buf(0)*coef_mat(5,0)+this->p2_pow_buf(1)*coef_mat(5,1)+this->p2_pow_buf(2)*coef_mat(5,2)+this->p2_pow_buf(3)*coef_mat(5,3)+this->p2_pow_buf(4)*coef_mat(5,4)+this->p2_pow_buf(5)*coef_mat(5,5))*this->p1_pow_buf(5);
3668 }
3669
3670 template <typename T_container>
3671 inline typename quintic_interp_base<T_container>::const_container& quintic_interp_base<T_container>::first_order(double p1, double p2) const {
3672 if (out_of_bounds(p1,p2)) {
3673 this->first_order_buf(0) = this->first_order_buf(1) = this->first_order_buf(2) = std::numeric_limits<value_type>::quiet_NaN();
3674 return this->first_order_buf;
3675 }
3676
3677 double delta_p1 = p1 - std::floor(p1);
3678 double delta_p2 = p2 - std::floor(p2);
3679
3680 this->p1_pow_buf(0) = 1.0;
3681 this->p1_pow_buf(1) = delta_p1;
3682 this->p1_pow_buf(2) = this->p1_pow_buf(1)*delta_p1;
3683 this->p1_pow_buf(3) = this->p1_pow_buf(2)*delta_p1;
3684 this->p1_pow_buf(4) = this->p1_pow_buf(3)*delta_p1;
3685 this->p1_pow_buf(5) = this->p1_pow_buf(4)*delta_p1;
3686
3687 this->p1_pow_dp1_buf(0) = 0.0;
3688 this->p1_pow_dp1_buf(1) = 1.0;
3689 this->p1_pow_dp1_buf(2) = 2.0 * this->p1_pow_buf(1);
3690 this->p1_pow_dp1_buf(3) = 3.0 * this->p1_pow_buf(2);
3691 this->p1_pow_dp1_buf(4) = 4.0 * this->p1_pow_buf(3);
3692 this->p1_pow_dp1_buf(5) = 5.0 * this->p1_pow_buf(4);
3693
3694 this->p2_pow_buf(0) = 1.0;
3695 this->p2_pow_buf(1) = delta_p2;
3696 this->p2_pow_buf(2) = this->p2_pow_buf(1)*delta_p2;
3697 this->p2_pow_buf(3) = this->p2_pow_buf(2)*delta_p2;
3698 this->p2_pow_buf(4) = this->p2_pow_buf(3)*delta_p2;
3699 this->p2_pow_buf(5) = this->p2_pow_buf(4)*delta_p2;
3700
3701 this->p2_pow_dp2_buf(0) = 0.0;
3702 this->p2_pow_dp2_buf(1) = 1.0;
3703 this->p2_pow_dp2_buf(2) = 2.0 * this->p2_pow_buf(1);
3704 this->p2_pow_dp2_buf(3) = 3.0 * this->p2_pow_buf(2);
3705 this->p2_pow_dp2_buf(4) = 4.0 * this->p2_pow_buf(3);
3706 this->p2_pow_dp2_buf(5) = 5.0 * this->p2_pow_buf(4);
3707
3708 const auto &coef_mat = this->get_coef_mat(p1, p2);
3709
3710 this->first_order_buf(0) = (this->p2_pow_buf(0)*coef_mat(0,0)+this->p2_pow_buf(1)*coef_mat(0,1)+this->p2_pow_buf(2)*coef_mat(0,2)+this->p2_pow_buf(3)*coef_mat(0,3)+this->p2_pow_buf(4)*coef_mat(0,4)+this->p2_pow_buf(5)*coef_mat(0,5))*this->p1_pow_buf(0)+
3711 (this->p2_pow_buf(0)*coef_mat(1,0)+this->p2_pow_buf(1)*coef_mat(1,1)+this->p2_pow_buf(2)*coef_mat(1,2)+this->p2_pow_buf(3)*coef_mat(1,3)+this->p2_pow_buf(4)*coef_mat(1,4)+this->p2_pow_buf(5)*coef_mat(1,5))*this->p1_pow_buf(1)+
3712 (this->p2_pow_buf(0)*coef_mat(2,0)+this->p2_pow_buf(1)*coef_mat(2,1)+this->p2_pow_buf(2)*coef_mat(2,2)+this->p2_pow_buf(3)*coef_mat(2,3)+this->p2_pow_buf(4)*coef_mat(2,4)+this->p2_pow_buf(5)*coef_mat(2,5))*this->p1_pow_buf(2)+
3713 (this->p2_pow_buf(0)*coef_mat(3,0)+this->p2_pow_buf(1)*coef_mat(3,1)+this->p2_pow_buf(2)*coef_mat(3,2)+this->p2_pow_buf(3)*coef_mat(3,3)+this->p2_pow_buf(4)*coef_mat(3,4)+this->p2_pow_buf(5)*coef_mat(3,5))*this->p1_pow_buf(3)+
3714 (this->p2_pow_buf(0)*coef_mat(4,0)+this->p2_pow_buf(1)*coef_mat(4,1)+this->p2_pow_buf(2)*coef_mat(4,2)+this->p2_pow_buf(3)*coef_mat(4,3)+this->p2_pow_buf(4)*coef_mat(4,4)+this->p2_pow_buf(5)*coef_mat(4,5))*this->p1_pow_buf(4)+
3715 (this->p2_pow_buf(0)*coef_mat(5,0)+this->p2_pow_buf(1)*coef_mat(5,1)+this->p2_pow_buf(2)*coef_mat(5,2)+this->p2_pow_buf(3)*coef_mat(5,3)+this->p2_pow_buf(4)*coef_mat(5,4)+this->p2_pow_buf(5)*coef_mat(5,5))*this->p1_pow_buf(5);
3716
3717 this->first_order_buf(1) = (this->p2_pow_buf(0)*coef_mat(0,0)+this->p2_pow_buf(1)*coef_mat(0,1)+this->p2_pow_buf(2)*coef_mat(0,2)+this->p2_pow_buf(3)*coef_mat(0,3)+this->p2_pow_buf(4)*coef_mat(0,4)+this->p2_pow_buf(5)*coef_mat(0,5))*this->p1_pow_dp1_buf(0)+
3718 (this->p2_pow_buf(0)*coef_mat(1,0)+this->p2_pow_buf(1)*coef_mat(1,1)+this->p2_pow_buf(2)*coef_mat(1,2)+this->p2_pow_buf(3)*coef_mat(1,3)+this->p2_pow_buf(4)*coef_mat(1,4)+this->p2_pow_buf(5)*coef_mat(1,5))*this->p1_pow_dp1_buf(1)+
3719 (this->p2_pow_buf(0)*coef_mat(2,0)+this->p2_pow_buf(1)*coef_mat(2,1)+this->p2_pow_buf(2)*coef_mat(2,2)+this->p2_pow_buf(3)*coef_mat(2,3)+this->p2_pow_buf(4)*coef_mat(2,4)+this->p2_pow_buf(5)*coef_mat(2,5))*this->p1_pow_dp1_buf(2)+
3720 (this->p2_pow_buf(0)*coef_mat(3,0)+this->p2_pow_buf(1)*coef_mat(3,1)+this->p2_pow_buf(2)*coef_mat(3,2)+this->p2_pow_buf(3)*coef_mat(3,3)+this->p2_pow_buf(4)*coef_mat(3,4)+this->p2_pow_buf(5)*coef_mat(3,5))*this->p1_pow_dp1_buf(3)+
3721 (this->p2_pow_buf(0)*coef_mat(4,0)+this->p2_pow_buf(1)*coef_mat(4,1)+this->p2_pow_buf(2)*coef_mat(4,2)+this->p2_pow_buf(3)*coef_mat(4,3)+this->p2_pow_buf(4)*coef_mat(4,4)+this->p2_pow_buf(5)*coef_mat(4,5))*this->p1_pow_dp1_buf(4)+
3722 (this->p2_pow_buf(0)*coef_mat(5,0)+this->p2_pow_buf(1)*coef_mat(5,1)+this->p2_pow_buf(2)*coef_mat(5,2)+this->p2_pow_buf(3)*coef_mat(5,3)+this->p2_pow_buf(4)*coef_mat(5,4)+this->p2_pow_buf(5)*coef_mat(5,5))*this->p1_pow_dp1_buf(5);
3723
3724 this->first_order_buf(2) = (this->p2_pow_dp2_buf(0)*coef_mat(0,0)+this->p2_pow_dp2_buf(1)*coef_mat(0,1)+this->p2_pow_dp2_buf(2)*coef_mat(0,2)+this->p2_pow_dp2_buf(3)*coef_mat(0,3)+this->p2_pow_dp2_buf(4)*coef_mat(0,4)+this->p2_pow_dp2_buf(5)*coef_mat(0,5))*this->p1_pow_buf(0)+
3725 (this->p2_pow_dp2_buf(0)*coef_mat(1,0)+this->p2_pow_dp2_buf(1)*coef_mat(1,1)+this->p2_pow_dp2_buf(2)*coef_mat(1,2)+this->p2_pow_dp2_buf(3)*coef_mat(1,3)+this->p2_pow_dp2_buf(4)*coef_mat(1,4)+this->p2_pow_dp2_buf(5)*coef_mat(1,5))*this->p1_pow_buf(1)+
3726 (this->p2_pow_dp2_buf(0)*coef_mat(2,0)+this->p2_pow_dp2_buf(1)*coef_mat(2,1)+this->p2_pow_dp2_buf(2)*coef_mat(2,2)+this->p2_pow_dp2_buf(3)*coef_mat(2,3)+this->p2_pow_dp2_buf(4)*coef_mat(2,4)+this->p2_pow_dp2_buf(5)*coef_mat(2,5))*this->p1_pow_buf(2)+
3727 (this->p2_pow_dp2_buf(0)*coef_mat(3,0)+this->p2_pow_dp2_buf(1)*coef_mat(3,1)+this->p2_pow_dp2_buf(2)*coef_mat(3,2)+this->p2_pow_dp2_buf(3)*coef_mat(3,3)+this->p2_pow_dp2_buf(4)*coef_mat(3,4)+this->p2_pow_dp2_buf(5)*coef_mat(3,5))*this->p1_pow_buf(3)+
3728 (this->p2_pow_dp2_buf(0)*coef_mat(4,0)+this->p2_pow_dp2_buf(1)*coef_mat(4,1)+this->p2_pow_dp2_buf(2)*coef_mat(4,2)+this->p2_pow_dp2_buf(3)*coef_mat(4,3)+this->p2_pow_dp2_buf(4)*coef_mat(4,4)+this->p2_pow_dp2_buf(5)*coef_mat(4,5))*this->p1_pow_buf(4)+
3729 (this->p2_pow_dp2_buf(0)*coef_mat(5,0)+this->p2_pow_dp2_buf(1)*coef_mat(5,1)+this->p2_pow_dp2_buf(2)*coef_mat(5,2)+this->p2_pow_dp2_buf(3)*coef_mat(5,3)+this->p2_pow_dp2_buf(4)*coef_mat(5,4)+this->p2_pow_dp2_buf(5)*coef_mat(5,5))*this->p1_pow_buf(5);
3730
3731 return this->first_order_buf;
3732 }
3733
3734 // Unser-Aldroubi-Eden recursive B-spline coefficient filter for the
3735 // quintic B-spline (degree 5). Operates in-place on a single 1D signal of
3736 // length N >= 2. Uses whole-sample mirror boundary conditions which match
3737 // the standard literature (Unser 1993, "B-spline signal processing: Part
3738 // I -- Theory"). Replaces the previous FFT-based circular deconvolution
3739 // path, which produced a ~+29% spectral bias at integer query points
3740 // when the input array had a non-trivial top<->bottom or left<->right
3741 // gradient (the circular FFT wrap created a synthetic discontinuity that
3742 // the deconvolution amplified). With this recursive filter the result
3743 // round-trips exactly: at integer query points (p1, p2), the biquintic
3744 // evaluator returns the source array value within floating-point precision
3745 // regardless of the array's edge values.
3746 template <typename T_storage>
3747 inline void quintic_bspline_recursive_1d(T_storage* s, std::ptrdiff_t N,
3748 std::ptrdiff_t stride = 1) {
3749 // Stable poles of the quintic B-spline coefficient inverse filter
3750 // (roots of z^4 + 26 z^3 + 66 z^2 + 26 z + 1 that lie inside the unit
3751 // circle, derived from the cardinal kernel [1/120, 13/60, 11/20,
3752 // 13/60, 1/120]).
3753 constexpr double z[2] = {
3754 -0.43057534709997432, // -13 + sqrt(105)/2 ... root #1
3755 -0.04309628799923444 // smaller pole; second root
3756 };
3757 constexpr int NB_POLES = 2;
3758
3759 if (N < 2) return;
3760
3761 // Overall gain c0 = prod_p (1 - z_p)(1 - 1/z_p). Applied first.
3762 double lambda = 1.0;
3763 for (int p = 0; p < NB_POLES; ++p) {
3764 lambda *= (1.0 - z[p]) * (1.0 - 1.0 / z[p]);
3765 }
3766 for (std::ptrdiff_t i = 0; i < N; ++i) {
3767 s[i * stride] = T_storage(double(s[i * stride]) * lambda);
3768 }
3769
3770 // Apply each pole's causal + anti-causal recursion sequentially.
3771 for (int p = 0; p < NB_POLES; ++p) {
3772 const double zp = z[p];
3773
3774 // Causal initialization (truncated power series for mirror BC).
3775 constexpr double tol = 1e-9;
3776 std::ptrdiff_t horizon = static_cast<std::ptrdiff_t>(
3777 std::ceil(std::log(tol) / std::log(std::abs(zp))));
3778 if (horizon > N) horizon = N;
3779 double sum_zk = double(s[0]);
3780 double zk = zp;
3781 for (std::ptrdiff_t k = 1; k < horizon; ++k) {
3782 sum_zk += double(s[k * stride]) * zk;
3783 zk *= zp;
3784 }
3785 s[0] = T_storage(sum_zk);
3786
3787 // Causal recursion.
3788 for (std::ptrdiff_t i = 1; i < N; ++i) {
3789 s[i * stride] = T_storage(double(s[i * stride]) +
3790 zp * double(s[(i - 1) * stride]));
3791 }
3792
3793 // Anti-causal initialization (mirror BC, whole-sample symmetric).
3794 s[(N - 1) * stride] = T_storage(
3795 (zp / (zp * zp - 1.0)) *
3796 (double(s[(N - 1) * stride]) + zp * double(s[(N - 2) * stride])));
3797
3798 // Anti-causal recursion.
3799 for (std::ptrdiff_t i = N - 2; i >= 0; --i) {
3800 s[i * stride] = T_storage(
3801 zp * (double(s[(i + 1) * stride]) - double(s[i * stride])));
3802 }
3803 }
3804 }
3805
3806 template <typename T_container>
3807 std::shared_ptr<typename quintic_interp_base<T_container>::container> quintic_interp_base<T_container>::get_bspline_mat_ptr(const_container &A) const {
3808 #ifndef NDEBUG
3809 if (bcoef_border < 3) {
3810 throw std::invalid_argument("B-coefficient border cannot be less than three when calling get_bspline_coef() - this is a programmer error.");
3811 }
3812 #endif
3813
3814 // Pad the input so that calc_coef_mat's 5x5 window access (which uses
3815 // bcoef_border = 20 to land safely inside the padded array for any
3816 // in-bounds query) remains valid. EXPAND_EDGES replicates the
3817 // boundary values; with the recursive (non-FFT) bcoef filter below,
3818 // this padding only widens the support and does NOT introduce a
3819 // circular wraparound discontinuity.
3820 auto padded = pad(A, bcoef_border, PAD::EXPAND_EDGES);
3821 const auto H = padded.height();
3822 const auto W = padded.width();
3823 if (H < 2 || W < 2) {
3824 return std::make_shared<container>(std::move(padded));
3825 }
3826
3827 // Apply the separable recursive Unser filter along rows then columns.
3828 // The container is column-major: A(p1, p2) maps to data()[p1 + p2*H].
3829 // Row pass: stride = H, length = W, base ptr at p1.
3830 for (typename container::difference_type p1 = 0; p1 < H; ++p1) {
3831 quintic_bspline_recursive_1d<double>(&padded(p1, 0), W, H);
3832 }
3833 // Column pass: stride = 1, length = H, base ptr at column p2.
3834 for (typename container::difference_type p2 = 0; p2 < W; ++p2) {
3835 quintic_bspline_recursive_1d<double>(&padded(0, p2), H, 1);
3836 }
3837
3838 return std::make_shared<container>(std::move(padded));
3839 }
3840
3841 template <typename T_container>
3842 inline typename quintic_interp_base<T_container>::const_container& quintic_interp_base<T_container>::calc_coef_mat(container &coef_mat_buf, const_container &bcoef, difference_type p1, difference_type p2) const {
3843 // p1 and p2 refer to the top-left corner of the desired coefficient matrix
3844 #ifndef NDEBUG
3845 if (p1 < 0 || p1+5 >= bcoef.height() || p2 < 0 || p2+5 >= bcoef.width()) {
3846 throw std::invalid_argument("p1 and p2 are outside range of array for calc_coef_mat() with quintic interpolation - this is a programmer error.");
3847 }
3848 #endif
3849
3850 coef_mat_buf(0,0) = 0.00006944444444444444*bcoef(p1,p2)+0.001805555555555556*bcoef(p1+1,p2)+0.001805555555555556*bcoef(p1+4,p2+1)+0.004583333333333333*bcoef(p1,p2+2)+0.1191666666666667*bcoef(p1+1,p2+2)+0.3025*bcoef(p1+2,p2+2)+0.1191666666666667*bcoef(p1+3,p2+2)+0.004583333333333333*bcoef(p1+4,p2+2)+0.001805555555555556*bcoef(p1,p2+3)+0.04694444444444444*bcoef(p1+1,p2+3)+0.004583333333333333*bcoef(p1+2,p2)+0.1191666666666667*bcoef(p1+2,p2+3)+0.04694444444444444*bcoef(p1+3,p2+3)+0.001805555555555556*bcoef(p1+4,p2+3)+0.00006944444444444444*bcoef(p1,p2+4)+0.001805555555555556*bcoef(p1+1,p2+4)+0.004583333333333333*bcoef(p1+2,p2+4)+0.001805555555555556*bcoef(p1+3,p2+4)+0.00006944444444444444*bcoef(p1+4,p2+4)+0.001805555555555556*bcoef(p1+3,p2)+0.00006944444444444444*bcoef(p1+4,p2)+0.001805555555555556*bcoef(p1,p2+1)+0.04694444444444444*bcoef(p1+1,p2+1)+0.1191666666666667*bcoef(p1+2,p2+1)+0.04694444444444444*bcoef(p1+3,p2+1);
3851 coef_mat_buf(1,0) = 0.009027777777777778*bcoef(p1+4,p2+1)-0.003472222222222222*bcoef(p1+1,p2)-0.0003472222222222222*bcoef(p1,p2)-0.02291666666666667*bcoef(p1,p2+2)-0.2291666666666667*bcoef(p1+1,p2+2)+0.2291666666666667*bcoef(p1+3,p2+2)+0.02291666666666667*bcoef(p1+4,p2+2)-0.009027777777777778*bcoef(p1,p2+3)-0.09027777777777778*bcoef(p1+1,p2+3)+0.09027777777777778*bcoef(p1+3,p2+3)+0.009027777777777778*bcoef(p1+4,p2+3)-0.0003472222222222222*bcoef(p1,p2+4)-0.003472222222222222*bcoef(p1+1,p2+4)+0.003472222222222222*bcoef(p1+3,p2+4)+0.0003472222222222222*bcoef(p1+4,p2+4)+0.003472222222222222*bcoef(p1+3,p2)+0.0003472222222222222*bcoef(p1+4,p2)-0.009027777777777778*bcoef(p1,p2+1)-0.09027777777777778*bcoef(p1+1,p2+1)+0.09027777777777778*bcoef(p1+3,p2+1);
3852 coef_mat_buf(2,0) = 0.0006944444444444444*bcoef(p1,p2)+0.001388888888888889*bcoef(p1+1,p2)+0.01805555555555556*bcoef(p1+4,p2+1)+0.04583333333333333*bcoef(p1,p2+2)+0.09166666666666667*bcoef(p1+1,p2+2)-0.275*bcoef(p1+2,p2+2)+0.09166666666666667*bcoef(p1+3,p2+2)+0.04583333333333333*bcoef(p1+4,p2+2)+0.01805555555555556*bcoef(p1,p2+3)+0.03611111111111111*bcoef(p1+1,p2+3)-0.004166666666666667*bcoef(p1+2,p2)-0.1083333333333333*bcoef(p1+2,p2+3)+0.03611111111111111*bcoef(p1+3,p2+3)+0.01805555555555556*bcoef(p1+4,p2+3)+0.0006944444444444444*bcoef(p1,p2+4)+0.001388888888888889*bcoef(p1+1,p2+4)-0.004166666666666667*bcoef(p1+2,p2+4)+0.001388888888888889*bcoef(p1+3,p2+4)+0.0006944444444444444*bcoef(p1+4,p2+4)+0.001388888888888889*bcoef(p1+3,p2)+0.0006944444444444444*bcoef(p1+4,p2)+0.01805555555555556*bcoef(p1,p2+1)+0.03611111111111111*bcoef(p1+1,p2+1)-0.1083333333333333*bcoef(p1+2,p2+1)+0.03611111111111111*bcoef(p1+3,p2+1);
3853 coef_mat_buf(3,0) = 0.001388888888888889*bcoef(p1+1,p2)-0.0006944444444444444*bcoef(p1,p2)+0.01805555555555556*bcoef(p1+4,p2+1)-0.04583333333333333*bcoef(p1,p2+2)+0.09166666666666667*bcoef(p1+1,p2+2)-0.09166666666666667*bcoef(p1+3,p2+2)+0.04583333333333333*bcoef(p1+4,p2+2)-0.01805555555555556*bcoef(p1,p2+3)+0.03611111111111111*bcoef(p1+1,p2+3)-0.03611111111111111*bcoef(p1+3,p2+3)+0.01805555555555556*bcoef(p1+4,p2+3)-0.0006944444444444444*bcoef(p1,p2+4)+0.001388888888888889*bcoef(p1+1,p2+4)-0.001388888888888889*bcoef(p1+3,p2+4)+0.0006944444444444444*bcoef(p1+4,p2+4)-0.001388888888888889*bcoef(p1+3,p2)+0.0006944444444444444*bcoef(p1+4,p2)-0.01805555555555556*bcoef(p1,p2+1)+0.03611111111111111*bcoef(p1+1,p2+1)-0.03611111111111111*bcoef(p1+3,p2+1);
3854 coef_mat_buf(4,0) = 0.0003472222222222222*bcoef(p1,p2)-0.001388888888888889*bcoef(p1+1,p2)+0.009027777777777778*bcoef(p1+4,p2+1)+0.02291666666666667*bcoef(p1,p2+2)-0.09166666666666667*bcoef(p1+1,p2+2)+0.1375*bcoef(p1+2,p2+2)-0.09166666666666667*bcoef(p1+3,p2+2)+0.02291666666666667*bcoef(p1+4,p2+2)+0.009027777777777778*bcoef(p1,p2+3)-0.03611111111111111*bcoef(p1+1,p2+3)+0.002083333333333333*bcoef(p1+2,p2)+0.05416666666666667*bcoef(p1+2,p2+3)-0.03611111111111111*bcoef(p1+3,p2+3)+0.009027777777777778*bcoef(p1+4,p2+3)+0.0003472222222222222*bcoef(p1,p2+4)-0.001388888888888889*bcoef(p1+1,p2+4)+0.002083333333333333*bcoef(p1+2,p2+4)-0.001388888888888889*bcoef(p1+3,p2+4)+0.0003472222222222222*bcoef(p1+4,p2+4)-0.001388888888888889*bcoef(p1+3,p2)+0.0003472222222222222*bcoef(p1+4,p2)+0.009027777777777778*bcoef(p1,p2+1)-0.03611111111111111*bcoef(p1+1,p2+1)+0.05416666666666667*bcoef(p1+2,p2+1)-0.03611111111111111*bcoef(p1+3,p2+1);
3855 coef_mat_buf(5,0) = 0.0003472222222222222*bcoef(p1+1,p2)-0.00006944444444444444*bcoef(p1,p2)-0.009027777777777778*bcoef(p1+4,p2+1)+0.001805555555555556*bcoef(p1+5,p2+1)-0.004583333333333333*bcoef(p1,p2+2)+0.02291666666666667*bcoef(p1+1,p2+2)-0.04583333333333333*bcoef(p1+2,p2+2)+0.04583333333333333*bcoef(p1+3,p2+2)-0.02291666666666667*bcoef(p1+4,p2+2)+0.004583333333333333*bcoef(p1+5,p2+2)-0.001805555555555556*bcoef(p1,p2+3)+0.009027777777777778*bcoef(p1+1,p2+3)-0.0006944444444444444*bcoef(p1+2,p2)-0.01805555555555556*bcoef(p1+2,p2+3)+0.01805555555555556*bcoef(p1+3,p2+3)-0.009027777777777778*bcoef(p1+4,p2+3)+0.001805555555555556*bcoef(p1+5,p2+3)-0.00006944444444444444*bcoef(p1,p2+4)+0.0003472222222222222*bcoef(p1+1,p2+4)-0.0006944444444444444*bcoef(p1+2,p2+4)+0.0006944444444444444*bcoef(p1+3,p2+4)-0.0003472222222222222*bcoef(p1+4,p2+4)+0.00006944444444444444*bcoef(p1+5,p2+4)+0.0006944444444444444*bcoef(p1+3,p2)-0.0003472222222222222*bcoef(p1+4,p2)+0.00006944444444444444*bcoef(p1+5,p2)-0.001805555555555556*bcoef(p1,p2+1)+0.009027777777777778*bcoef(p1+1,p2+1)-0.01805555555555556*bcoef(p1+2,p2+1)+0.01805555555555556*bcoef(p1+3,p2+1);
3856 coef_mat_buf(0,1) = 0.003472222222222222*bcoef(p1,p2+3)-0.009027777777777778*bcoef(p1+1,p2)-0.003472222222222222*bcoef(p1+4,p2+1)-0.0003472222222222222*bcoef(p1,p2)+0.09027777777777778*bcoef(p1+1,p2+3)-0.02291666666666667*bcoef(p1+2,p2)+0.2291666666666667*bcoef(p1+2,p2+3)+0.09027777777777778*bcoef(p1+3,p2+3)+0.003472222222222222*bcoef(p1+4,p2+3)+0.0003472222222222222*bcoef(p1,p2+4)+0.009027777777777778*bcoef(p1+1,p2+4)+0.02291666666666667*bcoef(p1+2,p2+4)+0.009027777777777778*bcoef(p1+3,p2+4)+0.0003472222222222222*bcoef(p1+4,p2+4)-0.009027777777777778*bcoef(p1+3,p2)-0.0003472222222222222*bcoef(p1+4,p2)-0.003472222222222222*bcoef(p1,p2+1)-0.09027777777777778*bcoef(p1+1,p2+1)-0.2291666666666667*bcoef(p1+2,p2+1)-0.09027777777777778*bcoef(p1+3,p2+1);
3857 coef_mat_buf(1,1) = 0.001736111111111111*bcoef(p1,p2)+0.01736111111111111*bcoef(p1+1,p2)-0.01736111111111111*bcoef(p1+4,p2+1)-0.01736111111111111*bcoef(p1,p2+3)-0.1736111111111111*bcoef(p1+1,p2+3)+0.1736111111111111*bcoef(p1+3,p2+3)+0.01736111111111111*bcoef(p1+4,p2+3)-0.001736111111111111*bcoef(p1,p2+4)-0.01736111111111111*bcoef(p1+1,p2+4)+0.01736111111111111*bcoef(p1+3,p2+4)+0.001736111111111111*bcoef(p1+4,p2+4)-0.01736111111111111*bcoef(p1+3,p2)-0.001736111111111111*bcoef(p1+4,p2)+0.01736111111111111*bcoef(p1,p2+1)+0.1736111111111111*bcoef(p1+1,p2+1)-0.1736111111111111*bcoef(p1+3,p2+1);
3858 coef_mat_buf(2,1) = 0.03472222222222222*bcoef(p1,p2+3)-0.006944444444444444*bcoef(p1+1,p2)-0.03472222222222222*bcoef(p1+4,p2+1)-0.003472222222222222*bcoef(p1,p2)+0.06944444444444444*bcoef(p1+1,p2+3)+0.02083333333333333*bcoef(p1+2,p2)-0.2083333333333333*bcoef(p1+2,p2+3)+0.06944444444444444*bcoef(p1+3,p2+3)+0.03472222222222222*bcoef(p1+4,p2+3)+0.003472222222222222*bcoef(p1,p2+4)+0.006944444444444444*bcoef(p1+1,p2+4)-0.02083333333333333*bcoef(p1+2,p2+4)+0.006944444444444444*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)-0.006944444444444444*bcoef(p1+3,p2)-0.003472222222222222*bcoef(p1+4,p2)-0.03472222222222222*bcoef(p1,p2+1)-0.06944444444444444*bcoef(p1+1,p2+1)+0.2083333333333333*bcoef(p1+2,p2+1)-0.06944444444444444*bcoef(p1+3,p2+1);
3859 coef_mat_buf(3,1) = 0.003472222222222222*bcoef(p1,p2)-0.006944444444444444*bcoef(p1+1,p2)-0.03472222222222222*bcoef(p1+4,p2+1)-0.03472222222222222*bcoef(p1,p2+3)+0.06944444444444444*bcoef(p1+1,p2+3)-0.06944444444444444*bcoef(p1+3,p2+3)+0.03472222222222222*bcoef(p1+4,p2+3)-0.003472222222222222*bcoef(p1,p2+4)+0.006944444444444444*bcoef(p1+1,p2+4)-0.006944444444444444*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)+0.006944444444444444*bcoef(p1+3,p2)-0.003472222222222222*bcoef(p1+4,p2)+0.03472222222222222*bcoef(p1,p2+1)-0.06944444444444444*bcoef(p1+1,p2+1)+0.06944444444444444*bcoef(p1+3,p2+1);
3860 coef_mat_buf(4,1) = 0.006944444444444444*bcoef(p1+1,p2)-0.001736111111111111*bcoef(p1,p2)-0.01736111111111111*bcoef(p1+4,p2+1)+0.01736111111111111*bcoef(p1,p2+3)-0.06944444444444444*bcoef(p1+1,p2+3)-0.01041666666666667*bcoef(p1+2,p2)+0.1041666666666667*bcoef(p1+2,p2+3)-0.06944444444444444*bcoef(p1+3,p2+3)+0.01736111111111111*bcoef(p1+4,p2+3)+0.001736111111111111*bcoef(p1,p2+4)-0.006944444444444444*bcoef(p1+1,p2+4)+0.01041666666666667*bcoef(p1+2,p2+4)-0.006944444444444444*bcoef(p1+3,p2+4)+0.001736111111111111*bcoef(p1+4,p2+4)+0.006944444444444444*bcoef(p1+3,p2)-0.001736111111111111*bcoef(p1+4,p2)-0.01736111111111111*bcoef(p1,p2+1)+0.06944444444444444*bcoef(p1+1,p2+1)-0.1041666666666667*bcoef(p1+2,p2+1)+0.06944444444444444*bcoef(p1+3,p2+1);
3861 coef_mat_buf(5,1) = 0.0003472222222222222*bcoef(p1,p2)-0.001736111111111111*bcoef(p1+1,p2)+0.01736111111111111*bcoef(p1+4,p2+1)-0.003472222222222222*bcoef(p1+5,p2+1)-0.003472222222222222*bcoef(p1,p2+3)+0.01736111111111111*bcoef(p1+1,p2+3)+0.003472222222222222*bcoef(p1+2,p2)-0.03472222222222222*bcoef(p1+2,p2+3)+0.03472222222222222*bcoef(p1+3,p2+3)-0.01736111111111111*bcoef(p1+4,p2+3)+0.003472222222222222*bcoef(p1+5,p2+3)-0.0003472222222222222*bcoef(p1,p2+4)+0.001736111111111111*bcoef(p1+1,p2+4)-0.003472222222222222*bcoef(p1+2,p2+4)+0.003472222222222222*bcoef(p1+3,p2+4)-0.001736111111111111*bcoef(p1+4,p2+4)+0.0003472222222222222*bcoef(p1+5,p2+4)-0.003472222222222222*bcoef(p1+3,p2)+0.001736111111111111*bcoef(p1+4,p2)-0.0003472222222222222*bcoef(p1+5,p2)+0.003472222222222222*bcoef(p1,p2+1)-0.01736111111111111*bcoef(p1+1,p2+1)+0.03472222222222222*bcoef(p1+2,p2+1)-0.03472222222222222*bcoef(p1+3,p2+1);
3862 coef_mat_buf(0,2) = 0.0006944444444444444*bcoef(p1,p2)+0.01805555555555556*bcoef(p1+1,p2)+0.001388888888888889*bcoef(p1+4,p2+1)-0.004166666666666667*bcoef(p1,p2+2)-0.1083333333333333*bcoef(p1+1,p2+2)-0.275*bcoef(p1+2,p2+2)-0.1083333333333333*bcoef(p1+3,p2+2)-0.004166666666666667*bcoef(p1+4,p2+2)+0.001388888888888889*bcoef(p1,p2+3)+0.03611111111111111*bcoef(p1+1,p2+3)+0.04583333333333333*bcoef(p1+2,p2)+0.09166666666666667*bcoef(p1+2,p2+3)+0.03611111111111111*bcoef(p1+3,p2+3)+0.001388888888888889*bcoef(p1+4,p2+3)+0.0006944444444444444*bcoef(p1,p2+4)+0.01805555555555556*bcoef(p1+1,p2+4)+0.04583333333333333*bcoef(p1+2,p2+4)+0.01805555555555556*bcoef(p1+3,p2+4)+0.0006944444444444444*bcoef(p1+4,p2+4)+0.01805555555555556*bcoef(p1+3,p2)+0.0006944444444444444*bcoef(p1+4,p2)+0.001388888888888889*bcoef(p1,p2+1)+0.03611111111111111*bcoef(p1+1,p2+1)+0.09166666666666667*bcoef(p1+2,p2+1)+0.03611111111111111*bcoef(p1+3,p2+1);
3863 coef_mat_buf(1,2) = 0.006944444444444444*bcoef(p1+4,p2+1)-0.03472222222222222*bcoef(p1+1,p2)-0.003472222222222222*bcoef(p1,p2)+0.02083333333333333*bcoef(p1,p2+2)+0.2083333333333333*bcoef(p1+1,p2+2)-0.2083333333333333*bcoef(p1+3,p2+2)-0.02083333333333333*bcoef(p1+4,p2+2)-0.006944444444444444*bcoef(p1,p2+3)-0.06944444444444444*bcoef(p1+1,p2+3)+0.06944444444444444*bcoef(p1+3,p2+3)+0.006944444444444444*bcoef(p1+4,p2+3)-0.003472222222222222*bcoef(p1,p2+4)-0.03472222222222222*bcoef(p1+1,p2+4)+0.03472222222222222*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)+0.03472222222222222*bcoef(p1+3,p2)+0.003472222222222222*bcoef(p1+4,p2)-0.006944444444444444*bcoef(p1,p2+1)-0.06944444444444444*bcoef(p1+1,p2+1)+0.06944444444444444*bcoef(p1+3,p2+1);
3864 coef_mat_buf(2,2) = 0.006944444444444444*bcoef(p1,p2)+0.01388888888888889*bcoef(p1+1,p2)+0.01388888888888889*bcoef(p1+4,p2+1)-0.04166666666666667*bcoef(p1,p2+2)-0.08333333333333333*bcoef(p1+1,p2+2)+0.25*bcoef(p1+2,p2+2)-0.08333333333333333*bcoef(p1+3,p2+2)-0.04166666666666667*bcoef(p1+4,p2+2)+0.01388888888888889*bcoef(p1,p2+3)+0.02777777777777778*bcoef(p1+1,p2+3)-0.04166666666666667*bcoef(p1+2,p2)-0.08333333333333333*bcoef(p1+2,p2+3)+0.02777777777777778*bcoef(p1+3,p2+3)+0.01388888888888889*bcoef(p1+4,p2+3)+0.006944444444444444*bcoef(p1,p2+4)+0.01388888888888889*bcoef(p1+1,p2+4)-0.04166666666666667*bcoef(p1+2,p2+4)+0.01388888888888889*bcoef(p1+3,p2+4)+0.006944444444444444*bcoef(p1+4,p2+4)+0.01388888888888889*bcoef(p1+3,p2)+0.006944444444444444*bcoef(p1+4,p2)+0.01388888888888889*bcoef(p1,p2+1)+0.02777777777777778*bcoef(p1+1,p2+1)-0.08333333333333333*bcoef(p1+2,p2+1)+0.02777777777777778*bcoef(p1+3,p2+1);
3865 coef_mat_buf(3,2) = 0.01388888888888889*bcoef(p1+1,p2)-0.006944444444444444*bcoef(p1,p2)+0.01388888888888889*bcoef(p1+4,p2+1)+0.04166666666666667*bcoef(p1,p2+2)-0.08333333333333333*bcoef(p1+1,p2+2)+0.08333333333333333*bcoef(p1+3,p2+2)-0.04166666666666667*bcoef(p1+4,p2+2)-0.01388888888888889*bcoef(p1,p2+3)+0.02777777777777778*bcoef(p1+1,p2+3)-0.02777777777777778*bcoef(p1+3,p2+3)+0.01388888888888889*bcoef(p1+4,p2+3)-0.006944444444444444*bcoef(p1,p2+4)+0.01388888888888889*bcoef(p1+1,p2+4)-0.01388888888888889*bcoef(p1+3,p2+4)+0.006944444444444444*bcoef(p1+4,p2+4)-0.01388888888888889*bcoef(p1+3,p2)+0.006944444444444444*bcoef(p1+4,p2)-0.01388888888888889*bcoef(p1,p2+1)+0.02777777777777778*bcoef(p1+1,p2+1)-0.02777777777777778*bcoef(p1+3,p2+1);
3866 coef_mat_buf(4,2) = 0.003472222222222222*bcoef(p1,p2)-0.01388888888888889*bcoef(p1+1,p2)+0.006944444444444444*bcoef(p1+4,p2+1)-0.02083333333333333*bcoef(p1,p2+2)+0.08333333333333333*bcoef(p1+1,p2+2)-0.125*bcoef(p1+2,p2+2)+0.08333333333333333*bcoef(p1+3,p2+2)-0.02083333333333333*bcoef(p1+4,p2+2)+0.006944444444444444*bcoef(p1,p2+3)-0.02777777777777778*bcoef(p1+1,p2+3)+0.02083333333333333*bcoef(p1+2,p2)+0.04166666666666667*bcoef(p1+2,p2+3)-0.02777777777777778*bcoef(p1+3,p2+3)+0.006944444444444444*bcoef(p1+4,p2+3)+0.003472222222222222*bcoef(p1,p2+4)-0.01388888888888889*bcoef(p1+1,p2+4)+0.02083333333333333*bcoef(p1+2,p2+4)-0.01388888888888889*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)-0.01388888888888889*bcoef(p1+3,p2)+0.003472222222222222*bcoef(p1+4,p2)+0.006944444444444444*bcoef(p1,p2+1)-0.02777777777777778*bcoef(p1+1,p2+1)+0.04166666666666667*bcoef(p1+2,p2+1)-0.02777777777777778*bcoef(p1+3,p2+1);
3867 coef_mat_buf(5,2) = 0.003472222222222222*bcoef(p1+1,p2)-0.0006944444444444444*bcoef(p1,p2)-0.006944444444444444*bcoef(p1+4,p2+1)+0.001388888888888889*bcoef(p1+5,p2+1)+0.004166666666666667*bcoef(p1,p2+2)-0.02083333333333333*bcoef(p1+1,p2+2)+0.04166666666666667*bcoef(p1+2,p2+2)-0.04166666666666667*bcoef(p1+3,p2+2)+0.02083333333333333*bcoef(p1+4,p2+2)-0.004166666666666667*bcoef(p1+5,p2+2)-0.001388888888888889*bcoef(p1,p2+3)+0.006944444444444444*bcoef(p1+1,p2+3)-0.006944444444444444*bcoef(p1+2,p2)-0.01388888888888889*bcoef(p1+2,p2+3)+0.01388888888888889*bcoef(p1+3,p2+3)-0.006944444444444444*bcoef(p1+4,p2+3)+0.001388888888888889*bcoef(p1+5,p2+3)-0.0006944444444444444*bcoef(p1,p2+4)+0.003472222222222222*bcoef(p1+1,p2+4)-0.006944444444444444*bcoef(p1+2,p2+4)+0.006944444444444444*bcoef(p1+3,p2+4)-0.003472222222222222*bcoef(p1+4,p2+4)+0.0006944444444444444*bcoef(p1+5,p2+4)+0.006944444444444444*bcoef(p1+3,p2)-0.003472222222222222*bcoef(p1+4,p2)+0.0006944444444444444*bcoef(p1+5,p2)-0.001388888888888889*bcoef(p1,p2+1)+0.006944444444444444*bcoef(p1+1,p2+1)-0.01388888888888889*bcoef(p1+2,p2+1)+0.01388888888888889*bcoef(p1+3,p2+1);
3868 coef_mat_buf(0,3) = 0.001388888888888889*bcoef(p1+4,p2+1)-0.01805555555555556*bcoef(p1+1,p2)-0.0006944444444444444*bcoef(p1,p2)-0.001388888888888889*bcoef(p1,p2+3)-0.03611111111111111*bcoef(p1+1,p2+3)-0.04583333333333333*bcoef(p1+2,p2)-0.09166666666666667*bcoef(p1+2,p2+3)-0.03611111111111111*bcoef(p1+3,p2+3)-0.001388888888888889*bcoef(p1+4,p2+3)+0.0006944444444444444*bcoef(p1,p2+4)+0.01805555555555556*bcoef(p1+1,p2+4)+0.04583333333333333*bcoef(p1+2,p2+4)+0.01805555555555556*bcoef(p1+3,p2+4)+0.0006944444444444444*bcoef(p1+4,p2+4)-0.01805555555555556*bcoef(p1+3,p2)-0.0006944444444444444*bcoef(p1+4,p2)+0.001388888888888889*bcoef(p1,p2+1)+0.03611111111111111*bcoef(p1+1,p2+1)+0.09166666666666667*bcoef(p1+2,p2+1)+0.03611111111111111*bcoef(p1+3,p2+1);
3869 coef_mat_buf(1,3) = 0.003472222222222222*bcoef(p1,p2)+0.03472222222222222*bcoef(p1+1,p2)+0.006944444444444444*bcoef(p1+4,p2+1)+0.006944444444444444*bcoef(p1,p2+3)+0.06944444444444444*bcoef(p1+1,p2+3)-0.06944444444444444*bcoef(p1+3,p2+3)-0.006944444444444444*bcoef(p1+4,p2+3)-0.003472222222222222*bcoef(p1,p2+4)-0.03472222222222222*bcoef(p1+1,p2+4)+0.03472222222222222*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)-0.03472222222222222*bcoef(p1+3,p2)-0.003472222222222222*bcoef(p1+4,p2)-0.006944444444444444*bcoef(p1,p2+1)-0.06944444444444444*bcoef(p1+1,p2+1)+0.06944444444444444*bcoef(p1+3,p2+1);
3870 coef_mat_buf(2,3) = 0.01388888888888889*bcoef(p1+4,p2+1)-0.01388888888888889*bcoef(p1+1,p2)-0.006944444444444444*bcoef(p1,p2)-0.01388888888888889*bcoef(p1,p2+3)-0.02777777777777778*bcoef(p1+1,p2+3)+0.04166666666666667*bcoef(p1+2,p2)+0.08333333333333333*bcoef(p1+2,p2+3)-0.02777777777777778*bcoef(p1+3,p2+3)-0.01388888888888889*bcoef(p1+4,p2+3)+0.006944444444444444*bcoef(p1,p2+4)+0.01388888888888889*bcoef(p1+1,p2+4)-0.04166666666666667*bcoef(p1+2,p2+4)+0.01388888888888889*bcoef(p1+3,p2+4)+0.006944444444444444*bcoef(p1+4,p2+4)-0.01388888888888889*bcoef(p1+3,p2)-0.006944444444444444*bcoef(p1+4,p2)+0.01388888888888889*bcoef(p1,p2+1)+0.02777777777777778*bcoef(p1+1,p2+1)-0.08333333333333333*bcoef(p1+2,p2+1)+0.02777777777777778*bcoef(p1+3,p2+1);
3871 coef_mat_buf(3,3) = 0.006944444444444444*bcoef(p1,p2)-0.01388888888888889*bcoef(p1+1,p2)+0.01388888888888889*bcoef(p1+4,p2+1)+0.01388888888888889*bcoef(p1,p2+3)-0.02777777777777778*bcoef(p1+1,p2+3)+0.02777777777777778*bcoef(p1+3,p2+3)-0.01388888888888889*bcoef(p1+4,p2+3)-0.006944444444444444*bcoef(p1,p2+4)+0.01388888888888889*bcoef(p1+1,p2+4)-0.01388888888888889*bcoef(p1+3,p2+4)+0.006944444444444444*bcoef(p1+4,p2+4)+0.01388888888888889*bcoef(p1+3,p2)-0.006944444444444444*bcoef(p1+4,p2)-0.01388888888888889*bcoef(p1,p2+1)+0.02777777777777778*bcoef(p1+1,p2+1)-0.02777777777777778*bcoef(p1+3,p2+1);
3872 coef_mat_buf(4,3) = 0.01388888888888889*bcoef(p1+1,p2)-0.003472222222222222*bcoef(p1,p2)+0.006944444444444444*bcoef(p1+4,p2+1)-0.006944444444444444*bcoef(p1,p2+3)+0.02777777777777778*bcoef(p1+1,p2+3)-0.02083333333333333*bcoef(p1+2,p2)-0.04166666666666667*bcoef(p1+2,p2+3)+0.02777777777777778*bcoef(p1+3,p2+3)-0.006944444444444444*bcoef(p1+4,p2+3)+0.003472222222222222*bcoef(p1,p2+4)-0.01388888888888889*bcoef(p1+1,p2+4)+0.02083333333333333*bcoef(p1+2,p2+4)-0.01388888888888889*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)+0.01388888888888889*bcoef(p1+3,p2)-0.003472222222222222*bcoef(p1+4,p2)+0.006944444444444444*bcoef(p1,p2+1)-0.02777777777777778*bcoef(p1+1,p2+1)+0.04166666666666667*bcoef(p1+2,p2+1)-0.02777777777777778*bcoef(p1+3,p2+1);
3873 coef_mat_buf(5,3) = 0.0006944444444444444*bcoef(p1,p2)-0.003472222222222222*bcoef(p1+1,p2)-0.006944444444444444*bcoef(p1+4,p2+1)+0.001388888888888889*bcoef(p1+5,p2+1)+0.001388888888888889*bcoef(p1,p2+3)-0.006944444444444444*bcoef(p1+1,p2+3)+0.006944444444444444*bcoef(p1+2,p2)+0.01388888888888889*bcoef(p1+2,p2+3)-0.01388888888888889*bcoef(p1+3,p2+3)+0.006944444444444444*bcoef(p1+4,p2+3)-0.001388888888888889*bcoef(p1+5,p2+3)-0.0006944444444444444*bcoef(p1,p2+4)+0.003472222222222222*bcoef(p1+1,p2+4)-0.006944444444444444*bcoef(p1+2,p2+4)+0.006944444444444444*bcoef(p1+3,p2+4)-0.003472222222222222*bcoef(p1+4,p2+4)+0.0006944444444444444*bcoef(p1+5,p2+4)-0.006944444444444444*bcoef(p1+3,p2)+0.003472222222222222*bcoef(p1+4,p2)-0.0006944444444444444*bcoef(p1+5,p2)-0.001388888888888889*bcoef(p1,p2+1)+0.006944444444444444*bcoef(p1+1,p2+1)-0.01388888888888889*bcoef(p1+2,p2+1)+0.01388888888888889*bcoef(p1+3,p2+1);
3874 coef_mat_buf(0,4) = 0.0003472222222222222*bcoef(p1,p2)+0.009027777777777778*bcoef(p1+1,p2)-0.001388888888888889*bcoef(p1+4,p2+1)+0.002083333333333333*bcoef(p1,p2+2)+0.05416666666666667*bcoef(p1+1,p2+2)+0.1375*bcoef(p1+2,p2+2)+0.05416666666666667*bcoef(p1+3,p2+2)+0.002083333333333333*bcoef(p1+4,p2+2)-0.001388888888888889*bcoef(p1,p2+3)-0.03611111111111111*bcoef(p1+1,p2+3)+0.02291666666666667*bcoef(p1+2,p2)-0.09166666666666667*bcoef(p1+2,p2+3)-0.03611111111111111*bcoef(p1+3,p2+3)-0.001388888888888889*bcoef(p1+4,p2+3)+0.0003472222222222222*bcoef(p1,p2+4)+0.009027777777777778*bcoef(p1+1,p2+4)+0.02291666666666667*bcoef(p1+2,p2+4)+0.009027777777777778*bcoef(p1+3,p2+4)+0.0003472222222222222*bcoef(p1+4,p2+4)+0.009027777777777778*bcoef(p1+3,p2)+0.0003472222222222222*bcoef(p1+4,p2)-0.001388888888888889*bcoef(p1,p2+1)-0.03611111111111111*bcoef(p1+1,p2+1)-0.09166666666666667*bcoef(p1+2,p2+1)-0.03611111111111111*bcoef(p1+3,p2+1);
3875 coef_mat_buf(1,4) = 0.1041666666666667*bcoef(p1+3,p2+2)-0.01736111111111111*bcoef(p1+1,p2)-0.006944444444444444*bcoef(p1+4,p2+1)-0.01041666666666667*bcoef(p1,p2+2)-0.1041666666666667*bcoef(p1+1,p2+2)-0.001736111111111111*bcoef(p1,p2)+0.01041666666666667*bcoef(p1+4,p2+2)+0.006944444444444444*bcoef(p1,p2+3)+0.06944444444444444*bcoef(p1+1,p2+3)-0.06944444444444444*bcoef(p1+3,p2+3)-0.006944444444444444*bcoef(p1+4,p2+3)-0.001736111111111111*bcoef(p1,p2+4)-0.01736111111111111*bcoef(p1+1,p2+4)+0.01736111111111111*bcoef(p1+3,p2+4)+0.001736111111111111*bcoef(p1+4,p2+4)+0.01736111111111111*bcoef(p1+3,p2)+0.001736111111111111*bcoef(p1+4,p2)+0.006944444444444444*bcoef(p1,p2+1)+0.06944444444444444*bcoef(p1+1,p2+1)-0.06944444444444444*bcoef(p1+3,p2+1);
3876 coef_mat_buf(2,4) = 0.003472222222222222*bcoef(p1,p2)+0.006944444444444444*bcoef(p1+1,p2)-0.01388888888888889*bcoef(p1+4,p2+1)+0.02083333333333333*bcoef(p1,p2+2)+0.04166666666666667*bcoef(p1+1,p2+2)-0.125*bcoef(p1+2,p2+2)+0.04166666666666667*bcoef(p1+3,p2+2)+0.02083333333333333*bcoef(p1+4,p2+2)-0.01388888888888889*bcoef(p1,p2+3)-0.02777777777777778*bcoef(p1+1,p2+3)-0.02083333333333333*bcoef(p1+2,p2)+0.08333333333333333*bcoef(p1+2,p2+3)-0.02777777777777778*bcoef(p1+3,p2+3)-0.01388888888888889*bcoef(p1+4,p2+3)+0.003472222222222222*bcoef(p1,p2+4)+0.006944444444444444*bcoef(p1+1,p2+4)-0.02083333333333333*bcoef(p1+2,p2+4)+0.006944444444444444*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)+0.006944444444444444*bcoef(p1+3,p2)+0.003472222222222222*bcoef(p1+4,p2)-0.01388888888888889*bcoef(p1,p2+1)-0.02777777777777778*bcoef(p1+1,p2+1)+0.08333333333333333*bcoef(p1+2,p2+1)-0.02777777777777778*bcoef(p1+3,p2+1);
3877 coef_mat_buf(3,4) = 0.006944444444444444*bcoef(p1+1,p2)-0.003472222222222222*bcoef(p1,p2)-0.01388888888888889*bcoef(p1+4,p2+1)-0.02083333333333333*bcoef(p1,p2+2)+0.04166666666666667*bcoef(p1+1,p2+2)-0.04166666666666667*bcoef(p1+3,p2+2)+0.02083333333333333*bcoef(p1+4,p2+2)+0.01388888888888889*bcoef(p1,p2+3)-0.02777777777777778*bcoef(p1+1,p2+3)+0.02777777777777778*bcoef(p1+3,p2+3)-0.01388888888888889*bcoef(p1+4,p2+3)-0.003472222222222222*bcoef(p1,p2+4)+0.006944444444444444*bcoef(p1+1,p2+4)-0.006944444444444444*bcoef(p1+3,p2+4)+0.003472222222222222*bcoef(p1+4,p2+4)-0.006944444444444444*bcoef(p1+3,p2)+0.003472222222222222*bcoef(p1+4,p2)+0.01388888888888889*bcoef(p1,p2+1)-0.02777777777777778*bcoef(p1+1,p2+1)+0.02777777777777778*bcoef(p1+3,p2+1);
3878 coef_mat_buf(4,4) = 0.001736111111111111*bcoef(p1,p2)-0.006944444444444444*bcoef(p1+1,p2)-0.006944444444444444*bcoef(p1+4,p2+1)+0.01041666666666667*bcoef(p1,p2+2)-0.04166666666666667*bcoef(p1+1,p2+2)+0.0625*bcoef(p1+2,p2+2)-0.04166666666666667*bcoef(p1+3,p2+2)+0.01041666666666667*bcoef(p1+4,p2+2)-0.006944444444444444*bcoef(p1,p2+3)+0.02777777777777778*bcoef(p1+1,p2+3)+0.01041666666666667*bcoef(p1+2,p2)-0.04166666666666667*bcoef(p1+2,p2+3)+0.02777777777777778*bcoef(p1+3,p2+3)-0.006944444444444444*bcoef(p1+4,p2+3)+0.001736111111111111*bcoef(p1,p2+4)-0.006944444444444444*bcoef(p1+1,p2+4)+0.01041666666666667*bcoef(p1+2,p2+4)-0.006944444444444444*bcoef(p1+3,p2+4)+0.001736111111111111*bcoef(p1+4,p2+4)-0.006944444444444444*bcoef(p1+3,p2)+0.001736111111111111*bcoef(p1+4,p2)-0.006944444444444444*bcoef(p1,p2+1)+0.02777777777777778*bcoef(p1+1,p2+1)-0.04166666666666667*bcoef(p1+2,p2+1)+0.02777777777777778*bcoef(p1+3,p2+1);
3879 coef_mat_buf(5,4) = 0.001736111111111111*bcoef(p1+1,p2)-0.0003472222222222222*bcoef(p1,p2)+0.006944444444444444*bcoef(p1+4,p2+1)-0.001388888888888889*bcoef(p1+5,p2+1)-0.002083333333333333*bcoef(p1,p2+2)+0.01041666666666667*bcoef(p1+1,p2+2)-0.02083333333333333*bcoef(p1+2,p2+2)+0.02083333333333333*bcoef(p1+3,p2+2)-0.01041666666666667*bcoef(p1+4,p2+2)+0.002083333333333333*bcoef(p1+5,p2+2)+0.001388888888888889*bcoef(p1,p2+3)-0.006944444444444444*bcoef(p1+1,p2+3)-0.003472222222222222*bcoef(p1+2,p2)+0.01388888888888889*bcoef(p1+2,p2+3)-0.01388888888888889*bcoef(p1+3,p2+3)+0.006944444444444444*bcoef(p1+4,p2+3)-0.001388888888888889*bcoef(p1+5,p2+3)-0.0003472222222222222*bcoef(p1,p2+4)+0.001736111111111111*bcoef(p1+1,p2+4)-0.003472222222222222*bcoef(p1+2,p2+4)+0.003472222222222222*bcoef(p1+3,p2+4)-0.001736111111111111*bcoef(p1+4,p2+4)+0.0003472222222222222*bcoef(p1+5,p2+4)+0.003472222222222222*bcoef(p1+3,p2)-0.001736111111111111*bcoef(p1+4,p2)+0.0003472222222222222*bcoef(p1+5,p2)+0.001388888888888889*bcoef(p1,p2+1)-0.006944444444444444*bcoef(p1+1,p2+1)+0.01388888888888889*bcoef(p1+2,p2+1)-0.01388888888888889*bcoef(p1+3,p2+1);
3880 coef_mat_buf(0,5) = 0.0003472222222222222*bcoef(p1+4,p2+1)-0.001805555555555556*bcoef(p1+1,p2)-0.00006944444444444444*bcoef(p1,p2)-0.0006944444444444444*bcoef(p1,p2+2)-0.01805555555555556*bcoef(p1+1,p2+2)-0.04583333333333333*bcoef(p1+2,p2+2)-0.01805555555555556*bcoef(p1+3,p2+2)-0.0006944444444444444*bcoef(p1+4,p2+2)+0.0006944444444444444*bcoef(p1,p2+3)+0.01805555555555556*bcoef(p1+1,p2+3)-0.004583333333333333*bcoef(p1+2,p2)+0.04583333333333333*bcoef(p1+2,p2+3)+0.01805555555555556*bcoef(p1+3,p2+3)+0.0006944444444444444*bcoef(p1+4,p2+3)-0.0003472222222222222*bcoef(p1,p2+4)-0.009027777777777778*bcoef(p1+1,p2+4)-0.02291666666666667*bcoef(p1+2,p2+4)-0.009027777777777778*bcoef(p1+3,p2+4)-0.0003472222222222222*bcoef(p1+4,p2+4)-0.001805555555555556*bcoef(p1+3,p2)+0.00006944444444444444*bcoef(p1,p2+5)+0.001805555555555556*bcoef(p1+1,p2+5)+0.004583333333333333*bcoef(p1+2,p2+5)+0.001805555555555556*bcoef(p1+3,p2+5)+0.00006944444444444444*bcoef(p1+4,p2+5)-0.00006944444444444444*bcoef(p1+4,p2)+0.0003472222222222222*bcoef(p1,p2+1)+0.009027777777777778*bcoef(p1+1,p2+1)+0.02291666666666667*bcoef(p1+2,p2+1)+0.009027777777777778*bcoef(p1+3,p2+1);
3881 coef_mat_buf(1,5) = 0.0003472222222222222*bcoef(p1,p2)+0.003472222222222222*bcoef(p1+1,p2)+0.001736111111111111*bcoef(p1+4,p2+1)+0.003472222222222222*bcoef(p1,p2+2)+0.03472222222222222*bcoef(p1+1,p2+2)-0.03472222222222222*bcoef(p1+3,p2+2)-0.003472222222222222*bcoef(p1+4,p2+2)-0.003472222222222222*bcoef(p1,p2+3)-0.03472222222222222*bcoef(p1+1,p2+3)+0.03472222222222222*bcoef(p1+3,p2+3)+0.003472222222222222*bcoef(p1+4,p2+3)+0.001736111111111111*bcoef(p1,p2+4)+0.01736111111111111*bcoef(p1+1,p2+4)-0.01736111111111111*bcoef(p1+3,p2+4)-0.001736111111111111*bcoef(p1+4,p2+4)-0.003472222222222222*bcoef(p1+3,p2)-0.0003472222222222222*bcoef(p1,p2+5)-0.003472222222222222*bcoef(p1+1,p2+5)+0.003472222222222222*bcoef(p1+3,p2+5)+0.0003472222222222222*bcoef(p1+4,p2+5)-0.0003472222222222222*bcoef(p1+4,p2)-0.001736111111111111*bcoef(p1,p2+1)-0.01736111111111111*bcoef(p1+1,p2+1)+0.01736111111111111*bcoef(p1+3,p2+1);
3882 coef_mat_buf(2,5) = 0.003472222222222222*bcoef(p1+4,p2+1)-0.001388888888888889*bcoef(p1+1,p2)-0.0006944444444444444*bcoef(p1,p2)-0.006944444444444444*bcoef(p1,p2+2)-0.01388888888888889*bcoef(p1+1,p2+2)+0.04166666666666667*bcoef(p1+2,p2+2)-0.01388888888888889*bcoef(p1+3,p2+2)-0.006944444444444444*bcoef(p1+4,p2+2)+0.006944444444444444*bcoef(p1,p2+3)+0.01388888888888889*bcoef(p1+1,p2+3)+0.004166666666666667*bcoef(p1+2,p2)-0.04166666666666667*bcoef(p1+2,p2+3)+0.01388888888888889*bcoef(p1+3,p2+3)+0.006944444444444444*bcoef(p1+4,p2+3)-0.003472222222222222*bcoef(p1,p2+4)-0.006944444444444444*bcoef(p1+1,p2+4)+0.02083333333333333*bcoef(p1+2,p2+4)-0.006944444444444444*bcoef(p1+3,p2+4)-0.003472222222222222*bcoef(p1+4,p2+4)-0.001388888888888889*bcoef(p1+3,p2)+0.0006944444444444444*bcoef(p1,p2+5)+0.001388888888888889*bcoef(p1+1,p2+5)-0.004166666666666667*bcoef(p1+2,p2+5)+0.001388888888888889*bcoef(p1+3,p2+5)+0.0006944444444444444*bcoef(p1+4,p2+5)-0.0006944444444444444*bcoef(p1+4,p2)+0.003472222222222222*bcoef(p1,p2+1)+0.006944444444444444*bcoef(p1+1,p2+1)-0.02083333333333333*bcoef(p1+2,p2+1)+0.006944444444444444*bcoef(p1+3,p2+1);
3883 coef_mat_buf(3,5) = 0.0006944444444444444*bcoef(p1,p2)-0.001388888888888889*bcoef(p1+1,p2)+0.003472222222222222*bcoef(p1+4,p2+1)+0.006944444444444444*bcoef(p1,p2+2)-0.01388888888888889*bcoef(p1+1,p2+2)+0.01388888888888889*bcoef(p1+3,p2+2)-0.006944444444444444*bcoef(p1+4,p2+2)-0.006944444444444444*bcoef(p1,p2+3)+0.01388888888888889*bcoef(p1+1,p2+3)-0.01388888888888889*bcoef(p1+3,p2+3)+0.006944444444444444*bcoef(p1+4,p2+3)+0.003472222222222222*bcoef(p1,p2+4)-0.006944444444444444*bcoef(p1+1,p2+4)+0.006944444444444444*bcoef(p1+3,p2+4)-0.003472222222222222*bcoef(p1+4,p2+4)+0.001388888888888889*bcoef(p1+3,p2)-0.0006944444444444444*bcoef(p1,p2+5)+0.001388888888888889*bcoef(p1+1,p2+5)-0.001388888888888889*bcoef(p1+3,p2+5)+0.0006944444444444444*bcoef(p1+4,p2+5)-0.0006944444444444444*bcoef(p1+4,p2)-0.003472222222222222*bcoef(p1,p2+1)+0.006944444444444444*bcoef(p1+1,p2+1)-0.006944444444444444*bcoef(p1+3,p2+1);
3884 coef_mat_buf(4,5) = 0.001388888888888889*bcoef(p1+1,p2)-0.0003472222222222222*bcoef(p1,p2)+0.001736111111111111*bcoef(p1+4,p2+1)-0.003472222222222222*bcoef(p1,p2+2)+0.01388888888888889*bcoef(p1+1,p2+2)-0.02083333333333333*bcoef(p1+2,p2+2)+0.01388888888888889*bcoef(p1+3,p2+2)-0.003472222222222222*bcoef(p1+4,p2+2)+0.003472222222222222*bcoef(p1,p2+3)-0.01388888888888889*bcoef(p1+1,p2+3)-0.002083333333333333*bcoef(p1+2,p2)+0.02083333333333333*bcoef(p1+2,p2+3)-0.01388888888888889*bcoef(p1+3,p2+3)+0.003472222222222222*bcoef(p1+4,p2+3)-0.001736111111111111*bcoef(p1,p2+4)+0.006944444444444444*bcoef(p1+1,p2+4)-0.01041666666666667*bcoef(p1+2,p2+4)+0.006944444444444444*bcoef(p1+3,p2+4)-0.001736111111111111*bcoef(p1+4,p2+4)+0.001388888888888889*bcoef(p1+3,p2)+0.0003472222222222222*bcoef(p1,p2+5)-0.001388888888888889*bcoef(p1+1,p2+5)+0.002083333333333333*bcoef(p1+2,p2+5)-0.001388888888888889*bcoef(p1+3,p2+5)+0.0003472222222222222*bcoef(p1+4,p2+5)-0.0003472222222222222*bcoef(p1+4,p2)+0.001736111111111111*bcoef(p1,p2+1)-0.006944444444444444*bcoef(p1+1,p2+1)+0.01041666666666667*bcoef(p1+2,p2+1)-0.006944444444444444*bcoef(p1+3,p2+1);
3885 coef_mat_buf(5,5) = 0.00006944444444444444*bcoef(p1,p2)-0.0003472222222222222*bcoef(p1+1,p2)-0.001736111111111111*bcoef(p1+4,p2+1)+0.0003472222222222222*bcoef(p1+5,p2+1)+0.0006944444444444444*bcoef(p1,p2+2)-0.003472222222222222*bcoef(p1+1,p2+2)+0.006944444444444444*bcoef(p1+2,p2+2)-0.006944444444444444*bcoef(p1+3,p2+2)+0.003472222222222222*bcoef(p1+4,p2+2)-0.0006944444444444444*bcoef(p1+5,p2+2)-0.0006944444444444444*bcoef(p1,p2+3)+0.003472222222222222*bcoef(p1+1,p2+3)+0.0006944444444444444*bcoef(p1+2,p2)-0.006944444444444444*bcoef(p1+2,p2+3)+0.006944444444444444*bcoef(p1+3,p2+3)-0.003472222222222222*bcoef(p1+4,p2+3)+0.0006944444444444444*bcoef(p1+5,p2+3)+0.0003472222222222222*bcoef(p1,p2+4)-0.001736111111111111*bcoef(p1+1,p2+4)+0.003472222222222222*bcoef(p1+2,p2+4)-0.003472222222222222*bcoef(p1+3,p2+4)+0.001736111111111111*bcoef(p1+4,p2+4)-0.0003472222222222222*bcoef(p1+5,p2+4)-0.0006944444444444444*bcoef(p1+3,p2)-0.00006944444444444444*bcoef(p1,p2+5)+0.0003472222222222222*bcoef(p1+1,p2+5)-0.0006944444444444444*bcoef(p1+2,p2+5)+0.0006944444444444444*bcoef(p1+3,p2+5)-0.0003472222222222222*bcoef(p1+4,p2+5)+0.00006944444444444444*bcoef(p1+5,p2+5)+0.0003472222222222222*bcoef(p1+4,p2)-0.00006944444444444444*bcoef(p1+5,p2)-0.0003472222222222222*bcoef(p1,p2+1)+0.001736111111111111*bcoef(p1+1,p2+1)-0.003472222222222222*bcoef(p1+2,p2+1)+0.003472222222222222*bcoef(p1+3,p2+1);
3886
3887 return coef_mat_buf;
3888 }
3889
3890 // Precomputed Biquintic B-spline Interpolator ---------------------------//
3891 template <typename T_container>
3893 // pre-allocate memory for entire coefficient array - note that this will
3894 // be a lot of memory - 36 times the size of the original array.
3895 coef_mat_precompute_ptr = std::make_shared<Array2D<container>>(this->A_ptr->height(), this->A_ptr->width(), container(6,6));
3896
3897 auto bcoef = this->get_bspline_mat_ptr(A);
3898 for (difference_type p2 = 0; p2 < this->A_ptr->width(); ++p2) {
3899 for (difference_type p1 = 0; p1 < this->A_ptr->height(); ++p1) {
3900 this->calc_coef_mat((*coef_mat_precompute_ptr)(p1,p2), *bcoef, p1 + this->bcoef_border - 2, p2 + this->bcoef_border - 2);
3901 }
3902 }
3903 }
3904
3905 // base_linsolver --------------------------------------------------------//
3906 template <typename T_container>
3908 if (A.height() != A.width()) {
3909 throw std::invalid_argument("Attempted to perform backward substitution using an Array with size " + A.size_2D_string() +
3910 ". Array must be square.");
3911 }
3912 if (A.height() != b.height() || b.width() != 1) {
3913 throw std::invalid_argument("Attempted to perform backward substitution using an A with size " + A.size_2D_string() +
3914 " and a b with size " + b.size_2D_string() + ".");
3915 }
3916
3917 // Copy b into x_buf, and then solve in-place - since A is square, they
3918 // are the same size.
3919 std::copy(b.get_pointer(), b.get_pointer() + b.size(), x_buf.get_pointer());
3920 for (difference_type p = A.height()-1; p > 0; --p) {
3921 if ((std::abs((*A_factored_ptr)(p,p)) < std::numeric_limits<value_type>::epsilon())) {
3922 // Set this x value to 1 for singular matrices
3923 x_buf(p) = 1;
3924 } else {
3925 x_buf(p) /= (*A_factored_ptr)(p,p);
3926 }
3927
3928 for (difference_type p1 = 0; p1 < p; ++p1) {
3929 x_buf(p1) -= x_buf(p) * (*A_factored_ptr)(p1,p);
3930 }
3931 }
3932
3933 if ((std::abs((*A_factored_ptr)(0,0)) < std::numeric_limits<value_type>::epsilon())) {
3934 x_buf(0) = 1;
3935 } else {
3936 x_buf(0) /= (*A_factored_ptr)(0,0);
3937 }
3938
3939 return x_buf;
3940 }
3941
3942 template <typename T_container>
3944 if (A.height() != A.width()) {
3945 throw std::invalid_argument("Attempted to perform forward substitution using an Array with size " + A.size_2D_string() +
3946 ". Array must be square.");
3947 }
3948 if (A.height() != b.height() || b.width() != 1) {
3949 throw std::invalid_argument("Attempted to perform forward substitution using an A with size " + A.size_2D_string() +
3950 " and a b with size " + b.size_2D_string() + ".");
3951 }
3952
3953 // Copy b into x_buf, and then solve in-place - since A is square, they
3954 // are the same size.
3955 std::copy(b.get_pointer(), b.get_pointer() + b.size(), x_buf.get_pointer());
3956 for (difference_type p = 0; p < A.height() - 1; ++p) {
3957 if ((std::abs((*A_factored_ptr)(p,p)) < std::numeric_limits<value_type>::epsilon())) {
3958 // Set this x value to 1 for singular matrices
3959 x_buf(p) = 1;
3960 } else {
3961 x_buf(p) /= (*A_factored_ptr)(p,p);
3962 }
3963
3964 for (difference_type p1 = p + 1; p1 < A_factored_ptr->height(); ++p1) {
3965 x_buf(p1) -= x_buf(p) * (*A_factored_ptr)(p1,p);
3966 }
3967 }
3968
3969 if ((std::abs((*A_factored_ptr)(last,last)) < std::numeric_limits<value_type>::epsilon())) {
3970 x_buf(last) = 1;
3971 } else {
3972 x_buf(last) /= (*A_factored_ptr)(last,last);
3973 }
3974
3975 return x_buf;
3976 }
3977
3978 // LU_linsolver ----------------------------------------------------------//
3979 template <typename T_container>
3980 LU_linsolver<T_container>::LU_linsolver(const_container &A) : base_linsolver<container>(A), piv_ptr(std::make_shared<container>(A.height(),1)), full_rank(true) {
3981 if (A.height() != A.width()) {
3982 throw std::invalid_argument("Attempted to perform LU decomposition on array of size " + A.size_2D_string() +
3983 ". Array must be square.");
3984 }
3985
3986 // From Matrix Operations Golab & Van Loan
3987 // LU decomposition with partial pivoting
3988 for (difference_type p = 0; p < this->A_factored_ptr->height()-1; ++p) {
3989 // Find mu, the pivot
3990 difference_type mu = std::max_element(&(*this->A_factored_ptr)(p,p), &(*this->A_factored_ptr)(0,p) + this->A_factored_ptr->height()) - &(*this->A_factored_ptr)(0,p);
3991 (*this->piv_ptr)(p) = mu; // store it
3992
3993 // Swap rows
3994 for (difference_type p2 = p; p2 < this->A_factored_ptr->width(); ++p2) {
3995 value_type buf = (*this->A_factored_ptr)(p,p2);
3996 (*this->A_factored_ptr)(p,p2) = (*this->A_factored_ptr)(mu,p2);
3997 (*this->A_factored_ptr)(mu,p2) = buf;
3998 }
3999
4000 // Test to make sure index at (i,i) isn't close to zero
4001 if (std::abs((*this->A_factored_ptr)(p,p)) < std::numeric_limits<value_type>::epsilon()) {
4002 full_rank = false;
4003 } else {
4004 for (difference_type p1 = p+1; p1 < this->A_factored_ptr->height(); ++p1) {
4005 (*this->A_factored_ptr)(p1,p) /= (*this->A_factored_ptr)(p,p);
4006 }
4007
4008 for (difference_type p2 = p+1; p2 < this->A_factored_ptr->width(); ++p2) {
4009 for (difference_type p1 = p+1; p1 < this->A_factored_ptr->height(); ++p1) {
4010 (*this->A_factored_ptr)(p1,p2) -= (*this->A_factored_ptr)(p1,p) * (*this->A_factored_ptr)(p,p2);
4011 }
4012 }
4013 }
4014 }
4015
4016 // Test last diagonal since loop exits before then
4017 if (std::abs((*this->A_factored_ptr)(last,last)) < std::numeric_limits<value_type>::epsilon()) {
4018 full_rank = false;
4019 }
4020 }
4021
4022 template <typename T_container>
4024 if ((*this->A_factored_ptr).height() != b.height() || b.width() != 1) {
4025 throw std::invalid_argument("Attempted to solve LU decomposition using b of size " + b.size_2D_string() +
4026 " on an Array of size " + (*this->A_factored_ptr).size_2D_string() + ".");
4027 }
4028
4029 // For singular matrices, this will substitute 1 for indeterminant coordinates
4030 // t(P)LUx = b
4031 // 1) Solve Ly = Pb
4032 // 2) Solve Ux = y
4033
4034 // copy b into x_buf first
4035 std::copy(b.get_pointer(), b.get_pointer() + b.size(), this->x_buf.get_pointer());
4036 for (difference_type p = 0; p < b.height()-1; ++p) {
4037 // Swap element
4038 value_type buf = this->x_buf((*piv_ptr)(p));
4039 this->x_buf((*piv_ptr)(p)) = this->x_buf(p);
4040 this->x_buf(p) = buf;
4041
4042 // Scale
4043 for (difference_type p1 = p+1; p1 < b.height(); ++p1) {
4044 this->x_buf(p1) -= this->x_buf(p) * (*this->A_factored_ptr)(p1,p);
4045 }
4046 }
4047 // Solve Ux = y and return it
4048 return this->backward_sub((*this->A_factored_ptr), this->x_buf);
4049 }
4050
4051 // QR_linsolver ----------------------------------------------------------//
4052 template <typename T_container>
4053 QR_linsolver<T_container>::QR_linsolver(const_container &A) : base_linsolver<container>(A), piv_ptr(std::make_shared<container>(A.width(),1)), beta_ptr(std::make_shared<container>(A.width(),1)), full_rank(true), rank(0) {
4054 // From Matrix Operations Golab & Van Loan
4055 // QR decomposition with column pivoting
4056
4057 // QR related algorithms use the Array2D interface since most of the
4058 // bottleneck should be computational. This simplifies some arithmetic.
4059
4060 container c(A.width(),1);
4061 for (difference_type p2 = 0; p2 < A.width(); ++p2) {
4062 c(p2) = dot(A(all,p2),A(all,p2));
4063 }
4064 value_type tau = max(c);
4065 difference_type k = find(c == tau);
4066 difference_type min_dim = std::min(A.height(), A.width());
4067 while (std::abs(tau) >= std::numeric_limits<value_type>::epsilon() && tau > 0) {
4068 ++rank;
4069 (*piv_ptr)(rank-1) = k;
4070
4071 // Swap columns
4072 container col_buf = (*this->A_factored_ptr)(all,k);
4073 (*this->A_factored_ptr)(all,k) = (*this->A_factored_ptr)(all,rank-1);
4074 (*this->A_factored_ptr)(all,rank-1) = col_buf;
4075
4076 // Swap c
4077 value_type buf_c = c(k);
4078 c(k) = c(rank-1);
4079 c(rank-1) = buf_c;
4080
4081 // Get householder vector
4082 auto h_pair = house((*this->A_factored_ptr)({rank-1,last},rank-1));
4083 (*beta_ptr)(rank-1) = h_pair.second; // store beta
4084
4085 (*this->A_factored_ptr)({rank-1,last},{rank-1,last}) = (*this->A_factored_ptr)({rank-1,last},{rank-1,last}) - h_pair.second * h_pair.first * ( t(h_pair.first) * (*this->A_factored_ptr)({rank-1,last},{rank-1,last}) );
4086 (*this->A_factored_ptr)({rank,last},rank-1) = h_pair.first({1,(*this->A_factored_ptr).height()-rank});
4087
4088 for (difference_type p2 = rank; p2 < (*this->A_factored_ptr).width(); ++p2) {
4089 c(p2) = c(p2) - std::pow((*this->A_factored_ptr)(rank-1,p2),2);
4090 }
4091
4092 if (rank < min_dim) {
4093 tau = max(c({rank,last}));
4094 k = find(c == tau, rank);
4095 } else {
4096 tau = 0;
4097 }
4098 }
4099 // Test if full (column) rank
4100 full_rank = (rank == (*this->A_factored_ptr).width());
4101 }
4102
4103 template <typename T_container>
4104 std::pair<typename QR_linsolver<T_container>::container,typename QR_linsolver<T_container>::value_type> QR_linsolver<T_container>::house(const_container &x) const {
4105 if (x.width() != 1) {
4106 throw std::invalid_argument("Attempted to get household vector for vector of size " + x.size_2D_string() +
4107 ". Vector must be a column vector.");
4108 }
4109
4110 value_type sigma = dot(x({1,last}),x({1,last}));
4111 container v(x.height(),1,1);
4112 v({1,last}) = x({1,last});
4113 value_type beta = 0;
4114 if (std::abs(sigma) > std::numeric_limits<value_type>::epsilon()) {
4115 value_type mu = std::sqrt(std::pow(x(0),2) + sigma);
4116 if (std::abs(x(0)) < std::numeric_limits<value_type>::epsilon() || x(0) < 0) {
4117 v(0) = x(0) - mu;
4118 } else {
4119 v(0) = -sigma / (x(0) + mu);
4120 }
4121 beta = 2 * std::pow(v(0),2) / (sigma + std::pow(v(0),2));
4122 v = v/v(0);
4123 }
4124
4125 return {std::move(v),std::move(beta)};
4126 }
4127
4128 template <typename T_container>
4130 if ((*this->A_factored_ptr).height() != b.height() || b.width() != 1) {
4131 throw std::invalid_argument("Attempted to solve QR decomposition using b of size " + b.size_2D_string() +
4132 " on an Array of size " + (*this->A_factored_ptr).size_2D_string() + ".");
4133 }
4134
4135 // Obtains the least squares solution for over determined systems. For
4136 // non full-rank systems, this will determine the basic solution.
4137 // QRt(P)x = b
4138 // 1) Find Rt(P)x = t(Q)b = y
4139 // 2) Solve Rt(P)x = y
4140 container y(b);
4141 container v(b.height(),1); // buffer for householder vector
4142 for (difference_type p = 0; p < rank; ++p) {
4143 v(p) = 1;
4144 v({p+1,last}) = (*this->A_factored_ptr)({p+1,last},p);
4145 y({p,last}) = y({p,last}) - (*beta_ptr)(p) * v({p,last}) * (t( v({p,last}) ) * y({p,last}));
4146 }
4147
4148 // Solve for t(P)*x - stores results in x_buf
4149 this->backward_sub((*this->A_factored_ptr)({0,rank-1},{0,rank-1}),y({0,rank-1}));
4150
4151 // Solve for basic solution
4152 this->x_buf({rank,last}) = 0; // set rest of x is set to zero for basic solution
4153 for (difference_type p = rank; p > 0; --p) {
4154 value_type buf = this->x_buf((*piv_ptr)(p-1));
4155 this->x_buf((*piv_ptr)(p-1)) = this->x_buf(p-1);
4156 this->x_buf(p-1) = buf;
4157 }
4158
4159 return this->x_buf;
4160 }
4161
4162 // CHOL_linsolver ----------------------------------------------------------//
4163 template <typename T_container>
4165 if (A.height() != A.width()) {
4166 throw std::invalid_argument("Attempted to perform Cholesky decomposition on array of size " + A.size_2D_string() +
4167 ". Array must be square.");
4168 }
4169
4170 // From Matrix Operations Golab & Van Loan
4171 // Returns Cholesky decomposition in the lower AND upper half of the matrix.
4172 // This allows forward and backward substitution to be used without transposing.
4173 for (difference_type p = 0; p < (*this->A_factored_ptr).height(); ++p) {
4174 if (p > 0) {
4175 for (difference_type p1 = this->A_factored_ptr->height() - 1; p1 >= p; --p1) {
4176 double buf = 0.0;
4177 for (difference_type p2 = 0; p2 < p; ++p2) {
4178 buf += (*this->A_factored_ptr)(p1,p2) * (*this->A_factored_ptr)(p,p2);
4179 }
4180 (*this->A_factored_ptr)(p1,p) -= buf;
4181 }
4182 }
4183
4184 // Check to make sure diagonal element is greater than zero
4185 if ((*this->A_factored_ptr)(p,p) >= std::numeric_limits<value_type>::epsilon()) {
4186 double diag_sqrt = std::sqrt((*this->A_factored_ptr)(p,p));
4187 for (difference_type p1 = p; p1 < this->A_factored_ptr->height(); ++p1) {
4188 (*this->A_factored_ptr)(p1,p) /= diag_sqrt;
4189 }
4190 } else {
4191 pos_def = false;
4192 return; // Must return because Cholesky decomposition does not exist
4193 }
4194 }
4195
4196 // Copy lower half into upperhalf
4197 for (difference_type p2 = 0; p2 < this->A_factored_ptr->width() - 1; ++p2) {
4198 for (difference_type p1 = p2 + 1; p1 < this->A_factored_ptr->height(); ++p1) {
4199 (*this->A_factored_ptr)(p2,p1) = (*this->A_factored_ptr)(p1,p2);
4200 }
4201 }
4202 }
4203
4204 template <typename T_container>
4206 if (!pos_def) {
4207 throw std::invalid_argument("Attempted to solve Cholesky decomposition with a non positive definite matrix.");
4208 }
4209 if ((*this->A_factored_ptr).height() != b.height() || b.width() != 1) {
4210 throw std::invalid_argument("Attempted to solve Cholesky decomposition using b of size " + b.size_2D_string() +
4211 " on an Array of size " + (*this->A_factored_ptr).size_2D_string() + ".");
4212 }
4213
4214 // LUx = b
4215 // 1) Solve Ly = b
4216 // 2) Solve Ux = y
4217 // Since Cholesky decomp stores factorization in lower and upper half,
4218 // you can use backward_sub without transposing the matrix.
4219 return this->backward_sub((*this->A_factored_ptr), this->forward_sub((*this->A_factored_ptr), b));
4220 }
4221}
4222
4223// General Functions ---------------------------------------------------------//
4224template <typename T = double,typename T_alloc = std::allocator<T>>
4225Array2D<T,T_alloc> eye(typename Array2D<T,T_alloc>::difference_type n, T type = T(), T_alloc = T_alloc()) {
4226 typedef typename Array2D<T,T_alloc>::difference_type difference_type;
4227
4228 if (n < 0) {
4229 throw std::invalid_argument("Attempted to create identity matrix with a size of: " + std::to_string(n) + ".");
4230 }
4231
4232 Array2D<T,T_alloc> A(n,n);
4233 for (difference_type p = 0; p < n; ++p) {
4234 A(p,p) = 1;
4235 }
4236
4237 return A;
4238}
4239
4240}
4241
4242#endif /* ARRAY2D_H */
void dgemm_(char *, char *, int *, int *, int *, double *, double *, int *, double *, int *, double *, double *, int *)
const_reference operator()(const details::last_index &, difference_type p2) const
Definition Array2D.h:163
region operator()(const r_convert_1D &r_sub_1D)
Definition Array2D.h:217
friend Array2D sort(Array2D A)
Definition Array2D.h:376
friend bool_container operator<=(const Array2D &A, const_reference val)
Definition Array2D.h:327
friend Array2D operator/(const_reference val, const Array2D &A)
Definition Array2D.h:373
friend Array2D pad(const Array2D &A, difference_type padding, PAD pad_type=PAD::ZEROS)
Definition Array2D.h:299
friend bool_container operator>=(const Array2D &A, const_reference val)
Definition Array2D.h:323
friend Array2D operator*(const Array2D &A, const Array2D &B)
Definition Array2D.h:394
difference_type sub2ind(difference_type p1, difference_type p2) const
Definition Array2D.h:418
friend Array2D operator+(Array2D &&A, Array2D &&B)
Definition Array2D.h:333
friend cv::Mat get_cv_img(const Array2D &A, value_type min, value_type max)
Definition Array2D.h:295
details::interface_region< details::base_region< Array2D > > region
Definition Array2D.h:100
friend Array2D operator-(const Array2D &A, const Array2D &B)
Definition Array2D.h:342
region operator()()
Definition Array2D.h:214
difference_type width() const
Definition Array2D.h:410
friend bool_container operator!=(const Array2D &A, const_reference val)
Definition Array2D.h:310
Array2D() noexcept
Definition Array2D.h:115
friend bool_container operator<(const Array2D &A, const Array2D &B)
Definition Array2D.h:324
const_reference operator()(const details::last_index &) const
Definition Array2D.h:154
Array2D(const region &reg)
Definition Array2D.h:132
~Array2D() noexcept
Definition Array2D.h:120
friend bool_container operator>=(const Array2D &A, const Array2D &B)
Definition Array2D.h:322
reference operator()(const details::last_index &last1, const details::last_index &last2)
Definition Array2D.h:166
bool in_bounds(difference_type p1, difference_type p2) const
Definition Array2D.h:421
friend Array2D pow(Array2D A, double n)
Definition Array2D.h:390
region operator()(const r_convert_2D_1 &r_sub1_2D, const r_convert_2D_2 &r_sub2_2D)
Definition Array2D.h:221
reference operator()(difference_type p1, difference_type p2)
Definition Array2D.h:159
std::string size_2D_string() const
Definition Array2D.h:423
friend std::ostream & operator<<(std::ostream &os, const Array2D &A)
Definition Array2D.h:297
friend Array2D operator-(Array2D &&A, Array2D &&B)
Definition Array2D.h:345
friend Array2D operator+(const_reference val, const Array2D &A)
Definition Array2D.h:337
const_region operator()() const
Definition Array2D.h:213
friend Array2D conv(const Array2D &A, const Array2D &B)
Definition Array2D.h:395
friend bool_container operator==(const Array2D &A, const_reference val)
Definition Array2D.h:307
const_reference operator()(const details::last_index &, const details::last_index &) const
Definition Array2D.h:165
reference operator()(difference_type p)
Definition Array2D.h:152
friend Array2D t(const Array2D &A)
Definition Array2D.h:300
Array2D container
Definition Array2D.h:105
const Array2D const_container
Definition Array2D.h:106
friend Array2D repmat(const Array2D &A, difference_type rows, difference_type cols)
Definition Array2D.h:298
details::interface_iterator< details::base_iterator< Array2D > > iterator
Definition Array2D.h:98
iterator begin()
Definition Array2D.h:242
Array2D(const Array2D &A)
Definition Array2D.h:116
friend Array2D operator*(Array2D &&A, const_reference val)
Definition Array2D.h:360
friend value_type median(Array2D A)
Definition Array2D.h:385
friend void imshow(const Array2D &A, difference_type delay)
Definition Array2D.h:296
Array2D< bool, bool_allocator > bool_container
Definition Array2D.h:108
friend bool_container operator==(const Array2D &A, const Array2D &B)
Definition Array2D.h:306
friend Array2D operator-(Array2D &&A, const Array2D &B)
Definition Array2D.h:344
friend Array2D operator/(const Array2D &A, Array2D &&B)
Definition Array2D.h:367
pointer get_pointer() const
Definition Array2D.h:412
friend Array2D< T2, typename allocator_type::template rebind< T2 >::other > convert(const Array2D &A, const T2 &)
Definition Array2D.h:294
friend void save(const Array2D &A, std::ofstream &os)
Definition Array2D.h:302
std::enable_if< std::is_same< typenameT_container::container, bool_container >::value, region >::type operator()(T_container A)
Definition Array2D.h:231
friend Array2D operator-(const Array2D &A, Array2D &&B)
Definition Array2D.h:343
std::enable_if< std::is_floating_point< value_type >::value, T_output >::type get_linsolver(LINSOLVER linsolver_type) const
Definition Array2D.h:267
friend value_type dot(const Array2D &x, const Array2D &y)
Definition Array2D.h:400
friend bool_container operator>(const Array2D &A, const Array2D &B)
Definition Array2D.h:320
friend Array2D operator+(const Array2D &A, const Array2D &B)
Definition Array2D.h:330
const_reference operator()(difference_type p1, const details::last_index &) const
Definition Array2D.h:161
friend Array2D sqrt(Array2D A)
Definition Array2D.h:388
friend value_type prctile(Array2D A, double percent)
Definition Array2D.h:383
friend Array2D operator-(const Array2D &A, const_reference val)
Definition Array2D.h:347
static std::enable_if< std::is_arithmetic< T >::value, T_output >::type load(const std::string &)
Definition Array2D.h:1931
std::ptrdiff_t difference_type
Definition Array2D.h:96
Array2D(Array2D &&A) noexcept
Definition Array2D.h:117
difference_type height() const
Definition Array2D.h:409
details::interface_iterator< details::base_iterator< const Array2D > > const_iterator
Definition Array2D.h:99
allocator_type::template rebind< bool >::other bool_allocator
Definition Array2D.h:107
reference operator()(const details::last_index &last)
Definition Array2D.h:155
Array2D(const Array2D< T2, T_alloc2 > &A)
Definition Array2D.h:128
std::pair< difference_type, difference_type > coords
Definition Array2D.h:97
friend value_type sum(const Array2D &A)
Definition Array2D.h:378
friend bool_container operator<(const Array2D &A, const_reference val)
Definition Array2D.h:325
friend Array2D xcorr(const Array2D &A, const Array2D &B)
Definition Array2D.h:397
bool empty() const
Definition Array2D.h:415
const_region operator()(const r_convert_1D &r_sub_1D) const
Definition Array2D.h:216
friend Array2D operator+(const Array2D &A, Array2D &&B)
Definition Array2D.h:331
friend Array2D deconv(const Array2D &A, const Array2D &B)
Definition Array2D.h:396
T_alloc allocator_type
Definition Array2D.h:104
friend bool_container operator>(const Array2D &A, const_reference val)
Definition Array2D.h:321
std::enable_if< std::is_floating_point< value_type >::value, T_output >::type get_interpolator(INTERP interp_type) const
Definition Array2D.h:251
details::interface_linsolver< details::base_linsolver< Array2D > > linsolver
Definition Array2D.h:103
const_region operator()(const r_convert_2D_1 &r_sub1_2D, const r_convert_2D_2 &r_sub2_2D) const
Definition Array2D.h:220
friend Array2D linsolve(const Array2D &A, const Array2D &b)
Definition Array2D.h:402
std::enable_if< std::is_same< typenameT_container::container, bool_container >::value, const_region >::type operator()(const details::interface_region< details::base_region< T_container > > &reg) const
Definition Array2D.h:236
std::enable_if< std::is_same< typenameT_container::container, bool_container >::value, const_region >::type operator()(T_container A) const
Definition Array2D.h:229
friend bool all_true(const Array2D &A)
Definition Array2D.h:316
Array2D(difference_type, difference_type, const_reference=value_type())
Definition Array2D.h:1889
Array2D & operator=(const Array2D &)
Definition Array2D.h:1857
reference operator()(const details::last_index &last, difference_type p2)
Definition Array2D.h:164
coords ind2sub(difference_type p) const
Definition Array2D.h:419
friend void save(const Array2D &A, const std::string &filename)
Definition Array2D.h:301
bool same_size(const T_container &A) const
Definition Array2D.h:417
friend Array2D operator/(const_reference val, Array2D &&A)
Definition Array2D.h:374
friend Array2D operator-(const_reference val, Array2D &&A)
Definition Array2D.h:350
friend difference_type find(const Array2D &A, difference_type start=0)
Definition Array2D.h:317
details::interface_region< details::base_region< const Array2D > > const_region
Definition Array2D.h:101
Array2D(std::initializer_list< value_type >)
Definition Array2D.h:1896
friend Array2D operator-(const_reference val, const Array2D &A)
Definition Array2D.h:349
details::interface_interp< details::base_interp< Array2D > > interpolator
Definition Array2D.h:102
friend Array2D mult(Array2D &&A, const Array2D &B)
Definition Array2D.h:356
const_iterator cbegin() const
Definition Array2D.h:246
std::size_t size_type
Definition Array2D.h:95
friend bool_container operator==(const_reference val, const Array2D &A)
Definition Array2D.h:308
const T & const_reference
Definition Array2D.h:94
friend bool_container operator!=(const Array2D &A, const Array2D &B)
Definition Array2D.h:309
friend bool isequal(const Array2D &A, const Array2D &B)
Definition Array2D.h:305
friend Array2D operator-(Array2D &&A, const_reference val)
Definition Array2D.h:348
std::string size_string() const
Definition Array2D.h:422
const_reference operator()(difference_type, difference_type) const
Definition Array2D.h:1988
friend Array2D operator/(const Array2D &A, const_reference val)
Definition Array2D.h:371
friend bool_container operator<=(const Array2D &A, const Array2D &B)
Definition Array2D.h:326
difference_type size() const
Definition Array2D.h:411
friend bool_container operator~(const Array2D &A)
Definition Array2D.h:314
friend value_type max(const Array2D &A)
Definition Array2D.h:380
friend Array2D operator+(Array2D &&A, const Array2D &B)
Definition Array2D.h:332
friend bool_container operator|(const Array2D &A, const Array2D &B)
Definition Array2D.h:313
friend bool_container operator!=(const_reference val, const Array2D &A)
Definition Array2D.h:311
friend bool_container operator&(const Array2D &A, const Array2D &B)
Definition Array2D.h:312
friend Array2D operator/(Array2D &&A, Array2D &&B)
Definition Array2D.h:369
std::enable_if< std::is_same< typenameT_container::container, bool_container >::value, region >::type operator()(const details::interface_region< details::base_region< T_container > > &reg)
Definition Array2D.h:238
friend Array2D mult(Array2D &&A, Array2D &&B)
Definition Array2D.h:357
const_iterator cend() const
Definition Array2D.h:247
friend class Array2D
Definition Array2D.h:111
Array2D(const const_region &reg)
Definition Array2D.h:131
friend Array2D operator/(const Array2D &A, const Array2D &B)
Definition Array2D.h:366
friend Array2D operator/(Array2D &&A, const Array2D &B)
Definition Array2D.h:368
friend Array2D normalize(Array2D A)
Definition Array2D.h:401
Array2D & operator=(Array2D &&) noexcept
Definition Array2D.h:1871
const T * const_pointer
Definition Array2D.h:92
static std::enable_if< std::is_arithmetic< T >::value, T_output >::type load(std::ifstream &)
Definition Array2D.h:1949
friend Array2D operator/(Array2D &&A, const_reference val)
Definition Array2D.h:372
friend value_type min(const Array2D &A)
Definition Array2D.h:381
iterator end()
Definition Array2D.h:243
friend Array2D operator*(const Array2D &A, const_reference val)
Definition Array2D.h:359
friend Array2D operator+(const_reference val, Array2D &&A)
Definition Array2D.h:338
bool in_bounds(difference_type p) const
Definition Array2D.h:420
friend Array2D mult(const Array2D &A, Array2D &&B)
Definition Array2D.h:355
reference operator()(difference_type p1, const details::last_index &last)
Definition Array2D.h:162
const_iterator end() const
Definition Array2D.h:245
friend Array2D operator*(const_reference val, Array2D &&A)
Definition Array2D.h:362
friend Array2D operator*(const_reference val, const Array2D &A)
Definition Array2D.h:361
friend bool any_true(const Array2D &A)
Definition Array2D.h:315
friend Array2D operator+(const Array2D &A, const_reference val)
Definition Array2D.h:335
Array2D(std::initializer_list< std::initializer_list< value_type > >)
Definition Array2D.h:1902
friend Array2D operator+(Array2D &&A, const_reference val)
Definition Array2D.h:336
const_iterator begin() const
Definition Array2D.h:244
friend Array2D mult(const Array2D &A, const Array2D &B)
Definition Array2D.h:354
const_reference operator()(difference_type) const
Definition Array2D.h:1977
base_linsolver< T_container >::value_type value_type
Definition Array2D.h:1772
base_linsolver< T_container >::difference_type difference_type
Definition Array2D.h:1775
base_linsolver< T_container >::container container
Definition Array2D.h:1777
base_linsolver< T_container >::size_type size_type
Definition Array2D.h:1774
base_linsolver< T_container >::coords coords
Definition Array2D.h:1776
const_container & solve(const_container &) const override
Definition Array2D.h:4205
CHOL_linsolver * clone() const override
Definition Array2D.h:1801
base_linsolver< T_container >::const_container const_container
Definition Array2D.h:1778
CHOL_linsolver(const CHOL_linsolver &)=default
base_linsolver< T_container >::reference reference
Definition Array2D.h:1773
CHOL_linsolver(CHOL_linsolver &&) noexcept=default
base_linsolver< T_container >::const_container const_container
Definition Array2D.h:1695
LU_linsolver(LU_linsolver &&) noexcept=default
base_linsolver< T_container >::size_type size_type
Definition Array2D.h:1691
base_linsolver< T_container >::container container
Definition Array2D.h:1694
base_linsolver< T_container >::value_type value_type
Definition Array2D.h:1689
LU_linsolver(const LU_linsolver &)=default
base_linsolver< T_container >::coords coords
Definition Array2D.h:1693
LU_linsolver * clone() const override
Definition Array2D.h:1718
base_linsolver< T_container >::reference reference
Definition Array2D.h:1690
const_container & solve(const_container &) const override
Definition Array2D.h:4023
base_linsolver< T_container >::difference_type difference_type
Definition Array2D.h:1692
QR_linsolver * clone() const override
Definition Array2D.h:1759
QR_linsolver(QR_linsolver &&) noexcept=default
base_linsolver< T_container >::container container
Definition Array2D.h:1734
base_linsolver< T_container >::difference_type difference_type
Definition Array2D.h:1732
base_linsolver< T_container >::const_container const_container
Definition Array2D.h:1735
base_linsolver< T_container >::coords coords
Definition Array2D.h:1733
QR_linsolver(const QR_linsolver &)=default
const_container & solve(const_container &) const override
Definition Array2D.h:4129
base_linsolver< T_container >::value_type value_type
Definition Array2D.h:1729
base_linsolver< T_container >::reference reference
Definition Array2D.h:1730
std::pair< container, value_type > house(const_container &) const
Definition Array2D.h:4104
base_linsolver< T_container >::size_type size_type
Definition Array2D.h:1731
virtual const_container & first_order(double, double) const =0
T_container::value_type value_type
Definition Array2D.h:1193
virtual value_type operator()(double, double) const =0
T_container::reference reference
Definition Array2D.h:1194
container_traits< T_container >::const_container const_container
Definition Array2D.h:1199
virtual bool out_of_bounds(double, double) const =0
base_interp(const base_interp &)=default
T_container::size_type size_type
Definition Array2D.h:1195
T_container::coords coords
Definition Array2D.h:1197
T_container::difference_type difference_type
Definition Array2D.h:1196
const_container * A_ptr
Definition Array2D.h:1230
virtual base_interp * clone() const =0
base_interp(base_interp &&) noexcept=default
container_traits< T_container >::nonconst_container container
Definition Array2D.h:1198
base_iterator(const base_iterator &) noexcept=default
container_traits< T_container >::reference reference
Definition Array2D.h:616
T_container::value_type value_type
Definition Array2D.h:611
difference_type pos() const
Definition Array2D.h:640
container_traits< T_container >::container container
Definition Array2D.h:618
virtual base_iterator< const_container > * const_clone() const =0
virtual base_iterator & operator--()=0
container_traits< T_container >::const_container const_container
Definition Array2D.h:619
void chk_valid_increment() const
Definition Array2D.h:3129
T_container::size_type size_type
Definition Array2D.h:612
base_iterator(const base_iterator< T_container2 > &it, typename std::enable_if< std::is_same< T_container2, nonconst_container >::value, int >::type=0)
Definition Array2D.h:637
container_traits< T_container >::pointer pointer
Definition Array2D.h:615
virtual base_iterator * clone() const =0
container_traits< T_container >::nonconst_container nonconst_container
Definition Array2D.h:617
base_iterator(base_iterator &&) noexcept=default
reference operator*() const
Definition Array2D.h:3122
std::enable_if< std::is_same< typenamecontainer_traits< T_container2 >::nonconst_container, nonconst_container >::value, bool >::type operator==(const base_iterator< T_container2 > &it) const
Definition Array2D.h:649
void chk_valid_decrement() const
Definition Array2D.h:3136
std::bidirectional_iterator_tag iterator_category
Definition Array2D.h:610
virtual base_iterator & operator++()=0
T_container::difference_type difference_type
Definition Array2D.h:613
T_container::coords coords
Definition Array2D.h:614
std::enable_if< std::is_same< typenamecontainer_traits< T_container2 >::nonconst_container, nonconst_container >::value, bool >::type operator!=(const base_iterator< T_container2 > &it) const
Definition Array2D.h:653
container & forward_sub(const_container &, const_container &) const
Definition Array2D.h:3943
virtual base_linsolver * clone() const =0
container_traits< T_container >::const_container const_container
Definition Array2D.h:1652
std::shared_ptr< container > A_factored_ptr
Definition Array2D.h:1682
container & backward_sub(const_container &, const_container &) const
Definition Array2D.h:3907
T_container::reference reference
Definition Array2D.h:1647
virtual const_container & solve(const_container &) const =0
T_container::value_type value_type
Definition Array2D.h:1646
T_container::difference_type difference_type
Definition Array2D.h:1649
base_linsolver() noexcept=default
T_container::size_type size_type
Definition Array2D.h:1648
T_container::coords coords
Definition Array2D.h:1650
container_traits< T_container >::nonconst_container container
Definition Array2D.h:1651
virtual ~base_region() noexcept=default
difference_type region_h
Definition Array2D.h:945
virtual const_iterator cend() const =0
container_traits< T_container >::nonconst_container nonconst_container
Definition Array2D.h:889
container_traits< T_container >::const_pointer const_pointer
Definition Array2D.h:884
container_traits< T_container >::iterator iterator
Definition Array2D.h:887
virtual base_region * clone() const =0
base_region(const base_region< T_container2 > &reg, typename std::enable_if< std::is_same< T_container2, nonconst_container >::value, int >::type=0)
Definition Array2D.h:909
container_traits< T_container >::reference reference
Definition Array2D.h:885
virtual base_region< const_container > * const_clone() const =0
difference_type region_height() const
Definition Array2D.h:922
T_container::coords coords
Definition Array2D.h:882
difference_type region_width() const
Definition Array2D.h:923
T_container::difference_type difference_type
Definition Array2D.h:881
virtual iterator begin() const =0
T_container::value_type value_type
Definition Array2D.h:879
container_traits< T_container >::const_reference const_reference
Definition Array2D.h:886
difference_type region_size() const
Definition Array2D.h:924
base_region(const base_region &) noexcept=default
difference_type region_w
Definition Array2D.h:946
container_traits< T_container >::const_container const_container
Definition Array2D.h:891
container_traits< T_container >::const_iterator const_iterator
Definition Array2D.h:888
T_container::size_type size_type
Definition Array2D.h:880
std::string region_size_2D_string() const
Definition Array2D.h:941
virtual iterator end() const =0
base_region & operator=(base_region &&reg)
Definition Array2D.h:902
base_region(base_region &&) noexcept=default
base_region & operator=(const base_region &)
Definition Array2D.h:3265
std::string region_size_string() const
Definition Array2D.h:940
virtual const_iterator cbegin() const =0
container_traits< T_container >::pointer pointer
Definition Array2D.h:883
difference_type region_s
Definition Array2D.h:947
container_traits< T_container >::container container
Definition Array2D.h:890
T_container::bool_container bool_container
Definition Array2D.h:780
bool_iterator(bool_iterator &&) noexcept=default
base_iterator< T_container >::size_type size_type
Definition Array2D.h:772
bool_iterator(const bool_iterator &) noexcept=default
base_iterator< T_container >::pointer pointer
Definition Array2D.h:775
base_iterator< T_container >::value_type value_type
Definition Array2D.h:771
bool_iterator * clone() const override
Definition Array2D.h:806
base_iterator< T_container >::coords coords
Definition Array2D.h:774
bool_iterator & operator++() override
Definition Array2D.h:3229
bool_iterator< const_container > * const_clone() const override
Definition Array2D.h:807
base_iterator< T_container >::iterator_category iterator_category
Definition Array2D.h:770
bool_iterator & operator--() override
Definition Array2D.h:3242
base_iterator< T_container >::nonconst_container nonconst_container
Definition Array2D.h:777
base_iterator< T_container >::difference_type difference_type
Definition Array2D.h:773
base_iterator< T_container >::reference reference
Definition Array2D.h:776
base_iterator< T_container >::const_container const_container
Definition Array2D.h:779
base_iterator< T_container >::container container
Definition Array2D.h:778
bool_region & operator=(bool_region &&reg)
Definition Array2D.h:1092
bool_region< const_container > * const_clone() const override
Definition Array2D.h:1104
T_container::bool_container bool_container
Definition Array2D.h:1081
base_region< T_container >::const_iterator const_iterator
Definition Array2D.h:1077
iterator begin() const override
Definition Array2D.h:1107
bool_region() noexcept=default
base_region< T_container >::size_type size_type
Definition Array2D.h:1069
base_region< T_container >::pointer pointer
Definition Array2D.h:1072
base_region< T_container >::reference reference
Definition Array2D.h:1074
base_region< T_container >::coords coords
Definition Array2D.h:1071
base_region< T_container >::iterator iterator
Definition Array2D.h:1076
iterator end() const override
Definition Array2D.h:1108
base_region< T_container >::value_type value_type
Definition Array2D.h:1068
~bool_region() noexcept override=default
const_iterator cbegin() const override
Definition Array2D.h:1109
base_region< T_container >::difference_type difference_type
Definition Array2D.h:1070
bool_region * clone() const override
Definition Array2D.h:1103
base_region< T_container >::const_pointer const_pointer
Definition Array2D.h:1073
const_iterator cend() const override
Definition Array2D.h:1110
base_region< T_container >::const_container const_container
Definition Array2D.h:1080
base_region< T_container >::container container
Definition Array2D.h:1079
base_region< T_container >::const_reference const_reference
Definition Array2D.h:1075
base_region< T_container >::nonconst_container nonconst_container
Definition Array2D.h:1078
cubic_interp_base< T_container >::size_type size_type
Definition Array2D.h:1450
cubic_interp_base< T_container >::container container
Definition Array2D.h:1453
cubic_interp_precompute(cubic_interp_precompute &&) noexcept=default
cubic_interp_base< T_container >::difference_type difference_type
Definition Array2D.h:1451
cubic_interp_base< T_container >::const_container const_container
Definition Array2D.h:1454
cubic_interp_base< T_container >::reference reference
Definition Array2D.h:1449
cubic_interp_base< T_container >::value_type value_type
Definition Array2D.h:1448
cubic_interp_precompute * clone() const override
Definition Array2D.h:1470
cubic_interp_precompute(const cubic_interp_precompute &)=default
cubic_interp_base< T_container >::coords coords
Definition Array2D.h:1452
cubic_interp * clone() const override
Definition Array2D.h:1430
cubic_interp_base< T_container >::value_type value_type
Definition Array2D.h:1408
cubic_interp_base< T_container >::const_container const_container
Definition Array2D.h:1414
cubic_interp(cubic_interp &&) noexcept=default
cubic_interp_base< T_container >::difference_type difference_type
Definition Array2D.h:1411
cubic_interp_base< T_container >::size_type size_type
Definition Array2D.h:1410
cubic_interp_base< T_container >::coords coords
Definition Array2D.h:1412
cubic_interp_base< T_container >::container container
Definition Array2D.h:1413
cubic_interp_base< T_container >::reference reference
Definition Array2D.h:1409
cubic_interp(const cubic_interp &)=default
value_type operator()(double p1, double p2) const
Definition Array2D.h:1633
~interface_interp() noexcept=default
T_interp::container container
Definition Array2D.h:1612
interface_interp & operator=(interface_interp &&interp)
Definition Array2D.h:1624
const_container & first_order(double p1, double p2) const
Definition Array2D.h:1634
T_interp::value_type value_type
Definition Array2D.h:1607
T_interp::const_container const_container
Definition Array2D.h:1613
interface_interp(const interface_interp &interp)
Definition Array2D.h:1621
interface_interp & operator=(const interface_interp &interp)
Definition Array2D.h:1623
T_interp::size_type size_type
Definition Array2D.h:1609
interface_interp(interface_interp &&interp)
Definition Array2D.h:1622
T_interp::difference_type difference_type
Definition Array2D.h:1610
T_interp::reference reference
Definition Array2D.h:1608
T_iterator::difference_type difference_type
Definition Array2D.h:824
~interface_iterator() noexcept=default
interface_iterator & operator++()
Definition Array2D.h:859
T_iterator::reference reference
Definition Array2D.h:827
T_iterator::container container
Definition Array2D.h:829
T_iterator::iterator_category iterator_category
Definition Array2D.h:821
T_iterator::value_type value_type
Definition Array2D.h:822
std::enable_if< std::is_same< typenameT_iterator2::nonconst_container, nonconst_container >::value, bool >::type operator!=(const interface_iterator< T_iterator2 > &it) const
Definition Array2D.h:866
T_iterator::size_type size_type
Definition Array2D.h:823
T_iterator::nonconst_container nonconst_container
Definition Array2D.h:828
interface_iterator(const interface_iterator< T_iterator2 > &it, typename std::enable_if< std::is_same< typename T_iterator2::container, nonconst_container >::value, int >::type=0)
Definition Array2D.h:850
interface_iterator & operator--()
Definition Array2D.h:860
T_iterator::const_container const_container
Definition Array2D.h:830
std::enable_if< std::is_same< typenameT_iterator2::nonconst_container, nonconst_container >::value, bool >::type operator==(const interface_iterator< T_iterator2 > &it) const
Definition Array2D.h:862
interface_iterator() noexcept=default
interface_iterator & operator=(const interface_iterator &it)
Definition Array2D.h:840
difference_type pos() const
Definition Array2D.h:854
T_iterator::pointer pointer
Definition Array2D.h:826
interface_iterator(interface_iterator &&it)
Definition Array2D.h:839
interface_iterator & operator=(interface_iterator &&it)
Definition Array2D.h:841
T_linsolver::difference_type difference_type
Definition Array2D.h:1815
interface_linsolver(const interface_linsolver &linsolver)
Definition Array2D.h:1826
interface_linsolver & operator=(interface_linsolver &&linsolver)
Definition Array2D.h:1829
interface_linsolver & operator=(const interface_linsolver &linsolver)
Definition Array2D.h:1828
T_linsolver::reference reference
Definition Array2D.h:1813
T_linsolver::const_container const_container
Definition Array2D.h:1818
T_linsolver::value_type value_type
Definition Array2D.h:1812
~interface_linsolver() noexcept=default
interface_linsolver(interface_linsolver &&linsolver)
Definition Array2D.h:1827
const_container & solve(const_container &b) const
Definition Array2D.h:1844
T_linsolver::container container
Definition Array2D.h:1817
T_linsolver::size_type size_type
Definition Array2D.h:1814
T_region::size_type size_type
Definition Array2D.h:1125
T_region::const_pointer const_pointer
Definition Array2D.h:1129
const_iterator cend() const
Definition Array2D.h:1177
T_region::container container
Definition Array2D.h:1135
interface_region(const interface_region< T_region2 > &reg, typename std::enable_if< std::is_same< typename T_region2::container, nonconst_container >::value, int >::type=0)
Definition Array2D.h:1159
difference_type region_size() const
Definition Array2D.h:1171
~interface_region() noexcept=default
difference_type region_height() const
Definition Array2D.h:1169
T_region::value_type value_type
Definition Array2D.h:1124
interface_region & operator=(const_container &A)
Definition Array2D.h:1165
interface_region & operator=(const interface_region &reg)
Definition Array2D.h:1149
T_region::nonconst_container nonconst_container
Definition Array2D.h:1134
const_iterator cbegin() const
Definition Array2D.h:1176
interface_region & operator=(const_reference val)
Definition Array2D.h:1166
std::string region_size_2D_string() const
Definition Array2D.h:1181
difference_type region_width() const
Definition Array2D.h:1170
std::enable_if< std::is_same< typenameT_region2::nonconst_container, nonconst_container >::value, interface_region & >::type operator=(const T_region2 &reg)
Definition Array2D.h:1164
interface_region & operator=(interface_region &&reg)
Definition Array2D.h:1150
interface_region() noexcept=default
T_region::const_container const_container
Definition Array2D.h:1136
T_region::const_reference const_reference
Definition Array2D.h:1131
T_region::difference_type difference_type
Definition Array2D.h:1126
interface_region(interface_region &&reg)
Definition Array2D.h:1145
T_region::const_iterator const_iterator
Definition Array2D.h:1133
T_region::iterator iterator
Definition Array2D.h:1132
T_region::reference reference
Definition Array2D.h:1130
std::string region_size_string() const
Definition Array2D.h:1180
const_container & first_order(double, double) const override
Definition Array2D.h:3401
base_interp< T_container >::coords coords
Definition Array2D.h:1281
base_interp< T_container >::difference_type difference_type
Definition Array2D.h:1280
linear_interp(const linear_interp &)=default
base_interp< T_container >::size_type size_type
Definition Array2D.h:1279
linear_interp(linear_interp &&) noexcept=default
linear_interp * clone() const override
Definition Array2D.h:1303
base_interp< T_container >::reference reference
Definition Array2D.h:1278
base_interp< T_container >::container container
Definition Array2D.h:1282
base_interp< T_container >::const_container const_container
Definition Array2D.h:1283
value_type operator()(double, double) const override
Definition Array2D.h:3386
base_interp< T_container >::value_type value_type
Definition Array2D.h:1277
base_interp< T_container >::container container
Definition Array2D.h:1243
value_type operator()(double, double) const override
Definition Array2D.h:3363
base_interp< T_container >::reference reference
Definition Array2D.h:1239
base_interp< T_container >::size_type size_type
Definition Array2D.h:1240
const_container & first_order(double, double) const override
Definition Array2D.h:3372
bool out_of_bounds(double p1, double p2) const override
Definition Array2D.h:1269
base_interp< T_container >::value_type value_type
Definition Array2D.h:1238
nearest_interp(nearest_interp &&) noexcept=default
nearest_interp(const nearest_interp &)=default
base_interp< T_container >::difference_type difference_type
Definition Array2D.h:1241
base_interp< T_container >::coords coords
Definition Array2D.h:1242
base_interp< T_container >::const_container const_container
Definition Array2D.h:1244
nearest_interp * clone() const override
Definition Array2D.h:1264
quintic_interp_base< T_container >::const_container const_container
Definition Array2D.h:1576
quintic_interp_precompute(const quintic_interp_precompute &)=default
quintic_interp_base< T_container >::value_type value_type
Definition Array2D.h:1570
quintic_interp_base< T_container >::reference reference
Definition Array2D.h:1571
quintic_interp_base< T_container >::size_type size_type
Definition Array2D.h:1572
quintic_interp_base< T_container >::coords coords
Definition Array2D.h:1574
quintic_interp_base< T_container >::container container
Definition Array2D.h:1575
quintic_interp_precompute(quintic_interp_precompute &&) noexcept=default
quintic_interp_precompute * clone() const override
Definition Array2D.h:1592
quintic_interp_base< T_container >::difference_type difference_type
Definition Array2D.h:1573
quintic_interp_base< T_container >::value_type value_type
Definition Array2D.h:1529
quintic_interp(quintic_interp &&) noexcept=default
quintic_interp(const quintic_interp &)=default
quintic_interp_base< T_container >::difference_type difference_type
Definition Array2D.h:1532
quintic_interp_base< T_container >::reference reference
Definition Array2D.h:1530
quintic_interp_base< T_container >::coords coords
Definition Array2D.h:1533
quintic_interp * clone() const override
Definition Array2D.h:1551
quintic_interp_base< T_container >::const_container const_container
Definition Array2D.h:1535
quintic_interp_base< T_container >::container container
Definition Array2D.h:1534
quintic_interp_base< T_container >::size_type size_type
Definition Array2D.h:1531
base_iterator< T_container >::size_type size_type
Definition Array2D.h:677
base_iterator< T_container >::pointer pointer
Definition Array2D.h:680
base_iterator< T_container >::reference reference
Definition Array2D.h:681
base_iterator< T_container >::const_container const_container
Definition Array2D.h:684
base_iterator< T_container >::difference_type difference_type
Definition Array2D.h:678
base_iterator< T_container >::container container
Definition Array2D.h:683
simple_iterator & operator++() override
Definition Array2D.h:3151
base_iterator< T_container >::nonconst_container nonconst_container
Definition Array2D.h:682
base_iterator< T_container >::value_type value_type
Definition Array2D.h:676
simple_iterator< const_container > * const_clone() const override
Definition Array2D.h:710
simple_iterator(const simple_iterator< T_container2 > &it, typename std::enable_if< std::is_same< T_container2, nonconst_container >::value, int >::type=0)
Definition Array2D.h:701
base_iterator< T_container >::iterator_category iterator_category
Definition Array2D.h:675
simple_iterator & operator--() override
Definition Array2D.h:3160
base_iterator< T_container >::coords coords
Definition Array2D.h:679
simple_iterator * clone() const override
Definition Array2D.h:709
simple_iterator() noexcept=default
base_region< T_container >::nonconst_container nonconst_container
Definition Array2D.h:964
simple_region(const simple_region &) noexcept=default
base_region< T_container >::const_reference const_reference
Definition Array2D.h:961
base_region< T_container >::const_pointer const_pointer
Definition Array2D.h:959
iterator end() const override
Definition Array2D.h:993
base_region< T_container >::container container
Definition Array2D.h:965
base_region< T_container >::iterator iterator
Definition Array2D.h:962
simple_region * clone() const override
Definition Array2D.h:988
base_region< T_container >::size_type size_type
Definition Array2D.h:955
iterator begin() const override
Definition Array2D.h:992
simple_region< const_container > * const_clone() const override
Definition Array2D.h:989
base_region< T_container >::coords coords
Definition Array2D.h:957
const_iterator cbegin() const override
Definition Array2D.h:994
simple_region(simple_region &&) noexcept=default
const_iterator cend() const override
Definition Array2D.h:995
base_region< T_container >::value_type value_type
Definition Array2D.h:954
base_region< T_container >::difference_type difference_type
Definition Array2D.h:956
simple_region & operator=(simple_region &&reg)
Definition Array2D.h:977
base_region< T_container >::reference reference
Definition Array2D.h:960
base_region< T_container >::const_iterator const_iterator
Definition Array2D.h:963
~simple_region() noexcept override=default
base_region< T_container >::pointer pointer
Definition Array2D.h:958
base_region< T_container >::const_container const_container
Definition Array2D.h:966
sub_iterator(sub_iterator &&) noexcept=default
base_iterator< T_container >::pointer pointer
Definition Array2D.h:722
sub_iterator * clone() const override
Definition Array2D.h:752
base_iterator< T_container >::value_type value_type
Definition Array2D.h:718
base_iterator< T_container >::nonconst_container nonconst_container
Definition Array2D.h:724
base_iterator< T_container >::iterator_category iterator_category
Definition Array2D.h:717
sub_iterator< const_container > * const_clone() const override
Definition Array2D.h:753
base_iterator< T_container >::difference_type difference_type
Definition Array2D.h:720
base_iterator< T_container >::const_container const_container
Definition Array2D.h:726
sub_iterator & operator++() override
Definition Array2D.h:3183
base_iterator< T_container >::container container
Definition Array2D.h:725
sub_iterator(const sub_iterator &) noexcept=default
base_iterator< T_container >::reference reference
Definition Array2D.h:723
base_iterator< T_container >::coords coords
Definition Array2D.h:721
sub_iterator & operator--() override
Definition Array2D.h:3194
base_iterator< T_container >::size_type size_type
Definition Array2D.h:719
sub_region(const sub_region &) noexcept=default
iterator begin() const override
Definition Array2D.h:1048
~sub_region() noexcept override=default
base_region< T_container >::iterator iterator
Definition Array2D.h:1016
base_region< T_container >::const_container const_container
Definition Array2D.h:1020
sub_region & operator=(sub_region &&reg)
Definition Array2D.h:1031
base_region< T_container >::size_type size_type
Definition Array2D.h:1009
base_region< T_container >::reference reference
Definition Array2D.h:1014
sub_region(sub_region &&) noexcept=default
base_region< T_container >::difference_type difference_type
Definition Array2D.h:1010
const_iterator cend() const override
Definition Array2D.h:1051
base_region< T_container >::const_pointer const_pointer
Definition Array2D.h:1013
base_region< T_container >::coords coords
Definition Array2D.h:1011
base_region< T_container >::container container
Definition Array2D.h:1019
base_region< T_container >::const_iterator const_iterator
Definition Array2D.h:1017
base_region< T_container >::const_reference const_reference
Definition Array2D.h:1015
base_region< T_container >::pointer pointer
Definition Array2D.h:1012
base_region< T_container >::value_type value_type
Definition Array2D.h:1008
sub_region< const_container > * const_clone() const override
Definition Array2D.h:1043
const_iterator cbegin() const override
Definition Array2D.h:1050
sub_region * clone() const override
Definition Array2D.h:1042
base_region< T_container >::nonconst_container nonconst_container
Definition Array2D.h:1018
iterator end() const override
Definition Array2D.h:1049
Lightweight, dependency-free logging facility for CppNCorr.
#define NLOG_ERROR
Definition log.h:164
std::mutex fftw_mutex
Definition Array2D.cpp:15
void quintic_bspline_recursive_1d(T_storage *s, std::ptrdiff_t N, std::ptrdiff_t stride=1)
Definition Array2D.h:3747
ROI2D::difference_type difference_type
Definition ncorr.cpp:5411
const class details::all_range all
Definition Array2D.h:70
std::pair< typename T_container::value_type, typename T_container::coords > min(T_container &A, const ROI2D::region_nlinfo &nlinfo)
Definition ROI2D.h:538
Array2D< T, T_alloc > eye(typename Array2D< T, T_alloc >::difference_type n, T type=T(), T_alloc=T_alloc())
Definition Array2D.h:4225
std::pair< typename T_container::value_type, typename T_container::coords > max(T_container &A, const ROI2D::region_nlinfo &nlinfo)
Definition ROI2D.h:509
const class details::last_index last
Definition Array2D.h:69
INTERP
Definition Array2D.h:77
@ QUINTIC_BSPLINE_PRECOMPUTE
LINSOLVER
Definition Array2D.h:78