gps_pvt 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -0
- data/README.md +86 -0
- data/Rakefile +86 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +6613 -0
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +16019 -0
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +21050 -0
- data/ext/gps_pvt/extconf.rb +70 -0
- data/ext/ninja-scan-light/tool/navigation/EGM.h +2971 -0
- data/ext/ninja-scan-light/tool/navigation/GPS.h +2432 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +479 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +1081 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +199 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +210 -0
- data/ext/ninja-scan-light/tool/navigation/MagneticField.h +928 -0
- data/ext/ninja-scan-light/tool/navigation/NTCM.h +211 -0
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +1781 -0
- data/ext/ninja-scan-light/tool/navigation/WGS84.h +186 -0
- data/ext/ninja-scan-light/tool/navigation/coordinate.h +406 -0
- data/ext/ninja-scan-light/tool/param/bit_array.h +145 -0
- data/ext/ninja-scan-light/tool/param/complex.h +558 -0
- data/ext/ninja-scan-light/tool/param/matrix.h +4049 -0
- data/ext/ninja-scan-light/tool/param/matrix_fixed.h +665 -0
- data/ext/ninja-scan-light/tool/param/matrix_special.h +562 -0
- data/ext/ninja-scan-light/tool/param/quaternion.h +765 -0
- data/ext/ninja-scan-light/tool/param/vector3.h +651 -0
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +177 -0
- data/ext/ninja-scan-light/tool/swig/GPS.i +1102 -0
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1234 -0
- data/ext/ninja-scan-light/tool/swig/extconf.rb +5 -0
- data/ext/ninja-scan-light/tool/swig/makefile +53 -0
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +417 -0
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +489 -0
- data/gps_pvt.gemspec +57 -0
- data/lib/gps_pvt/receiver.rb +375 -0
- data/lib/gps_pvt/ubx.rb +148 -0
- data/lib/gps_pvt/version.rb +5 -0
- data/lib/gps_pvt.rb +9 -0
- data/sig/gps_pvt.rbs +4 -0
- 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> ©_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 */
|