gps_pvt 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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 */