gps_pvt 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +5 -0
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/Gemfile +10 -0
  6. data/README.md +86 -0
  7. data/Rakefile +86 -0
  8. data/bin/console +15 -0
  9. data/bin/setup +8 -0
  10. data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +6613 -0
  11. data/ext/gps_pvt/GPS/GPS_wrap.cxx +16019 -0
  12. data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +21050 -0
  13. data/ext/gps_pvt/extconf.rb +70 -0
  14. data/ext/ninja-scan-light/tool/navigation/EGM.h +2971 -0
  15. data/ext/ninja-scan-light/tool/navigation/GPS.h +2432 -0
  16. data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +479 -0
  17. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +1081 -0
  18. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +199 -0
  19. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +210 -0
  20. data/ext/ninja-scan-light/tool/navigation/MagneticField.h +928 -0
  21. data/ext/ninja-scan-light/tool/navigation/NTCM.h +211 -0
  22. data/ext/ninja-scan-light/tool/navigation/RINEX.h +1781 -0
  23. data/ext/ninja-scan-light/tool/navigation/WGS84.h +186 -0
  24. data/ext/ninja-scan-light/tool/navigation/coordinate.h +406 -0
  25. data/ext/ninja-scan-light/tool/param/bit_array.h +145 -0
  26. data/ext/ninja-scan-light/tool/param/complex.h +558 -0
  27. data/ext/ninja-scan-light/tool/param/matrix.h +4049 -0
  28. data/ext/ninja-scan-light/tool/param/matrix_fixed.h +665 -0
  29. data/ext/ninja-scan-light/tool/param/matrix_special.h +562 -0
  30. data/ext/ninja-scan-light/tool/param/quaternion.h +765 -0
  31. data/ext/ninja-scan-light/tool/param/vector3.h +651 -0
  32. data/ext/ninja-scan-light/tool/swig/Coordinate.i +177 -0
  33. data/ext/ninja-scan-light/tool/swig/GPS.i +1102 -0
  34. data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1234 -0
  35. data/ext/ninja-scan-light/tool/swig/extconf.rb +5 -0
  36. data/ext/ninja-scan-light/tool/swig/makefile +53 -0
  37. data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +417 -0
  38. data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +489 -0
  39. data/gps_pvt.gemspec +57 -0
  40. data/lib/gps_pvt/receiver.rb +375 -0
  41. data/lib/gps_pvt/ubx.rb +148 -0
  42. data/lib/gps_pvt/version.rb +5 -0
  43. data/lib/gps_pvt.rb +9 -0
  44. data/sig/gps_pvt.rbs +4 -0
  45. metadata +117 -0
@@ -0,0 +1,4049 @@
1
+ /*
2
+ * Copyright (c) 2015, M.Naruoka (fenrir)
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without modification,
6
+ * are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice,
9
+ * this list of conditions and the following disclaimer.
10
+ * - Redistributions in binary form must reproduce the above copyright notice,
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ * - Neither the name of the naruoka.org nor the names of its contributors
14
+ * may be used to endorse or promote products derived from this software
15
+ * without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
21
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ */
31
+
32
+ #ifndef __MATRIX_H
33
+ #define __MATRIX_H
34
+
35
+ /** @file
36
+ * @brief Portable matrix library
37
+ *
38
+ * This is hand-made matrix library whose features are
39
+ * 1) to use template for generic primitive type
40
+ * including not only double for general purpose,
41
+ * but also int used with fixed float for embedded environment.
42
+ * 2) to utilize shallow copy for small memory usage,
43
+ * which is very important for embedded environment.
44
+ * 3) to use views for transposed and partial matrices
45
+ * to reduce copies.
46
+ * 4) to use expression template technique
47
+ * for matrix multiplying, adding, and subtracting
48
+ * to eliminate temporary objects.
49
+ *
50
+ * Currently it only supports dense matrices,
51
+ * whose storage is prepared as continuous array,
52
+ * however it can support sparse matrices by extending
53
+ * the Array2D class structure.
54
+ */
55
+
56
+ #include <string>
57
+ #include <stdexcept>
58
+
59
+ #include <cstring>
60
+ #include <cmath>
61
+ #include <cfloat>
62
+ #include <cstdlib>
63
+ #include <ostream>
64
+ #include <limits>
65
+ #include "param/complex.h"
66
+
67
+ #include <iterator>
68
+
69
+ #if (__cplusplus < 201103L) && !defined(noexcept)
70
+ #define noexcept throw()
71
+ #endif
72
+ #if defined(DEBUG) && !defined(throws_when_debug)
73
+ #define throws_when_debug
74
+ #else
75
+ #define throws_when_debug noexcept
76
+ #endif
77
+
78
+ #if defined(_MSC_VER)
79
+ #define DELETE_IF_MSC(x)
80
+ #else
81
+ #define DELETE_IF_MSC(x) x
82
+ #endif
83
+
84
+ /**
85
+ * @brief 2D array abstract class for fixed content
86
+ *
87
+ * This class provides basic interface of 2D array, such as row and column numbers,
88
+ * accessor for element.
89
+ *
90
+ * @param T precision, for example, double
91
+ */
92
+ template<class T>
93
+ class Array2D_Frozen{
94
+ public:
95
+ typedef Array2D_Frozen<T> self_t;
96
+ static const bool writable = false;
97
+
98
+ protected:
99
+ unsigned int m_rows; ///< Rows
100
+ unsigned int m_columns; ///< Columns
101
+
102
+ public:
103
+ typedef T content_t;
104
+
105
+ /**
106
+ * Constructor of Array2D
107
+ *
108
+ * @param rows Rows
109
+ * @param columns Columns
110
+ */
111
+ Array2D_Frozen(const unsigned int &rows, const unsigned int &columns) noexcept
112
+ : m_rows(rows), m_columns(columns){}
113
+
114
+ /**
115
+ * Destructor of Array2D
116
+ */
117
+ virtual ~Array2D_Frozen(){}
118
+
119
+ /**
120
+ * Return rows
121
+ *
122
+ * @return (unsigned int) Rows
123
+ */
124
+ const unsigned int &rows() const noexcept {return m_rows;}
125
+ /**
126
+ * Return columns
127
+ *
128
+ * @return (int) Columns
129
+ */
130
+ const unsigned int &columns() const noexcept {return m_columns;}
131
+
132
+ /**
133
+ * Accessor for element
134
+ *
135
+ * @param row Row index (the first row is zero)
136
+ * @param column Column index (the first column is zero)
137
+ * @return (T) content
138
+ */
139
+ virtual T operator()(
140
+ const unsigned int &row,
141
+ const unsigned int &column) const = 0;
142
+
143
+ inline void check_index(
144
+ const unsigned int &row,
145
+ const unsigned int &column) const {
146
+ if(row >= rows()){
147
+ throw std::out_of_range("Row index incorrect");
148
+ }else if(column >= columns()){
149
+ throw std::out_of_range("Column index incorrect");
150
+ }
151
+ }
152
+
153
+ protected:
154
+ self_t &operator=(const self_t &array);
155
+ };
156
+
157
+ /**
158
+ * @brief 2D array abstract class for changeable content
159
+ *
160
+ * @param T precision, for example, double
161
+ */
162
+ template<class T, class ImplementedT>
163
+ class Array2D : public Array2D_Frozen<T> {
164
+ public:
165
+ typedef Array2D<T, ImplementedT> self_t;
166
+ static const bool writable = true;
167
+
168
+ /**
169
+ * Constructor of Array2D
170
+ *
171
+ * @param rows Rows
172
+ * @param columns Columns
173
+ */
174
+ Array2D(const unsigned int &rows, const unsigned int &columns) noexcept
175
+ : Array2D_Frozen<T>(rows, columns){}
176
+
177
+ /**
178
+ * Destructor of Array2D
179
+ */
180
+ virtual ~Array2D(){}
181
+
182
+ /**
183
+ * Assigner, which performs shallow copy if possible.
184
+ *
185
+ * @param array another one
186
+ * @return (ImplementedT)
187
+ */
188
+ virtual ImplementedT &operator=(const ImplementedT &array) = 0;
189
+
190
+ /**
191
+ * Accessor for element
192
+ *
193
+ * @param row Row index (the first row is zero)
194
+ * @param column Column index (the first column is zero)
195
+ * @return (T) content
196
+ */
197
+ using Array2D_Frozen<T>::operator();
198
+ virtual T &operator()(
199
+ const unsigned int &row,
200
+ const unsigned int &column) = 0;
201
+
202
+ /**
203
+ * Perform zero clear
204
+ *
205
+ */
206
+ virtual void clear() = 0;
207
+
208
+ /**
209
+ * Perform copy
210
+ *
211
+ * @param is_deep If true, return deep copy if possible, otherwise return shallow copy (just link).
212
+ * @return (ImplementedT) Copy
213
+ */
214
+ virtual ImplementedT copy(const bool &is_deep = false) const = 0;
215
+ };
216
+
217
+ /**
218
+ * @brief Array2D whose elements are dense, and are stored in sequential 1D array.
219
+ * In other words, (i, j) element is mapped to [i * rows + j].
220
+ *
221
+ * @param T precision, for example, double
222
+ */
223
+ template <class T>
224
+ class Array2D_Dense : public Array2D<T, Array2D_Dense<T> > {
225
+ public:
226
+ typedef Array2D_Dense<T> self_t;
227
+ typedef Array2D<T, self_t> super_t;
228
+
229
+ template <class T2>
230
+ struct cast_t {
231
+ typedef Array2D_Dense<T2> res_t;
232
+ };
233
+
234
+ using super_t::rows;
235
+ using super_t::columns;
236
+
237
+ protected:
238
+ static const int offset = (sizeof(T) >= sizeof(int)) ? 1 : ((sizeof(int) + sizeof(T) - 1) / sizeof(T));
239
+ int *ref; ///< reference counter TODO alignment?
240
+ T *values; ///< array for values
241
+
242
+ template <class T2, bool do_memory_op = std::numeric_limits<T2>::is_specialized>
243
+ struct setup_t {
244
+ static void copy(Array2D_Dense<T2> &dest, const T2 *src){
245
+ for(int i(dest.rows() * dest.columns() - 1); i >= 0; --i){
246
+ dest.values[i] = src[i];
247
+ }
248
+ }
249
+ static void clear(Array2D_Dense<T2> &target){
250
+ for(int i(target.rows() * target.columns() - 1); i >= 0; --i){
251
+ target.values[i] = T2();
252
+ }
253
+ }
254
+ };
255
+ template <class T2>
256
+ struct setup_t<T2, true> {
257
+ static void copy(Array2D_Dense<T2> &dest, const T2 *src){
258
+ std::memcpy(dest.values, src, sizeof(T2) * dest.rows() * dest.columns());
259
+ }
260
+ static void clear(Array2D_Dense<T2> &target){
261
+ std::memset(target.values, 0, sizeof(T2) * target.rows() * target.columns());
262
+ }
263
+ };
264
+
265
+ public:
266
+ Array2D_Dense() : super_t(0, 0), ref(NULL), values(NULL) {
267
+ }
268
+
269
+ /**
270
+ * Constructor
271
+ *
272
+ * @param rows Rows
273
+ * @param columns Columns
274
+ */
275
+ Array2D_Dense(
276
+ const unsigned int &rows,
277
+ const unsigned int &columns)
278
+ : super_t(rows, columns),
279
+ ref(reinterpret_cast<int *>(new T[offset + (rows * columns)])),
280
+ values(reinterpret_cast<T *>(ref) + offset) {
281
+ *ref = 1;
282
+ }
283
+ /**
284
+ * Constructor with initializer
285
+ *
286
+ * @param rows Rows
287
+ * @param columns Columns
288
+ * @param serialized Initializer
289
+ */
290
+ Array2D_Dense(
291
+ const unsigned int &rows,
292
+ const unsigned int &columns,
293
+ const T *serialized)
294
+ : super_t(rows, columns),
295
+ ref(reinterpret_cast<int *>(new T[offset + (rows * columns)])),
296
+ values(reinterpret_cast<T *>(ref) + offset) {
297
+ *ref = 1;
298
+ setup_t<T>::copy(*this, serialized);
299
+ }
300
+ /**
301
+ * Copy constructor, which performs shallow copy.
302
+ *
303
+ * @param array another one
304
+ */
305
+ Array2D_Dense(const self_t &array)
306
+ : super_t(array.m_rows, array.m_columns),
307
+ ref(array.ref), values(array.values){
308
+ if(ref){++(*ref);}
309
+ }
310
+ /**
311
+ * Constructor based on another type array, which performs deep copy.
312
+ *
313
+ * @param array another one
314
+ */
315
+ template <class T2>
316
+ Array2D_Dense(const Array2D_Frozen<T2> &array)
317
+ : super_t(array.rows(), array.columns()),
318
+ ref(reinterpret_cast<int *>(new T[offset + (array.rows() * array.columns())])),
319
+ values(reinterpret_cast<T *>(ref) + offset) {
320
+ *ref = 1;
321
+ T *buf(values);
322
+ const unsigned int i_end(array.rows()), j_end(array.columns());
323
+ for(unsigned int i(0); i < i_end; ++i){
324
+ for(unsigned int j(0); j < j_end; ++j){
325
+ *(buf++) = array(i, j);
326
+ }
327
+ }
328
+ }
329
+ /**
330
+ * Destructor
331
+ *
332
+ * The reference counter will be decreased, and when the counter equals to zero,
333
+ * allocated memory for elements will be deleted.
334
+ */
335
+ ~Array2D_Dense(){
336
+ if(ref && ((--(*ref)) <= 0)){
337
+ delete [] reinterpret_cast<T *>(ref);
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Assigner, which performs shallow copy.
343
+ *
344
+ * @param array another one
345
+ * @return self_t
346
+ */
347
+ self_t &operator=(const self_t &array){
348
+ if(this != &array){
349
+ if(ref && ((--(*ref)) <= 0)){delete [] reinterpret_cast<T *>(ref);}
350
+ super_t::m_rows = array.m_rows;
351
+ super_t::m_columns = array.m_columns;
352
+ if((ref = array.ref)){++(*ref);}
353
+ values = array.values;
354
+ }
355
+ return *this;
356
+ }
357
+
358
+ /**
359
+ * Assigner for different type, which performs deep copy.
360
+ *
361
+ * @param array another one
362
+ * @return self_t
363
+ */
364
+ template <class T2>
365
+ self_t &operator=(const Array2D_Frozen<T2> &array){
366
+ return ((*this) = self_t(array));
367
+ }
368
+ protected:
369
+ inline const T &get(
370
+ const unsigned int &row,
371
+ const unsigned int &column) const throws_when_debug {
372
+ #if defined(DEBUG)
373
+ super_t::check_index(row, column);
374
+ #endif
375
+ return values[(row * columns()) + column];
376
+ }
377
+
378
+ public:
379
+ /**
380
+ * Accessor for element
381
+ *
382
+ * @param row Row index
383
+ * @param column Column Index
384
+ * @return (T) Element
385
+ * @throw std::out_of_range When the indices are out of range
386
+ */
387
+ T operator()(
388
+ const unsigned int &row,
389
+ const unsigned int &column) const throws_when_debug {
390
+ return get(row, column);
391
+ }
392
+ T &operator()(
393
+ const unsigned int &row,
394
+ const unsigned int &column) throws_when_debug {
395
+ return const_cast<T &>(
396
+ const_cast<const self_t *>(this)->get(row, column));
397
+ }
398
+
399
+ void clear(){
400
+ setup_t<T>::clear(*this);
401
+ }
402
+
403
+ /**
404
+ * Perform copy
405
+ *
406
+ * @param is_deep If true, return deep copy, otherwise return shallow copy (just link).
407
+ * @return (self_t) copy
408
+ */
409
+ self_t copy(const bool &is_deep = false) const {
410
+ return is_deep ? self_t(rows(), columns(), values) : self_t(*this);
411
+ }
412
+ };
413
+
414
+ /**
415
+ * @brief special Array2D representing scaled unit
416
+ *
417
+ * @param T precision, for example, double
418
+ */
419
+ template <class T>
420
+ class Array2D_ScaledUnit : public Array2D_Frozen<T> {
421
+ public:
422
+ typedef Array2D_ScaledUnit<T> self_t;
423
+ typedef Array2D_Frozen<T> super_t;
424
+
425
+ protected:
426
+ const T value; ///< scaled unit
427
+
428
+ public:
429
+ /**
430
+ * Constructor
431
+ *
432
+ * @param rows Rows
433
+ * @param columns Columns
434
+ */
435
+ Array2D_ScaledUnit(const unsigned int &size, const T &v)
436
+ : super_t(size, size), value(v){}
437
+
438
+ /**
439
+ * Accessor for element
440
+ *
441
+ * @param row Row index
442
+ * @param column Column Index
443
+ * @return (T) Element
444
+ * @throw std::out_of_range When the indices are out of range
445
+ */
446
+ T operator()(
447
+ const unsigned int &row, const unsigned int &column) const throws_when_debug {
448
+ #if defined(DEBUG)
449
+ super_t::check_index(row, column);
450
+ #endif
451
+ return (row == column) ? value : 0;
452
+ }
453
+ };
454
+
455
+ /**
456
+ * @brief special Array2D representing operation
457
+ *
458
+ * @param T precision, for example, double
459
+ */
460
+ template <class T, class OperatorT>
461
+ struct Array2D_Operator : public Array2D_Frozen<T> {
462
+ public:
463
+ typedef OperatorT op_t;
464
+ typedef Array2D_Operator<T, op_t> self_t;
465
+ typedef Array2D_Frozen<T> super_t;
466
+
467
+ const op_t op;
468
+
469
+ /**
470
+ * Constructor
471
+ *
472
+ * @param rows Rows
473
+ * @param columns Columns
474
+ */
475
+ Array2D_Operator(
476
+ const unsigned int &r, const unsigned int &c,
477
+ const op_t &_op)
478
+ : super_t(r, c), op(_op){}
479
+
480
+ /**
481
+ * Accessor for element
482
+ *
483
+ * @param row Row index
484
+ * @param column Column Index
485
+ * @return (T) Element
486
+ * @throw std::out_of_range When the indices are out of range
487
+ */
488
+ T operator()(
489
+ const unsigned int &row, const unsigned int &column) const throws_when_debug {
490
+ #if defined(DEBUG)
491
+ super_t::check_index(row, colunmn);
492
+ #endif
493
+ return op(row, column);
494
+ }
495
+ };
496
+
497
+ template <class LHS_T, class RHS_T>
498
+ struct Array2D_Operator_Binary {
499
+ typedef LHS_T first_t;
500
+ typedef LHS_T lhs_t;
501
+ typedef RHS_T rhs_t;
502
+ lhs_t lhs; ///< Left hand side value
503
+ rhs_t rhs; ///< Right hand side value
504
+ Array2D_Operator_Binary(const lhs_t &_lhs, const rhs_t &_rhs) noexcept
505
+ : lhs(_lhs), rhs(_rhs) {}
506
+ };
507
+
508
+ template <class LHS_T, class RHS_T>
509
+ struct Array2D_Operator_Multiply_by_Matrix;
510
+
511
+ template <class LHS_T, class RHS_T>
512
+ struct Array2D_Operator_Multiply_by_Scalar;
513
+
514
+ template <class LHS_T, class RHS_T, bool rhs_positive>
515
+ struct Array2D_Operator_Add;
516
+
517
+
518
+ template <class BaseView = void>
519
+ struct MatrixViewBase {
520
+ typedef MatrixViewBase self_t;
521
+
522
+ struct {} prop;
523
+
524
+ static const char *name;
525
+ template<class CharT, class Traits>
526
+ friend std::basic_ostream<CharT, Traits> &operator<<(
527
+ std::basic_ostream<CharT, Traits> &out, const self_t &view){
528
+ return out << name;
529
+ }
530
+
531
+ inline const unsigned int rows(
532
+ const unsigned int &_rows, const unsigned int &_columns) const noexcept {
533
+ return _rows;
534
+ }
535
+ inline const unsigned int columns(
536
+ const unsigned int &_rows, const unsigned int &_columns) const noexcept {
537
+ return _columns;
538
+ }
539
+ template <class T, class Array2D_Type>
540
+ inline T operator()(Array2D_Type &storage, const unsigned int &i, const unsigned int &j) const {
541
+ return storage.Array2D_Type::operator()(i, j); // direct call instead of via vtable
542
+ }
543
+
544
+ void update_size(const unsigned int &rows, const unsigned int &columns){}
545
+ void update_offset(const unsigned int &row, const unsigned int &column){}
546
+ void update_loop(const unsigned int &rows, const unsigned int &columns){}
547
+ };
548
+ template <class BaseView>
549
+ const char *MatrixViewBase<BaseView>::name = "[Base]";
550
+
551
+ template <class BaseView>
552
+ struct MatrixViewTranspose;
553
+
554
+ template <class BaseView>
555
+ struct MatrixViewConjugate;
556
+
557
+ template <class BaseView>
558
+ struct MatrixViewSizeVariable;
559
+
560
+ template <class BaseView>
561
+ struct MatrixViewOffset;
562
+
563
+ template <class BaseView>
564
+ struct MatrixViewLoop;
565
+
566
+
567
+ template <class View>
568
+ struct MatrixViewProperty {
569
+ typedef View self_t;
570
+ static const bool anchor = true;
571
+ static const bool viewless = false;
572
+ static const bool transposed = false;
573
+ static const bool conjugated = false;
574
+ static const bool offset = false;
575
+ static const bool variable_size = false;
576
+
577
+ static const char *name;
578
+
579
+ struct inspect_t {
580
+ template<class CharT, class Traits>
581
+ friend std::basic_ostream<CharT, Traits> &operator<<(
582
+ std::basic_ostream<CharT, Traits> &out, const inspect_t &){
583
+ return out << name;
584
+ }
585
+ };
586
+ static inspect_t inspect(){return inspect_t();}
587
+ };
588
+ template <class View>
589
+ const char *MatrixViewProperty<View>::name = "";
590
+
591
+ template <class V1, template <class> class V2>
592
+ struct MatrixViewProperty<V2<V1> > {
593
+ typedef V2<V1> self_t;
594
+ static const bool anchor = false;
595
+
596
+ template <template <class> class TargetView>
597
+ struct check_of_t {
598
+ template <template <class> class T, class U = void>
599
+ struct check_t {
600
+ template <bool is_next_anchor, class U2 = void>
601
+ struct next_t {
602
+ static const bool res = MatrixViewProperty<V1>::template check_of_t<TargetView>::res;
603
+ };
604
+ template <class U2>
605
+ struct next_t<true, U2> {
606
+ static const bool res = false;
607
+ };
608
+ static const bool res = next_t<MatrixViewProperty<V1>::anchor>::res;
609
+ };
610
+ template <class U>
611
+ struct check_t<TargetView, U> {
612
+ static const bool res = true;
613
+ };
614
+ static const bool res = check_t<V2>::res;
615
+ };
616
+
617
+ static const bool viewless = MatrixViewProperty<V2<void> >::template check_of_t<MatrixViewBase>::res;
618
+ static const bool transposed = check_of_t<MatrixViewTranspose>::res;
619
+ static const bool conjugated = check_of_t<MatrixViewConjugate>::res;
620
+ static const bool offset = check_of_t<MatrixViewOffset>::res;
621
+ static const bool variable_size = check_of_t<MatrixViewSizeVariable>::res;
622
+
623
+ static const char *name;
624
+
625
+ struct inspect_t {
626
+ template<class CharT, class Traits>
627
+ friend std::basic_ostream<CharT, Traits> &operator<<(
628
+ std::basic_ostream<CharT, Traits> &out, const inspect_t &){
629
+ if(MatrixViewProperty<V1>::anchor){
630
+ return out << name;
631
+ }else{
632
+ return out << name << " " << MatrixViewProperty<V1>::inspect();
633
+ }
634
+ }
635
+ };
636
+ static inspect_t inspect(){return inspect_t();}
637
+ };
638
+ template <class V1, template <class> class V2>
639
+ const char *MatrixViewProperty<V2<V1> >::name = V2<MatrixViewBase<> >::name;
640
+
641
+ template <class View>
642
+ struct MatrixViewBuilder {
643
+ typedef MatrixViewProperty<View> property_t;
644
+
645
+ template <template <class> class V, class U = void>
646
+ struct priority_t {
647
+ static const int priority = -1;
648
+ };
649
+ enum {
650
+ Offset = 0,
651
+ Loop = Offset,
652
+ SizeVariable,
653
+ Transpose,
654
+ Conjugate,
655
+ };
656
+ #define make_priority_table(name) \
657
+ template <class U> \
658
+ struct priority_t<MatrixView ## name, U> { \
659
+ static const int priority = name; \
660
+ }
661
+ make_priority_table(Offset);
662
+ make_priority_table(Loop);
663
+ make_priority_table(SizeVariable);
664
+ make_priority_table(Transpose);
665
+ make_priority_table(Conjugate);
666
+ #undef make_priority_table
667
+
668
+ template <template <class> class AddView, class BaseView = View>
669
+ struct add_t {
670
+ /* Add view in accordance with view priority
671
+ * The first rule is that higher priority view is outer, lower one is inner.
672
+ * The second rule is if two views have a same priority, then original oredr is kept.
673
+ * For example;
674
+ * Adding "2-C" to "3 <2-A <2-B <1 <0> > > >" yields "3 <2-C <2-A <2-B <1 <0> > > > >"
675
+ */
676
+ typedef AddView<BaseView> res_t;
677
+ };
678
+ template <template <class> class V1, template <class> class V2, class V3>
679
+ struct add_t<V1, V2<V3> > {
680
+ template <bool is_V1_has_higher_priority, class U = void>
681
+ struct rebuild_t {
682
+ typedef V1<typename add_t<V2, V3>::res_t> res_t;
683
+ };
684
+ template <class U>
685
+ struct rebuild_t<false, U> {
686
+ typedef V2<typename add_t<V1, V3>::res_t> res_t;
687
+ };
688
+ typedef typename rebuild_t<
689
+ (priority_t<V1>::priority >= priority_t<V2>::priority)>::res_t res_t;
690
+ };
691
+
692
+ template <template <class> class RemoveView>
693
+ struct remove_t {
694
+ template <class V>
695
+ struct rebuild_t {
696
+ template <class V1>
697
+ struct check_t {
698
+ typedef V1 res_t;
699
+ };
700
+ template <class V1, template <class> class V2>
701
+ struct check_t<V2<V1> > {
702
+ typedef V2<typename rebuild_t<V1>::res_t> res_t;
703
+ };
704
+ typedef typename check_t<V>::res_t res_t;
705
+ };
706
+ template <class V>
707
+ struct rebuild_t<RemoveView<V> > {
708
+ typedef typename rebuild_t<V>::res_t res_t;
709
+ };
710
+ typedef typename rebuild_t<View>::res_t res_t;
711
+ };
712
+
713
+ template <template <class> class SwitchView>
714
+ struct switch_t { // off => on => off => ...
715
+ template <class V>
716
+ struct rebuild_t {
717
+ typedef V res_t;
718
+ };
719
+ template <class V1, template <class> class V2>
720
+ struct rebuild_t<V2<V1> > {
721
+ typedef V2<typename rebuild_t<V1>::res_t> res_t;
722
+ };
723
+ template <class V>
724
+ struct rebuild_t<SwitchView<SwitchView<V> > > {
725
+ typedef typename rebuild_t<V>::res_t res_t;
726
+ };
727
+ typedef typename rebuild_t<typename add_t<SwitchView>::res_t>::res_t res_t;
728
+ };
729
+
730
+ template <template <class> class UniqueView>
731
+ struct unique_t { // off => on => on => ...
732
+ typedef typename MatrixViewBuilder<
733
+ typename remove_t<UniqueView>::res_t> // remove all UniqueViews, then add an UniqueView
734
+ ::template add_t<UniqueView>::res_t res_t;
735
+ };
736
+
737
+ template <template <class> class GroupView>
738
+ struct group_t {
739
+ /* If GroupViews are consecutive, then summarize them into one;
740
+ * if no GroupViews, just add it
741
+ */
742
+ template <class V>
743
+ struct rebuild_t {
744
+ typedef V res_t;
745
+ };
746
+ template <class V1, template <class> class V2>
747
+ struct rebuild_t<V2<V1> > {
748
+ typedef V2<typename rebuild_t<V1>::res_t> res_t;
749
+ };
750
+ template <class V>
751
+ struct rebuild_t<GroupView<GroupView<V> > > {
752
+ typedef typename rebuild_t<GroupView<V> >::res_t res_t;
753
+ };
754
+ typedef typename rebuild_t<typename add_t<GroupView>::res_t>::res_t res_t;
755
+ };
756
+
757
+ typedef typename switch_t<MatrixViewTranspose>::res_t transpose_t;
758
+ typedef typename switch_t<MatrixViewConjugate>::res_t conjugate_t;
759
+ typedef typename group_t<MatrixViewOffset>::res_t offset_t;
760
+ typedef typename unique_t<MatrixViewSizeVariable>::res_t size_variable_t;
761
+ typedef typename group_t<MatrixViewLoop>::res_t loop_t;
762
+
763
+ struct reverse_op_t {
764
+ template <class V1, class V2>
765
+ struct rebuild_t {
766
+ typedef V2 res_t;
767
+ };
768
+ template <template <class> class V1, class V2, class V3>
769
+ struct rebuild_t<V1<V2>, V3> {
770
+ typedef typename rebuild_t<V2, V1<V3> >::res_t res_t;
771
+ };
772
+ typedef typename rebuild_t<View, void>::res_t res_t;
773
+ };
774
+ typedef typename reverse_op_t::res_t reverse_t;
775
+
776
+ /**
777
+ * Calculate view to which another view is applied
778
+ * For example, current = [Transpose(2)] [Offset(0)],
779
+ * and applied = [Transpose(2)] [VariableSize(1)],
780
+ * then intermediate = [Transpose(2)] [Transpose(2)] [VariableSize(1)] [Offset(0)],
781
+ * and finally, result = [VariableSize(1)] [Offset(0)].
782
+ * Here, each view elements are applied in accordance with their characteristics.
783
+ * @param SrcView view to be applied to current view
784
+ */
785
+ template <class SrcView>
786
+ struct apply_t {
787
+ template <class SrcView_Reverse, class DestView>
788
+ struct next_t {
789
+ typedef DestView res_t;
790
+ };
791
+ template <template <class> class V1, class V2, class DestView>
792
+ struct next_t<V1<V2>, DestView> {
793
+ typedef typename next_t<V2, DestView>::res_t res_t;
794
+ };
795
+ #define make_entry(view_name, result_type) \
796
+ template <class V, class DestView> \
797
+ struct next_t<view_name<V>, DestView> { \
798
+ typedef typename next_t<V, typename MatrixViewBuilder<DestView>::result_type>::res_t res_t; \
799
+ };
800
+ make_entry(MatrixViewTranspose, transpose_t);
801
+ make_entry(MatrixViewConjugate, conjugate_t);
802
+ make_entry(MatrixViewOffset, offset_t);
803
+ make_entry(MatrixViewSizeVariable, size_variable_t);
804
+ make_entry(MatrixViewLoop, loop_t);
805
+ #undef make_entry
806
+ typedef typename next_t<typename MatrixViewBuilder<SrcView>::reverse_t, View>::res_t res_t;
807
+ };
808
+
809
+ template <
810
+ class DestView, class DestView_Reverse,
811
+ class SrcView, class SrcView_Reverse>
812
+ struct copy_t {
813
+ template <class DestR = DestView_Reverse, class SrcR = SrcView_Reverse>
814
+ struct downcast_copy_t {
815
+ static void run(DestView *dest, const SrcView *src){}
816
+ };
817
+ template <
818
+ template <class> class Dest_Src_R1,
819
+ class DestR2, class SrcR2>
820
+ struct downcast_copy_t<Dest_Src_R1<DestR2>, Dest_Src_R1<SrcR2> > {
821
+ // catch if same views exist at the same stack level in both source and destination
822
+ static void run(DestView *dest, const SrcView *src){
823
+ std::memcpy(
824
+ &static_cast<Dest_Src_R1<DestView> *>(dest)->prop,
825
+ &static_cast<const Dest_Src_R1<SrcView> *>(src)->prop,
826
+ sizeof(static_cast<Dest_Src_R1<DestView> *>(dest)->prop));
827
+ copy_t<
828
+ Dest_Src_R1<DestView>, DestR2,
829
+ Dest_Src_R1<SrcView>, SrcR2>::run(
830
+ static_cast<Dest_Src_R1<DestView> *>(dest),
831
+ static_cast<const Dest_Src_R1<SrcView> *>(src));
832
+ }
833
+ };
834
+ template <
835
+ template <class> class DestR1, class DestR2,
836
+ template <class> class SrcR1, class SrcR2>
837
+ struct downcast_copy_t<DestR1<DestR2>, SrcR1<SrcR2> > {
838
+ template<
839
+ bool is_DestR1_higher = (priority_t<DestR1>::priority > priority_t<SrcR1>::priority),
840
+ bool is_DestR1_lower = (priority_t<DestR1>::priority < priority_t<SrcR1>::priority)>
841
+ struct next_t { // catch srcR1.priority == destR1.priority
842
+ typedef DestR1<DestView> dest_t;
843
+ typedef DestR2 dest_R_t;
844
+ typedef SrcR1<SrcView> src_t;
845
+ typedef SrcR2 src_R_t;
846
+ };
847
+ template<bool is_DestR1_lower>
848
+ struct next_t<true, is_DestR1_lower> { // catch destR1.priority > srcR1.priority
849
+ typedef DestView dest_t;
850
+ typedef DestR1<DestR2> dest_R_t;
851
+ typedef SrcR1<SrcView> src_t;
852
+ typedef SrcR2 src_R_t;
853
+ };
854
+ template<bool is_DestR1_higher>
855
+ struct next_t<is_DestR1_higher, true> { // catch destR1.priority < srcR1.priority
856
+ typedef DestR1<DestView> dest_t;
857
+ typedef DestR2 dest_R_t;
858
+ typedef SrcView src_t;
859
+ typedef SrcR1<SrcR2> src_R_t;
860
+ };
861
+ static void run(DestView *dest, const SrcView *src){
862
+ copy_t<
863
+ typename next_t<>::dest_t, typename next_t<>::dest_R_t,
864
+ typename next_t<>::src_t, typename next_t<>::src_R_t>::run(
865
+ static_cast<typename next_t<>::dest_t *>(dest),
866
+ static_cast<const typename next_t<>::src_t *>(src));
867
+ }
868
+ };
869
+ static void run(DestView *dest, const SrcView *src){
870
+ downcast_copy_t<>::run(dest, src);
871
+ }
872
+ };
873
+
874
+ /**
875
+ * Copy views as much as possible even if source and destination views are different.
876
+ * As the primary rule, the copy is performed from a lower view,
877
+ * which means a nearer component from MatrixViewBase, to higher one.
878
+ * The secondary rule is if both source and destination views have same component,
879
+ * its property such as offset is copied, otherwise copy is skipped.
880
+ *
881
+ * For example, destination = [Transpose(2)] [VariableSize(1)] [Offset(0)], and
882
+ * source = [Transpose(2)] [Offset(0)], then only properties of transpose and offset
883
+ * are copied.
884
+ *
885
+ * @param dest Destination view
886
+ * @param src Source view
887
+ */
888
+ template <class View2>
889
+ static void copy(View &dest, const View2 &src){
890
+ copy_t<
891
+ void, reverse_t,
892
+ void, typename MatrixViewBuilder<View2>::reverse_t>::run(&dest, &src);
893
+ }
894
+ };
895
+
896
+ template <class BaseView>
897
+ struct MatrixViewTranspose : public BaseView {
898
+ typedef MatrixViewTranspose<BaseView> self_t;
899
+
900
+ struct {} prop;
901
+
902
+ MatrixViewTranspose() : BaseView() {}
903
+ MatrixViewTranspose(const self_t &view)
904
+ : BaseView((const BaseView &)view) {}
905
+
906
+ template <class View>
907
+ friend struct MatrixViewBuilder;
908
+
909
+ static const char *name;
910
+
911
+ template<class CharT, class Traits>
912
+ friend std::basic_ostream<CharT, Traits> &operator<<(
913
+ std::basic_ostream<CharT, Traits> &out, const MatrixViewTranspose<BaseView> &view){
914
+ return out << name << " " << (const BaseView &)view;
915
+ }
916
+
917
+ inline const unsigned int rows(
918
+ const unsigned int &_rows, const unsigned int &_columns) const noexcept {
919
+ return BaseView::columns(_rows, _columns);
920
+ }
921
+ inline const unsigned int columns(
922
+ const unsigned int &_rows, const unsigned int &_columns) const noexcept {
923
+ return BaseView::rows(_rows, _columns);
924
+ }
925
+ template <class T, class Array2D_Type>
926
+ inline T operator()(
927
+ Array2D_Type &storage, const unsigned int &i, const unsigned int &j) const {
928
+ return BaseView::DELETE_IF_MSC(template) operator()<T, Array2D_Type>(storage, j, i);
929
+ }
930
+
931
+ void update_size(const unsigned int &rows, const unsigned int &columns){
932
+ BaseView::update_size(columns, rows);
933
+ }
934
+ void update_offset(const unsigned int &row, const unsigned int &column){
935
+ BaseView::update_offset(column, row);
936
+ }
937
+ void update_loop(const unsigned int &rows, const unsigned int &columns){
938
+ BaseView::update_loop(columns, rows);
939
+ }
940
+ };
941
+ template <class BaseView>
942
+ const char *MatrixViewTranspose<BaseView>::name = "[T]";
943
+
944
+ template <class BaseView>
945
+ struct MatrixViewConjugate : public BaseView {
946
+ typedef MatrixViewConjugate<BaseView> self_t;
947
+
948
+ struct {} prop;
949
+
950
+ MatrixViewConjugate() : BaseView() {}
951
+ MatrixViewConjugate(const self_t &view)
952
+ : BaseView((const BaseView &)view) {}
953
+
954
+ template <class View>
955
+ friend struct MatrixViewBuilder;
956
+
957
+ static const char *name;
958
+
959
+ template<class CharT, class Traits>
960
+ friend std::basic_ostream<CharT, Traits> &operator<<(
961
+ std::basic_ostream<CharT, Traits> &out, const MatrixViewConjugate<BaseView> &view){
962
+ return out << name << " " << (const BaseView &)view;
963
+ }
964
+
965
+ template <class T, class Array2D_Type>
966
+ inline T operator()(
967
+ Array2D_Type &storage, const unsigned int &i, const unsigned int &j) const {
968
+ return BaseView::DELETE_IF_MSC(template) operator()<T, Array2D_Type>(storage, i, j).conjugate();
969
+ }
970
+ };
971
+ template <class BaseView>
972
+ const char *MatrixViewConjugate<BaseView>::name = "[~]";
973
+
974
+ template <class BaseView>
975
+ struct MatrixViewOffset : public BaseView {
976
+ typedef MatrixViewOffset<BaseView> self_t;
977
+
978
+ struct {
979
+ unsigned int row, column;
980
+ } prop;
981
+
982
+ MatrixViewOffset() : BaseView() {
983
+ prop.row = prop.column = 0;
984
+ }
985
+ MatrixViewOffset(const self_t &view)
986
+ : BaseView((const BaseView &)view), prop(view.prop) {
987
+ }
988
+
989
+ template <class View>
990
+ friend struct MatrixViewBuilder;
991
+
992
+ static const char *name;
993
+
994
+ template<class CharT, class Traits>
995
+ friend std::basic_ostream<CharT, Traits> &operator<<(
996
+ std::basic_ostream<CharT, Traits> &out, const MatrixViewOffset<BaseView> &view){
997
+ return out << name << "("
998
+ << view.prop.row << ","
999
+ << view.prop.column << ") "
1000
+ << (const BaseView &)view;
1001
+ }
1002
+
1003
+ template <class T, class Array2D_Type>
1004
+ inline T operator()(
1005
+ Array2D_Type &storage, const unsigned int &i, const unsigned int &j) const {
1006
+ return BaseView::DELETE_IF_MSC(template) operator()<T, Array2D_Type>(
1007
+ storage, i + prop.row, j + prop.column);
1008
+ }
1009
+
1010
+ void update_offset(const unsigned int &row, const unsigned int &column){
1011
+ prop.row += row;
1012
+ prop.column += column;
1013
+ }
1014
+ };
1015
+ template <class BaseView>
1016
+ const char *MatrixViewOffset<BaseView>::name = "[Offset]";
1017
+
1018
+ template <class BaseView>
1019
+ struct MatrixViewSizeVariable : public BaseView {
1020
+ typedef MatrixViewSizeVariable<BaseView> self_t;
1021
+
1022
+ struct {
1023
+ unsigned int rows, columns;
1024
+ } prop;
1025
+
1026
+ MatrixViewSizeVariable() : BaseView() {
1027
+ prop.rows = prop.columns = 0;
1028
+ }
1029
+ MatrixViewSizeVariable(const self_t &view)
1030
+ : BaseView((const BaseView &)view), prop(view.prop) {
1031
+ }
1032
+
1033
+ template <class View>
1034
+ friend struct MatrixViewBuilder;
1035
+
1036
+ static const char *name;
1037
+
1038
+ template<class CharT, class Traits>
1039
+ friend std::basic_ostream<CharT, Traits> &operator<<(
1040
+ std::basic_ostream<CharT, Traits> &out, const MatrixViewSizeVariable<BaseView> &view){
1041
+ return out << name << "("
1042
+ << view.prop.rows << ","
1043
+ << view.prop.columns << ") "
1044
+ << (const BaseView &)view;
1045
+ }
1046
+
1047
+ inline const unsigned int rows(
1048
+ const unsigned int &_rows, const unsigned int &_columns) const noexcept {
1049
+ return prop.rows;
1050
+ }
1051
+ inline const unsigned int columns(
1052
+ const unsigned int &_rows, const unsigned int &_columns) const noexcept {
1053
+ return prop.columns;
1054
+ }
1055
+
1056
+ void update_size(const unsigned int &rows, const unsigned int &columns){
1057
+ prop.rows = rows;
1058
+ prop.columns = columns;
1059
+ }
1060
+ };
1061
+ template <class BaseView>
1062
+ const char *MatrixViewSizeVariable<BaseView>::name = "[Size]";
1063
+
1064
+ template <class BaseView>
1065
+ struct MatrixViewLoop : public BaseView {
1066
+ typedef MatrixViewLoop<BaseView> self_t;
1067
+
1068
+ struct {
1069
+ unsigned int rows, columns;
1070
+ } prop;
1071
+
1072
+ MatrixViewLoop() : BaseView() {
1073
+ prop.rows = prop.columns = 0;
1074
+ }
1075
+ MatrixViewLoop(const self_t &view)
1076
+ : BaseView((const BaseView &)view), prop(view.prop) {
1077
+ }
1078
+
1079
+ template <class View>
1080
+ friend struct MatrixViewBuilder;
1081
+
1082
+ static const char *name;
1083
+
1084
+ template<class CharT, class Traits>
1085
+ friend std::basic_ostream<CharT, Traits> &operator<<(
1086
+ std::basic_ostream<CharT, Traits> &out, const MatrixViewLoop<BaseView> &view){
1087
+ return out << name << "("
1088
+ << view.prop.rows << ","
1089
+ << view.prop.columns << ") "
1090
+ << (const BaseView &)view;
1091
+ }
1092
+
1093
+ template <class T, class Array2D_Type>
1094
+ inline T operator()(
1095
+ Array2D_Type &storage, const unsigned int &i, const unsigned int &j) const {
1096
+ return BaseView::DELETE_IF_MSC(template) operator()<T, Array2D_Type>(
1097
+ storage, i % prop.rows, j % prop.columns);
1098
+ }
1099
+
1100
+ void update_loop(const unsigned int &rows, const unsigned int &columns){
1101
+ prop.rows = rows;
1102
+ prop.columns = columns;
1103
+ }
1104
+ };
1105
+ template <class BaseView>
1106
+ const char *MatrixViewLoop<BaseView>::name = "[Loop]";
1107
+
1108
+
1109
+ template <
1110
+ class T,
1111
+ class Array2D_Type = Array2D_Dense<T>,
1112
+ class ViewType = MatrixViewBase<> >
1113
+ class Matrix;
1114
+
1115
+ template <class MatrixT>
1116
+ struct MatrixBuilder_ViewTransformerBase;
1117
+
1118
+ template <
1119
+ template <class, class, class> class MatrixT,
1120
+ class T, class Array2D_Type, class ViewType>
1121
+ struct MatrixBuilder_ViewTransformerBase<
1122
+ MatrixT<T, Array2D_Type, ViewType> > {
1123
+ typedef MatrixViewBuilder<ViewType> view_builder_t;
1124
+
1125
+ typedef MatrixT<T, Array2D_Type,
1126
+ typename view_builder_t::transpose_t> transpose_t;
1127
+ typedef MatrixT<T, Array2D_Type,
1128
+ typename view_builder_t::size_variable_t> partial_offsetless_t;
1129
+ typedef MatrixT<T, Array2D_Type,
1130
+ typename MatrixViewBuilder<
1131
+ typename view_builder_t::offset_t>::size_variable_t> partial_t;
1132
+ typedef MatrixT<T, Array2D_Type,
1133
+ typename MatrixViewBuilder<
1134
+ typename view_builder_t::loop_t>::offset_t> circular_bijective_t;
1135
+ typedef MatrixT<T, Array2D_Type,
1136
+ typename MatrixViewBuilder<
1137
+ typename MatrixViewBuilder<
1138
+ typename view_builder_t::loop_t>::offset_t>::size_variable_t> circular_t;
1139
+
1140
+ template <class T2 = T>
1141
+ struct check_complex_t {
1142
+ typedef MatrixT<T, Array2D_Type, ViewType> conjugate_t;
1143
+ };
1144
+ template <class T2>
1145
+ struct check_complex_t<Complex<T2> > {
1146
+ typedef MatrixT<T, Array2D_Type, typename view_builder_t::conjugate_t> conjugate_t;
1147
+ };
1148
+ typedef typename check_complex_t<>::conjugate_t conjugate_t;
1149
+
1150
+ template <class ViewType2>
1151
+ struct view_replace_t {
1152
+ typedef MatrixT<T, Array2D_Type, ViewType2> replaced_t;
1153
+ };
1154
+ template <class ViewType2>
1155
+ struct view_apply_t {
1156
+ typedef MatrixT<T, Array2D_Type,
1157
+ typename view_builder_t::template apply_t<ViewType2>::res_t> applied_t;
1158
+ };
1159
+ };
1160
+
1161
+ template <class MatrixT>
1162
+ struct MatrixBuilder_ViewTransformer
1163
+ : public MatrixBuilder_ViewTransformerBase<MatrixT> {};
1164
+
1165
+ template <template <class, class, class> class MatrixT, class T>
1166
+ struct MatrixBuilder_ViewTransformer<MatrixT<T, Array2D_ScaledUnit<T>, MatrixViewBase<> > >
1167
+ : public MatrixBuilder_ViewTransformerBase<
1168
+ MatrixT<T, Array2D_ScaledUnit<T>, MatrixViewBase<> > > {
1169
+ typedef MatrixT<T, Array2D_ScaledUnit<T>, MatrixViewBase<> > transpose_t;
1170
+ };
1171
+
1172
+ template <class MatrixT>
1173
+ struct MatrixBuilder_ValueCopier {
1174
+ template <class T2, class Array2D_Type2, class ViewType2>
1175
+ static Matrix<T2, Array2D_Type2, ViewType2> &copy_value(
1176
+ Matrix<T2, Array2D_Type2, ViewType2> &dest, const MatrixT &src) {
1177
+ const unsigned int i_end(src.rows()), j_end(src.columns());
1178
+ for(unsigned int i(0); i < i_end; ++i){
1179
+ for(unsigned int j(0); j < j_end; ++j){
1180
+ dest(i, j) = (T2)(src(i, j));
1181
+ }
1182
+ }
1183
+ return dest;
1184
+ }
1185
+ };
1186
+
1187
+ template <class MatrixT>
1188
+ struct MatrixBuilder_Dependency;
1189
+
1190
+ template <class MatrixT>
1191
+ struct MatrixBuilderBase
1192
+ : public MatrixBuilder_ViewTransformer<MatrixT>,
1193
+ public MatrixBuilder_ValueCopier<MatrixT>,
1194
+ public MatrixBuilder_Dependency<MatrixT> {};
1195
+
1196
+ template <class MatrixT>
1197
+ struct MatrixBuilder : public MatrixBuilderBase<MatrixT> {};
1198
+
1199
+ template <
1200
+ template <class, class, class> class MatrixT,
1201
+ class T, class Array2D_Type, class ViewType>
1202
+ struct MatrixBuilder_Dependency<MatrixT<T, Array2D_Type, ViewType> > {
1203
+ static const int row_buffer = 0; // unknown
1204
+ static const int column_buffer = 0;
1205
+
1206
+ template <class T2, bool is_writable_array = Array2D_Type::writable>
1207
+ struct assignable_matrix_t {
1208
+ typedef Matrix<T2> res_t;
1209
+ };
1210
+ template <class T2>
1211
+ struct assignable_matrix_t<T2, true> {
1212
+ typedef Matrix<T2, typename Array2D_Type::template cast_t<T2>::res_t> res_t;
1213
+ };
1214
+ typedef typename assignable_matrix_t<T>::res_t assignable_t;
1215
+
1216
+ template <class T2>
1217
+ struct cast_t {
1218
+ typedef typename MatrixBuilder<
1219
+ typename assignable_matrix_t<T2>::res_t>::assignable_t assignable_t;
1220
+ };
1221
+
1222
+ template <int nR_add = 0, int nC_add = 0, int nR_multiply = 1, int nC_multiply = 1>
1223
+ struct resize_t {
1224
+ typedef typename MatrixBuilder_Dependency<MatrixT<T, Array2D_Type, ViewType> >::assignable_t assignable_t;
1225
+ };
1226
+ };
1227
+
1228
+ template <class LHS_MatrixT, class RHS_T>
1229
+ struct Matrix_multiplied_by_Scalar;
1230
+
1231
+ /**
1232
+ * @brief Matrix for unchangeable content
1233
+ *
1234
+ * @see Matrix
1235
+ */
1236
+ template <
1237
+ class T, class Array2D_Type,
1238
+ class ViewType = MatrixViewBase<> >
1239
+ class Matrix_Frozen {
1240
+ public:
1241
+ typedef Array2D_Type storage_t;
1242
+ typedef ViewType view_t;
1243
+ typedef Matrix_Frozen<T, Array2D_Type, ViewType> self_t;
1244
+ typedef self_t frozen_t;
1245
+
1246
+ typedef MatrixBuilder<self_t> builder_t;
1247
+
1248
+ template <class T2, class Array2D_Type2, class ViewType2>
1249
+ friend class Matrix_Frozen;
1250
+
1251
+ template <class T2>
1252
+ static char (&check_storage(Array2D_Frozen<T2> *) )[1];
1253
+ static const int storage_t_should_be_derived_from_Array2D_Frozen
1254
+ = sizeof(check_storage(static_cast<storage_t *>(0)));
1255
+
1256
+ protected:
1257
+ storage_t storage; ///< 2D storage
1258
+ view_t view;
1259
+
1260
+ /**
1261
+ * Constructor without storage.
1262
+ *
1263
+ */
1264
+ Matrix_Frozen() : storage(), view(){}
1265
+
1266
+ /**
1267
+ * Constructor with storage
1268
+ *
1269
+ * @param new_storage new storage
1270
+ */
1271
+ Matrix_Frozen(const storage_t &new_storage)
1272
+ : storage(new_storage),
1273
+ view() {}
1274
+ public:
1275
+ /**
1276
+ * Return row number.
1277
+ *
1278
+ * @return row number.
1279
+ */
1280
+ const unsigned int rows() const noexcept {
1281
+ return view.rows(storage.rows(), storage.columns());
1282
+ }
1283
+
1284
+ /**
1285
+ * Return column number.
1286
+ *
1287
+ * @return column number.
1288
+ */
1289
+ const unsigned int columns() const noexcept {
1290
+ return view.columns(storage.rows(), storage.columns());
1291
+ }
1292
+
1293
+ /**
1294
+ * Return matrix element of specified indices.
1295
+ *
1296
+ * @param row Row index starting from 0.
1297
+ * @param column Column index starting from 0.
1298
+ * @return element
1299
+ */
1300
+ T operator()(
1301
+ const unsigned int &row,
1302
+ const unsigned int &column) const {
1303
+ // T and Array2D_Type::content_t are not always identical,
1304
+ // for example, T = Complex<double>, Array2D_Type::content_t = double
1305
+ return (T)(view.DELETE_IF_MSC(template) operator()<
1306
+ typename Array2D_Type::content_t, const Array2D_Type>(storage, row, column));
1307
+ }
1308
+
1309
+ template <class impl_t>
1310
+ class iterator_base_t {
1311
+ public:
1312
+ typedef impl_t self_type;
1313
+ typedef int difference_type;
1314
+ typedef std::random_access_iterator_tag iterator_category;
1315
+ protected:
1316
+ difference_type idx;
1317
+ unsigned int row(const self_t &mat) const {
1318
+ return (mat.columns() > 0) ? (idx / mat.columns()) : 0;
1319
+ }
1320
+ unsigned int column(const self_t &mat) const {
1321
+ return (mat.columns() > 0) ? (idx % mat.columns()) : idx;
1322
+ }
1323
+ public:
1324
+ // @see http://www.cplusplus.com/reference/iterator/
1325
+ // required for input iterator
1326
+ iterator_base_t(const difference_type &idx_ = 0) : idx(idx_) {}
1327
+ self_type &operator++() {++idx; return static_cast<self_type &>(*this);}
1328
+ self_type operator++(int) {self_type res(static_cast<self_type &>(*this)); ++idx; return res;}
1329
+ friend bool operator==(const self_type &lhs, const self_type &rhs) {
1330
+ return lhs.idx == rhs.idx;
1331
+ }
1332
+ friend bool operator!=(const self_type &lhs, const self_type &rhs) {return !(lhs == rhs);}
1333
+
1334
+ // required for forward iterator
1335
+ //iterator_t() : mat(), idx(0) {}
1336
+
1337
+ // required for bidirectional iterator
1338
+ self_type &operator--() {--idx; return static_cast<self_type &>(*this);}
1339
+ self_type operator--(int) {self_type res(static_cast<self_type &>(*this)); --idx; return res;}
1340
+
1341
+ // required for random access iterator
1342
+ friend bool operator<(const self_type &lhs, const self_type &rhs){
1343
+ return lhs.idx < rhs.idx;
1344
+ }
1345
+ friend bool operator>(const self_type &lhs, const self_type &rhs){
1346
+ return !((lhs < rhs) || (lhs == rhs));
1347
+ }
1348
+ friend bool operator<=(const self_type &lhs, const self_type &rhs){
1349
+ return !(lhs > rhs);
1350
+ }
1351
+ friend bool operator>=(const self_type &lhs, const self_type &rhs){
1352
+ return !(lhs < rhs);
1353
+ }
1354
+
1355
+ // required for random access iterator
1356
+ self_type &operator+=(const difference_type &n){
1357
+ idx += n;
1358
+ return static_cast<self_type &>(*this);
1359
+ }
1360
+ friend self_type operator+(const self_type &lhs, const difference_type &n){
1361
+ return self_type(lhs) += n;
1362
+ }
1363
+ friend self_type operator+(const difference_type &n, const self_type &rhs){
1364
+ return rhs + n;
1365
+ }
1366
+ self_type &operator-=(const difference_type &n){
1367
+ return operator+=(-n);
1368
+ }
1369
+ friend self_type operator-(const self_type &lhs, const difference_type &n){
1370
+ return lhs + (-n);
1371
+ }
1372
+ friend self_type operator-(const difference_type &n, const self_type &rhs){
1373
+ return rhs - n;
1374
+ }
1375
+ friend difference_type operator-(const self_type &lhs, const self_type &rhs){
1376
+ return lhs.idx - rhs.idx;
1377
+ }
1378
+ };
1379
+
1380
+ class const_iterator : public iterator_base_t<const_iterator> {
1381
+ public:
1382
+ typedef const T value_type;
1383
+ typedef const T& reference;
1384
+ typedef const T* pointer;
1385
+ protected:
1386
+ typedef iterator_base_t<const_iterator> base_t;
1387
+ self_t mat;
1388
+ mutable T tmp;
1389
+ public:
1390
+ unsigned int row() const {return base_t::row(mat);}
1391
+ unsigned int column() const {return base_t::column(mat);}
1392
+ reference operator*() const {
1393
+ std::div_t rc(std::div(base_t::idx, mat.columns()));
1394
+ return tmp = mat((unsigned int)rc.quot, (unsigned int)rc.rem);
1395
+ }
1396
+ pointer operator->() const {
1397
+ return &(operator*());
1398
+ }
1399
+ const_iterator(const self_t &mat_, const typename base_t::difference_type &idx_ = 0)
1400
+ : base_t(idx_), mat(mat_), tmp() {}
1401
+ const_iterator()
1402
+ : base_t(), mat(), tmp() {}
1403
+ reference operator[](const typename base_t::difference_type &n) const {
1404
+ return tmp = *((*this) + n);
1405
+ }
1406
+ };
1407
+ const_iterator begin() const {return const_iterator(*this);}
1408
+ const_iterator end() const {return const_iterator(*this, rows() * columns());}
1409
+
1410
+ /**
1411
+ * Copy constructor generating shallow copy linking to source matrix
1412
+ *
1413
+ * @param another source matrix
1414
+ */
1415
+ Matrix_Frozen(const self_t &another)
1416
+ : storage(another.storage),
1417
+ view(another.view){}
1418
+
1419
+ /**
1420
+ * Constructor with different storage type
1421
+ */
1422
+ template <class T2, class Array2D_Type2>
1423
+ Matrix_Frozen(const Matrix_Frozen<T2, Array2D_Type2, ViewType> &matrix)
1424
+ : storage(matrix.storage),
1425
+ view(matrix.view) {}
1426
+ protected:
1427
+ /**
1428
+ * Constructor with different view
1429
+ */
1430
+ template <class ViewType2>
1431
+ Matrix_Frozen(const Matrix_Frozen<T, Array2D_Type, ViewType2> &matrix)
1432
+ : storage(matrix.storage),
1433
+ view() {
1434
+ builder_t::view_builder_t::copy(view, matrix.view);
1435
+ }
1436
+
1437
+ public:
1438
+ /**
1439
+ * Destructor
1440
+ */
1441
+ virtual ~Matrix_Frozen(){}
1442
+
1443
+ typedef Matrix_Frozen<T, Array2D_ScaledUnit<T> > scalar_matrix_t;
1444
+
1445
+ /**
1446
+ * Generate scalar matrix
1447
+ *
1448
+ * @param size Row and column number
1449
+ * @param scalar
1450
+ */
1451
+ static scalar_matrix_t getScalar(const unsigned int &size, const T &scalar){
1452
+ return scalar_matrix_t(typename scalar_matrix_t::storage_t(size, scalar));
1453
+ }
1454
+
1455
+ /**
1456
+ * Generate unit matrix
1457
+ *
1458
+ * @param size Row and column number
1459
+ */
1460
+ static scalar_matrix_t getI(const unsigned int &size){
1461
+ return getScalar(size, T(1));
1462
+ }
1463
+
1464
+ /**
1465
+ * Down cast by creating deep (totally unlinked to this) copy having changeable content
1466
+ *
1467
+ */
1468
+ operator typename builder_t::assignable_t() const {
1469
+ typedef typename builder_t::assignable_t res_t;
1470
+ res_t res(res_t::blank(rows(), columns()));
1471
+ builder_t::copy_value(res, *this);
1472
+ return res;
1473
+ }
1474
+
1475
+ protected:
1476
+ /**
1477
+ * Assigner for subclass to modify storage and view
1478
+ * Its copy storategy is deoendent on storage assigner implementation.
1479
+ */
1480
+ self_t &operator=(const self_t &another){
1481
+ if(this != &another){
1482
+ storage = another.storage;
1483
+ view = another.view;
1484
+ }
1485
+ return *this;
1486
+ }
1487
+ /**
1488
+ * Assigner for subclass to modify storage and view with different storage type
1489
+ * Its copy storategy is deoendent on storage assigner implementation.
1490
+ */
1491
+ template <class T2, class Array2D_Type2>
1492
+ self_t &operator=(const Matrix_Frozen<T2, Array2D_Type2, ViewType> &matrix){
1493
+ storage = matrix.storage;
1494
+ view = matrix.view;
1495
+ return *this;
1496
+ }
1497
+
1498
+ public:
1499
+ /**
1500
+ * Test whether elements are identical
1501
+ *
1502
+ * @param matrix Matrix to be compared
1503
+ * @return true when elements of two matrices are identical, otherwise false.
1504
+ */
1505
+ template <
1506
+ class T2, class Array2D_Type2,
1507
+ class ViewType2>
1508
+ bool operator==(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const noexcept {
1509
+ if(static_cast<const void *>(this) == static_cast<const void *>(&matrix)){return true;}
1510
+ if((rows() != matrix.rows())
1511
+ || columns() != matrix.columns()){
1512
+ return false;
1513
+ }
1514
+ const unsigned int i_end(rows()), j_end(columns());
1515
+ for(unsigned int i(0); i < i_end; i++){
1516
+ for(unsigned int j(0); j < j_end; j++){
1517
+ if((*this)(i, j) != matrix(i, j)){
1518
+ return false;
1519
+ }
1520
+ }
1521
+ }
1522
+ return true;
1523
+ }
1524
+
1525
+ template <
1526
+ class T2, class Array2D_Type2,
1527
+ class ViewType2>
1528
+ bool operator!=(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const noexcept {
1529
+ return !(operator==(matrix));
1530
+ }
1531
+
1532
+ /**
1533
+ * Test whether matrix is square
1534
+ *
1535
+ * @return true when square, otherwise false.
1536
+ */
1537
+ bool isSquare() const noexcept {return rows() == columns();}
1538
+
1539
+ /**
1540
+ * Test whether matrix is diagonal
1541
+ *
1542
+ * @return true when diagonal, otherwise false.
1543
+ */
1544
+ bool isDiagonal() const noexcept {
1545
+ if(isSquare()){
1546
+ const unsigned int i_end(rows()), j_end(columns());
1547
+ for(unsigned int i(0); i < i_end; i++){
1548
+ for(unsigned int j(i + 1); j < j_end; j++){
1549
+ if(((*this)(i, j) != T(0)) || ((*this)(j, i) != T(0))){
1550
+ return false;
1551
+ }
1552
+ }
1553
+ }
1554
+ return true;
1555
+ }else{return false;}
1556
+ }
1557
+
1558
+ /**
1559
+ * Test whether matrix is symmetric
1560
+ *
1561
+ * @return true when symmetric, otherwise false.
1562
+ */
1563
+ bool isSymmetric() const noexcept {
1564
+ if(isSquare()){
1565
+ const unsigned int i_end(rows()), j_end(columns());
1566
+ for(unsigned int i(0); i < i_end; i++){
1567
+ for(unsigned int j(i + 1); j < j_end; j++){
1568
+ if((*this)(i, j) != (*this)(j, i)){return false;}
1569
+ }
1570
+ }
1571
+ return true;
1572
+ }else{return false;}
1573
+ }
1574
+
1575
+ /**
1576
+ * Test whether size of matrices is different
1577
+ *
1578
+ * @param matrix Matrix to be compared
1579
+ * @return true when size different, otherwise false.
1580
+ */
1581
+ template <class T2, class Array2D_Type2, class ViewType2>
1582
+ bool isDifferentSize(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const noexcept {
1583
+ return (rows() != matrix.rows()) || (columns() != matrix.columns());
1584
+ }
1585
+
1586
+ /**
1587
+ * Return trace of matrix
1588
+ *
1589
+ * @param do_check Check matrix size property. The default is true
1590
+ * @return Trace
1591
+ * @throw std::logic_error When matrix is not square
1592
+ */
1593
+ T trace(const bool &do_check = true) const {
1594
+ if(do_check && !isSquare()){throw std::logic_error("rows != columns");}
1595
+ T tr(0);
1596
+ for(unsigned i(0), i_end(rows()); i < i_end; i++){
1597
+ tr += (*this)(i, i);
1598
+ }
1599
+ return tr;
1600
+ }
1601
+
1602
+ /**
1603
+ * Return sum of matrix elements
1604
+ *
1605
+ * @return Summation
1606
+ */
1607
+ T sum() const noexcept {
1608
+ T sum(0);
1609
+ for(unsigned int i(0), i_end(rows()); i < i_end; i++){
1610
+ for(unsigned int j(0), j_end(columns()); j < j_end; j++){
1611
+ sum += (*this)(i, j);
1612
+ }
1613
+ }
1614
+ return sum;
1615
+ }
1616
+
1617
+ /**
1618
+ * Test whether matrix is LU decomposed.
1619
+ * The assumption of elements is
1620
+ * (0, 0)-(n-1, n-1): L matrix
1621
+ * (0, n)-(n-1, 2n-1): U matrix
1622
+ *
1623
+ * @return true when LU, otherwise false.
1624
+ */
1625
+ bool isLU() const noexcept {
1626
+ if(rows() * 2 != columns()){return false;}
1627
+ const unsigned int i_end(rows() - 1), j_end(rows());
1628
+ for(unsigned int i(0), i_U(rows()); i < i_end; i++, i_U++){
1629
+ for(unsigned int j(i + 1); j < j_end; j++){
1630
+ if((*this)(i, j) != T(0)){return false;} // check L
1631
+ if((*this)(j, i_U) != T(0)){return false;} // check U
1632
+ }
1633
+ }
1634
+ return true;
1635
+ }
1636
+
1637
+ typedef typename builder_t::transpose_t transpose_t;
1638
+ /**
1639
+ * Generate transpose matrix
1640
+ *
1641
+ * @return Transpose matrix
1642
+ */
1643
+ transpose_t transpose() const noexcept {
1644
+ return transpose_t(*this);
1645
+ }
1646
+
1647
+ typedef typename builder_t::conjugate_t conjugate_t;
1648
+ /**
1649
+ * Generate conjugate matrix
1650
+ *
1651
+ * @return Conjugate matrix
1652
+ */
1653
+ conjugate_t conjugate() const noexcept {
1654
+ return conjugate_t(*this);
1655
+ }
1656
+
1657
+ typedef typename builder_t::transpose_t::builder_t::conjugate_t adjoint_t;
1658
+ /**
1659
+ * Generate adjoint matrix
1660
+ *
1661
+ * @return Adjoint matrix
1662
+ */
1663
+ adjoint_t adjoint() const noexcept {
1664
+ return adjoint_t(*this);
1665
+ }
1666
+
1667
+ protected:
1668
+ template <class MatrixT>
1669
+ static typename MatrixBuilder<MatrixT>::partial_t partial_internal(
1670
+ const MatrixT &self,
1671
+ const unsigned int &new_rows,
1672
+ const unsigned int &new_columns,
1673
+ const unsigned int &row_offset,
1674
+ const unsigned int &column_offset){
1675
+ if(new_rows + row_offset > self.rows()){
1676
+ throw std::out_of_range("Row size exceeding");
1677
+ }else if(new_columns + column_offset > self.columns()){
1678
+ throw std::out_of_range("Column size exceeding");
1679
+ }
1680
+ typename MatrixBuilder<MatrixT>::partial_t res(self);
1681
+ res.view.update_size(new_rows, new_columns);
1682
+ res.view.update_offset(row_offset, column_offset);
1683
+ return res;
1684
+ }
1685
+
1686
+ public:
1687
+ typedef typename builder_t::partial_t partial_t;
1688
+ /**
1689
+ * Generate partial matrix
1690
+ *
1691
+ * @param rowSize Row number
1692
+ * @param columnSize Column number
1693
+ * @param rowOffset Upper row index of original matrix for partial matrix
1694
+ * @param columnOffset Left column index of original matrix for partial matrix
1695
+ * @throw std::out_of_range When either row or column size exceeds original one
1696
+ * @return partial matrix
1697
+ *
1698
+ */
1699
+ partial_t partial(
1700
+ const unsigned int &new_rows,
1701
+ const unsigned int &new_columns,
1702
+ const unsigned int &row_offset,
1703
+ const unsigned int &column_offset) const {
1704
+ return partial_internal(*this,
1705
+ new_rows, new_columns, row_offset, column_offset);
1706
+ }
1707
+
1708
+ /**
1709
+ * Generate row vector by using partial()
1710
+ *
1711
+ * @param row Row index of original matrix for row vector
1712
+ * @return Row vector
1713
+ * @see partial()
1714
+ */
1715
+ partial_t rowVector(const unsigned int &row) const {
1716
+ return partial(1, columns(), row, 0);
1717
+ }
1718
+ /**
1719
+ * Generate column vector by using partial()
1720
+ *
1721
+ * @param column Column index of original matrix for column vector
1722
+ * @return Column vector
1723
+ * @see partial()
1724
+ */
1725
+ partial_t columnVector(const unsigned int &column) const {
1726
+ return partial(rows(), 1, 0, column);
1727
+ }
1728
+
1729
+ protected:
1730
+ template <class MatrixT>
1731
+ static typename MatrixBuilder<MatrixT>::partial_offsetless_t partial_internal(
1732
+ const MatrixT &self,
1733
+ const unsigned int &new_rows,
1734
+ const unsigned int &new_columns){
1735
+ if(new_rows > self.rows()){
1736
+ throw std::out_of_range("Row size exceeding");
1737
+ }else if(new_columns > self.columns()){
1738
+ throw std::out_of_range("Column size exceeding");
1739
+ }
1740
+ typename MatrixBuilder<MatrixT>::partial_offsetless_t res(self);
1741
+ res.view.update_size(new_rows, new_columns);
1742
+ return res;
1743
+ }
1744
+
1745
+ public:
1746
+ typedef typename builder_t::partial_offsetless_t partial_offsetless_t;
1747
+ /**
1748
+ * Generate partial matrix by just reducing its size;
1749
+ * The origins and direction of original and return matrices are the same.
1750
+ *
1751
+ * @param rowSize Row number
1752
+ * @param columnSize Column number
1753
+ * @throw std::out_of_range When either row or column size exceeds original one
1754
+ * @return partial matrix
1755
+ */
1756
+ partial_offsetless_t partial(
1757
+ const unsigned int &new_rows,
1758
+ const unsigned int &new_columns) const {
1759
+ return partial_internal(*this, new_rows, new_columns);
1760
+ }
1761
+
1762
+ protected:
1763
+ template <class MatrixT>
1764
+ static typename MatrixBuilder<MatrixT>::circular_t circular_internal(
1765
+ const MatrixT &self,
1766
+ const unsigned int &loop_rows,
1767
+ const unsigned int &loop_columns,
1768
+ const unsigned int &new_rows,
1769
+ const unsigned int &new_columns,
1770
+ const unsigned int &row_offset,
1771
+ const unsigned int &column_offset){
1772
+ if(loop_rows > self.rows()){
1773
+ throw std::out_of_range("Row loop exceeding");
1774
+ }else if(loop_columns > self.columns()){
1775
+ throw std::out_of_range("Column loop exceeding");
1776
+ }
1777
+ typename MatrixBuilder<MatrixT>::circular_t res(self);
1778
+ res.view.update_loop(loop_rows, loop_columns);
1779
+ res.view.update_size(new_rows, new_columns);
1780
+ res.view.update_offset(row_offset, column_offset);
1781
+ return res;
1782
+ }
1783
+ public:
1784
+ typedef typename builder_t::circular_t circular_t;
1785
+ /**
1786
+ * Generate matrix with circular view
1787
+ * "circular" means its index is treated with roll over correction, for example,
1788
+ * if specified index is 5 to a matrix of 4 rows, then it will be treated
1789
+ * as the same as index 1 (= 5 % 4) is selected.
1790
+ *
1791
+ * Another example; [4x3].circular(1,2,5,6) is
1792
+ * 00 01 02 => 12 10 11 12 10
1793
+ * 10 11 12 22 20 21 22 20
1794
+ * 20 21 22 32 30 31 32 30
1795
+ * 30 31 32 02 00 01 02 00
1796
+ * 12 10 11 12 10
1797
+ *
1798
+ * @param row_offset Upper row index of original matrix for circular matrix
1799
+ * @param column_offset Left column index of original matrix for circular matrix
1800
+ * @param new_rows Row number
1801
+ * @param new_columns Column number
1802
+ * @throw std::out_of_range When either row or column loop exceeds original size
1803
+ * @return matrix with circular view
1804
+ */
1805
+ circular_t circular(
1806
+ const unsigned int &row_offset,
1807
+ const unsigned int &column_offset,
1808
+ const unsigned int &new_rows,
1809
+ const unsigned int &new_columns) const {
1810
+ return circular_internal(*this,
1811
+ rows(), columns(), new_rows, new_columns, row_offset, column_offset);
1812
+ }
1813
+
1814
+ protected:
1815
+ template <class MatrixT>
1816
+ static typename MatrixBuilder<MatrixT>::circular_bijective_t circular_internal(
1817
+ const MatrixT &self,
1818
+ const unsigned int &row_offset,
1819
+ const unsigned int &column_offset) noexcept {
1820
+ typename MatrixBuilder<MatrixT>::circular_bijective_t res(self);
1821
+ res.view.update_loop(self.rows(), self.columns());
1822
+ res.view.update_offset(row_offset, column_offset);
1823
+ return res;
1824
+ }
1825
+ public:
1826
+ typedef typename builder_t::circular_bijective_t circular_bijective_t;
1827
+ /**
1828
+ * Generate matrix with circular view, keeping original size version.
1829
+ * For example, [4x3].circular(1,2) is
1830
+ * 00 01 02 => 12 10 11
1831
+ * 10 11 12 22 20 21
1832
+ * 20 21 22 32 30 31
1833
+ * 30 31 32 02 00 01
1834
+ * In addition, this view is "bijective", that is, one-to-one mapping.
1835
+ *
1836
+ * @param row_offset Upper row index of original matrix for circular matrix
1837
+ * @param column_offset Left column index of original matrix for circular matrix
1838
+ * @return matrix with circular view
1839
+ * @see circular(
1840
+ * const unsigned int &, const unsigned int &,
1841
+ * const unsigned int &, const unsigned int &)
1842
+ */
1843
+ circular_bijective_t circular(
1844
+ const unsigned int &row_offset,
1845
+ const unsigned int &column_offset) const noexcept {
1846
+ return circular_internal(*this, row_offset, column_offset);
1847
+ }
1848
+
1849
+
1850
+ enum {
1851
+ OPERATOR_2_Multiply_Matrix_by_Scalar,
1852
+ OPERATOR_2_Add_Matrix_to_Matrix,
1853
+ OPERATOR_2_Subtract_Matrix_from_Matrix,
1854
+ OPERATOR_2_Multiply_Matrix_by_Matrix,
1855
+ OPERATOR_NONE,
1856
+ };
1857
+
1858
+ template <class MatrixT = self_t>
1859
+ struct OperatorProperty {
1860
+ template <class U>
1861
+ struct check1_t {
1862
+ static const int tag = OPERATOR_NONE;
1863
+ typedef void operator_t;
1864
+ };
1865
+ template <class T2, class Array2D_Type2, class View_Type2>
1866
+ struct check1_t<Matrix_Frozen<T2, Array2D_Type2, View_Type2> > {
1867
+ template <class Array2D_Type3>
1868
+ struct check2_t {
1869
+ static const int tag = OPERATOR_NONE;
1870
+ typedef void operator_t;
1871
+ };
1872
+ template <class T2_op, class OperatorT>
1873
+ struct check2_t<Array2D_Operator<T2_op, OperatorT> >{
1874
+ static const int tag = OperatorT::tag;
1875
+ typedef OperatorT operator_t;
1876
+ };
1877
+ static const int tag = check2_t<Array2D_Type2>::tag;
1878
+ typedef typename check2_t<Array2D_Type2>::operator_t operator_t;
1879
+ };
1880
+ static const int tag = check1_t<MatrixT>::tag;
1881
+ typedef typename check1_t<MatrixT>::operator_t operator_t;
1882
+ };
1883
+
1884
+ template <class LHS_MatrixT, class RHS_T>
1885
+ friend struct Matrix_multiplied_by_Scalar;
1886
+
1887
+ template <class RHS_T, class LHS_MatrixT = self_t>
1888
+ struct Multiply_Matrix_by_Scalar {
1889
+
1890
+ template <
1891
+ bool is_lhs_multi_mat_by_scalar
1892
+ = (OperatorProperty<LHS_MatrixT>::tag == OPERATOR_2_Multiply_Matrix_by_Scalar),
1893
+ class U = void>
1894
+ struct check_lhs_t {
1895
+ typedef Matrix_multiplied_by_Scalar<LHS_MatrixT, RHS_T> op_t;
1896
+ typedef typename op_t::mat_t res_t;
1897
+ static res_t generate(const LHS_MatrixT &mat, const RHS_T &scalar) noexcept {
1898
+ return op_t::generate(mat, scalar);
1899
+ }
1900
+ };
1901
+ #if 1 // 0 = Remove optimization
1902
+ /*
1903
+ * Optimization policy: If upper pattern is M * scalar, then reuse it.
1904
+ * For example, (M * scalar) * scalar is transformed to M * (scalar * scalar).
1905
+ */
1906
+ template <class U>
1907
+ struct check_lhs_t<true, U> {
1908
+ typedef self_t res_t;
1909
+ static res_t generate(const LHS_MatrixT &mat, const RHS_T &scalar) noexcept {
1910
+ return res_t(
1911
+ typename res_t::storage_t(
1912
+ mat.rows(), mat.columns(),
1913
+ typename OperatorProperty<res_t>::operator_t(
1914
+ mat.storage.op.lhs, mat.storage.op.rhs * scalar)));
1915
+ }
1916
+ };
1917
+ #endif
1918
+ typedef typename check_lhs_t<>::res_t mat_t;
1919
+ static mat_t generate(const LHS_MatrixT &mat, const RHS_T &scalar) noexcept {
1920
+ return check_lhs_t<>::generate(mat, scalar);
1921
+ }
1922
+ };
1923
+ template <class RHS_T>
1924
+ struct Multiply_Matrix_by_Scalar<RHS_T, scalar_matrix_t> {
1925
+ typedef scalar_matrix_t mat_t;
1926
+ static mat_t generate(const self_t &mat, const RHS_T &scalar) noexcept {
1927
+ return getScalar(mat.rows(), mat(0, 0) * scalar);
1928
+ }
1929
+ };
1930
+ typedef Multiply_Matrix_by_Scalar<T> mul_mat_scalar_t;
1931
+
1932
+ /**
1933
+ * Multiply matrix by scalar
1934
+ *
1935
+ * @param scalar
1936
+ * @return multiplied matrix
1937
+ */
1938
+ typename mul_mat_scalar_t::mat_t operator*(const T &scalar) const noexcept {
1939
+ return mul_mat_scalar_t::generate(*this, scalar);
1940
+ }
1941
+
1942
+ /**
1943
+ * Multiply scalar by matrix
1944
+ *
1945
+ * @param scalar
1946
+ * @param matrix
1947
+ * @return multiplied matrix
1948
+ */
1949
+ friend typename mul_mat_scalar_t::mat_t operator*(const T &scalar, const self_t &matrix) noexcept {
1950
+ return matrix * scalar;
1951
+ }
1952
+
1953
+ /**
1954
+ * Divide matrix by scalar
1955
+ *
1956
+ * @param scalar
1957
+ * @return divided matrix
1958
+ */
1959
+ typename mul_mat_scalar_t::mat_t operator/(const T &scalar) const noexcept {
1960
+ return operator*(T(1) / scalar);
1961
+ }
1962
+
1963
+ /**
1964
+ * Unary minus operator, which is alias of matrix * -1.
1965
+ *
1966
+ * @return matrix * -1.
1967
+ */
1968
+ typename mul_mat_scalar_t::mat_t operator-() const noexcept {
1969
+ return operator*(-1);
1970
+ }
1971
+
1972
+
1973
+ template <class RHS_MatrixT, bool rhs_positive = true>
1974
+ struct Add_Matrix_to_Matrix {
1975
+ typedef Array2D_Operator_Add<self_t, RHS_MatrixT, rhs_positive> op_t;
1976
+ typedef Matrix_Frozen<T, Array2D_Operator<T, op_t> > mat_t;
1977
+ static mat_t generate(const self_t &mat1, const RHS_MatrixT &mat2){
1978
+ if(mat1.isDifferentSize(mat2)){throw std::invalid_argument("Incorrect size");}
1979
+ return mat_t(
1980
+ typename mat_t::storage_t(
1981
+ mat1.rows(), mat1.columns(), op_t(mat1, mat2)));
1982
+ }
1983
+ };
1984
+
1985
+ /**
1986
+ * Add matrix to matrix
1987
+ *
1988
+ * @param matrix Matrix to add
1989
+ * @return added matrix
1990
+ * @throw std::invalid_argument When matrix sizes are not identical
1991
+ */
1992
+ template <class T2, class Array2D_Type2, class ViewType2>
1993
+ typename Add_Matrix_to_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2> >::mat_t
1994
+ operator+(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const {
1995
+ return Add_Matrix_to_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2> >::generate(*this, matrix);
1996
+ }
1997
+
1998
+ /**
1999
+ * Subtract matrix from matrix
2000
+ *
2001
+ * @param matrix Matrix to subtract
2002
+ * @return subtracted matrix
2003
+ * @throw std::invalid_argument When matrix sizes are not identical
2004
+ */
2005
+ template <class T2, class Array2D_Type2, class ViewType2>
2006
+ typename Add_Matrix_to_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2>, false>::mat_t
2007
+ operator-(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const{
2008
+ return Add_Matrix_to_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2>, false>::generate(*this, matrix);
2009
+ }
2010
+
2011
+ /**
2012
+ * Add scalar to matrix
2013
+ *
2014
+ * @param scalar scalar to add
2015
+ * @return added matrix
2016
+ * @throw std::invalid_argument When matrix sizes are not identical
2017
+ */
2018
+ typename Add_Matrix_to_Matrix<scalar_matrix_t>::mat_t
2019
+ operator+(const T &scalar) const {
2020
+ return *this + getScalar(rows(), scalar);
2021
+ }
2022
+
2023
+ /**
2024
+ * Subtract scalar from matrix
2025
+ *
2026
+ * @param scalar scalar to subtract
2027
+ * @return subtracted matrix
2028
+ * @throw std::invalid_argument When matrix sizes are not identical
2029
+ */
2030
+ typename Add_Matrix_to_Matrix<scalar_matrix_t>::mat_t
2031
+ operator-(const T &scalar) const {
2032
+ return *this + (-scalar);
2033
+ }
2034
+
2035
+ /**
2036
+ * Add matrix to scalar
2037
+ *
2038
+ * @param scalar scalar to be added
2039
+ * @param matrix matrix to add
2040
+ * @return added matrix
2041
+ * @throw std::invalid_argument When matrix sizes are not identical
2042
+ */
2043
+ friend typename Add_Matrix_to_Matrix<scalar_matrix_t>::mat_t
2044
+ operator+(const T &scalar, const self_t &matrix){
2045
+ return matrix + scalar;
2046
+ }
2047
+
2048
+ /**
2049
+ * Subtract matrix from scalar
2050
+ *
2051
+ * @param scalar to be subtracted
2052
+ * @param matrix matrix to subtract
2053
+ * @return added matrix
2054
+ * @throw std::invalid_argument When matrix sizes are not identical
2055
+ */
2056
+ friend typename scalar_matrix_t::template Add_Matrix_to_Matrix<self_t, false>::mat_t
2057
+ operator-(const T &scalar, const self_t &matrix){
2058
+ return getScalar(matrix.rows(), scalar) - matrix;
2059
+ }
2060
+
2061
+
2062
+ template <class LHS_T, class RHS_T>
2063
+ friend struct Array2D_Operator_Multiply_by_Matrix;
2064
+
2065
+ template <class RHS_MatrixT, class LHS_MatrixT = self_t>
2066
+ struct Multiply_Matrix_by_Matrix {
2067
+
2068
+ template <class MatrixT, int tag = OperatorProperty<MatrixT>::tag>
2069
+ struct check_t {
2070
+ template <bool is_binary, class U = void>
2071
+ struct check_binary_t {
2072
+ static const bool has_multi_mat_by_mat = false;
2073
+ };
2074
+ template <class U>
2075
+ struct check_binary_t<true, U> {
2076
+ static const bool has_multi_mat_by_mat
2077
+ = (check_t<typename OperatorProperty<MatrixT>::operator_t::lhs_t>
2078
+ ::has_multi_mat_by_mat)
2079
+ || (check_t<typename OperatorProperty<MatrixT>::operator_t::rhs_t>
2080
+ ::has_multi_mat_by_mat);
2081
+ };
2082
+ static const bool has_multi_mat_by_mat
2083
+ = (tag == OPERATOR_2_Multiply_Matrix_by_Matrix)
2084
+ || check_binary_t<
2085
+ (tag == OPERATOR_2_Multiply_Matrix_by_Scalar)
2086
+ || (tag == OPERATOR_2_Add_Matrix_to_Matrix)
2087
+ || (tag == OPERATOR_2_Subtract_Matrix_from_Matrix)
2088
+ || (tag == OPERATOR_2_Multiply_Matrix_by_Matrix)
2089
+ >::has_multi_mat_by_mat;
2090
+ static const bool is_multi_mat_by_scalar
2091
+ = (tag == OPERATOR_2_Multiply_Matrix_by_Scalar);
2092
+ };
2093
+
2094
+ /*
2095
+ * [Optimization policy 1]
2096
+ * If each side include M * M, then use cache.
2097
+ * For example, (M * M) * M, and (M * M + M) * M use cache for the first parenthesis terms.
2098
+ * (M * M + M) * (M * M + M) uses cache for the first and second parenthesis terms.
2099
+ */
2100
+ template <class MatrixT, bool cache_on = check_t<MatrixT>::has_multi_mat_by_mat>
2101
+ struct optimizer1_t {
2102
+ typedef MatrixT res_t;
2103
+ };
2104
+ #if 1 // 0 = remove optimizer
2105
+ template <class MatrixT>
2106
+ struct optimizer1_t<MatrixT, true> {
2107
+ typedef typename MatrixT::builder_t::assignable_t res_t;
2108
+ };
2109
+ #endif
2110
+ typedef typename optimizer1_t<self_t>::res_t lhs_buf_t;
2111
+ typedef typename optimizer1_t<RHS_MatrixT>::res_t rhs_buf_t;
2112
+
2113
+ /*
2114
+ * [Optimization policy 2]
2115
+ * Sort lhs and rhs to make the scalar multiplication term last.
2116
+ */
2117
+ template <
2118
+ bool lhs_m_by_s = check_t<self_t>::is_multi_mat_by_scalar,
2119
+ bool rhs_m_by_s = check_t<RHS_MatrixT>::is_multi_mat_by_scalar,
2120
+ class U = void>
2121
+ struct optimizer2_t {
2122
+ // M * M
2123
+ typedef Array2D_Operator_Multiply_by_Matrix<lhs_buf_t, rhs_buf_t> op_t;
2124
+ typedef typename op_t::mat_t res_t;
2125
+ static res_t generate(const self_t &mat1, const RHS_MatrixT &mat2){
2126
+ return op_t::generate(mat1, mat2);
2127
+ }
2128
+ };
2129
+ #if 1 // 0 = remove optimizer
2130
+ template <class U>
2131
+ struct optimizer2_t<true, false, U> {
2132
+ // (M * S) * M => (M * M) * S
2133
+ typedef typename OperatorProperty<self_t>::operator_t::lhs_t
2134
+ ::template Multiply_Matrix_by_Matrix<RHS_MatrixT> stage1_t;
2135
+ typedef typename stage1_t::mat_t
2136
+ ::template Multiply_Matrix_by_Scalar<
2137
+ typename OperatorProperty<self_t>::operator_t::rhs_t> stage2_t;
2138
+ typedef typename stage2_t::mat_t res_t;
2139
+ static res_t generate(const self_t &mat1, const RHS_MatrixT &mat2){
2140
+ return stage2_t::generate(
2141
+ stage1_t::generate(mat1.storage.op.lhs, mat2), mat1.storage.op.rhs);
2142
+ }
2143
+ };
2144
+ template <class U>
2145
+ struct optimizer2_t<false, true, U> {
2146
+ // M * (M * S) => (M * M) * S
2147
+ typedef typename self_t
2148
+ ::template Multiply_Matrix_by_Matrix<
2149
+ typename OperatorProperty<RHS_MatrixT>::operator_t::lhs_t> stage1_t;
2150
+ typedef typename stage1_t::mat_t
2151
+ ::template Multiply_Matrix_by_Scalar<
2152
+ typename OperatorProperty<RHS_MatrixT>::operator_t::rhs_t> stage2_t;
2153
+ typedef typename stage2_t::mat_t res_t;
2154
+ static res_t generate(const self_t &mat1, const RHS_MatrixT &mat2){
2155
+ return stage2_t::generate(
2156
+ stage1_t::generate(mat1, mat2.storage.op.lhs), mat2.storage.op.rhs);
2157
+ }
2158
+ };
2159
+ template <class U>
2160
+ struct optimizer2_t<true, true, U> {
2161
+ // (M * S) * (M * S) => (M * M) * (S * S)
2162
+ typedef typename OperatorProperty<self_t>::operator_t::lhs_t
2163
+ ::template Multiply_Matrix_by_Matrix<
2164
+ typename OperatorProperty<RHS_MatrixT>::operator_t::lhs_t> stage1_t;
2165
+ typedef typename stage1_t::mat_t
2166
+ ::template Multiply_Matrix_by_Scalar<
2167
+ typename OperatorProperty<self_t>::operator_t::rhs_t> stage2_t;
2168
+ typedef typename stage2_t::mat_t res_t;
2169
+ static res_t generate(const self_t &mat1, const RHS_MatrixT &mat2){
2170
+ return stage2_t::generate(
2171
+ stage1_t::generate(mat1.storage.op.lhs, mat2.storage.op.lhs),
2172
+ mat1.storage.op.rhs * mat2.storage.op.rhs);
2173
+ }
2174
+ };
2175
+ #endif
2176
+
2177
+ typedef typename optimizer2_t<>::res_t mat_t;
2178
+ static mat_t generate(const self_t &mat1, const RHS_MatrixT &mat2) noexcept {
2179
+ return optimizer2_t<>::generate(mat1, mat2);
2180
+ }
2181
+ };
2182
+
2183
+ template <class RHS_MatrixT>
2184
+ struct Multiply_Matrix_by_Matrix<RHS_MatrixT, scalar_matrix_t> {
2185
+ // Specialization for (Scalar_M * M)
2186
+ typedef typename RHS_MatrixT::template Multiply_Matrix_by_Scalar<T, RHS_MatrixT> generator_t;
2187
+ typedef typename generator_t::mat_t mat_t;
2188
+ static mat_t generate(const self_t &mat1, const RHS_MatrixT &mat2) noexcept {
2189
+ return generator_t::generate(mat2, mat1(0, 0));
2190
+ }
2191
+ };
2192
+
2193
+ /**
2194
+ * Multiply matrix by matrix
2195
+ * The following special cases are in consideration.
2196
+ * If this matrix is a scalar matrix, and if the right hand side matrix is also a scalar matrix,
2197
+ * multiplied scalar matrix will be returned; otherwise, then right hand side matrix
2198
+ * multiplied by this (as scalar) will be returned.
2199
+ * Only If the right hand side matrix is a scalar matrix,
2200
+ * matrix multiplied by scalar will be returned.
2201
+ * Otherwise, matrix * matrix will be returned.
2202
+ *
2203
+ * @param matrix matrix to multiply
2204
+ * @return multiplied matrix
2205
+ * @throw std::invalid_argument When operation is undefined
2206
+ */
2207
+ template <class T2, class Array2D_Type2, class ViewType2>
2208
+ typename Multiply_Matrix_by_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2> >::mat_t
2209
+ operator*(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const {
2210
+ if(columns() != matrix.rows()){throw std::invalid_argument("Incorrect size");}
2211
+ return Multiply_Matrix_by_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2> >::generate(*this, matrix);
2212
+ }
2213
+
2214
+ /**
2215
+ * Generate a matrix in which i-th row and j-th column are removed to calculate minor (determinant)
2216
+ *
2217
+ * @param row Row to be removed
2218
+ * @param column Column to be removed
2219
+ * @return Removed matrix
2220
+ */
2221
+ typename builder_t::template resize_t<-1, -1>::assignable_t matrix_for_minor(
2222
+ const unsigned int &row,
2223
+ const unsigned int &column) const noexcept {
2224
+ typedef typename builder_t::template resize_t<-1, -1>::assignable_t res_t;
2225
+ res_t res(res_t::blank(rows() - 1, columns() - 1));
2226
+ unsigned int i(0), i2(0);
2227
+ const unsigned int i_end(res.rows()), j_end(res.columns());
2228
+ for( ; i < row; ++i, ++i2){
2229
+ unsigned int j(0), j2(0);
2230
+ for( ; j < column; ++j, ++j2){
2231
+ res(i, j) = operator()(i2, j2);
2232
+ }
2233
+ ++j2;
2234
+ for( ; j < j_end; ++j, ++j2){
2235
+ res(i, j) = operator()(i2, j2);
2236
+ }
2237
+ }
2238
+ ++i2;
2239
+ for( ; i < i_end; ++i, ++i2){
2240
+ unsigned int j(0), j2(0);
2241
+ for( ; j < column; ++j, ++j2){
2242
+ res(i, j) = operator()(i2, j2);
2243
+ }
2244
+ ++j2;
2245
+ for( ; j < j_end; ++j, ++j2){
2246
+ res(i, j) = operator()(i2, j2);
2247
+ }
2248
+ }
2249
+ return res;
2250
+ }
2251
+
2252
+ /**
2253
+ * Calculate determinant by using minor
2254
+ *
2255
+ * @param do_check Whether check size property. The default is true.
2256
+ * @return Determinant
2257
+ * @throw std::logic_error When operation is undefined
2258
+ */
2259
+ T determinant_minor(const bool &do_check = true) const {
2260
+ if(do_check && !isSquare()){throw std::logic_error("rows() != columns()");}
2261
+ if(rows() == 1){
2262
+ return (*this)(0, 0);
2263
+ }else{
2264
+ T sum(0);
2265
+ T sign(1);
2266
+ for(unsigned int i(0), i_end(rows()); i < i_end; i++){
2267
+ if((*this)(i, 0) != T(0)){
2268
+ sum += (*this)(i, 0) * (matrix_for_minor(i, 0).determinant(false)) * sign;
2269
+ }
2270
+ sign = -sign;
2271
+ }
2272
+ return sum;
2273
+ }
2274
+ }
2275
+
2276
+ /**
2277
+ * Perform LUP decomposition
2278
+ * Return matrix is
2279
+ * (0, 0)-(n-1, n-1): L matrix
2280
+ * (0, n)-(n-1, 2n-1): U matrix
2281
+ *
2282
+ * @param pivot_num Number of pivoting to be returned
2283
+ * @param pivot Array of pivoting indices to be returned, NULL is acceptable (no return).
2284
+ * For example, [0,2,1] means the left hand side pivot matrix,
2285
+ * which multiplies original matrix (not to be multiplied), equals to
2286
+ * [[1,0,0], [0,0,1], [0,1,0]].
2287
+ * @param do_check Check size, the default is true.
2288
+ * @return LU decomposed matrix
2289
+ * @throw std::logic_error When operation is undefined
2290
+ * @throw std::runtime_error When operation is unavailable
2291
+ */
2292
+ typename builder_t::template resize_t<0, 0, 1, 2>::assignable_t decomposeLUP(
2293
+ unsigned int &pivot_num,
2294
+ unsigned int *pivot = NULL,
2295
+ const bool &do_check = true) const {
2296
+ if(do_check && !isSquare()){throw std::logic_error("rows() != columns()");}
2297
+
2298
+ typedef typename builder_t::template resize_t<0, 0, 1, 2>::assignable_t res_t;
2299
+ res_t LU(res_t::blank(rows(), columns() * 2));
2300
+
2301
+ typename res_t::partial_offsetless_t L(LU.partial(rows(), columns()));
2302
+ typename res_t::partial_t U(LU.partial(rows(), columns(), 0, columns()));
2303
+ const unsigned int rows_(rows());
2304
+ for(unsigned int i(0); i < rows_; ++i){
2305
+ U(i, i) = (*this)(i, i);
2306
+ L(i, i) = T(1);
2307
+ for(unsigned int j(i + 1); j < rows_; ++j){
2308
+ U(i, j) = (*this)(i, j);
2309
+ U(j, i) = (*this)(j, i); // U is full copy
2310
+ L(i, j) = T(0);
2311
+ }
2312
+ }
2313
+ pivot_num = 0;
2314
+ if(pivot){
2315
+ for(unsigned int i(0); i < rows_; ++i){
2316
+ pivot[i] = i;
2317
+ }
2318
+ }
2319
+ // apply Gaussian elimination
2320
+ for(unsigned int i(0); i < rows_; ++i){
2321
+ if(U(i, i) == T(0)){ // check (i, i) is not zero
2322
+ unsigned int j(i);
2323
+ do{
2324
+ if(++j == rows_){
2325
+ throw std::runtime_error("LU decomposition cannot be performed");
2326
+ }
2327
+ }while(U(i, j) == T(0));
2328
+ for(unsigned int i2(0); i2 < rows_; ++i2){ // swap i-th and j-th columns
2329
+ T temp(U(i2, i));
2330
+ U(i2, i) = U(i2, j);
2331
+ U(i2, j) = temp;
2332
+ }
2333
+ pivot_num++;
2334
+ if(pivot){
2335
+ unsigned int temp(pivot[i]);
2336
+ pivot[i] = pivot[j];
2337
+ pivot[j] = temp;
2338
+ }
2339
+ }
2340
+ for(unsigned int i2(i + 1); i2 < rows_; ++i2){
2341
+ L(i2, i) = U(i2, i) / U(i, i);
2342
+ U(i2, i) = T(0);
2343
+ for(unsigned int j2(i + 1); j2 < rows_; ++j2){
2344
+ U(i2, j2) -= L(i2, i) * U(i, j2);
2345
+ }
2346
+ }
2347
+ }
2348
+ return LU;
2349
+ }
2350
+
2351
+ typename builder_t::template resize_t<0, 0, 1, 2>::assignable_t decomposeLU(
2352
+ const bool &do_check = true) const {
2353
+ unsigned int pivot_num;
2354
+ return decomposeLUP(pivot_num, NULL, do_check);
2355
+ }
2356
+
2357
+ /**
2358
+ * Resolve x of (Ax = y), where this matrix is A and has already been decomposed as LU.
2359
+ *
2360
+ * @param y Right hand term
2361
+ * @param do_check Check whether already LU decomposed
2362
+ * @return Left hand second term
2363
+ * @throw std::logic_error When operation is undefined
2364
+ * @throw std::invalid_argument When input is incorrect
2365
+ * @see decomposeLU(const bool &)
2366
+ */
2367
+ template <class T2, class Array2D_Type2, class ViewType2>
2368
+ typename Matrix_Frozen<T2, Array2D_Type2, ViewType2>::builder_t::assignable_t
2369
+ solve_linear_eq_with_LU(
2370
+ const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &y, const bool &do_check = true)
2371
+ const {
2372
+ if(do_check && (!isLU())){
2373
+ throw std::logic_error("Not LU decomposed matrix!!");
2374
+ }
2375
+ if(do_check && ((y.columns() != 1) || (y.rows() != rows()))){
2376
+ throw std::invalid_argument("Incorrect y size");
2377
+ }
2378
+
2379
+ typename builder_t::partial_offsetless_t L(partial(rows(), rows()));
2380
+ typename builder_t::partial_t U(partial(rows(), rows(), 0, rows()));
2381
+ typedef typename Matrix_Frozen<T2, Array2D_Type2, ViewType2>::builder_t::assignable_t y_t;
2382
+ // By using L(Ux) = y, firstly y' = (Ux) will be solved; L(Ux) = y �� y' = (Ux)���܂�����
2383
+ y_t y_copy(y.operator y_t());
2384
+ y_t y_prime(y_t::blank(y.rows(), 1));
2385
+ for(unsigned i(0), rows_(rows()); i < rows_; i++){
2386
+ y_prime(i, 0) = y_copy(i, 0) / L(i, i);
2387
+ for(unsigned j(i + 1); j < rows_; j++){
2388
+ y_copy(j, 0) -= L(j, i) * y_prime(i, 0);
2389
+ }
2390
+ }
2391
+
2392
+ // Then, Ux = y' gives solution of x; ������Ux = y'�� x������
2393
+ y_t x(y_t::blank(y.rows(), 1));
2394
+ for(unsigned i(rows()); i > 0;){
2395
+ i--;
2396
+ x(i, 0) = y_prime(i, 0) / U(i, i);
2397
+ for(unsigned j(i); j > 0;){
2398
+ j--;
2399
+ y_prime(j, 0) -= U(j, i) * x(i, 0);
2400
+ }
2401
+ }
2402
+
2403
+ return x;
2404
+ }
2405
+
2406
+ /**
2407
+ * Calculate determinant by using LU decomposition
2408
+ *
2409
+ * @param do_check Whether check size property. The default is true.
2410
+ * @return Determinant
2411
+ */
2412
+ T determinant_LU(const bool &do_check = true) const {
2413
+ unsigned int pivot_num;
2414
+ typename builder_t::template resize_t<0, 0, 1, 2>::assignable_t LU(
2415
+ decomposeLUP(pivot_num, NULL, do_check));
2416
+ T res((pivot_num % 2 == 0) ? 1 : -1);
2417
+ for(unsigned int i(0), i_end(rows()), j(rows()); i < i_end; ++i, ++j){
2418
+ res *= LU(i, i) * LU(i, j);
2419
+ }
2420
+ return res;
2421
+ }
2422
+
2423
+ T determinant(const bool &do_check = true) const {
2424
+ return determinant_LU(do_check);
2425
+ }
2426
+
2427
+ /**
2428
+ * Perform UD decomposition
2429
+ * Return matrix is
2430
+ * (0, 0)-(n-1,n-1): U matrix
2431
+ * (0, n)-(n-1,2n-1): D matrix
2432
+ *
2433
+ * @param do_check Check size, the default is true.
2434
+ * @return UD decomposed matrix
2435
+ * @throw std::logic_error When operation is undefined
2436
+ */
2437
+ typename builder_t::template resize_t<0, 0, 1, 2>::assignable_t decomposeUD(
2438
+ const bool &do_check = true) const {
2439
+ if(do_check && !isSymmetric()){throw std::logic_error("not symmetric");}
2440
+ typename builder_t::assignable_t P(this->operator typename builder_t::assignable_t());
2441
+ typedef typename builder_t::template resize_t<0, 0, 1, 2>::assignable_t res_t;
2442
+ res_t UD(rows(), columns() * 2);
2443
+ typename res_t::partial_offsetless_t U(UD.partial(rows(), columns()));
2444
+ typename res_t::partial_t D(UD.partial(rows(), columns(), 0, columns()));
2445
+ for(int i(rows() - 1); i >= 0; i--){
2446
+ D(i, i) = P(i, i);
2447
+ U(i, i) = T(1);
2448
+ for(int j(0); j < i; j++){
2449
+ U(j, i) = P(j, i) / D(i, i);
2450
+ for(int k(0); k <= j; k++){
2451
+ P(k, j) -= U(k, i) * D(i, i) * U(j, i);
2452
+ }
2453
+ }
2454
+ }
2455
+ return UD;
2456
+ }
2457
+
2458
+ template <class MatrixT = self_t, class U = void>
2459
+ struct Inverse_Matrix {
2460
+ typedef typename MatrixT::builder_t::assignable_t mat_t;
2461
+ static mat_t generate(const MatrixT &mat) {
2462
+ if(!mat.isSquare()){throw std::logic_error("rows() != columns()");}
2463
+
2464
+ #if 0
2465
+ // Cramer (slow); �N�����[��
2466
+ mat_t result(rows(), columns());
2467
+ T det;
2468
+ if((det = mat.determinant()) == 0){throw std::runtime_error("Operation void!!");}
2469
+ const unsigned int i_end(mat.rows()), j_end(mat.columns());
2470
+ for(unsigned int i(0); i < i_end; i++){
2471
+ for(unsigned int j(0); j < j_end; j++){
2472
+ result(i, j) = mat.matrix_for_minor(i, j).determinant() * ((i + j) % 2 == 0 ? 1 : -1);
2473
+ }
2474
+ }
2475
+ return result.transpose() / det;
2476
+ #endif
2477
+
2478
+ // Gaussian elimination; �K�E�X�����@
2479
+ mat_t left(mat.operator mat_t());
2480
+ mat_t right(getI(mat.rows()));
2481
+ const unsigned int rows_(left.rows()), columns_(left.columns());
2482
+ for(unsigned int i(0); i < rows_; i++){
2483
+ if(left(i, i) == T(0)){
2484
+ unsigned int i2(i);
2485
+ do{
2486
+ if(++i2 == rows_){
2487
+ throw std::runtime_error("invert matrix not exist");
2488
+ }
2489
+ }while(left(i2, i) == T(0));
2490
+ // swap i-th and i2-th rows
2491
+ for(unsigned int j(i); j < columns_; ++j){
2492
+ T temp(left(i, j));
2493
+ left(i, j) = left(i2, j);
2494
+ left(i2, j) = temp;
2495
+ }
2496
+ right.swapRows(i, i2);
2497
+ }
2498
+ if(left(i, i) != T(1)){
2499
+ for(unsigned int j(0); j < columns_; j++){right(i, j) /= left(i, i);}
2500
+ for(unsigned int j(i+1); j < columns_; j++){left(i, j) /= left(i, i);}
2501
+ left(i, i) = T(1);
2502
+ }
2503
+ for(unsigned int k(0); k < rows_; k++){
2504
+ if(k == i){continue;}
2505
+ if(left(k, i) != T(0)){
2506
+ for(unsigned int j(0); j < columns_; j++){right(k, j) -= right(i, j) * left(k, i);}
2507
+ for(unsigned int j(i+1); j < columns_; j++){left(k, j) -= left(i, j) * left(k, i);}
2508
+ left(k, i) = T(0);
2509
+ }
2510
+ }
2511
+ }
2512
+ //std::cout << "L:" << left << std::endl;
2513
+ //std::cout << "R:" << right << std::endl;
2514
+
2515
+ return right;
2516
+
2517
+ // TODO: method to use LU decomposition
2518
+ /*
2519
+ */
2520
+ }
2521
+ };
2522
+ template <class U>
2523
+ struct Inverse_Matrix<scalar_matrix_t, U> {
2524
+ typedef scalar_matrix_t mat_t;
2525
+ static mat_t generate(const scalar_matrix_t &mat) noexcept {
2526
+ return getScalar(mat.rows(), T(1) / mat(0, 0));
2527
+ }
2528
+ };
2529
+
2530
+ /**
2531
+ * Calculate inverse matrix
2532
+ *
2533
+ * @return Inverse matrix
2534
+ * @throw std::logic_error When operation is undefined
2535
+ * @throw std::runtime_error When operation is unavailable
2536
+ */
2537
+ typename Inverse_Matrix<>::mat_t inverse() const {
2538
+ return Inverse_Matrix<>::generate(*this);
2539
+ }
2540
+
2541
+ /**
2542
+ * Divide matrix by matrix, in other words, multiply by inverse matrix
2543
+ *
2544
+ * @param matrix Matrix to divide
2545
+ * @return divided matrix
2546
+ */
2547
+ template <class T2, class Array2D_Type2, class ViewType2>
2548
+ typename Multiply_Matrix_by_Matrix<
2549
+ typename Matrix_Frozen<T2, Array2D_Type2, ViewType2>
2550
+ ::template Inverse_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2> >::mat_t>::mat_t
2551
+ operator/(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const {
2552
+ typedef typename Matrix_Frozen<T2, Array2D_Type2, ViewType2>
2553
+ ::template Inverse_Matrix<Matrix_Frozen<T2, Array2D_Type2, ViewType2> >::mat_t inv_t;
2554
+ return Multiply_Matrix_by_Matrix<inv_t>::generate(
2555
+ *this, matrix.inverse()); // equal to (*this) * matrix.inverse()
2556
+ }
2557
+
2558
+ /**
2559
+ * Divide scalar by matrix, which is equivalent to inverted matrix multiplied by scalar
2560
+ *
2561
+ * @param scalar
2562
+ * @param matrix
2563
+ * @return result matrix
2564
+ */
2565
+ friend typename Multiply_Matrix_by_Scalar<T, typename Inverse_Matrix<>::mat_t>::mat_t
2566
+ operator/(const T &scalar, const self_t &matrix) {
2567
+ return Multiply_Matrix_by_Scalar<T, typename Inverse_Matrix<>::mat_t>
2568
+ ::generate(matrix.inverse(), scalar); // equal to matrix.inverse() * scalar
2569
+ }
2570
+
2571
+ /**
2572
+ * Add matrix to matrix with specified pivot
2573
+ *
2574
+ * @param row Upper row index (pivot) of matrix to be added
2575
+ * @param column Left column index (pivot) of matrix to be added
2576
+ * @param matrix Matrix to add
2577
+ * @return added (deep) copy
2578
+ */
2579
+ template <class T2, class Array2D_Type2, class ViewType2>
2580
+ typename builder_t::assignable_t pivotAdd(
2581
+ const unsigned int &row, const unsigned int &column,
2582
+ const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const{
2583
+ return this->operator typename builder_t::assignable_t().pivotMerge(row, column, matrix);
2584
+ }
2585
+
2586
+ struct complex_t {
2587
+ template <class T2>
2588
+ struct check_t {
2589
+ static const bool hit = false;
2590
+ typedef T2 r_t;
2591
+ typedef Complex<T2> c_t;
2592
+ };
2593
+ template <class T2>
2594
+ struct check_t<Complex<T2> > {
2595
+ static const bool hit = true;
2596
+ typedef T2 r_t;
2597
+ typedef Complex<T2> c_t;
2598
+ };
2599
+ static const bool is_complex = check_t<T>::hit;
2600
+ typedef typename check_t<T>::c_t v_t;
2601
+ typedef typename builder_t::template cast_t<v_t>::assignable_t m_t;
2602
+ typedef typename check_t<T>::r_t real_t;
2603
+ static real_t get_real(const real_t &v) noexcept {
2604
+ return v;
2605
+ }
2606
+ static real_t get_real(const v_t &v) noexcept {
2607
+ return v.real();
2608
+ }
2609
+ static v_t get_sqrt(const real_t &v) noexcept {
2610
+ return (v >= 0) ? v_t(std::sqrt(v)) : v_t(0, std::sqrt(-v));
2611
+ }
2612
+ static v_t get_sqrt(const v_t &v) noexcept {
2613
+ return v.sqrt();
2614
+ }
2615
+ static real_t get_abs(const real_t &v) noexcept {
2616
+ return std::abs(v);
2617
+ }
2618
+ static real_t get_abs(const v_t &v) noexcept {
2619
+ return v.abs();
2620
+ }
2621
+ static real_t get_abs2(const real_t &v) noexcept {
2622
+ return v * v;
2623
+ }
2624
+ static real_t get_abs2(const v_t &v) noexcept {
2625
+ return v.abs2();
2626
+ }
2627
+ static bool is_nan_or_infinite(const real_t &v) noexcept {
2628
+ #if defined(_MSC_VER)
2629
+ return _isnan(v) || !_finite(v);
2630
+ #else
2631
+ return std::isnan(v) || !std::isfinite(v);
2632
+ #endif
2633
+ }
2634
+ static bool is_nan_or_infinite(const v_t &v) noexcept {
2635
+ return is_nan_or_infinite(v.real())
2636
+ || is_nan_or_infinite(v.imaginary());
2637
+ }
2638
+ };
2639
+
2640
+ Matrix_Frozen<typename complex_t::v_t, Array2D_Type, ViewType>
2641
+ complex() const noexcept {
2642
+ return Matrix_Frozen<typename complex_t::v_t, Array2D_Type, ViewType>(*this);
2643
+ }
2644
+
2645
+ /**
2646
+ * Calculate the 2nd power of Frobenius norm.
2647
+ *
2648
+ * @return tr(A* * A)
2649
+ */
2650
+ typename complex_t::real_t norm2F() const noexcept {
2651
+ // return complex_t::get_real((adjoint() * (*this)).trace(false));
2652
+ /* The above is as definition, however, double calculation may occure
2653
+ * when (*this) is a expression matrix such as multiplication.
2654
+ * To avoid such overhead, its expansion form to take summation of
2655
+ * abs(element)**2 is used.
2656
+ */
2657
+ typename complex_t::real_t res(0);
2658
+ for(unsigned int i(0), i_end(rows()); i < i_end; ++i){
2659
+ for(unsigned int j(0), j_end(columns()); j < j_end; ++j){
2660
+ res += complex_t::get_abs2((*this)(i, j));
2661
+ }
2662
+ }
2663
+ return res;
2664
+ }
2665
+
2666
+ protected:
2667
+ /**
2668
+ * Convert to a scaled vector having to be used for Householder transformation
2669
+ *
2670
+ * @param x column vector to be converted (bang method)
2671
+ * @return 2nd power of Frobenius norm of x
2672
+ */
2673
+ template <class Array2D_Type2, class ViewType2>
2674
+ static typename complex_t::real_t householder_vector(
2675
+ Matrix<T, Array2D_Type2, ViewType2> &x){
2676
+ // x = {(0,0), (1,0), ..., (N-1,0)}^{T}
2677
+
2678
+ typename complex_t::real_t x_abs2(x.norm2F());
2679
+ if(x_abs2 == 0){return x_abs2;}
2680
+
2681
+ typename complex_t::real_t x_abs(std::sqrt(x_abs2));
2682
+ typename complex_t::real_t x_top_abs(std::abs(x(0, 0))); // x(0,0)
2683
+ T rho(x(0, 0) / x_top_abs * -1);
2684
+ // if x(0,0) is real, then rho = -sign(x(0,0)),
2685
+ // otherwise rho = - e^{i \phi}, where x(0,0) \equiv e^{i \phi} |x(0,0)|
2686
+
2687
+ // x -> x_dash
2688
+ // x_dash = {(0,0) - \rho |x|, (1,0), ..., (N-1,0)}^{T}
2689
+ // x_dash_abs2
2690
+ // = x_abs2 * (1 + \rho \bar{\rho}) - x_abs * (\rho \bar{x(0,0)} + \bar{\rho} x(0,0))
2691
+ // = (x_abs2 + x_top_abs * x_abs) * 2
2692
+ x(0, 0) -= rho * x_abs;
2693
+ typename complex_t::real_t x_dash_abs2((x_abs2 + x_top_abs * x_abs) * 2);
2694
+
2695
+ return x_dash_abs2;
2696
+ }
2697
+
2698
+ public:
2699
+
2700
+ struct opt_decomposeQR_t {
2701
+ bool force_zeros;
2702
+ opt_decomposeQR_t()
2703
+ : force_zeros(true)
2704
+ {};
2705
+ };
2706
+
2707
+ /**
2708
+ * Perform QR decomposition
2709
+ * Return matrix is
2710
+ * (0, 0)-(n-1, n-1): Q matrix
2711
+ * (0, n)-(n-1, n + c): R matrix
2712
+ *
2713
+ * @return QR decomposed matrix
2714
+ */
2715
+ typename builder_t::template resize_t<0, builder_t::row_buffer>::assignable_t decomposeQR(
2716
+ const opt_decomposeQR_t &opt = opt_decomposeQR_t()) const {
2717
+
2718
+ typedef typename builder_t::template resize_t<0, builder_t::row_buffer>::assignable_t res_t;
2719
+ res_t QR(res_t::blank(rows(), rows() + columns()));
2720
+ typename res_t::partial_offsetless_t Q(QR.partial(rows(), rows()));
2721
+ typename res_t::partial_t R(QR.partial(rows(), columns(), 0, rows()));
2722
+ Q.replace(getI(rows()), false);
2723
+ R.replace(*this, false);
2724
+
2725
+ typedef typename builder_t::template resize_t<0, builder_t::row_buffer, 1, 0>::assignable_t Q_t;
2726
+ typedef typename builder_t::assignable_t R_t;
2727
+
2728
+ unsigned int rc_min(columns() > rows() ? rows() : columns());
2729
+
2730
+ { // Householder transformation
2731
+ typedef typename builder_t::template resize_t<0, 1, 1, 0>::assignable_t x_buf_t;
2732
+ x_buf_t x_buf(x_buf_t::blank(rows(), 1));
2733
+
2734
+ for(unsigned int j(0); j < rc_min; j++){
2735
+ typename x_buf_t::partial_offsetless_t x(x_buf.partial(rows() - j, 1));
2736
+ x.replace(R.partial(x.rows(), 1, j, j), false);
2737
+ // x_0 = {(0,0), (1,0), ..., (N-1,0)}^{T}, (N-1)*1
2738
+ // x_1 = {(1,1), (2,1), ..., (N-1,1)}^{T}, (N-2)*1, ...
2739
+
2740
+ typename complex_t::real_t x_abs2(householder_vector(x));
2741
+ // x_0 <- {(0,0) - \rho |x|, (1,0), ..., (N-1,0)}^{T}
2742
+ // x_1 <- {(1,1) - \rho |x|, (2,1), ..., (N-1,1)}^{T}, ...
2743
+ if(x_abs2 == 0){continue;}
2744
+
2745
+ if(false){ // as definition
2746
+ Q_t P(getI(rows()));
2747
+ P.pivotMerge(j, j, x * x.adjoint() * -2 / x_abs2);
2748
+ R.replace(R_t(P * R), false); // R and Q have partial views, therefore R = P * R, Q = Q * P raise build error.
2749
+ Q.replace(Q_t(Q * P), false);
2750
+ }else{ // optimized
2751
+ Q_t P((x * x.adjoint() * -2 / x_abs2) + 1);
2752
+ R.partial(rows() - j, columns(), j, 0).replace(R_t(P * R.partial(rows() - j, columns(), j, 0)), false);
2753
+ Q.partial(rows(), rows() - j, 0, j).replace(Q_t(Q.partial(rows(), rows() - j, 0, j) * P), false);
2754
+ }
2755
+ }
2756
+ }
2757
+
2758
+ // TODO Gram-Schmidt orthonormalization
2759
+ // TODO Givens rotation
2760
+
2761
+ if(opt.force_zeros){ // Zero clear
2762
+ for(unsigned int j(0), j_end(rc_min); j < j_end; j++){
2763
+ for(unsigned int i(j + 1), i_end(rows()); i < i_end; i++){
2764
+ R(i, j) = T(0);
2765
+ }
2766
+ }
2767
+ }
2768
+
2769
+ return QR;
2770
+ }
2771
+
2772
+ struct opt_hessenberg_t {
2773
+ enum {
2774
+ NOT_CHECKED, SQUARE, SYMMETRIC,
2775
+ } mat_prop;
2776
+ bool force_zeros;
2777
+ opt_hessenberg_t()
2778
+ : mat_prop(NOT_CHECKED), force_zeros(true)
2779
+ {};
2780
+ };
2781
+
2782
+ /**
2783
+ * Calculate Hessenberg matrix by performing householder conversion
2784
+ *
2785
+ * @param transform Pointer to store multiplication of matrices used for the transformation.
2786
+ * If NULL is specified, the store will not be performed, The default is NULL.
2787
+ * @param opt calculation options
2788
+ * @return Hessenberg matrix
2789
+ * @throw std::logic_error When operation is undefined
2790
+ * @see https://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter4.pdf
2791
+ */
2792
+ template <class T2, class Array2D_Type2, class ViewType2>
2793
+ typename builder_t::assignable_t hessenberg(
2794
+ Matrix<T2, Array2D_Type2, ViewType2> *transform,
2795
+ const opt_hessenberg_t &opt = opt_hessenberg_t()) const {
2796
+ if((opt.mat_prop == opt_hessenberg_t::NOT_CHECKED) && !isSquare()){
2797
+ throw std::logic_error("rows() != columns()");
2798
+ }
2799
+
2800
+ bool real_symmetric(
2801
+ (!complex_t::is_complex)
2802
+ && ((opt.mat_prop == opt_hessenberg_t::SYMMETRIC)
2803
+ || ((opt.mat_prop == opt_hessenberg_t::NOT_CHECKED) && isSymmetric())));
2804
+
2805
+ typename builder_t::assignable_t result(this->operator typename builder_t::assignable_t());
2806
+ typedef typename builder_t::template resize_t<0, 1, 1, 0>::assignable_t x_buf_t;
2807
+ x_buf_t x_buf(x_buf_t::blank(rows() - 1, 1));
2808
+ for(unsigned int j(0), j_end(columns() - 2); j < j_end; j++){
2809
+ typename x_buf_t::partial_offsetless_t x(x_buf.partial(rows() - (j+1), 1));
2810
+ x.replace(result.partial(x.rows(), 1, j+1, j), false);
2811
+ // x_0 = {(1,0), (2,0), ..., (N-1,0)}^{T}, (N-1)*1
2812
+ // x_1 = {(2,1), (3,1), ..., (N-1,1)}^{T}, (N-2)*1, ...
2813
+
2814
+ typename complex_t::real_t x_abs2(householder_vector(x));
2815
+ // x_0 <- {(1,0) - \rho |x|, (2,0), ..., (N-1,0)}^{T}
2816
+ // x_1 <- {(2,1) - \rho |x|, (3,1), ..., (N-1,1)}^{T}, ...
2817
+ if(x_abs2 == 0){continue;}
2818
+
2819
+ // Householder transformation
2820
+ if(false){ // as definition
2821
+ typename builder_t::assignable_t P(getI(rows()));
2822
+ P.pivotMerge(j+1, j+1, x * x.adjoint() * -2 / x_abs2);
2823
+ result = P * result * P;
2824
+ if(transform){(*transform) *= P;}
2825
+ }else{ // optimized
2826
+ typename builder_t::assignable_t P((x * x.adjoint() * -2 / x_abs2) + 1);
2827
+ typename builder_t::assignable_t PX(P * result.partial(rows() - (j+1), columns(), j+1, 0));
2828
+ result.partial(rows() - (j+1), columns(), j+1, 0).replace(PX, false);
2829
+ typename builder_t::assignable_t PXP(result.partial(rows(), columns()-(j+1), 0, j+1) * P);
2830
+ result.partial(rows(), columns()-(j+1), 0, j+1).replace(PXP, false);
2831
+ if(transform){
2832
+ typename Matrix<T2, Array2D_Type2, ViewType2>::builder_t::assignable_t Pk(
2833
+ transform->partial(rows(), columns() - (j+1), 0, (j+1)) * P);
2834
+ transform->partial(rows(), columns() - (j+1), 0, (j+1)).replace(Pk, false);
2835
+ }
2836
+ }
2837
+ }
2838
+
2839
+ if(opt.force_zeros){ // Zero clear
2840
+ for(unsigned int j(0), j_end(columns() - 2); j < j_end; j++){
2841
+ for(unsigned int i(j + 2), i_end(rows()); i < i_end; i++){
2842
+ result(i, j) = T(0);
2843
+ if(real_symmetric){result(j, i) = T(0);}
2844
+ }
2845
+ }
2846
+ }
2847
+
2848
+ return result;
2849
+ }
2850
+
2851
+ /**
2852
+ * Calculate Hessenberg matrix by performing householder conversion without return of multipled matrices
2853
+ *
2854
+ * @param opt calculation options
2855
+ * @return Hessenberg matrix
2856
+ * @throw std::logic_error When operation is undefined
2857
+ * @see https://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter4.pdf
2858
+ */
2859
+ typename builder_t::assignable_t hessenberg(const opt_hessenberg_t &opt = opt_hessenberg_t()) const {
2860
+ return hessenberg(static_cast<typename builder_t::assignable_t *>(NULL), opt);
2861
+ }
2862
+
2863
+ /**
2864
+ * Calculate eigenvalues of 2 by 2 partial matrix.
2865
+ *
2866
+ * @param row Upper row index of the partial matrix
2867
+ * @param column Left column index of the partial matrix
2868
+ * @param upper Eigenvalue (1)
2869
+ * @param lower Eigenvalue (2)
2870
+ */
2871
+ void eigen22(
2872
+ const unsigned int &row, const unsigned int &column,
2873
+ typename complex_t::v_t &upper, typename complex_t::v_t &lower) const {
2874
+ const T
2875
+ &a((*this)(row, column)), &b((*this)(row, column + 1)),
2876
+ &c((*this)(row + 1, column)), &d((*this)(row + 1, column + 1));
2877
+ typename complex_t::v_t root(complex_t::get_sqrt((a - d) * (a - d) + b * c * 4));
2878
+ upper = ((root + a + d) / 2);
2879
+ lower = ((-root + a + d) / 2);
2880
+ }
2881
+
2882
+ struct opt_eigen_t {
2883
+ enum {
2884
+ NOT_CHECKED, SQUARE,
2885
+ } mat_prop;
2886
+ typename complex_t::real_t threshold_abs; ///< Absolute error to be used for convergence determination
2887
+ typename complex_t::real_t threshold_rel; ///< Relative error to be used for convergence determination
2888
+ unsigned int inverse_power_max_iter;
2889
+
2890
+ opt_eigen_t()
2891
+ : mat_prop(NOT_CHECKED),
2892
+ threshold_abs(1E-10), threshold_rel(1E-7),
2893
+ inverse_power_max_iter(10)
2894
+ {}
2895
+ };
2896
+
2897
+ /**
2898
+ * Calculate eigenvalues and eigenvectors.
2899
+ * The return (n, n+1) matrix consists of
2900
+ * (0,j)-(n-1,j): Eigenvector (j) (0 <= j <= n-1)
2901
+ * (j,n): Eigenvalue (j)
2902
+ *
2903
+ * @param opt option to calculate eigenvalue/eigenvector
2904
+ * @return Eigenvalues and eigenvectors
2905
+ * @throw std::logic_error When operation is undefined
2906
+ * @throw std::runtime_error When operation is unavailable
2907
+ */
2908
+ typename MatrixBuilder<typename complex_t::m_t>::template resize_t<0, 1>::assignable_t eigen(
2909
+ const opt_eigen_t &opt = opt_eigen_t()) const {
2910
+
2911
+ typedef typename complex_t::m_t cmat_t;
2912
+ typedef typename MatrixBuilder<cmat_t>::template resize_t<0, 1, 1, 0>::assignable_t cvec_t;
2913
+ typedef typename MatrixBuilder<cmat_t>::template resize_t<0, 1>::assignable_t res_t;
2914
+
2915
+ if((opt.mat_prop == opt_eigen_t::NOT_CHECKED) && (!isSquare())){
2916
+ throw std::logic_error("rows() != columns()");
2917
+ }
2918
+
2919
+ #if 0
2920
+ //�p���[�@(�ׂ���@)
2921
+ const unsigned int rows_(rows()), columns_(columns());
2922
+ typename builder_t::template resize_t<0, 1>::assignable_t result(rows_, rows_ + 1);
2923
+ typename builder_t::assignable_t source(this->operator typename builder_t::assignable_t());
2924
+ for(unsigned int i(0); i < columns_; i++){result(0, i) = T(1);}
2925
+ for(unsigned int i(0); i < columns_; i++){
2926
+ while(true){
2927
+ typename builder_t::template resize_t<0, 1>::assignable_t approxVec(
2928
+ source * result.columnVector(i));
2929
+ T approxVal(0);
2930
+ for(unsigned int j(0); j < approxVec.rows(); j++){approxVal += pow(approxVec(j, 0), 2);}
2931
+ approxVal = sqrt(approxVal);
2932
+ for(unsigned int j(0); j < approxVec.rows(); j++){result(j, i) = approxVec(j, 0) / approxVal;}
2933
+ T before = result(i, rows_);
2934
+ if(abs(before - (result(i, rows_) = approxVal)) < threshold){break;}
2935
+ }
2936
+ for(unsigned int j(0); (i < rows_ - 1) && (j < rows_); j++){
2937
+ for(unsigned int k(0); k < rows_; k++){
2938
+ source(j, k) -= result(i, rows_) * result(j, i) * result(k, i);
2939
+ }
2940
+ }
2941
+ }
2942
+ return result;
2943
+ #endif
2944
+
2945
+ // Double QR method
2946
+ /* <Procedure>
2947
+ * 1) Transform upper Hessenburg's matrix by using Householder's method
2948
+ * �n�E�X�z���_�[�@��K�p���āA��w�b�Z���x���N�s��ɒu����
2949
+ * 2) Then, Apply double QR method to get eigenvalues
2950
+ * �_�u��QR�@��K�p�B
2951
+ * 3) Finally, compute eigenvectors
2952
+ * ���ʁA�ŗL�l��������̂ŁA�ŗL�x�N�g�����v�Z�B
2953
+ */
2954
+
2955
+ const unsigned int &_rows(rows());
2956
+
2957
+ // ���ʂ̊i�[�p�̍s��
2958
+ res_t result(res_t::blank(_rows, _rows + 1));
2959
+
2960
+ // �ŗL�l�̌v�Z
2961
+ #define lambda(i) result(i, _rows)
2962
+
2963
+ int m = _rows;
2964
+
2965
+ typename builder_t::assignable_t transform(getI(_rows));
2966
+ opt_hessenberg_t opt_A;
2967
+ opt_A.mat_prop = isSymmetric() ? opt_hessenberg_t::SYMMETRIC : opt_hessenberg_t::SQUARE;
2968
+ typename builder_t::assignable_t A(hessenberg(&transform, opt_A));
2969
+ typename builder_t::assignable_t A_(A.copy());
2970
+
2971
+ while(true){
2972
+
2973
+ //m = 1 or m = 2
2974
+ if(m == 1){
2975
+ lambda(0) = A(0, 0);
2976
+ break;
2977
+ }else if(m == 2){
2978
+ A.eigen22(0, 0, lambda(0), lambda(1));
2979
+ break;
2980
+ }
2981
+
2982
+ //�n�E�X�z���_�[�ϊ����J��Ԃ�
2983
+ for(int i(0); i < m - 1; i++){
2984
+ typename builder_t::template resize_t<3, 1, 0, 0>::assignable_t omega(3, 1);
2985
+ if(i == 0){ // calculate double shift of initial Householder transformation
2986
+ // @see https://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter4.pdf
2987
+ T trace_22(A(m-2, m-2) + A(m-1, m-1));
2988
+ T det_22(A(m-2, m-2) * A(m-1, m-1) - A(m-2, m-1) * A(m-1, m-2));
2989
+ omega(0, 0) = A(0, 0) * A(0, 0) + A(0, 1) * A(1, 0) - trace_22 * A(0, 0) + det_22;
2990
+ omega(1, 0) = A(1, 0) * (A(0, 0) + A(1, 1) - trace_22);
2991
+ omega(2, 0) = A(2, 1) * A(1, 0);
2992
+ }else{
2993
+ omega(0, 0) = A(i, i - 1);
2994
+ omega(1, 0) = A(i + 1, i - 1);
2995
+ omega(2, 0) = (i == m - 2 ? T(0) : A(i + 2, i - 1));
2996
+ // caution: omega size is 3x3 if i in [0, m-2), however, 2x2 when i == m-2
2997
+ }
2998
+
2999
+ typename complex_t::real_t omega_abs2(householder_vector(omega));
3000
+ if(omega_abs2 == 0){continue;}
3001
+ //std::cout << "omega_abs(" << m << ") " << omega_abs << std::endl;
3002
+
3003
+ if(false){ // as definition
3004
+ typename builder_t::assignable_t P(getI(_rows));
3005
+ P.pivotMerge(i, i, omega * omega.adjoint() * -2 / omega_abs2);
3006
+ A = P * A * P;
3007
+ }else{ // optimized
3008
+ if(i < m - 2){
3009
+ typename builder_t::template resize_t<3, 3, 0, 0>::assignable_t P(
3010
+ (omega * omega.adjoint() * -2 / omega_abs2) + 1);
3011
+ // P multiplication from left
3012
+ unsigned i2((i <= 1) ? 0 : i - 2);
3013
+ typename builder_t::template resize_t<3, 0, 0, 1>::assignable_t PX(
3014
+ P * A.partial(3, m - i2, i, i2));
3015
+ A.partial(3, m - i2, i, i2).replace(PX, false);
3016
+ // P multiplication from right
3017
+ unsigned i3((i >= m - 3) ? (i + 3) : (i + 4));
3018
+ typename builder_t::template resize_t<0, 3, 1, 0>::assignable_t PXP(
3019
+ A.partial(i3, 3, 0, i) * P);
3020
+ A.partial(i3, 3, 0, i).replace(PXP, false);
3021
+ }else{ // i == m - 2
3022
+ typename builder_t::template resize_t<2, 2, 0, 0>::assignable_t P(
3023
+ ((omega * omega.adjoint()).partial(2, 2) * -2 / omega_abs2) + 1);
3024
+ typename builder_t::template resize_t<2, 3, 0, 0>::assignable_t PX(
3025
+ P * A.partial(2, 3, i, i - 1));
3026
+ A.partial(2, 3, i, i - 1).replace(PX, false);
3027
+ typename builder_t::template resize_t<0, 2, 1, 0>::assignable_t PXP(
3028
+ A.partial(m, 2, 0, i) * P);
3029
+ A.partial(m, 2, 0, i).replace(PXP, false);
3030
+ }
3031
+ }
3032
+ }
3033
+ //std::cout << "A_scl(" << m << ") " << A(m-1,m-2) << std::endl;
3034
+
3035
+ if(complex_t::is_nan_or_infinite(A(m-1,m-2))){
3036
+ throw std::runtime_error("eigen values calculation failed");
3037
+ }
3038
+
3039
+ // Convergence test; ��������
3040
+ typename complex_t::real_t
3041
+ A_m2_abs(complex_t::get_abs(A(m-2, m-2))),
3042
+ A_m1_abs(complex_t::get_abs(A(m-1, m-1)));
3043
+ typename complex_t::real_t epsilon(opt.threshold_abs
3044
+ + opt.threshold_rel * ((A_m2_abs < A_m1_abs) ? A_m2_abs : A_m1_abs));
3045
+
3046
+ //std::cout << "epsil(" << m << ") " << epsilon << std::endl;
3047
+
3048
+ if(complex_t::get_abs(A(m-1, m-2)) < epsilon){
3049
+ --m;
3050
+ lambda(m) = A(m, m);
3051
+ }else if(complex_t::get_abs(A(m-2, m-3)) < epsilon){
3052
+ A.eigen22(m-2, m-2, lambda(m-1), lambda(m-2));
3053
+ m -= 2;
3054
+ }
3055
+ }
3056
+
3057
+ #if defined(MATRIX_EIGENVEC_SIMPLE)
3058
+ // �ŗL�x�N�g���̌v�Z
3059
+ cmat_t x(_rows, _rows); // �ŗL�x�N�g��
3060
+ A = A_;
3061
+
3062
+ for(unsigned int j(0); j < _rows; j++){
3063
+ unsigned int n = _rows;
3064
+ for(unsigned int i(0); i < j; i++){
3065
+ if((lambda(j) - lambda(i)).abs() <= threshold_abs){--n;}
3066
+ }
3067
+ //std::cout << n << ", " << lambda(j) << std::endl;
3068
+ x(--n, j) = 1;
3069
+ while(n-- > 0){
3070
+ x(n, j) = x(n+1, j) * (lambda(j) - A(n+1, n+1));
3071
+ for(unsigned int i(n+2); i < _rows; i++){
3072
+ x(n, j) -= x(i, j) * A(n+1, i);
3073
+ }
3074
+ if(A(n+1, n)){x(n, j) /= A(n+1, n);}
3075
+ }
3076
+ //std::cout << x.partial(_rows, 1, 0, j).transpose() << std::endl;
3077
+ }
3078
+ #else
3079
+ // Inverse iteration to compute eigenvectors; �ŗL�x�N�g���̌v�Z(�t�����@)
3080
+ cmat_t x(cmat_t::getI(_rows)); //�ŗL�x�N�g��
3081
+
3082
+ for(unsigned int j(0); j < _rows; j++){
3083
+ /* https://web.archive.org/web/20120702040824/http://www.prefield.com/algorithm/math/eigensystem.html
3084
+ * (Previously, http://www.prefield.com/algorithm/math/eigensystem.html)
3085
+ * is referred, and Numerical receipt
3086
+ * http://www.nrbook.com/a/bookcpdf/c11-7.pdf
3087
+ * is also utilized in case some eigenvalues are identical.
3088
+ */
3089
+ typename complex_t::v_t approx_lambda(lambda(j));
3090
+ approx_lambda += complex_t::get_abs(approx_lambda) * 1E-4; // 0.01%
3091
+ typename MatrixBuilder<cmat_t>::template resize_t<0, 0, 1, 2>::assignable_t
3092
+ A_C_lambda_LU((A_.complex() - approx_lambda).decomposeLU(false));
3093
+
3094
+ cvec_t target_x(cvec_t::blank(_rows, 1));
3095
+ target_x.replace(x.columnVector(j), false);
3096
+ for(unsigned int loop(0); true; loop++){
3097
+ cvec_t target_x_new(
3098
+ A_C_lambda_LU.solve_linear_eq_with_LU(target_x, false));
3099
+ typename complex_t::v_t mu((target_x_new.adjoint() * target_x)(0, 0)); // inner product
3100
+ typename complex_t::real_t v2(target_x_new.norm2F());
3101
+ target_x.replace(target_x_new / std::sqrt(v2), false);
3102
+ //std::cout << j << ": " << target_x.transpose() << ", " << mu << ", " << v2 << std::endl;
3103
+ if(std::abs(mu.abs2() / v2 - 1) < opt.threshold_abs){
3104
+ x.columnVector(j).replace(target_x, false);
3105
+ break;
3106
+ }
3107
+ if(loop > opt.inverse_power_max_iter){
3108
+ throw std::runtime_error("eigen vectors calculation failed");
3109
+ }
3110
+ }
3111
+ }
3112
+ #endif
3113
+
3114
+ /*res_t lambda2(_rows, _rows);
3115
+ for(unsigned int i(0); i < _rows; i++){
3116
+ lambda2(i, i) = lambda(i);
3117
+ }
3118
+
3119
+ std::cout << "A:" << A << std::endl;
3120
+ //std::cout << "x * x^-1" << x * x.inverse() << std::endl;
3121
+ std::cout << "x * lambda * x^-1:" << x * lambda2 * x.inverse() << std::endl;*/
3122
+
3123
+ // Register eigenvectors; ���ʂ̊i�[
3124
+ result.partial(_rows, _rows).replace(transform.complex() * x, false);
3125
+ // result.partial(_rows, _rows).replace(transform * x, false); is desireable,
3126
+ // however, (real) * (complex) may occur and fail to build.
3127
+
3128
+ #if 0
3129
+ // Normalization(���K��) is skipable due to transform matrix is unitary
3130
+ for(unsigned int j(0), j_end(x.columns()); j < j_end; j++){
3131
+ result.columnVector(j) /= complex_t::get_sqrt(result.columnVector(j).norm2F());
3132
+ }
3133
+ #endif
3134
+ #undef lambda
3135
+
3136
+ return result;
3137
+ }
3138
+
3139
+ protected:
3140
+ /**
3141
+ * Calculate square root of a matrix
3142
+ *
3143
+ * If matrix (A) can be decomposed as
3144
+ * @f[
3145
+ * A = V D V^{-1},
3146
+ * @f]
3147
+ * where D and V are diagonal matrix consisting of eigenvalues and eigenvectors, respectively,
3148
+ * the square root A^{1/2} is
3149
+ * @f[
3150
+ * A^{1/2} = V D^{1/2} V^{-1}.
3151
+ * @f]
3152
+ *
3153
+ * @param eigen_mat result of eigen()
3154
+ * @return square root
3155
+ * @see eiegn(const T &, const T &)
3156
+ */
3157
+ template <class MatrixT>
3158
+ static typename MatrixBuilder<MatrixT>::template resize_t<0, -1>::assignable_t sqrt(
3159
+ const MatrixT &eigen_mat){
3160
+ unsigned int n(eigen_mat.rows());
3161
+ typename MatrixT::partial_offsetless_t VsD(eigen_mat.partial(n, n));
3162
+ typename MatrixBuilder<MatrixT>::template resize_t<0, -1>::assignable_t nV(VsD.inverse());
3163
+ for(unsigned int i(0); i < n; i++){
3164
+ nV.partial(1, n, i, 0) *= (eigen_mat(i, n).sqrt());
3165
+ }
3166
+
3167
+ return (typename MatrixBuilder<MatrixT>::template resize_t<0, -1>::assignable_t)(VsD * nV);
3168
+ }
3169
+
3170
+ public:
3171
+ /**
3172
+ * Calculate square root of a matrix
3173
+ *
3174
+ * @param opt option to calculate eigenvalue/eigenvector
3175
+ * @return square root
3176
+ * @see eigen(const opt_eigen_t &)
3177
+ */
3178
+ typename complex_t::m_t sqrt(const opt_eigen_t &opt = opt_eigen_t()) const {
3179
+ return sqrt(eigen(opt));
3180
+ }
3181
+
3182
+ /**
3183
+ * Print matrix
3184
+ *
3185
+ */
3186
+ template<class CharT, class Traits>
3187
+ friend std::basic_ostream<CharT, Traits> &operator<<(
3188
+ std::basic_ostream<CharT, Traits> &out, const self_t &matrix){
3189
+ const unsigned int i_end(matrix.rows()), j_end(matrix.columns());
3190
+ out << "{";
3191
+ for(unsigned int i(0); i < i_end; i++){
3192
+ out << (i == 0 ? "" : ",") << std::endl << "{";
3193
+ for(unsigned int j(0); j < j_end; j++){
3194
+ out << (j == 0 ? "" : ",") << matrix(i, j);
3195
+ }
3196
+ out << "}";
3197
+ }
3198
+ out << std::endl << "}";
3199
+ return out;
3200
+ }
3201
+
3202
+ struct inspect_t {
3203
+ self_t mat;
3204
+ inspect_t(const self_t &target) : mat(target){}
3205
+
3206
+ template <class CharT, class Traits>
3207
+ struct format_t {
3208
+ std::basic_ostream<CharT, Traits> &out;
3209
+ format_t(std::basic_ostream<CharT, Traits> &_out) : out(_out) {}
3210
+
3211
+ template <class U>
3212
+ format_t &operator<<(const U &u){
3213
+ out << u;
3214
+ return *this;
3215
+ }
3216
+ format_t &operator<<(std::basic_ostream<CharT, Traits> &(*f)(std::basic_ostream<CharT, Traits> &)){
3217
+ // for std::endl, which is defined with template<class CharT, class Traits>
3218
+ out << f;
3219
+ return *this;
3220
+ }
3221
+
3222
+ template <class T2, class Array2D_Type2, class View_Type2>
3223
+ format_t &operator<<(const Matrix_Frozen<T2, Array2D_Type2, View_Type2> &m){
3224
+ (*this) << "M"
3225
+ << (MatrixViewProperty<View_Type2>::conjugated ? "~" : "")
3226
+ << (MatrixViewProperty<View_Type2>::transposed ? "t" : "")
3227
+ << (MatrixViewProperty<View_Type2>::variable_size ? "p" : "")
3228
+ << "(" << m.rows() << "," << m.columns() << ")";
3229
+ return *this;
3230
+ }
3231
+
3232
+ template <class LHS_T, class RHS_T, bool rhs_positive>
3233
+ format_t &operator<<(const Array2D_Operator_Add<LHS_T, RHS_T, rhs_positive> &op){
3234
+ return (*this) << op.lhs << ", " << op.rhs;
3235
+ }
3236
+ template <class LHS_T, class RHS_T>
3237
+ format_t &operator<<(const Array2D_Operator_Multiply_by_Scalar<LHS_T, RHS_T> &op){
3238
+ return (*this) << op.lhs << ", " << op.rhs;
3239
+ }
3240
+ template <class LHS_T, class RHS_T>
3241
+ format_t &operator<<(const Array2D_Operator_Multiply_by_Matrix<LHS_T, RHS_T> &op){
3242
+ return (*this) << op.lhs << ", " << op.rhs;
3243
+ }
3244
+
3245
+ template <class T2, class T2_op, class OperatorT, class View_Type2>
3246
+ format_t &operator<<(
3247
+ const Matrix_Frozen<T2, Array2D_Operator<T2_op, OperatorT>, View_Type2> &m){
3248
+ const char *symbol = "";
3249
+ switch(OperatorProperty<
3250
+ Matrix_Frozen<T2, Array2D_Operator<T2_op, OperatorT>, View_Type2> >::tag){
3251
+ case OPERATOR_2_Multiply_Matrix_by_Scalar:
3252
+ case OPERATOR_2_Multiply_Matrix_by_Matrix:
3253
+ symbol = "*"; break;
3254
+ case OPERATOR_2_Add_Matrix_to_Matrix:
3255
+ symbol = "+"; break;
3256
+ case OPERATOR_2_Subtract_Matrix_from_Matrix:
3257
+ symbol = "-"; break;
3258
+ default:
3259
+ return (*this) << "(?)";
3260
+ }
3261
+ return (*this) << "(" << symbol << ", "
3262
+ << m.storage.op << ")"
3263
+ << (MatrixViewProperty<View_Type2>::transposed ? "t" : "")
3264
+ << (MatrixViewProperty<View_Type2>::variable_size ? "p" : "");
3265
+ }
3266
+ };
3267
+
3268
+ template<class CharT, class Traits>
3269
+ std::basic_ostream<CharT, Traits> &operator()(std::basic_ostream<CharT, Traits> &out) const {
3270
+ format_t<CharT, Traits>(out)
3271
+ << "prop: {" << std::endl
3272
+ << " *(R,C): (" << mat.rows() << "," << mat.columns() << ")" << std::endl
3273
+ << " *view: " << mat.view << std::endl
3274
+ << " *storage: " << mat << std::endl
3275
+ << "}";
3276
+ return out;
3277
+ }
3278
+ };
3279
+ template<class CharT, class Traits>
3280
+ friend std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &out, const inspect_t &inspector){
3281
+ return inspector(out);
3282
+ }
3283
+ inspect_t inspect() const {
3284
+ return inspect_t(*this);
3285
+ }
3286
+ };
3287
+
3288
+ template <
3289
+ class T, class Array2D_Type, class ViewType,
3290
+ class RHS_T>
3291
+ struct Array2D_Operator_Multiply_by_Scalar<Matrix_Frozen<T, Array2D_Type, ViewType>, RHS_T>
3292
+ : public Array2D_Operator_Binary<Matrix_Frozen<T, Array2D_Type, ViewType>, RHS_T>{
3293
+ typedef Matrix_Frozen<T, Array2D_Type, ViewType> lhs_t;
3294
+ static const int tag = lhs_t::OPERATOR_2_Multiply_Matrix_by_Scalar;
3295
+ typedef Array2D_Operator_Binary<lhs_t, RHS_T> super_t;
3296
+ Array2D_Operator_Multiply_by_Scalar(const lhs_t &_lhs, const RHS_T &_rhs) noexcept
3297
+ : super_t(_lhs, _rhs) {}
3298
+ T operator()(const unsigned int &row, const unsigned int &column) const noexcept {
3299
+ return super_t::lhs(row, column) * super_t::rhs;
3300
+ }
3301
+ };
3302
+
3303
+ template <
3304
+ class T, class Array2D_Type, class ViewType,
3305
+ class RHS_T>
3306
+ struct Matrix_multiplied_by_Scalar<Matrix_Frozen<T, Array2D_Type, ViewType>, RHS_T> {
3307
+ typedef Matrix_Frozen<T, Array2D_Type, ViewType> lhs_t;
3308
+ typedef RHS_T rhs_t;
3309
+ typedef Array2D_Operator_Multiply_by_Scalar<lhs_t, rhs_t> impl_t;
3310
+ typedef Matrix_Frozen<T, Array2D_Operator<T, impl_t> > mat_t;
3311
+ static mat_t generate(const lhs_t &mat, const rhs_t &scalar) {
3312
+ return mat_t(
3313
+ typename mat_t::storage_t(
3314
+ mat.rows(), mat.columns(), impl_t(mat, scalar)));
3315
+ }
3316
+ };
3317
+
3318
+ template <class LHS_T, class RHS_T>
3319
+ struct Matrix_multiplied_by_Scalar<Matrix_Frozen<LHS_T, Array2D_ScaledUnit<LHS_T> >, RHS_T> {
3320
+ typedef Matrix_Frozen<LHS_T, Array2D_ScaledUnit<LHS_T> > lhs_t;
3321
+ typedef RHS_T rhs_t;
3322
+ typedef lhs_t mat_t;
3323
+ static mat_t generate(const lhs_t &mat, const rhs_t &scalar) {
3324
+ return mat_t(mat.rows(), mat(0, 0) * scalar);
3325
+ }
3326
+ };
3327
+
3328
+ template <
3329
+ class T, class Array2D_Type, class ViewType,
3330
+ class T2, class Array2D_Type2, class ViewType2,
3331
+ bool rhs_positive>
3332
+ struct Array2D_Operator_Add<
3333
+ Matrix_Frozen<T, Array2D_Type, ViewType>,
3334
+ Matrix_Frozen<T2, Array2D_Type2, ViewType2>,
3335
+ rhs_positive>
3336
+ : public Array2D_Operator_Binary<
3337
+ Matrix_Frozen<T, Array2D_Type, ViewType>,
3338
+ Matrix_Frozen<T2, Array2D_Type2, ViewType2> >{
3339
+ typedef Array2D_Operator_Binary<
3340
+ Matrix_Frozen<T, Array2D_Type, ViewType>,
3341
+ Matrix_Frozen<T2, Array2D_Type2, ViewType2> > super_t;
3342
+ static const int tag = rhs_positive
3343
+ ? super_t::lhs_t::OPERATOR_2_Add_Matrix_to_Matrix
3344
+ : super_t::lhs_t::OPERATOR_2_Subtract_Matrix_from_Matrix;
3345
+ Array2D_Operator_Add(
3346
+ const typename super_t::lhs_t &_lhs,
3347
+ const typename super_t::rhs_t &_rhs) noexcept
3348
+ : super_t(_lhs, _rhs) {}
3349
+ T operator()(const unsigned int &row, const unsigned int &column) const noexcept {
3350
+ if(rhs_positive){
3351
+ return super_t::lhs(row, column) + super_t::rhs(row, column);
3352
+ }else{
3353
+ return super_t::lhs(row, column) - super_t::rhs(row, column);
3354
+ }
3355
+ }
3356
+ };
3357
+
3358
+ template <
3359
+ class T, class Array2D_Type, class ViewType,
3360
+ class T2, class Array2D_Type2, class ViewType2>
3361
+ struct Array2D_Operator_Multiply_by_Matrix<
3362
+ Matrix_Frozen<T, Array2D_Type, ViewType>,
3363
+ Matrix_Frozen<T2, Array2D_Type2, ViewType2> >
3364
+ : public Array2D_Operator_Binary<
3365
+ Matrix_Frozen<T, Array2D_Type, ViewType>,
3366
+ Matrix_Frozen<T2, Array2D_Type2, ViewType2> >{
3367
+ typedef Matrix_Frozen<T, Array2D_Type, ViewType> lhs_t;
3368
+ typedef Matrix_Frozen<T2, Array2D_Type2, ViewType2> rhs_t;
3369
+ typedef Array2D_Operator_Multiply_by_Matrix<lhs_t, rhs_t> self_t;
3370
+ typedef Array2D_Operator_Binary<lhs_t, rhs_t> super_t;
3371
+ static const int tag = lhs_t::OPERATOR_2_Multiply_Matrix_by_Matrix;
3372
+ Array2D_Operator_Multiply_by_Matrix(const lhs_t &_lhs, const rhs_t &_rhs) noexcept
3373
+ : super_t(_lhs, _rhs) {}
3374
+ T operator()(const unsigned int &row, const unsigned int &column) const noexcept {
3375
+ T res(0);
3376
+ for(unsigned int i(0), i_end(super_t::lhs.columns()); i < i_end; ++i){
3377
+ res += super_t::lhs(row, i) * super_t::rhs(i, column);
3378
+ }
3379
+ return res;
3380
+ }
3381
+ typedef Matrix_Frozen<T, Array2D_Operator<T, self_t> > mat_t;
3382
+ static mat_t generate(const lhs_t &mat1, const rhs_t &mat2) {
3383
+ return mat_t(
3384
+ typename mat_t::storage_t(
3385
+ mat1.rows(), mat2.columns(), self_t(mat1, mat2)));
3386
+ }
3387
+ };
3388
+
3389
+ template <
3390
+ class T, class Array2D_Type, class ViewType,
3391
+ class T2>
3392
+ struct Array2D_Operator_Multiply_by_Matrix<
3393
+ Matrix_Frozen<T, Array2D_Type, ViewType>,
3394
+ Matrix_Frozen<T2, Array2D_ScaledUnit<T2> > >
3395
+ : public Matrix_multiplied_by_Scalar<Matrix_Frozen<T, Array2D_Type, ViewType>, T2> {
3396
+ typedef Matrix_multiplied_by_Scalar<Matrix_Frozen<T, Array2D_Type, ViewType>, T2> super_t;
3397
+ static typename super_t::mat_t generate(
3398
+ const typename super_t::lhs_t &mat1, const Matrix_Frozen<T2, Array2D_ScaledUnit<T2> > &mat2) {
3399
+ return super_t::generate(mat1, mat2(0, 0));
3400
+ }
3401
+ };
3402
+
3403
+ /*
3404
+ * Downcast rules including operation
3405
+ * When multiplication of multiple matrices, the most left and right hand terms are extracted intermediately.
3406
+ * For example, type((M1 * M2) * M3) will be type(M1 * M3).
3407
+ * type((M1 * M2) * (M3 * M4)) will be (M1 * M4).
3408
+ * In addition, a type of the most left hand term is used for any operation.
3409
+ * Please see the following examples:
3410
+ * type((M1 + M2) + M3) will be type(M1 + M2), then type(M1).
3411
+ * type(((M1 * M2) * M3) + M4) will be type((M1 * M2) * M3), then type(M1 * M3), and finally type(M1).
3412
+ */
3413
+ template <
3414
+ class T, class T_op, class OperatorT, class ViewType>
3415
+ struct MatrixBuilder_Dependency<
3416
+ Matrix_Frozen<T, Array2D_Operator<T_op, OperatorT>, ViewType> > {
3417
+
3418
+ private:
3419
+ template <class OperatorT2>
3420
+ struct unpack_op_t {
3421
+ // consequently, M * S, M + M are captured
3422
+ // (op, M1, M2, ...) => M1, then apply ViewType
3423
+ typedef typename MatrixBuilder<typename OperatorT2::first_t::frozen_t>
3424
+ ::template view_apply_t<ViewType>::applied_t mat_t;
3425
+ };
3426
+ template <class LHS_T, class RHS_T>
3427
+ struct unpack_op_t<Array2D_Operator_Multiply_by_Matrix<LHS_T, RHS_T> > { // M * M
3428
+ template <
3429
+ class OperatorT_L = typename LHS_T::template OperatorProperty<>::operator_t,
3430
+ class OperatorT_R = typename RHS_T::template OperatorProperty<>::operator_t,
3431
+ class U = void>
3432
+ struct check_op_t {
3433
+ typedef Matrix_Frozen<T, Array2D_Operator<T, Array2D_Operator_Multiply_by_Matrix<
3434
+ typename MatrixBuilder<LHS_T>::assignable_t::frozen_t,
3435
+ typename MatrixBuilder<RHS_T>::assignable_t::frozen_t> >, ViewType> res_t;
3436
+ };
3437
+ template <class U>
3438
+ struct check_op_t<void, void, U> {
3439
+ // active when both left and right hand side terms are none operator
3440
+ // This may be overwritten by (M * M) if its MatrixBuilder specialization exists
3441
+ typedef typename MatrixBuilder<LHS_T>
3442
+ ::template view_apply_t<ViewType>::applied_t res_t;
3443
+ };
3444
+ typedef typename check_op_t<>::res_t mat_t;
3445
+ };
3446
+
3447
+ typedef MatrixBuilder<typename unpack_op_t<OperatorT>::mat_t> gen_t;
3448
+ public:
3449
+ static const int row_buffer = gen_t::row_buffer;
3450
+ static const int column_buffer = gen_t::column_buffer;
3451
+
3452
+ typedef typename gen_t::assignable_t assignable_t;
3453
+
3454
+ template <class T2>
3455
+ struct cast_t {
3456
+ typedef typename gen_t::template cast_t<T2>::assignable_t assignable_t;
3457
+ };
3458
+
3459
+ template <int nR_add = 0, int nC_add = 0, int nR_multiply = 1, int nC_multiply = 1>
3460
+ struct resize_t {
3461
+ typedef typename gen_t::template resize_t<nR_add, nC_add, nR_multiply, nC_multiply>::assignable_t assignable_t;
3462
+ };
3463
+ };
3464
+
3465
+
3466
+ /**
3467
+ * @brief Matrix
3468
+ *
3469
+ * Most of useful matrix operations are defined.
3470
+ *
3471
+ * Special care when you want to make copy;
3472
+ * The copy constructor(s) and change functions of view such as
3473
+ * transpose() are implemented by using shallow copy, which means
3474
+ * these return values are linked to their original operand.
3475
+ * If you unlink the relation between the original and returned matrices,
3476
+ * you have to use copy(), which makes a deep copy explicitly,
3477
+ * for example, mat.transpose().copy().
3478
+ *
3479
+ * @param T precision such as double
3480
+ * @param Array2D_Type Storage type. The default is Array2D_Dense
3481
+ * @param ViewType View type. The default is void, which means no view, i.e. direct access.
3482
+ */
3483
+ template <class T, class Array2D_Type, class ViewType>
3484
+ class Matrix : public Matrix_Frozen<T, Array2D_Type, ViewType> {
3485
+ public:
3486
+ typedef Matrix_Frozen<T, Array2D_Type, ViewType> super_t;
3487
+
3488
+ #if defined(__GNUC__) && (__GNUC__ < 5)
3489
+ typedef typename super_t::storage_t storage_t;
3490
+ #else
3491
+ using typename super_t::storage_t;
3492
+ #endif
3493
+
3494
+ typedef Matrix<T, Array2D_Type, ViewType> self_t;
3495
+ typedef MatrixViewProperty<ViewType> view_property_t;
3496
+ typedef MatrixBuilder<self_t> builder_t;
3497
+
3498
+ typedef typename builder_t::assignable_t clone_t;
3499
+
3500
+ template <class T2, class Array2D_Type2, class ViewType2>
3501
+ friend class Matrix_Frozen;
3502
+
3503
+ template <class T2, class Array2D_Type2, class ViewType2>
3504
+ friend class Matrix;
3505
+
3506
+ template <class ImplementedT>
3507
+ static char (&check_storage(Array2D<T, ImplementedT> *) )[1];
3508
+ static const int storage_t_should_be_derived_from_Array2D
3509
+ = sizeof(check_storage(static_cast<storage_t *>(0)));
3510
+
3511
+ protected:
3512
+ /**
3513
+ * Constructor with storage
3514
+ *
3515
+ * @param new_storage new storage
3516
+ */
3517
+ Matrix(const storage_t &new_storage) : super_t(new_storage) {}
3518
+
3519
+ using super_t::storage;
3520
+
3521
+ public:
3522
+ /**
3523
+ * Return matrix element of specified indices.
3524
+ *
3525
+ * @param row Row index starting from 0.
3526
+ * @param column Column index starting from 0.
3527
+ * @return element
3528
+ */
3529
+ using super_t::operator();
3530
+ T &operator()(
3531
+ const unsigned int &row,
3532
+ const unsigned int &column){
3533
+ return super_t::view.DELETE_IF_MSC(template) operator()<T &, Array2D_Type>(storage, row, column);
3534
+ }
3535
+
3536
+ using super_t::rows;
3537
+ using super_t::columns;
3538
+
3539
+ class iterator : public super_t::template iterator_base_t<iterator> {
3540
+ public:
3541
+ typedef T value_type;
3542
+ typedef T& reference;
3543
+ typedef T* pointer;
3544
+ protected:
3545
+ self_t mat;
3546
+ typedef typename super_t::template iterator_base_t<iterator> base_t;
3547
+ public:
3548
+ unsigned int row() const {return base_t::row(mat);}
3549
+ unsigned int column() const {return base_t::column(mat);}
3550
+ reference operator*() {
3551
+ std::div_t rc(std::div(base_t::idx, mat.columns()));
3552
+ return mat((unsigned int)rc.quot, (unsigned int)rc.rem);
3553
+ }
3554
+ pointer operator->() {
3555
+ return &(operator*());
3556
+ }
3557
+ iterator(const self_t &mat_, const typename base_t::difference_type &idx_ = 0)
3558
+ : base_t(idx_), mat(mat_) {}
3559
+ iterator()
3560
+ : base_t(), mat() {}
3561
+ reference operator[](const typename base_t::difference_type &n){
3562
+ return *((*this) + n);
3563
+ }
3564
+ };
3565
+ using super_t::begin;
3566
+ iterator begin() {return iterator(*this);}
3567
+ typename super_t::const_iterator cbegin() const {return super_t::begin();}
3568
+ using super_t::end;
3569
+ iterator end() {return iterator(*this, rows() * columns());}
3570
+ typename super_t::const_iterator cend() const {return super_t::end();}
3571
+
3572
+ /**
3573
+ * Clear elements.
3574
+ *
3575
+ */
3576
+ void clear(){
3577
+ if(view_property_t::variable_size){
3578
+ for(unsigned int i(0), i_end(rows()); i < i_end; i++){
3579
+ for(unsigned int j(0), j_end(columns()); j < j_end; j++){
3580
+ (*this)(i, j) = T(0);
3581
+ }
3582
+ }
3583
+ }else{
3584
+ storage.storage_t::clear();
3585
+ }
3586
+ }
3587
+
3588
+ /**
3589
+ * Constructor without storage.
3590
+ *
3591
+ */
3592
+ Matrix() : super_t(){}
3593
+
3594
+ /**
3595
+ * Constructor with specified row and column numbers.
3596
+ * The storage will be assigned with the size.
3597
+ * The elements will be cleared with T(0).
3598
+ *
3599
+ * @param rows Row number
3600
+ * @param columns Column number
3601
+ */
3602
+ Matrix(
3603
+ const unsigned int &rows,
3604
+ const unsigned int &columns)
3605
+ : super_t(Array2D_Type(rows, columns)){
3606
+ /* Array2D_Type is intentionally used instead of storage_t due to VC2010(C2514) */
3607
+ clear();
3608
+ }
3609
+
3610
+ /**
3611
+ * Constructor with specified row and column numbers, and values.
3612
+ * The storage will be assigned with the size.
3613
+ * The elements will be initialized with specified values�B
3614
+ *
3615
+ * @param rows Row number
3616
+ * @param columns Column number
3617
+ * @param serialized Initial values of elements
3618
+ */
3619
+ Matrix(
3620
+ const unsigned int &rows,
3621
+ const unsigned int &columns,
3622
+ const T *serialized)
3623
+ : super_t(Array2D_Type(rows, columns, serialized)){
3624
+ /* Array2D_Type is intentionally used instead of storage_t due to VC2010(C2514) */
3625
+ }
3626
+
3627
+ /**
3628
+ * Copy constructor generating shallow copy linking to source matrix
3629
+ *
3630
+ * @param another source matrix
3631
+ */
3632
+ Matrix(const self_t &another)
3633
+ : super_t(another){}
3634
+
3635
+ /**
3636
+ * Constructor with different storage type
3637
+ * This will be used as Matrix x(Matrix + Matrix) to get calculation results,
3638
+ * where most of calculations are returned in a Matrix_Frozen due to expression template technique.
3639
+ * Another example is Matrix<Complex<double> > (Matrix<double>::getI(N))
3640
+ * to cast real to complex type.
3641
+ */
3642
+ template <class T2, class Array2D_Type2>
3643
+ Matrix(const Matrix_Frozen<T2, Array2D_Type2, ViewType> &matrix)
3644
+ : super_t(matrix) {}
3645
+ protected:
3646
+ /**
3647
+ * Constructor with different view
3648
+ * This will be used for view change such as transpose().
3649
+ */
3650
+ template <class ViewType2>
3651
+ Matrix(const Matrix<T, Array2D_Type, ViewType2> &matrix)
3652
+ : super_t(matrix){}
3653
+
3654
+ public:
3655
+ /**
3656
+ * Destructor
3657
+ */
3658
+ virtual ~Matrix(){}
3659
+
3660
+
3661
+ /**
3662
+ * Matrix generator with specified row and column numbers.
3663
+ * The storage will be assigned with the size,
3664
+ * however, initialization of elements will NOT be performed.
3665
+ * In addition, its view is none.
3666
+ *
3667
+ * @param new_rows Row number
3668
+ * @param new_columns Column number
3669
+ */
3670
+ static typename builder_t::assignable_t blank(
3671
+ const unsigned int &new_rows,
3672
+ const unsigned int &new_columns){
3673
+ typedef typename builder_t::assignable_t res_t;
3674
+ typedef typename res_t::storage_t s_t; // work around of VC2010(C2514)
3675
+ return res_t(s_t(new_rows, new_columns));
3676
+ }
3677
+
3678
+ protected:
3679
+ clone_t blank_copy() const {
3680
+ return clone_t::blank(rows(), columns());
3681
+ }
3682
+
3683
+ public:
3684
+ /**
3685
+ * Assigner for the same type matrix
3686
+ * After this operation, another variable which shared the buffer before the operation will be unlinked.
3687
+ * Its modification strategy is dependent on the implementation of storage=(another.storage),
3688
+ * which is called in frozen_t::operator=(const frozen_t &).
3689
+ * For example, storage is a Array2D_Storage, then shallow copy is conducted.
3690
+ *
3691
+ * @return myself
3692
+ */
3693
+ self_t &operator=(const self_t &another){
3694
+ super_t::operator=(another); // frozen_t::operator=(const frozen_t &) is exactly called
3695
+ return *this;
3696
+ }
3697
+ /**
3698
+ * Assigner for matrix having a different storage type
3699
+ * After this operation, another variable which shared the buffer before the operation will be unlinked.
3700
+ * Its modification strategy is dependent on the implementation of storage=(another.storage),
3701
+ * which is called in frozen_t::operator=(const another_frozen_t &).
3702
+ * For example, storage is a Array2D_Storage, then deep copy is conducted.
3703
+ * This will be used as
3704
+ * Matrix<Complex<double> > mat_c;
3705
+ * mat_c = Matrix<double>::getI(N);
3706
+ *
3707
+ * @return myself
3708
+ */
3709
+ template <class T2, class Array2D_Type2>
3710
+ self_t &operator=(const Matrix<T2, Array2D_Type2, ViewType> &matrix){
3711
+ super_t::operator=(matrix); // frozen_t::operator=(const another_frozen_t &) is exactly called
3712
+ return *this;
3713
+ }
3714
+
3715
+ protected:
3716
+ template <bool clone_storage = false, class U = void>
3717
+ struct copy_t {
3718
+ static clone_t run(const self_t &self){
3719
+ clone_t res(self.blank_copy());
3720
+ builder_t::copy_value(res, self);
3721
+ return res;
3722
+ }
3723
+ };
3724
+ template <class U>
3725
+ struct copy_t<true, U> {
3726
+ static clone_t run(const self_t &self){
3727
+ return clone_t(self.storage.storage_t::copy(true));
3728
+ }
3729
+ };
3730
+
3731
+ public:
3732
+ /**
3733
+ * Perform (deep) copy
3734
+ *
3735
+ * @return (clone_t)
3736
+ */
3737
+ clone_t copy() const {
3738
+ // To avoid undefined reference of (future defined, such as Matrix_Fixed) downcast in GCC,
3739
+ // template is used.
3740
+ return copy_t<view_property_t::viewless>::run(*this);
3741
+ }
3742
+
3743
+ protected:
3744
+ /**
3745
+ * Cast to another Matrix defined in Matrix_Frozen is intentionally protected.
3746
+ *
3747
+ * Use copy() for Matrix
3748
+ */
3749
+ operator clone_t() const;
3750
+
3751
+ public:
3752
+ typedef typename builder_t::transpose_t transpose_t;
3753
+ /**
3754
+ * Generate transpose matrix
3755
+ * Be careful, the return value is linked to the original matrix.
3756
+ * In order to unlink, do transpose().copy().
3757
+ *
3758
+ * @return Transpose matrix
3759
+ */
3760
+ transpose_t transpose() const noexcept {
3761
+ return transpose_t(*this);
3762
+ }
3763
+
3764
+ typedef typename builder_t::partial_t partial_t;
3765
+ /**
3766
+ * Generate partial matrix
3767
+ * Be careful, the return value is linked to the original matrix.
3768
+ * In order to unlink, do partial().copy().
3769
+ *
3770
+ * @param rowSize Row number
3771
+ * @param columnSize Column number
3772
+ * @param rowOffset Upper row index of original matrix for partial matrix
3773
+ * @param columnOffset Left column index of original matrix for partial matrix
3774
+ * @throw std::out_of_range When either row or column size exceeds original one
3775
+ * @return partial matrix
3776
+ *
3777
+ */
3778
+ partial_t partial(
3779
+ const unsigned int &new_rows,
3780
+ const unsigned int &new_columns,
3781
+ const unsigned int &row_offset,
3782
+ const unsigned int &column_offset) const {
3783
+ return super_t::partial_internal(*this,
3784
+ new_rows, new_columns, row_offset, column_offset);
3785
+ }
3786
+
3787
+ typedef typename builder_t::partial_offsetless_t partial_offsetless_t;
3788
+ /**
3789
+ * Generate partial matrix by just reducing its size;
3790
+ * The origins and direction of original and return matrices are the same.
3791
+ * Be careful, the return value is linked to the original matrix.
3792
+ * In order to unlink, do partial().copy().
3793
+ *
3794
+ * @param rowSize Row number
3795
+ * @param columnSize Column number
3796
+ * @throw std::out_of_range When either row or column size exceeds original one
3797
+ * @return partial matrix
3798
+ */
3799
+ partial_offsetless_t partial(
3800
+ const unsigned int &new_rows,
3801
+ const unsigned int &new_columns) const {
3802
+ return super_t::partial_internal(*this, new_rows, new_columns);
3803
+ }
3804
+
3805
+ using super_t::circular;
3806
+
3807
+ typedef typename builder_t::circular_bijective_t circular_bijective_t;
3808
+ /**
3809
+ * Generate matrix with circular view, keeping original size version.
3810
+ * This version is still belonged into Matrix class.
3811
+ * Another size variable version returns Matrix_Frozen.
3812
+ *
3813
+ * @param row_offset Upper row index of original matrix for circular matrix
3814
+ * @param column_offset Left column index of original matrix for circular matrix
3815
+ * @return matrix with circular view
3816
+ * @see circular(
3817
+ * const unsigned int &, const unsigned int &,
3818
+ * const unsigned int &, const unsigned int &)
3819
+ */
3820
+ circular_bijective_t circular(
3821
+ const unsigned int &row_offset,
3822
+ const unsigned int &column_offset) const noexcept {
3823
+ return super_t::circular_internal(*this, row_offset, column_offset);
3824
+ }
3825
+
3826
+ /**
3827
+ * Generate row vector by using partial()
3828
+ *
3829
+ * @param row Row index of original matrix for row vector
3830
+ * @return Row vector
3831
+ * @see partial()
3832
+ */
3833
+ partial_t rowVector(const unsigned int &row) const {
3834
+ return partial(1, columns(), row, 0);
3835
+ }
3836
+ /**
3837
+ * Generate column vector by using partial()
3838
+ *
3839
+ * @param column Column index of original matrix for column vector
3840
+ * @return Column vector
3841
+ * @see partial()
3842
+ */
3843
+ partial_t columnVector(const unsigned int &column) const {
3844
+ return partial(rows(), 1, 0, column);
3845
+ }
3846
+
3847
+ /**
3848
+ * Swap rows (bang method).
3849
+ * This operation has a side effect to another variables sharing the buffer.
3850
+ *
3851
+ * @param row1 Target row (1)
3852
+ * @param row2 Target row (2)
3853
+ * @return myself
3854
+ * @throw std::out_of_range When row1 or row2 exceeds bound
3855
+ */
3856
+ self_t &swapRows(
3857
+ const unsigned int &row1, const unsigned int &row2){
3858
+ if(row1 >= rows() || row2 >= rows()){
3859
+ throw std::out_of_range("Row index incorrect");
3860
+ }
3861
+ T temp;
3862
+ for(unsigned int j(0), j_end(columns()); j < j_end; j++){
3863
+ temp = (*this)(row1, j);
3864
+ (*this)(row1, j) = (*this)(row2, j);
3865
+ (*this)(row2, j) = temp;
3866
+ }
3867
+ return *this;
3868
+ }
3869
+
3870
+ /**
3871
+ * Swap columns (bang method).
3872
+ * This operation has a side effect to another variables sharing the buffer.
3873
+ *
3874
+ * @param column1 Target column (1)
3875
+ * @param column2 Target column (2)
3876
+ * @return myself
3877
+ * @throw std::out_of_range When column1 or column2 exceeds bound
3878
+ */
3879
+ self_t &swapColumns(
3880
+ const unsigned int &column1, const unsigned int &column2){
3881
+ if(column1 >= columns() || column2 >= columns()){
3882
+ throw std::out_of_range("Column index incorrect");
3883
+ }
3884
+ T temp;
3885
+ for(unsigned int i(0), i_end(rows()); i < i_end; i++){
3886
+ temp = (*this)(i, column1);
3887
+ (*this)(i, column1) = (*this)(i, column2);
3888
+ (*this)(i, column2) = temp;
3889
+ }
3890
+ return *this;
3891
+ }
3892
+
3893
+ /**
3894
+ * Replace content
3895
+ * This operation has a side effect to another variable sharing the buffer.
3896
+ *
3897
+ * @param matrix matrix to be replaced to
3898
+ * @param do_check Check matrix size property. The default is true
3899
+ * @return matrix with new content
3900
+ */
3901
+ template <class T2, class Array2D_Type2, class ViewType2>
3902
+ self_t &replace(
3903
+ const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix,
3904
+ const bool &do_check = true){
3905
+ if(do_check && isDifferentSize(matrix)){
3906
+ throw std::invalid_argument("Incorrect size");
3907
+ }
3908
+ return Matrix_Frozen<T2, Array2D_Type2, ViewType2>::builder_t::copy_value(*this, matrix);
3909
+ }
3910
+
3911
+ using super_t::isSquare;
3912
+ using super_t::isDiagonal;
3913
+ using super_t::isSymmetric;
3914
+ using super_t::isDifferentSize;
3915
+ using super_t::isLU;
3916
+
3917
+ /*
3918
+ * operator+=, operator-=, operator*=, operator/= are shortcuts of this->replace((*this) op another).
3919
+ * Be careful, they affect another variable whose referenced buffer is the same as (*this).
3920
+ * They are different from (*this) = (this_type)((*this) op another),
3921
+ * which does not affect another variable whose referenced buffer was the same as (*this) before the operation.
3922
+ */
3923
+
3924
+ /**
3925
+ * Multiply matrix by scalar (bang method)
3926
+ *
3927
+ * @param scalar
3928
+ * @return myself
3929
+ */
3930
+ self_t &operator*=(const T &scalar) noexcept {
3931
+ return replace((*this) * scalar, false);
3932
+ }
3933
+
3934
+ /**
3935
+ * Divide matrix by scalar (bang method)
3936
+ *
3937
+ * @param scalar
3938
+ * @return myself
3939
+ */
3940
+ self_t &operator/=(const T &scalar) noexcept {
3941
+ return operator*=(T(1) / scalar);
3942
+ }
3943
+
3944
+ /**
3945
+ * Add matrix to matrix (bang method)
3946
+ *
3947
+ * @param matrix Matrix to add
3948
+ * @return myself
3949
+ */
3950
+ template <class T2, class Array2D_Type2, class ViewType2>
3951
+ self_t &operator+=(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix){
3952
+ return replace((*this) + matrix, false);
3953
+ }
3954
+
3955
+ /**
3956
+ * Subtract matrix from matrix (bang method)
3957
+ *
3958
+ * @param matrix Matrix to subtract
3959
+ * @return myself
3960
+ */
3961
+ template <class T2, class Array2D_Type2, class ViewType2>
3962
+ self_t &operator-=(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix){
3963
+ return replace((*this) - matrix, false);
3964
+ }
3965
+
3966
+ /**
3967
+ * Add scalar to matrix (bang method)
3968
+ *
3969
+ * @param scalar scalar to add
3970
+ * @return myself
3971
+ */
3972
+ self_t &operator+=(const T &scalar){
3973
+ return replace((*this) + scalar, false);
3974
+ }
3975
+
3976
+ /**
3977
+ * Subtract scalar from matrix (bang method)
3978
+ *
3979
+ * @param scalar scalar to subtract
3980
+ * @return myself
3981
+ */
3982
+ self_t &operator-=(const T &scalar){
3983
+ return replace((*this) - scalar, false);
3984
+ }
3985
+
3986
+ /**
3987
+ * Multiply matrix by matrix (bang method)
3988
+ *
3989
+ * @param matrix Matrix to multiply
3990
+ * @return myself
3991
+ */
3992
+ template <class T2, class Array2D_Type2, class ViewType2>
3993
+ self_t &operator*=(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix){
3994
+ return replace((clone_t)(*this * matrix));
3995
+ }
3996
+
3997
+ /**
3998
+ * Divide matrix by matrix, in other words, multiply matrix by inverse matrix. (bang method)
3999
+ *
4000
+ * @param matrix Matrix to divide
4001
+ * @return myself
4002
+ */
4003
+ template <class T2, class Array2D_Type2, class ViewType2>
4004
+ self_t &operator/=(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) {
4005
+ return replace((clone_t)(*this / matrix));
4006
+ }
4007
+
4008
+ /**
4009
+ * Add matrix to matrix with specified pivot (bang method)
4010
+ *
4011
+ * @param row Upper row index (pivot) of matrix to be added
4012
+ * @param column Left column index (pivot) of matrix to be added
4013
+ * @param matrix Matrix to add
4014
+ * @return myself
4015
+ */
4016
+ template <class T2, class Array2D_Type2, class ViewType2>
4017
+ self_t &pivotMerge(
4018
+ const int &row, const int &column,
4019
+ const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix){
4020
+
4021
+ unsigned int i_min(row < 0 ? 0 : row), j_min(column < 0 ? 0 : column),
4022
+ i_max((row + matrix.rows()) > rows() ? rows() : row + matrix.rows()),
4023
+ j_max((column + matrix.columns()) > columns() ? columns() : column + matrix.columns());
4024
+ for(unsigned int i(i_min), i2(i_min - row); i < i_max; i++, i2++){
4025
+ for(unsigned int j(j_min), j2(j_min - column); j < j_max; j++, j2++){
4026
+ (*this)(i, j) += matrix(i2, j2);
4027
+ }
4028
+ }
4029
+
4030
+ return *this;
4031
+ }
4032
+
4033
+ };
4034
+
4035
+ template <class T, class Array2D_Type, class ViewType, class RHS_T>
4036
+ struct Matrix_multiplied_by_Scalar<Matrix<T, Array2D_Type, ViewType>, RHS_T>
4037
+ : public Matrix_multiplied_by_Scalar<Matrix_Frozen<T, Array2D_Type, ViewType>, RHS_T> {};
4038
+
4039
+ template <class LHS_T, class RHS_T>
4040
+ struct Array2D_Operator_Multiply_by_Matrix
4041
+ : public Array2D_Operator_Multiply_by_Matrix<typename LHS_T::frozen_t, typename RHS_T::frozen_t> {};
4042
+
4043
+ #undef DELETE_IF_MSC
4044
+ #undef throws_when_debug
4045
+ #if (__cplusplus < 201103L) && defined(noexcept)
4046
+ #undef noexcept
4047
+ #endif
4048
+
4049
+ #endif /* __MATRIX_H */