Line data Source code
1 : /*
2 : * Copyright (c) 2006-2014, Visualization and Multimedia Lab,
3 : * University of Zurich <http://vmml.ifi.uzh.ch>,
4 : * Eyescale Software GmbH,
5 : * Blue Brain Project, EPFL
6 : *
7 : * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions are met:
11 : *
12 : * Redistributions of source code must retain the above copyright notice, this
13 : * list of conditions and the following disclaimer. Redistributions in binary
14 : * form must reproduce the above copyright notice, this list of conditions and
15 : * the following disclaimer in the documentation and/or other materials provided
16 : * with the distribution. Neither the name of the Visualization and Multimedia
17 : * Lab, University of Zurich nor the names of its contributors may be used to
18 : * endorse or promote products derived from this software without specific prior
19 : * written permission.
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 : #ifndef __VMML__MATRIX__HPP__
33 : #define __VMML__MATRIX__HPP__
34 :
35 : #include <vmmlib/vmmlib_config.hpp>
36 :
37 : #include <vmmlib/matrix_functors.hpp>
38 : #include <vmmlib/vector.hpp>
39 : #include <vmmlib/math.hpp>
40 : #include <vmmlib/exception.hpp>
41 : #include <vmmlib/enable_if.hpp>
42 :
43 : #include <iostream>
44 : #include <iomanip>
45 : #include <vector>
46 : #include <cstddef>
47 : #include <limits>
48 : #include <algorithm>
49 : #include <string>
50 : #include <cstring>
51 : #include <fstream> // file I/O
52 :
53 : namespace vmml
54 : {
55 :
56 : // matrix of type T with m rows and n columns
57 : template< size_t M, size_t N, typename T = float >
58 : class matrix
59 : {
60 : public:
61 : typedef T value_type;
62 : typedef T* iterator;
63 : typedef const T* const_iterator;
64 : typedef std::reverse_iterator< iterator > reverse_iterator;
65 : typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
66 :
67 : static const size_t ROWS = M;
68 : static const size_t COLS = N;
69 :
70 : // ctors
71 : matrix();
72 :
73 : template< size_t P, size_t Q, typename U >
74 : matrix( const matrix< P, Q, U >& source_ );
75 :
76 : // accessors
77 : inline T& operator()( size_t row_index, size_t col_index );
78 : inline const T& operator()( size_t row_index, size_t col_index ) const;
79 :
80 : inline T& at( size_t row_index, size_t col_index );
81 : inline const T& at( size_t row_index, size_t col_index ) const;
82 :
83 : // element iterators - NOTE: column-major order
84 : iterator begin();
85 : iterator end();
86 : const_iterator begin() const;
87 : const_iterator end() const;
88 :
89 : reverse_iterator rbegin();
90 : reverse_iterator rend();
91 : const_reverse_iterator rbegin() const;
92 : const_reverse_iterator rend() const;
93 :
94 : #ifndef VMMLIB_NO_CONVERSION_OPERATORS
95 : // auto conversion operator
96 : operator T*();
97 : operator const T*() const;
98 : #endif
99 :
100 : bool operator==( const matrix& other ) const;
101 : bool operator!=( const matrix& other ) const;
102 :
103 : // due to limited precision, two 'identical' matrices might seem different.
104 : // this function allows to specify a tolerance when comparing matrices.
105 : bool equals( const matrix& other, T tolerance ) const;
106 : // this version takes a comparison functor to compare the components of
107 : // the two matrices
108 : template< typename compare_t >
109 : bool equals( const matrix& other, compare_t& cmp ) const;
110 :
111 : void multiply_piecewise( const matrix& other );
112 :
113 : // (this) matrix = left matrix_mxp * right matrix_pxn
114 : template< size_t P > void multiply( const matrix< M, P, T >& left,
115 : const matrix< P, N, T >& right );
116 :
117 : // convolution operation (extending borders) of (this) matrix and the given kernel
118 : template< size_t U, size_t V >
119 : void convolve(const matrix< U, V, T >& kernel);
120 :
121 : // returned matrix_mxp = (this) matrix * other matrix_nxp;
122 : // note: using multiply(...) it avoids a copy of the resulting matrix
123 : template< size_t P >
124 : matrix< M, P, T > operator*( const matrix< N, P, T >& other ) const;
125 :
126 : // operator *= is only enabled for square matrices
127 : template< size_t O, size_t P, typename TT >
128 : typename enable_if< M == N && O == P && M == O, TT >::type*
129 : operator*=( const matrix< O, P, TT >& right );
130 :
131 : inline matrix operator+( const matrix& other ) const;
132 : inline matrix operator-( const matrix& other ) const;
133 :
134 : void operator+=( const matrix& other );
135 : void operator-=( const matrix& other );
136 :
137 : void operator+=( T scalar );
138 : void operator-=( T scalar );
139 :
140 : template< size_t O, size_t P, size_t Q, size_t R >
141 : typename enable_if< M == O + Q && N == P + R >::type*
142 : direct_sum( const matrix< O, P, T >& m0, const matrix< Q, R, T >& m1 );
143 :
144 : //
145 : // matrix-scalar operations / scaling
146 : //
147 : matrix operator*( T scalar );
148 : void operator*=( T scalar );
149 :
150 : matrix operator/( T scalar );
151 : void operator/=( T scalar );
152 :
153 : //
154 : // matrix-vector operations
155 : //
156 : // transform column vector by matrix ( vec = matrix * vec )
157 : vector< M, T > operator*( const vector< N, T >& other ) const;
158 :
159 : // transform column vector by matrix ( vec = matrix * vec )
160 : // assume homogenous coords, e.g. vec3 = mat4x4 * vec3, with w = 1.0
161 : template< size_t O >
162 : vector< O, T > operator*( const vector< O, T >& vector_ ) const;
163 :
164 : inline matrix< M, N, T > operator-() const;
165 : matrix< M, N, T > negate() const;
166 :
167 : // compute tensor product: (this) = vector (X) vector
168 : void tensor( const vector< M, T >& u, const vector< N, T >& v );
169 : // tensor, for api compatibility with old vmmlib version.
170 : // WARNING: for M = N = 4 only.
171 : template< size_t uM, size_t vM >
172 : typename enable_if< uM == 3 && vM == 3 && M == N && M == 4 >::type*
173 : tensor( const vector< uM, T >& u, const vector< vM, T >& v );
174 :
175 : // row_offset and col_offset define the starting indices for the sub_matrix
176 : // the sub_matrix is extracted according to the size of the target matrix, i.e. ( OXP )
177 : template< size_t O, size_t P >
178 : matrix< O, P, T >
179 : get_sub_matrix( size_t row_offset, size_t col_offset,
180 : typename enable_if< O <= M && P <= N >::type* = 0 ) const;
181 :
182 : template< size_t O, size_t P >
183 : typename enable_if< O <= M && P <= N >::type*
184 : get_sub_matrix( matrix< O, P, T >& result,
185 : size_t row_offset = 0, size_t col_offset = 0 ) const;
186 :
187 : template< size_t O, size_t P >
188 : typename enable_if< O <= M && P <= N >::type*
189 : set_sub_matrix( const matrix< O, P, T >& sub_matrix,
190 : size_t row_offset = 0, size_t col_offset = 0 );
191 :
192 : // copies a transposed version of *this into transposedMatrix
193 : void transpose_to( matrix< N, M, T >& transpose_ ) const;
194 :
195 : //symmetric covariance matrix of a right matrix multiplication: MxN x NxM = MxM
196 : void symmetric_covariance( matrix< M, M, T >& cov_m_ ) const;
197 :
198 :
199 : const matrix& operator=( const matrix< M, N, T >& source_ );
200 :
201 : // these assignment operators return nothing to avoid silent loss of
202 : // precision
203 : template< size_t P, size_t Q, typename U >
204 : void operator=( const matrix< P, Q, U >& source_ );
205 : void operator=( const T old_fashioned_matrix[ M ][ N ] );
206 :
207 : // WARNING: data_array[] must be at least of size M * N - otherwise CRASH!
208 : // WARNING: assumes row_by_row layout - if this is not the case,
209 : // use matrix::set( data_array, false )
210 : void operator=( const T* data_array );
211 : void operator=( const std::vector< T >& data );
212 :
213 : // sets all elements to fill_value
214 : void operator=( T fill_value );
215 : void fill( T fill_value );
216 :
217 : // note: this function copies elements until either the matrix is full or
218 : // the iterator equals end_.
219 : template< typename input_iterator_t >
220 : void set( input_iterator_t begin_, input_iterator_t end_,
221 : bool row_major_layout = true );
222 :
223 : //sets all matrix values with random values
224 : //remember to set srand( seed );
225 : //if seed is set to -1, srand( seed ) was set outside set_random
226 : //otherwise srand( seed ) will be called with the given seed
227 : void set_random( int seed = -1 );
228 :
229 : //sets all matrix values with discrete cosine transform coefficients (receive orthonormal coefficients)
230 : void set_dct();
231 :
232 : void zero();
233 :
234 : double frobenius_norm() const;
235 : double p_norm( double p ) const;
236 :
237 : template< typename TT >
238 : void cast_from( const matrix< M, N, TT >& other );
239 :
240 : void read_csv_file( const std::string& dir_, const std::string& filename_ );
241 : void write_csv_file( const std::string& dir_, const std::string& filename_ ) const;
242 : void write_to_raw( const std::string& dir_, const std::string& filename_ ) const;
243 : void read_from_raw( const std::string& dir_, const std::string& filename_ ) ;
244 :
245 : template< typename TT >
246 : void quantize_to( matrix< M, N, TT >& quantized_, const T& min_value, const T& max_value ) const;
247 : template< typename TT >
248 : void quantize( matrix< M, N, TT >& quantized_, T& min_value, T& max_value ) const;
249 : template< typename TT >
250 : void dequantize( matrix< M, N, TT >& quantized_, const TT& min_value, const TT& max_value ) const;
251 :
252 : void columnwise_sum( vector< N, T>& summed_columns_ ) const;
253 : double sum_elements() const;
254 :
255 : void sum_rows( matrix< M/2, N, T>& other ) const;
256 : void sum_columns( matrix< M, N/2, T>& other ) const;
257 :
258 : template< size_t R >
259 : typename enable_if< R == M && R == N >::type*
260 : diag( const vector< R, T >& diag_values_ );
261 :
262 :
263 : //Khatri-Rao Product: columns must be of same size
264 : template< size_t O >
265 : void khatri_rao_product( const matrix< O, N, T >& right_, matrix< M*O, N, T >& prod_ ) const;
266 : //Kronecker Product: MxN x_kronecker OxP = M*OxN*P
267 : template< size_t O, size_t P >
268 : void kronecker_product( const matrix< O, P, T >& right_, matrix< M*O, N*P, T >& result_) const;
269 :
270 : T get_min() const;
271 : T get_max() const;
272 : T get_abs_min() const;
273 : T get_abs_max() const;
274 :
275 : //returns number of non-zeros
276 : size_t nnz() const;
277 : size_t nnz( const T& threshold_ ) const;
278 : void threshold( const T& threshold_value_ );
279 :
280 : vector< M, T > get_column( size_t column_index ) const;
281 : void get_column( size_t column_index, vector< M, T>& column ) const;
282 :
283 : void set_column( size_t index, const vector< M, T >& column );
284 :
285 : void get_column( size_t index, matrix< M, 1, T >& column ) const;
286 : void set_column( size_t index, const matrix< M, 1, T >& column );
287 :
288 : vector< N, T > get_row( size_t index ) const;
289 : void get_row( size_t index, vector< N, T >& row ) const;
290 : void set_row( size_t index, const vector< N, T >& row );
291 :
292 : void get_row( size_t index, matrix< 1, N, T >& row ) const;
293 : void set_row( size_t index, const matrix< 1, N, T >& row );
294 :
295 : size_t size() const; // return M * N;
296 :
297 : size_t get_number_of_rows() const;
298 : size_t get_number_of_columns() const;
299 :
300 : T det() const;
301 :
302 : // the return value indicates if the matrix is invertible.
303 : // we need a tolerance term since the computation of the determinant is
304 : // subject to precision errors.
305 : template< size_t O, size_t P, typename TT >
306 : bool inverse( matrix< O, P, TT >& inverse_,
307 : T tolerance = std::numeric_limits<T>::epsilon(),
308 : typename enable_if< M == N && O == P && O == M && M >= 2 && M <= 4, TT >::type* = 0 ) const;
309 :
310 : template< size_t O, size_t P >
311 : typename enable_if< O == P && M == N && O == M && M >= 2 >::type*
312 : get_adjugate( matrix< O, P, T >& adjugate ) const;
313 :
314 : template< size_t O, size_t P >
315 : typename enable_if< O == P && M == N && O == M && M >= 2 >::type*
316 : get_cofactors( matrix< O, P, T >& cofactors ) const;
317 :
318 :
319 : // returns the determinant of a square matrix M-1, N-1
320 : template< size_t O, size_t P >
321 : T get_minor( matrix< O, P, T >& minor_, size_t row_to_cut, size_t col_to_cut,
322 : typename enable_if< O == M-1 && P == N-1 && M == N && M >= 2 >::type* = 0 ) const;
323 :
324 : //
325 : // 4*4 matrices only
326 : //
327 : /** create rotation matrix from parameters.
328 : * @param angle - angle in radians
329 : * @param rotation axis - must be normalized!
330 : */
331 : template< typename TT >
332 : matrix< M, N, T >& rotate( const TT angle, const vector< M-1, T >& axis,
333 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
334 :
335 : template< typename TT >
336 : matrix< M, N, T >& rotate_x( const TT angle,
337 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
338 :
339 : template< typename TT >
340 : matrix< M, N, T >& rotate_y( const TT angle,
341 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
342 :
343 : template< typename TT >
344 : matrix< M, N, T >& rotate_z( const TT angle,
345 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
346 :
347 : template< typename TT >
348 : matrix< M, N, T >& pre_rotate_x( const TT angle,
349 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
350 :
351 : template< typename TT >
352 : matrix< M, N, T >& pre_rotate_y( const TT angle,
353 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
354 :
355 : template< typename TT >
356 : matrix< M, N, T >& pre_rotate_z( const TT angle,
357 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
358 :
359 : template< typename TT >
360 : matrix< M, N, T >& scale( const TT scale[3],
361 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
362 :
363 : template< typename TT >
364 : matrix< M, N, T >& scale( const TT x_, const T y, const T z,
365 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
366 :
367 : template< typename TT >
368 : matrix< M, N, T >& scale( const vector< 3, TT >& scale_,
369 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
370 :
371 : template< typename TT >
372 : matrix< M, N, T >& scale_translation( const TT scale_[3],
373 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
374 :
375 : template< typename TT >
376 : matrix< M, N, T >& scale_translation( const vector< 3, TT >& scale_,
377 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
378 :
379 : template< typename TT >
380 : matrix< M, N, T >& set_translation( const TT x_, const TT y_, const TT z_,
381 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
382 :
383 : template< typename TT >
384 : matrix< M, N, T >& set_translation( const TT trans[3],
385 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
386 :
387 : template< typename TT >
388 : matrix< M, N, T >& set_translation( const vector< 3, TT >& t,
389 : typename enable_if< M == N && M == 4, TT >::type* = 0 );
390 :
391 : template< typename TT >
392 : void get_translation( vector< N-1, TT >& translation_ ) const;
393 :
394 : vector< N-1, T > get_translation() const;
395 :
396 : // hack for static-member-init
397 : template< typename init_functor_t >
398 : static const matrix get_initialized_matrix();
399 :
400 : inline T& x();
401 : inline T& y();
402 : inline T& z();
403 :
404 :
405 : // tests every component for isnan && isinf
406 : // inline bool is_valid() const; -> moved to class validator
407 :
408 : // legacy/compatibility accessor
409 : struct row_accessor
410 : {
411 : row_accessor( T* array_ ) : array( array_ ) {}
412 : T&
413 : operator[]( size_t col_index )
414 : {
415 : #ifdef VMMLIB_SAFE_ACCESSORS
416 : if ( col_index >= N )
417 : VMMLIB_ERROR( "column index out of bounds", VMMLIB_HERE );
418 : #endif
419 : return array[ col_index * M ];
420 : }
421 :
422 : const T&
423 : operator[]( size_t col_index ) const
424 : {
425 : #ifdef VMMLIB_SAFE_ACCESSORS
426 : if ( col_index >= N )
427 : VMMLIB_ERROR( "column index out of bounds", VMMLIB_HERE );
428 : #endif
429 : return array[ col_index * M ];
430 : }
431 :
432 : T* array;
433 : private: row_accessor() {} // disallow std ctor
434 : };
435 : // this is a hack to allow array-style access to matrix elements
436 : // usage: matrix< 2, 2, float > m; m[ 1 ][ 0 ] = 37.0f;
437 : inline row_accessor operator[]( size_t row_index )
438 : {
439 : #ifdef VMMLIB_SAFE_ACCESSORS
440 : if ( row_index > M )
441 : VMMLIB_ERROR( "row index out of bounds", VMMLIB_HERE );
442 : #endif
443 : return row_accessor( array + row_index );
444 : }
445 :
446 : // this is a hack to remove a warning about implicit conversions
447 : inline row_accessor operator[]( int row_index )
448 : {
449 : return ( *this )[ size_t ( row_index ) ];
450 : }
451 :
452 : friend std::ostream& operator << ( std::ostream& os,
453 : const matrix< M, N, T >& matrix )
454 : {
455 : const std::ios::fmtflags flags = os.flags();
456 : const int prec = os.precision();
457 :
458 : os.setf( std::ios::right, std::ios::adjustfield );
459 : os.precision( 5 );
460 :
461 : for( size_t row_index = 0; row_index < M; ++row_index )
462 : {
463 : os << "|";
464 : for( size_t col_index = 0; col_index < N; ++col_index )
465 : {
466 : os << std::setw(10) << matrix.at( row_index, col_index ) << " ";
467 : }
468 : os << "|" << std::endl;
469 : }
470 : os.precision( prec );
471 : os.setf( flags );
472 : return os;
473 : };
474 :
475 : // protected:
476 : T array[ M * N ]; //!< column by column storage
477 :
478 : // static members
479 : static const matrix< M, N, T > IDENTITY;
480 : static const matrix< M, N, T > ZERO;
481 :
482 : }; // class matrix
483 :
484 :
485 : #ifndef VMMLIB_NO_TYPEDEFS
486 : typedef vmml::matrix< 3, 3, double > Matrix3d; //!< A 3x3 double matrix
487 : typedef vmml::matrix< 4, 4, double > Matrix4d; //!< A 4x4 double matrix
488 : typedef vmml::matrix< 3, 3, float > Matrix3f; //!< A 3x3 float matrix
489 : typedef vmml::matrix< 4, 4, float > Matrix4f; //!< A 4x4 float matrix
490 : #endif
491 :
492 : /*
493 : * free functions
494 : */
495 :
496 : template< size_t M, size_t N, typename T >
497 : bool equals( const matrix< M, N, T >& m0, const matrix< M, N, T >& m1,
498 : const T tolerance = std::numeric_limits< T >::epsilon())
499 : {
500 : return m0.equals( m1, tolerance );
501 : }
502 :
503 :
504 : template< size_t M, size_t N, typename T >
505 : inline void multiply( const matrix< M, N, T >& left,
506 : const matrix< M, N, T >& right,
507 : matrix< M, N, T >& result )
508 : {
509 : result.multiply( left, right );
510 : }
511 :
512 :
513 :
514 : template< size_t M, size_t N, typename T >
515 : template< size_t U, size_t V >
516 : void matrix< M, N, T>::convolve(const matrix< U, V, T >& kernel)
517 : {
518 : matrix< M, N, T> temp; // do not override original values instantly as old values are needed for calculation
519 :
520 : for(size_t y_ = 0; y_ < N; ++y_)
521 : {
522 : for(size_t x_ = 0; x_ < M; ++x_)
523 : {
524 : double sum = 0.0;
525 :
526 : for(size_t j = 0; j < V; ++j)
527 : {
528 : int srcy = y_ - V/2 + j;
529 :
530 : // Extending border values
531 : if(srcy < 0) srcy = 0;
532 : if(srcy >= int(N)) srcy = N-1;
533 :
534 : for(size_t i = 0; i < U; ++i)
535 : {
536 : int srcx = x_ - U/2 + i;
537 :
538 : // Extending border values
539 : if(srcx < 0) srcx = 0;
540 : if(srcx >= int(M)) srcx = M-1;
541 :
542 : sum += kernel.at(j,i) * at(srcy,srcx);
543 : }
544 : }
545 : temp.at(y_,x_) = sum;
546 : }
547 : }
548 :
549 : *this = temp;
550 : }
551 :
552 :
553 :
554 : template< size_t M, size_t N, size_t P, typename T >
555 : inline void
556 : multiply( const matrix< M, P, T >& left, const matrix< P, N, T >& right,
557 : matrix< M, N, T >& result )
558 : {
559 : result.multiply( left, right );
560 : }
561 :
562 :
563 : template< size_t M, size_t N, typename T >
564 : inline typename enable_if< M == N >::type* identity( matrix< M, N, T >& m )
565 : {
566 : m = static_cast< T >( 0.0 );
567 : for( size_t index = 0; index < M; ++index )
568 : m( index, index ) = static_cast< T >( 1.0 );
569 : return 0; // for sfinae
570 : }
571 :
572 :
573 :
574 : template< typename T >
575 : inline T compute_determinant( const matrix< 1, 1, T >& matrix_ )
576 : {
577 : return matrix_.array[ 0 ];
578 : }
579 :
580 :
581 :
582 : template< typename T >
583 : inline T compute_determinant( const matrix< 2, 2, T >& matrix_ )
584 : {
585 : const T& a = matrix_( 0, 0 );
586 : const T& b = matrix_( 0, 1 );
587 : const T& c = matrix_( 1, 0 );
588 : const T& d = matrix_( 1, 1 );
589 : return a * d - b * c;
590 : }
591 :
592 :
593 :
594 : template< typename T >
595 : inline T compute_determinant( const matrix< 3, 3, T >& m_ )
596 : {
597 : return
598 : m_( 0,0 ) * ( m_( 1,1 ) * m_( 2,2 ) - m_( 1,2 ) * m_( 2,1 ) )
599 : + m_( 0,1 ) * ( m_( 1,2 ) * m_( 2,0 ) - m_( 1,0 ) * m_( 2,2 ) )
600 : + m_( 0,2 ) * ( m_( 1,0 ) * m_( 2,1 ) - m_( 1,1 ) * m_( 2,0 ) );
601 : }
602 :
603 :
604 : template< typename T >
605 : inline T compute_determinant( const matrix< 4, 4, T >& m )
606 : {
607 : T m00 = m( 0, 0 );
608 : T m10 = m( 1, 0 );
609 : T m20 = m( 2, 0 );
610 : T m30 = m( 3, 0 );
611 : T m01 = m( 0, 1 );
612 : T m11 = m( 1, 1 );
613 : T m21 = m( 2, 1 );
614 : T m31 = m( 3, 1 );
615 : T m02 = m( 0, 2 );
616 : T m12 = m( 1, 2 );
617 : T m22 = m( 2, 2 );
618 : T m32 = m( 3, 2 );
619 : T m03 = m( 0, 3 );
620 : T m13 = m( 1, 3 );
621 : T m23 = m( 2, 3 );
622 : T m33 = m( 3, 3 );
623 :
624 : return
625 : m03 * m12 * m21 * m30
626 : - m02 * m13 * m21 * m30
627 : - m03 * m11 * m22 * m30
628 : + m01 * m13 * m22 * m30
629 : + m02 * m11 * m23 * m30
630 : - m01 * m12 * m23 * m30
631 : - m03 * m12 * m20 * m31
632 : + m02 * m13 * m20 * m31
633 : + m03 * m10 * m22 * m31
634 : - m00 * m13 * m22 * m31
635 : - m02 * m10 * m23 * m31
636 : + m00 * m12 * m23 * m31
637 : + m03 * m11 * m20 * m32
638 : - m01 * m13 * m20 * m32
639 : - m03 * m10 * m21 * m32
640 : + m00 * m13 * m21 * m32
641 : + m01 * m10 * m23 * m32
642 : - m00 * m11 * m23 * m32
643 : - m02 * m11 * m20 * m33
644 : + m01 * m12 * m20 * m33
645 : + m02 * m10 * m21 * m33
646 : - m00 * m12 * m21 * m33
647 : - m01 * m10 * m22 * m33
648 : + m00 * m11 * m22 * m33;
649 : }
650 :
651 :
652 :
653 : template< typename T >
654 : bool compute_inverse( const matrix< 2, 2, T >& m_, matrix< 2, 2, T >& inverse_,
655 : T tolerance_ = std::numeric_limits<T>::epsilon())
656 : {
657 : const T det_ = compute_determinant( m_ );
658 : if( fabs( det_ ) < tolerance_ )
659 : return false;
660 :
661 : const T detinv = static_cast< T >( 1.0 ) / det_;
662 :
663 : m_.get_adjugate( inverse_ ); // set inverse_ to the adjugate of M
664 : inverse_ *= detinv;
665 : return true;
666 : }
667 :
668 :
669 :
670 : template< typename T >
671 : bool compute_inverse( const matrix< 3, 3, T >& m_, matrix< 3, 3, T >& inverse_,
672 : T tolerance_ = std::numeric_limits<T>::epsilon() )
673 : {
674 : // Invert a 3x3 using cofactors. This is about 8 times faster than
675 : // the Numerical Recipes code which uses Gaussian elimination.
676 : inverse_.at( 0, 0 ) = m_.at( 1, 1 ) * m_.at( 2, 2 ) - m_.at( 1, 2 ) * m_.at( 2, 1 );
677 : inverse_.at( 0, 1 ) = m_.at( 0, 2 ) * m_.at( 2, 1 ) - m_.at( 0, 1 ) * m_.at( 2, 2 );
678 : inverse_.at( 0, 2 ) = m_.at( 0, 1 ) * m_.at( 1, 2 ) - m_.at( 0, 2 ) * m_.at( 1, 1 );
679 : inverse_.at( 1, 0 ) = m_.at( 1, 2 ) * m_.at( 2, 0 ) - m_.at( 1, 0 ) * m_.at( 2, 2 );
680 : inverse_.at( 1, 1 ) = m_.at( 0, 0 ) * m_.at( 2, 2 ) - m_.at( 0, 2 ) * m_.at( 2, 0 );
681 : inverse_.at( 1, 2 ) = m_.at( 0, 2 ) * m_.at( 1, 0 ) - m_.at( 0, 0 ) * m_.at( 1, 2 );
682 : inverse_.at( 2, 0 ) = m_.at( 1, 0 ) * m_.at( 2, 1 ) - m_.at( 1, 1 ) * m_.at( 2, 0 );
683 : inverse_.at( 2, 1 ) = m_.at( 0, 1 ) * m_.at( 2, 0 ) - m_.at( 0, 0 ) * m_.at( 2, 1 );
684 : inverse_.at( 2, 2 ) = m_.at( 0, 0 ) * m_.at( 1, 1 ) - m_.at( 0, 1 ) * m_.at( 1, 0 );
685 :
686 : const T determinant =
687 : m_.at( 0, 0 ) * inverse_.at( 0, 0 )
688 : + m_.at( 0, 1 ) * inverse_.at( 1, 0 )
689 : + m_.at( 0, 2 ) * inverse_.at( 2, 0 );
690 :
691 : if ( fabs( determinant ) <= tolerance_ )
692 : return false; // matrix is not invertible
693 :
694 : const T detinv = static_cast< T >( 1.0 ) / determinant;
695 :
696 : inverse_.at( 0, 0 ) *= detinv;
697 : inverse_.at( 0, 1 ) *= detinv;
698 : inverse_.at( 0, 2 ) *= detinv;
699 : inverse_.at( 1, 0 ) *= detinv;
700 : inverse_.at( 1, 1 ) *= detinv;
701 : inverse_.at( 1, 2 ) *= detinv;
702 : inverse_.at( 2, 0 ) *= detinv;
703 : inverse_.at( 2, 1 ) *= detinv;
704 : inverse_.at( 2, 2 ) *= detinv;
705 :
706 : return true;
707 : }
708 :
709 :
710 : template< typename T >
711 : bool compute_inverse( const matrix< 4, 4, T >& m_,
712 : matrix< 4, 4, T >& inv_,
713 : T tolerance_ = std::numeric_limits<T>::epsilon() )
714 : {
715 : const T* array = m_.array;
716 :
717 : // tuned version from Claude Knaus
718 : /* first set of 2x2 determinants: 12 multiplications, 6 additions */
719 : const T t1[6] = { array[ 2] * array[ 7] - array[ 6] * array[ 3],
720 : array[ 2] * array[11] - array[10] * array[ 3],
721 : array[ 2] * array[15] - array[14] * array[ 3],
722 : array[ 6] * array[11] - array[10] * array[ 7],
723 : array[ 6] * array[15] - array[14] * array[ 7],
724 : array[10] * array[15] - array[14] * array[11] };
725 :
726 : /* first half of comatrix: 24 multiplications, 16 additions */
727 : inv_.array[0] = array[ 5] * t1[5] - array[ 9] * t1[4] + array[13] * t1[3];
728 : inv_.array[1] = array[ 9] * t1[2] - array[13] * t1[1] - array[ 1] * t1[5];
729 : inv_.array[2] = array[13] * t1[0] - array[ 5] * t1[2] + array[ 1] * t1[4];
730 : inv_.array[3] = array[ 5] * t1[1] - array[ 1] * t1[3] - array[ 9] * t1[0];
731 : inv_.array[4] = array[ 8] * t1[4] - array[ 4] * t1[5] - array[12] * t1[3];
732 : inv_.array[5] = array[ 0] * t1[5] - array[ 8] * t1[2] + array[12] * t1[1];
733 : inv_.array[6] = array[ 4] * t1[2] - array[12] * t1[0] - array[ 0] * t1[4];
734 : inv_.array[7] = array[ 0] * t1[3] - array[ 4] * t1[1] + array[ 8] * t1[0];
735 :
736 : /* second set of 2x2 determinants: 12 multiplications, 6 additions */
737 : const T t2[6] = { array[ 0] * array[ 5] - array[ 4] * array[ 1],
738 : array[ 0] * array[ 9] - array[ 8] * array[ 1],
739 : array[ 0] * array[13] - array[12] * array[ 1],
740 : array[ 4] * array[ 9] - array[ 8] * array[ 5],
741 : array[ 4] * array[13] - array[12] * array[ 5],
742 : array[ 8] * array[13] - array[12] * array[ 9] };
743 :
744 : /* second half of comatrix: 24 multiplications, 16 additions */
745 : inv_.array[8] = array[ 7] * t2[5] - array[11] * t2[4] + array[15] * t2[3];
746 : inv_.array[9] = array[11] * t2[2] - array[15] * t2[1] - array[ 3] * t2[5];
747 : inv_.array[10] = array[15] * t2[0] - array[ 7] * t2[2] + array[ 3] * t2[4];
748 : inv_.array[11] = array[ 7] * t2[1] - array[ 3] * t2[3] - array[11] * t2[0];
749 : inv_.array[12] = array[10] * t2[4] - array[ 6] * t2[5] - array[14] * t2[3];
750 : inv_.array[13] = array[ 2] * t2[5] - array[10] * t2[2] + array[14] * t2[1];
751 : inv_.array[14] = array[ 6] * t2[2] - array[14] * t2[0] - array[ 2] * t2[4];
752 : inv_.array[15] = array[ 2] * t2[3] - array[ 6] * t2[1] + array[10] * t2[0];
753 :
754 : /* determinant: 4 multiplications, 3 additions */
755 : const T determinant = array[0] * inv_.array[0] + array[4] * inv_.array[1] +
756 : array[8] * inv_.array[2] + array[12] * inv_.array[3];
757 :
758 : if( fabs( determinant ) <= tolerance_ )
759 : return false; // matrix is not invertible
760 :
761 : /* division: 16 multiplications, 1 division */
762 : const T detinv = static_cast< T >( 1.0 ) / determinant;
763 :
764 : for( size_t i = 0; i != 16; ++i )
765 : inv_.array[i] *= detinv;
766 :
767 : return true;
768 : }
769 :
770 :
771 : // this function returns the transpose of a matrix
772 : // however, using matrix::transpose_to( .. ) avoids the copy.
773 : template< size_t M, size_t N, typename T >
774 : inline matrix< N, M, T >
775 : transpose( const matrix< M, N, T >& matrix_ )
776 : {
777 : matrix< N, M, T > transpose_;
778 : matrix_.transpose_to( transpose_ );
779 : return transpose_;
780 : }
781 :
782 :
783 : template< size_t M, size_t N, typename T >
784 : bool is_positive_definite( const matrix< M, N, T >& matrix_,
785 : const T limit = -1e12,
786 : typename enable_if< M == N && M <= 3 >::type* = 0 )
787 : {
788 : if ( matrix_.at( 0, 0 ) < limit )
789 : return false;
790 :
791 : // sylvester criterion
792 : if ( M > 1 )
793 : {
794 : matrix< 2, 2, T > m;
795 : matrix_.get_sub_matrix( m, 0, 0 );
796 : if ( compute_determinant( m ) < limit )
797 : return false;
798 : }
799 :
800 : if ( M > 2 )
801 : {
802 : matrix< 3, 3, T > m;
803 : matrix_.get_sub_matrix( m, 0, 0 );
804 : if ( compute_determinant( m ) < limit )
805 : return false;
806 : }
807 :
808 : return true;
809 : }
810 :
811 :
812 : template< size_t M, size_t N, typename T >
813 1 : matrix< M, N, T >::matrix()
814 1 : : array() // http://stackoverflow.com/questions/5602030
815 : {
816 : if( M == N )
817 5 : for( size_t i = 0; i < M; ++i )
818 4 : at( i, i ) = static_cast< T >( 1.0 );
819 1 : }
820 :
821 : template< size_t M, size_t N, typename T >
822 : template< size_t P, size_t Q, typename U >
823 : matrix< M, N, T >::matrix( const matrix< P, Q, U >& source_ )
824 : {
825 : (*this) = source_;
826 : }
827 :
828 :
829 : template< size_t M, size_t N, typename T >
830 20 : inline T& matrix< M, N, T >::at( size_t row_index, size_t col_index )
831 : {
832 : #ifdef VMMLIB_SAFE_ACCESSORS
833 20 : if ( row_index >= M || col_index >= N )
834 0 : VMMLIB_ERROR( "at( row, col ) - index out of bounds", VMMLIB_HERE );
835 : #endif
836 20 : return array[ col_index * M + row_index ];
837 : }
838 :
839 :
840 :
841 : template< size_t M, size_t N, typename T >
842 : const inline T&
843 16 : matrix< M, N, T >::at( size_t row_index, size_t col_index ) const
844 : {
845 : #ifdef VMMLIB_SAFE_ACCESSORS
846 16 : if ( row_index >= M || col_index >= N )
847 0 : VMMLIB_ERROR( "at( row, col ) - index out of bounds", VMMLIB_HERE );
848 : #endif
849 16 : return array[ col_index * M + row_index ];
850 : }
851 :
852 :
853 : template< size_t M, size_t N, typename T >
854 : inline T&
855 16 : matrix< M, N, T >::operator()( size_t row_index, size_t col_index )
856 : {
857 16 : return at( row_index, col_index );
858 : }
859 :
860 :
861 :
862 : template< size_t M, size_t N, typename T >
863 : const inline T&
864 : matrix< M, N, T >::operator()( size_t row_index, size_t col_index ) const
865 : {
866 : return at( row_index, col_index );
867 : }
868 :
869 : #ifndef VMMLIB_NO_CONVERSION_OPERATORS
870 :
871 : template< size_t M, size_t N, typename T >
872 : matrix< M, N, T >::
873 : operator T*()
874 : {
875 : return array;
876 : }
877 :
878 :
879 :
880 : template< size_t M, size_t N, typename T >
881 : matrix< M, N, T >::
882 : operator const T*() const
883 : {
884 : return array;
885 : }
886 :
887 : #endif
888 :
889 :
890 : template< size_t M, size_t N, typename T >
891 : bool
892 : matrix< M, N, T >::
893 : operator==( const matrix< M, N, T >& other ) const
894 : {
895 : bool is_ok = true;
896 : for( size_t i = 0; is_ok && i < M * N; ++i )
897 : {
898 : is_ok = array[ i ] == other.array[ i ];
899 : }
900 : return is_ok;
901 : }
902 :
903 :
904 :
905 :
906 : template< size_t M, size_t N, typename T >
907 : bool
908 : matrix< M, N, T >::
909 : operator!=( const matrix< M, N, T >& other ) const
910 : {
911 : return ! operator==( other );
912 : }
913 :
914 :
915 :
916 : template< size_t M, size_t N, typename T >
917 : bool
918 : matrix< M, N, T >::
919 : equals( const matrix< M, N, T >& other, T tolerance ) const
920 : {
921 : bool is_ok = true;
922 : for( size_t row_index = 0; is_ok && row_index < M; row_index++)
923 : {
924 : for( size_t col_index = 0; is_ok && col_index < N; col_index++)
925 : {
926 : is_ok = fabs( at( row_index, col_index ) - other( row_index, col_index ) ) < tolerance;
927 : }
928 : }
929 : return is_ok;
930 : }
931 :
932 :
933 :
934 : template< size_t M, size_t N, typename T >
935 : template< typename compare_t >
936 : bool matrix< M, N, T >::equals( const matrix< M, N, T >& other_matrix,
937 : compare_t& cmp ) const
938 : {
939 : bool is_ok = true;
940 : for( size_t row = 0; is_ok && row < M; ++row )
941 : {
942 : for( size_t col = 0; is_ok && col < N; ++col)
943 : {
944 : is_ok = cmp( at( row, col ), other_matrix.at( row, col ) );
945 : }
946 : }
947 : return is_ok;
948 : }
949 :
950 : #if (( __GNUC__ > 4 ) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) )
951 : # pragma GCC diagnostic ignored "-Warray-bounds" // gcc 4.4.7 bug WAR
952 : #endif
953 : template< size_t M, size_t N, typename T >
954 : const matrix< M, N, T >&
955 : matrix< M, N, T >::operator=( const matrix< M, N, T >& source_ )
956 : {
957 : memcpy( array, source_.array, M * N * sizeof( T ));
958 : return *this;
959 : }
960 : #if (( __GNUC__ > 4 ) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) )
961 : # pragma GCC diagnostic warning "-Warray-bounds"
962 : #endif
963 :
964 : template< size_t M, size_t N, typename T >
965 : template< size_t P, size_t Q, typename U >
966 : void matrix< M, N, T >::operator=( const matrix< P, Q, U >& source_ )
967 : {
968 : const size_t minL = P < M ? P : M;
969 : const size_t minC = Q < N ? Q : N;
970 :
971 : if( minL < M || minC < N )
972 : zero();
973 :
974 : for ( size_t i = 0 ; i < minL ; i++ )
975 : for ( size_t j = 0 ; j < minC ; j++ )
976 : at( i,j ) = static_cast< T >( source_( i, j ));
977 : }
978 :
979 :
980 : template< size_t M, size_t N, typename T >
981 : void matrix< M, N, T >::operator=( const T old_fashioned_matrix[ M ][ N ] )
982 : {
983 : for( size_t row = 0; row < M; row++)
984 : {
985 : for( size_t col = 0; col < N; col++)
986 : {
987 : at( row, col ) = old_fashioned_matrix[ row ][ col ];
988 : }
989 : }
990 :
991 : }
992 :
993 :
994 : // WARNING: data_array[] must be at least of size M * N - otherwise CRASH!
995 : // WARNING: assumes row_by_row layout - if this is not the case,
996 : // use matrix::set( data_array, false )
997 : template< size_t M, size_t N, typename T >
998 : void
999 : matrix< M, N, T >::operator=( const T* data_array )
1000 : {
1001 : set( data_array, data_array + M * N, true );
1002 : }
1003 :
1004 :
1005 :
1006 : template< size_t M, size_t N, typename T >
1007 : void
1008 : matrix< M, N, T >::operator=( const std::vector< T >& data )
1009 : {
1010 : if ( data.size() < M * N )
1011 : VMMLIB_ERROR( "index out of bounds.", VMMLIB_HERE );
1012 :
1013 : set( data.begin(), data.end(), true );
1014 : }
1015 :
1016 :
1017 : template< size_t M, size_t N, typename T >
1018 : void
1019 : matrix< M, N, T >::multiply_piecewise( const matrix& other )
1020 : {
1021 : for( size_t row_index = 0; row_index < M; row_index++)
1022 : {
1023 : for( size_t col_index = 0; col_index < N; col_index++ )
1024 : {
1025 : T& value = at( row_index, col_index );
1026 : value *= other.at( row_index, col_index );
1027 : }
1028 : }
1029 : }
1030 :
1031 :
1032 : template< size_t M, size_t N, typename T >
1033 : template< size_t P >
1034 : void
1035 : matrix< M, N, T >::multiply(
1036 : const matrix< M, P, T >& left,
1037 : const matrix< P, N, T >& right
1038 : )
1039 : {
1040 : for( size_t row_index = 0; row_index < M; row_index++)
1041 : {
1042 : for( size_t col_index = 0; col_index < N; col_index++)
1043 : {
1044 : T& component = at( row_index, col_index );
1045 : component = static_cast< T >( 0.0 );
1046 : for( size_t p = 0; p < P; p++)
1047 : {
1048 : component += left.at( row_index, p ) * right.at( p, col_index );
1049 : }
1050 : }
1051 : }
1052 : }
1053 :
1054 :
1055 :
1056 : template< size_t M, size_t N, typename T >
1057 : template< size_t P >
1058 : matrix< M, P, T >
1059 : matrix< M, N, T >::operator*( const matrix< N, P, T >& other ) const
1060 : {
1061 : matrix< M, P, T > result;
1062 : result.multiply( *this, other );
1063 : return result;
1064 : }
1065 :
1066 :
1067 :
1068 : template< size_t M, size_t N, typename T >
1069 : template< size_t O, size_t P, typename TT >
1070 : typename enable_if< M == N && O == P && M == O, TT >::type*
1071 : matrix< M, N, T >::operator*=( const matrix< O, P, TT >& right )
1072 : {
1073 : matrix< M, N, T > copy( *this );
1074 : multiply( copy, right );
1075 : return 0;
1076 : }
1077 :
1078 : template< size_t M, size_t N, typename T >
1079 : matrix< M, N, T >
1080 : matrix< M, N, T >::operator/( T scalar )
1081 : {
1082 : matrix< M, N, T > result;
1083 :
1084 : for( size_t row_index = 0; row_index < M; ++row_index )
1085 : {
1086 : for( size_t col_index = 0; col_index < N; ++col_index )
1087 : {
1088 : result.at( row_index, col_index ) = at( row_index, col_index ) / scalar;
1089 : }
1090 : }
1091 : return result;
1092 : }
1093 :
1094 :
1095 :
1096 : template< size_t M, size_t N, typename T >
1097 : void
1098 : matrix< M, N, T >::operator/=( T scalar )
1099 : {
1100 : for( size_t row_index = 0; row_index < M; ++row_index )
1101 : {
1102 : for( size_t col_index = 0; col_index < N; ++col_index )
1103 : {
1104 : at( row_index, col_index ) /= scalar;
1105 : }
1106 : }
1107 : }
1108 :
1109 :
1110 :
1111 :
1112 :
1113 : template< size_t M, size_t N, typename T >
1114 : matrix< M, N, T >
1115 : matrix< M, N, T >::operator*( T scalar )
1116 : {
1117 : matrix< M, N, T > result;
1118 :
1119 : for( size_t row_index = 0; row_index < M; ++row_index )
1120 : {
1121 : for( size_t col_index = 0; col_index < N; ++col_index )
1122 : {
1123 : result.at( row_index, col_index ) = at( row_index, col_index ) * scalar;
1124 : }
1125 : }
1126 : return result;
1127 : }
1128 :
1129 :
1130 :
1131 : template< size_t M, size_t N, typename T >
1132 : void
1133 : matrix< M, N, T >::operator*=( T scalar )
1134 : {
1135 : for( size_t row_index = 0; row_index < M; ++row_index )
1136 : {
1137 : for( size_t col_index = 0; col_index < N; ++col_index )
1138 : {
1139 : at( row_index, col_index ) *= scalar;
1140 : }
1141 : }
1142 : }
1143 :
1144 :
1145 :
1146 : template< size_t M, size_t N, typename T >
1147 : vector< M, T > matrix< M, N, T >::operator*( const vector< N, T >& vec ) const
1148 : {
1149 : vector< M, T > result;
1150 :
1151 : // this < M, 1 > = < M, P > * < P, 1 >
1152 : for( size_t i = 0; i < M; ++i )
1153 : {
1154 : T tmp( 0 );
1155 : for( size_t j = 0; j < N; ++j )
1156 : tmp += at( i, j ) * vec.at( j );
1157 : result.at( i ) = tmp;
1158 : }
1159 : return result;
1160 : }
1161 :
1162 :
1163 :
1164 : // transform vector by matrix ( vec = matrix * vec )
1165 : // assume homogenous coords( for vec3 = mat4 * vec3 ), e.g. vec[3] = 1.0
1166 : template< size_t M, size_t N, typename T >
1167 : template< size_t O > vector< O, T >
1168 : matrix< M, N, T >::operator*( const vector< O, T >& vector_ ) const
1169 : {
1170 : vector< O, T > result;
1171 : T tmp;
1172 : for( size_t row_index = 0; row_index < M; ++row_index )
1173 : {
1174 : tmp = 0.0;
1175 : for( size_t col_index = 0; col_index < N-1; ++col_index )
1176 : {
1177 : tmp += vector_( col_index ) * at( row_index, col_index );
1178 : }
1179 : if ( row_index < N - 1 )
1180 : result( row_index ) = tmp + at( row_index, N-1 ); // * 1.0 -> homogeneous vec4
1181 : else
1182 : {
1183 : tmp += at( row_index, N - 1 );
1184 : for( size_t col_index = 0; col_index < N - 1; ++col_index )
1185 : {
1186 : result( col_index ) /= tmp;
1187 : }
1188 : }
1189 : }
1190 : return result;
1191 : }
1192 :
1193 :
1194 :
1195 : template< size_t M, size_t N, typename T >
1196 : inline matrix< M, N, T >
1197 : matrix< M, N, T >::operator-() const
1198 : {
1199 : return negate();
1200 : }
1201 :
1202 :
1203 :
1204 : template< size_t M, size_t N, typename T >
1205 : matrix< M, N, T >
1206 : matrix< M, N, T >::negate() const
1207 : {
1208 : matrix< M, N, T > result;
1209 : result *= -1.0;
1210 : return result;
1211 : }
1212 :
1213 :
1214 :
1215 : template< size_t M, size_t N, typename T >
1216 : void
1217 : matrix< M, N, T >::tensor( const vector< M, T >& u, const vector< N, T >& v )
1218 : {
1219 : for ( size_t col_index = 0; col_index < N; ++col_index )
1220 : for ( size_t row_index = 0; row_index < M; ++row_index )
1221 : at( row_index, col_index ) = u.array[ col_index ] *
1222 : v.array[ row_index ];
1223 : }
1224 :
1225 :
1226 :
1227 : template< size_t M, size_t N, typename T >
1228 : template< size_t uM, size_t vM >
1229 : typename enable_if< uM == 3 && vM == 3 && M == N && M == 4 >::type*
1230 : matrix< M, N, T >::tensor( const vector< uM, T >& u, const vector< vM, T >& v )
1231 : {
1232 : for ( size_t col_index = 0; col_index < 3; ++col_index )
1233 : {
1234 : for ( size_t row_index = 0; row_index < 3; ++row_index )
1235 : at( row_index, col_index ) = u.array[ col_index ] *
1236 : v.array[ row_index ];
1237 :
1238 : at( 3, col_index ) = u.array[ col_index ];
1239 : }
1240 :
1241 : for ( size_t row_index = 0; row_index < 3; ++row_index )
1242 : at( row_index, 3 ) = v.array[ row_index ];
1243 :
1244 : at( 3, 3 ) = 1.0;
1245 :
1246 : return 0;
1247 : }
1248 :
1249 :
1250 :
1251 : template< size_t M, size_t N, typename T >
1252 : void
1253 : matrix< M, N, T >::
1254 : transpose_to( matrix< N, M, T >& tM ) const
1255 : {
1256 : for( size_t row = 0; row < M; ++row )
1257 : {
1258 : for( size_t col = 0; col < N; ++col )
1259 : {
1260 : tM.at( col, row ) = at( row, col );
1261 : }
1262 : }
1263 : }
1264 :
1265 : template< size_t M, size_t N, typename T >
1266 : void
1267 : matrix< M, N, T >::
1268 : symmetric_covariance( matrix< M, M, T >& cov_m_ ) const
1269 : {
1270 : T tmp = 0;
1271 : for( size_t row = 0; row < M; ++row )
1272 : {
1273 : for( size_t col = row; col < M; ++col )
1274 : {
1275 : for ( size_t k = 0; k < N; ++k )
1276 : {
1277 : tmp += (at( row, k ) * at( col, k ));
1278 : }
1279 :
1280 : cov_m_.at( row, col ) = tmp;
1281 : cov_m_.at( col, row ) = tmp;
1282 : tmp = 0;
1283 : }
1284 : }
1285 : }
1286 :
1287 :
1288 :
1289 : template< size_t M, size_t N, typename T >
1290 : vector< M, T > matrix< M, N, T >::get_column( size_t index ) const
1291 : {
1292 : vector< M, T > column;
1293 : get_column( index, column );
1294 : return column;
1295 : }
1296 :
1297 :
1298 :
1299 : template< size_t M, size_t N, typename T >
1300 : void matrix< M, N, T >::get_column( size_t index, vector< M, T >& column ) const
1301 : {
1302 : #ifdef VMMLIB_SAFE_ACCESSORS
1303 : if ( index >= N )
1304 : VMMLIB_ERROR( "get_column() - index out of bounds.", VMMLIB_HERE );
1305 : #endif
1306 :
1307 : memcpy( &column.array[0], &array[ M * index ], M * sizeof( T ) );
1308 : }
1309 :
1310 :
1311 :
1312 : template< size_t M, size_t N, typename T >
1313 : void matrix< M, N, T >::set_column( size_t index, const vector< M, T >& column )
1314 : {
1315 : #ifdef VMMLIB_SAFE_ACCESSORS
1316 :
1317 : if ( index >= N )
1318 : VMMLIB_ERROR( "set_column() - index out of bounds.", VMMLIB_HERE );
1319 :
1320 : #endif
1321 :
1322 : memcpy( array + M * index, column.array, M * sizeof( T ) );
1323 : }
1324 :
1325 : template< size_t M, size_t N, typename T >
1326 : void matrix< M, N, T >::get_column( size_t index, matrix< M, 1, T >& column )
1327 : const
1328 : {
1329 : #ifdef VMMLIB_SAFE_ACCESSORS
1330 : if ( index >= N )
1331 : VMMLIB_ERROR( "get_column() - index out of bounds.", VMMLIB_HERE );
1332 : #endif
1333 :
1334 : memcpy( column.array, array + M * index, M * sizeof( T ) );
1335 : }
1336 :
1337 : template< size_t M, size_t N, typename T >
1338 : void matrix< M, N, T >::set_column( size_t index,
1339 : const matrix< M, 1, T >& column )
1340 : {
1341 : #ifdef VMMLIB_SAFE_ACCESSORS
1342 : if ( index >= N )
1343 : VMMLIB_ERROR( "set_column() - index out of bounds.", VMMLIB_HERE );
1344 : #endif
1345 :
1346 : memcpy( &array[ M * index ], column.array, M * sizeof( T ) );
1347 : }
1348 :
1349 : template< size_t M, size_t N, typename T >
1350 4 : vector< N, T > matrix< M, N, T >::get_row( size_t index ) const
1351 : {
1352 4 : vector< N, T > row;
1353 4 : get_row( index, row );
1354 4 : return row;
1355 : }
1356 :
1357 : template< size_t M, size_t N, typename T >
1358 4 : void matrix< M, N, T >::get_row( size_t row_index, vector< N, T >& row ) const
1359 : {
1360 : #ifdef VMMLIB_SAFE_ACCESSORS
1361 4 : if ( row_index >= M )
1362 0 : VMMLIB_ERROR( "get_row() - index out of bounds.", VMMLIB_HERE );
1363 : #endif
1364 :
1365 20 : for( size_t col_index = 0; col_index < N; ++col_index )
1366 : {
1367 16 : row.at( col_index ) = at( row_index, col_index );
1368 : }
1369 4 : }
1370 :
1371 : template< size_t M, size_t N, typename T >
1372 : void matrix< M, N, T >::set_row( size_t row_index, const vector< N, T >& row )
1373 : {
1374 : #ifdef VMMLIB_SAFE_ACCESSORS
1375 : if ( row_index >= M )
1376 : VMMLIB_ERROR( "set_row() - index out of bounds.", VMMLIB_HERE );
1377 : #endif
1378 :
1379 : for( size_t col_index = 0; col_index < N; ++col_index )
1380 : {
1381 : at( row_index, col_index ) = row.at( col_index );
1382 : }
1383 : }
1384 :
1385 : template< size_t M, size_t N, typename T >
1386 : void matrix< M, N, T >::get_row( size_t row_index, matrix< 1, N, T >& row )
1387 : const
1388 : {
1389 : #ifdef VMMLIB_SAFE_ACCESSORS
1390 : if ( row_index >= M )
1391 : VMMLIB_ERROR( "get_row() - index out of bounds.", VMMLIB_HERE );
1392 : #endif
1393 :
1394 : for( size_t col_index = 0; col_index < N; ++col_index )
1395 : {
1396 : row.at( 0, col_index ) = at( row_index, col_index );
1397 : }
1398 : }
1399 :
1400 : template< size_t M, size_t N, typename T >
1401 : void matrix< M, N, T >::set_row( size_t row_index,
1402 : const matrix< 1, N, T >& row )
1403 : {
1404 : #ifdef VMMLIB_SAFE_ACCESSORS
1405 : if ( row_index >= M )
1406 : VMMLIB_ERROR( "set_row() - index out of bounds.", VMMLIB_HERE );
1407 : #endif
1408 :
1409 : for( size_t col_index = 0; col_index < N; ++col_index )
1410 : {
1411 : at( row_index, col_index ) = row.at( 0, col_index );
1412 : }
1413 : }
1414 :
1415 : template< size_t M, size_t N, typename T >
1416 : size_t
1417 : matrix< M, N, T >::
1418 : get_number_of_rows() const
1419 : {
1420 : return M;
1421 : }
1422 :
1423 :
1424 :
1425 : template< size_t M, size_t N, typename T >
1426 : size_t
1427 : matrix< M, N, T >::
1428 : get_number_of_columns() const
1429 : {
1430 : return N;
1431 : }
1432 :
1433 :
1434 :
1435 : template< size_t M, size_t N, typename T >
1436 : void
1437 : matrix< M, N, T >::
1438 : fill( T fillValue )
1439 : {
1440 : for( size_t row_index = 0; row_index < M; ++row_index )
1441 : {
1442 : for( size_t col_index = 0; col_index < N; ++col_index )
1443 : {
1444 : at( row_index, col_index ) = fillValue;
1445 : }
1446 : }
1447 : }
1448 :
1449 :
1450 : template< size_t M, size_t N, typename T >
1451 : inline T&
1452 : matrix< M, N, T >::x()
1453 : {
1454 : return array[ 12 ];
1455 : }
1456 :
1457 :
1458 :
1459 : template< size_t M, size_t N, typename T >
1460 : inline T&
1461 : matrix< M, N, T >::y()
1462 : {
1463 : return array[ 13 ];
1464 : }
1465 :
1466 :
1467 :
1468 : template< size_t M, size_t N, typename T >
1469 : inline T&
1470 : matrix< M, N, T >::z()
1471 : {
1472 : return array[ 14 ];
1473 : }
1474 :
1475 : template< size_t M, size_t N, typename T >
1476 : template< typename input_iterator_t >
1477 : void matrix< M, N, T >::set( input_iterator_t begin_,
1478 : input_iterator_t end_, bool row_major_layout )
1479 : {
1480 : input_iterator_t it( begin_ );
1481 : if( row_major_layout )
1482 : {
1483 : for( size_t row = 0; row < M; ++row )
1484 : {
1485 : for( size_t col = 0; col < N; ++col, ++it )
1486 : {
1487 : if ( it == end_ )
1488 : return;
1489 : at( row, col ) = static_cast< T >( *it );
1490 : }
1491 : }
1492 : }
1493 : else
1494 : {
1495 : std::copy( it, it + ( M * N ), begin() );
1496 : }
1497 : }
1498 :
1499 :
1500 :
1501 : template< size_t M, size_t N, typename T >
1502 : void matrix< M, N, T >::zero()
1503 : {
1504 : fill( static_cast< T >( 0.0 ) );
1505 : }
1506 :
1507 : template< size_t M, size_t N, typename T >
1508 : void matrix< M, N, T >::operator=( T value_ )
1509 : {
1510 : std::fill( begin(), end(), value_ );
1511 : }
1512 :
1513 :
1514 :
1515 : template< size_t M, size_t N, typename T >
1516 : inline matrix< M, N, T >
1517 : matrix< M, N, T >::operator+( const matrix< M, N, T >& other ) const
1518 : {
1519 : matrix< M, N, T > result( *this );
1520 : result += other;
1521 : return result;
1522 : }
1523 :
1524 :
1525 :
1526 : template< size_t M, size_t N, typename T >
1527 : void matrix< M, N, T >::operator+=( const matrix< M, N, T >& other )
1528 : {
1529 : iterator it = begin(), it_end = end();
1530 : const_iterator other_it = other.begin();
1531 : for( ; it != it_end; ++it, ++other_it )
1532 : {
1533 : *it += *other_it;
1534 : }
1535 : }
1536 :
1537 :
1538 : template< size_t M, size_t N, typename T >
1539 : void matrix< M, N, T >::operator+=( T scalar )
1540 : {
1541 : iterator it = begin(), it_end = end();
1542 : for( ; it != it_end; ++it )
1543 : {
1544 : *it += scalar;
1545 : }
1546 : }
1547 :
1548 : template< size_t M, size_t N, typename T >
1549 : inline matrix< M, N, T >
1550 : matrix< M, N, T >::
1551 : operator-( const matrix< M, N, T >& other ) const
1552 : {
1553 : matrix< M, N, T > result( *this );
1554 : result -= other;
1555 : return result;
1556 : }
1557 :
1558 :
1559 :
1560 : template< size_t M, size_t N, typename T >
1561 : void
1562 : matrix< M, N, T >::
1563 : operator-=( const matrix< M, N, T >& other )
1564 : {
1565 : iterator it = begin(), it_end = end();
1566 : const_iterator other_it = other.begin();
1567 : for( ; it != it_end; ++it, ++other_it )
1568 : {
1569 : *it -= *other_it;
1570 : }
1571 : }
1572 :
1573 : template< size_t M, size_t N, typename T >
1574 : void
1575 : matrix< M, N, T >::operator-=( T scalar )
1576 : {
1577 : iterator it = begin(), it_end = end();
1578 : for( ; it != it_end; ++it )
1579 : {
1580 : *it -= scalar;
1581 : }
1582 : }
1583 :
1584 :
1585 : template< size_t M, size_t N, typename T >
1586 : template< size_t O, size_t P, size_t Q, size_t R >
1587 : typename enable_if< M == O + Q && N == P + R >::type*
1588 : matrix< M, N, T >::direct_sum( const matrix< O, P, T >& upper_left,
1589 : const matrix< Q, R, T >& lower_right )
1590 : {
1591 : (*this) = static_cast< T >( 0.0 );
1592 :
1593 : for( size_t row = 0; row < O; ++row )
1594 : {
1595 : for( size_t col = 0; col < P; ++col )
1596 : {
1597 : at( row, col ) = upper_left( row, col );
1598 : }
1599 : }
1600 :
1601 : for( size_t row = 0; row < Q; ++row )
1602 : {
1603 : for( size_t col = 0; col < R; ++col )
1604 : {
1605 : at( O + row, P + col ) = lower_right( row, col );
1606 : }
1607 : }
1608 :
1609 : return 0;
1610 : }
1611 :
1612 :
1613 :
1614 : template< size_t M, size_t N, typename T >
1615 : template< size_t O, size_t P >
1616 : matrix< O, P, T >
1617 : matrix< M, N, T >::get_sub_matrix( size_t row_offset, size_t col_offset,
1618 : typename enable_if< O <= M && P <= N >::type* ) const
1619 : {
1620 : matrix< O, P, T > result;
1621 : get_sub_matrix( result, row_offset, col_offset );
1622 : return result;
1623 : }
1624 :
1625 :
1626 :
1627 : template< size_t M, size_t N, typename T >
1628 : template< size_t O, size_t P >
1629 : typename enable_if< O <= M && P <= N >::type*
1630 : matrix< M, N, T >::
1631 : get_sub_matrix( matrix< O, P, T >& result,
1632 : size_t row_offset, size_t col_offset ) const
1633 : {
1634 : #ifdef VMMLIB_SAFE_ACCESSORS
1635 : if ( O + row_offset > M || P + col_offset > N )
1636 : VMMLIB_ERROR( "index out of bounds.", VMMLIB_HERE );
1637 : #endif
1638 :
1639 : for( size_t row = 0; row < O; ++row )
1640 : {
1641 : for( size_t col = 0; col < P; ++col )
1642 : {
1643 : result.at( row, col )
1644 : = at( row_offset + row, col_offset + col );
1645 : }
1646 : }
1647 : return 0;
1648 : }
1649 :
1650 :
1651 :
1652 : template< size_t M, size_t N, typename T >
1653 : template< size_t O, size_t P >
1654 : typename enable_if< O <= M && P <= N >::type*
1655 : matrix< M, N, T >::
1656 : set_sub_matrix( const matrix< O, P, T >& sub_matrix,
1657 : size_t row_offset, size_t col_offset )
1658 : {
1659 : for( size_t row = 0; row < O; ++row )
1660 : {
1661 : for( size_t col = 0; col < P; ++col )
1662 : {
1663 : at( row_offset + row, col_offset + col )
1664 : = sub_matrix.at( row, col );
1665 : }
1666 : }
1667 : return 0; // for sfinae
1668 : }
1669 :
1670 :
1671 :
1672 : template< size_t M, size_t N, typename T >
1673 : inline T
1674 : matrix< M, N, T >::det() const
1675 : {
1676 : return compute_determinant( *this );
1677 : }
1678 :
1679 :
1680 :
1681 : template< size_t M, size_t N, typename T >
1682 : template< size_t O, size_t P, typename TT >
1683 : inline bool matrix< M, N, T >::inverse( matrix< O, P, TT >& inverse_,
1684 : T tolerance, typename
1685 : enable_if< M == N && O == P && O == M && M >= 2 && M <= 4, TT >::type* )
1686 : const
1687 : {
1688 : return compute_inverse( *this, inverse_, tolerance );
1689 : }
1690 :
1691 :
1692 :
1693 : template< size_t M, size_t N, typename T >
1694 : template< size_t O, size_t P >
1695 : typename enable_if< O == P && M == N && O == M && M >= 2 >::type*
1696 : matrix< M, N, T >::
1697 : get_adjugate( matrix< O, P, T >& adjugate ) const
1698 : {
1699 : get_cofactors( adjugate );
1700 : adjugate = transpose( adjugate );
1701 : return 0;
1702 : }
1703 :
1704 :
1705 :
1706 : template< size_t M, size_t N, typename T >
1707 : template< size_t O, size_t P >
1708 : typename enable_if< O == P && M == N && O == M && M >= 2 >::type*
1709 : matrix< M, N, T >::
1710 : get_cofactors( matrix< O, P, T >& cofactors ) const
1711 : {
1712 : matrix< M-1, N-1, T > minor_;
1713 :
1714 : const size_t _negate = 1u;
1715 : for( size_t row_index = 0; row_index < M; ++row_index )
1716 : {
1717 : for( size_t col_index = 0; col_index < N; ++col_index )
1718 : {
1719 : if ( ( row_index + col_index ) & _negate )
1720 : cofactors( row_index, col_index ) = -get_minor( minor_, row_index, col_index );
1721 : else
1722 : cofactors( row_index, col_index ) = get_minor( minor_, row_index, col_index );
1723 : }
1724 : }
1725 : return 0;
1726 : }
1727 :
1728 :
1729 :
1730 : template< size_t M, size_t N, typename T >
1731 : template< size_t O, size_t P >
1732 : T
1733 : matrix< M, N, T >::
1734 : get_minor( matrix< O, P, T >& minor_, size_t row_to_cut, size_t col_to_cut,
1735 : typename enable_if< O == M-1 && P == N-1 && M == N && M >= 2 >::type* ) const
1736 : {
1737 : size_t row_offset = 0;
1738 : size_t col_offset = 0;
1739 : for( size_t row_index = 0; row_index < M; ++row_index )
1740 : {
1741 : if ( row_index == row_to_cut )
1742 : row_offset = -1;
1743 : else
1744 : {
1745 : for( size_t col_index = 0; col_index < M; ++col_index )
1746 : {
1747 : if ( col_index == col_to_cut )
1748 : col_offset = -1;
1749 : else
1750 : minor_.at( row_index + row_offset, col_index + col_offset )
1751 : = at( row_index, col_index );
1752 : }
1753 : col_offset = 0;
1754 : }
1755 : }
1756 : return compute_determinant( minor_ );
1757 : }
1758 :
1759 : template< size_t M, size_t N, typename T >
1760 : template< typename TT >
1761 : matrix< M, N, T >& matrix< M, N, T >::rotate(
1762 : const TT angle_, const vector< M-1, T >& axis,
1763 : typename enable_if< M == N && M == 4, TT >::type* )
1764 : {
1765 : const T angle = static_cast< T >( angle_ );
1766 :
1767 : const T sine = std::sin( angle );
1768 : const T cosine = std::cos( angle );
1769 :
1770 : // this is necessary since Visual Studio cannot resolve the
1771 : // std::pow()-call correctly if we just use 2.0 directly.
1772 : // this way, the '2.0' is converted to the same format
1773 : // as the axis components
1774 :
1775 : const T _zero = 0.0;
1776 : const T one = 1.0;
1777 : const T two = 2.0;
1778 :
1779 : array[0] = cosine + ( one - cosine ) * std::pow( axis.array[0], two );
1780 : array[1] = ( one - cosine ) * axis.array[0] * axis.array[1] + sine * axis.array[2];
1781 : array[2] = ( one - cosine ) * axis.array[0] * axis.array[2] - sine * axis.array[1];
1782 : array[3] = _zero;
1783 :
1784 : array[4] = ( one - cosine ) * axis.array[0] * axis.array[1] - sine * axis.array[2];
1785 : array[5] = cosine + ( one - cosine ) * std::pow( axis.array[1], two );
1786 : array[6] = ( one - cosine ) * axis.array[1] * axis.array[2] + sine * axis.array[0];
1787 : array[7] = _zero;
1788 :
1789 : array[8] = ( one - cosine ) * axis.array[0] * axis.array[2] + sine * axis.array[1];
1790 : array[9] = ( one - cosine ) * axis.array[1] * axis.array[2] - sine * axis.array[0];
1791 : array[10] = cosine + ( one - cosine ) * std::pow( axis.array[2], two );
1792 : array[11] = _zero;
1793 :
1794 : array[12] = _zero;
1795 : array[13] = _zero;
1796 : array[14] = _zero;
1797 : array[15] = one;
1798 :
1799 : return *this;
1800 : }
1801 :
1802 : template< size_t M, size_t N, typename T >
1803 : template< typename TT >
1804 : matrix< M, N, T >& matrix< M, N, T >::rotate_x( const TT angle_,
1805 : typename enable_if< M == N && M == 4, TT >::type* )
1806 : {
1807 : const T angle = static_cast< T >( angle_ );
1808 :
1809 : const T sine = std::sin( angle );
1810 : const T cosine = std::cos( angle );
1811 :
1812 : T tmp;
1813 :
1814 : tmp = array[ 4 ] * cosine + array[ 8 ] * sine;
1815 : array[ 8 ] = - array[ 4 ] * sine + array[ 8 ] * cosine;
1816 : array[ 4 ] = tmp;
1817 :
1818 : tmp = array[ 5 ] * cosine + array[ 9 ] * sine;
1819 : array[ 9 ] = - array[ 5 ] * sine + array[ 9 ] * cosine;
1820 : array[ 5 ] = tmp;
1821 :
1822 : tmp = array[ 6 ] * cosine + array[ 10 ] * sine;
1823 : array[ 10 ] = - array[ 6 ] * sine + array[ 10 ] * cosine;
1824 : array[ 6 ] = tmp;
1825 :
1826 : tmp = array[ 7 ] * cosine + array[ 11 ] * sine;
1827 : array[ 11 ] = - array[ 7 ] * sine + array[ 11 ] * cosine;
1828 : array[ 7 ] = tmp;
1829 :
1830 : return *this;
1831 : }
1832 :
1833 : template< size_t M, size_t N, typename T >
1834 : template< typename TT >
1835 : matrix< M, N, T >& matrix< M, N, T >::rotate_y( const TT angle_,
1836 : typename enable_if< M == N && M == 4, TT >::type* )
1837 : {
1838 : const T angle = static_cast< T >( angle_ );
1839 :
1840 : const T sine = std::sin( angle );
1841 : const T cosine = std::cos( angle );
1842 :
1843 : T tmp;
1844 :
1845 : tmp = array[ 0 ] * cosine - array[ 8 ] * sine;
1846 : array[ 8 ] = array[ 0 ] * sine + array[ 8 ] * cosine;
1847 : array[ 0 ] = tmp;
1848 :
1849 : tmp = array[ 1 ] * cosine - array[ 9 ] * sine;
1850 : array[ 9 ] = array[ 1 ] * sine + array[ 9 ] * cosine;
1851 : array[ 1 ] = tmp;
1852 :
1853 : tmp = array[ 2 ] * cosine - array[ 10 ] * sine;
1854 : array[ 10 ] = array[ 2 ] * sine + array[ 10 ] * cosine;
1855 : array[ 2 ] = tmp;
1856 :
1857 : tmp = array[ 3 ] * cosine - array[ 11 ] * sine;
1858 : array[ 11 ] = array[ 3 ] * sine + array[ 11 ] * cosine;
1859 : array[ 3 ] = tmp;
1860 :
1861 : return *this;
1862 : }
1863 :
1864 : template< size_t M, size_t N, typename T >
1865 : template< typename TT >
1866 : matrix< M, N, T >& matrix< M, N, T >::rotate_z( const TT angle_,
1867 : typename enable_if< M == N && M == 4, TT >::type* )
1868 : {
1869 : const T angle = static_cast< T >( angle_ );
1870 :
1871 : const T sine = std::sin( angle );
1872 : const T cosine = std::cos( angle );
1873 :
1874 : T tmp;
1875 :
1876 : tmp = array[ 0 ] * cosine + array[ 4 ] * sine;
1877 : array[ 4 ] = - array[ 0 ] * sine + array[ 4 ] * cosine;
1878 : array[ 0 ] = tmp;
1879 :
1880 : tmp = array[ 1 ] * cosine + array[ 5 ] * sine;
1881 : array[ 5 ] = - array[ 1 ] * sine + array[ 5 ] * cosine;
1882 : array[ 1 ] = tmp;
1883 :
1884 : tmp = array[ 2 ] * cosine + array[ 6 ] * sine;
1885 : array[ 6 ] = - array[ 2 ] * sine + array[ 6 ] * cosine;
1886 : array[ 2 ] = tmp;
1887 :
1888 : tmp = array[ 3 ] * cosine + array[ 7 ] * sine;
1889 : array[ 7 ] = - array[ 3 ] * sine + array[ 7 ] * cosine;
1890 : array[ 3 ] = tmp;
1891 :
1892 : return *this;
1893 : }
1894 :
1895 : template< size_t M, size_t N, typename T >
1896 : template< typename TT >
1897 : matrix< M, N, T >& matrix< M, N, T >::pre_rotate_x( const TT angle_,
1898 : typename enable_if< M == N && M == 4, TT >::type* )
1899 : {
1900 : const T angle = static_cast< T >( angle_ );
1901 :
1902 : const T sine = std::sin( angle );
1903 : const T cosine = std::cos( angle );
1904 :
1905 : T tmp;
1906 :
1907 : tmp = array[ 1 ];
1908 : array[ 1 ] = array[ 1 ] * cosine + array[ 2 ] * sine;
1909 : array[ 2 ] = tmp * -sine + array[ 2 ] * cosine;
1910 :
1911 : tmp = array[ 5 ];
1912 : array[ 5 ] = array[ 5 ] * cosine + array[ 6 ] * sine;
1913 : array[ 6 ] = tmp * -sine + array[ 6 ] * cosine;
1914 :
1915 : tmp = array[ 9 ];
1916 : array[ 9 ] = array[ 9 ] * cosine + array[ 10 ] * sine;
1917 : array[ 10 ] = tmp * -sine + array[ 10 ] * cosine;
1918 :
1919 : tmp = array[ 13 ];
1920 : array[ 13 ] = array[ 13 ] * cosine + array[ 14 ] * sine;
1921 : array[ 14 ] = tmp * -sine + array[ 14 ] * cosine;
1922 :
1923 : return *this;
1924 : }
1925 :
1926 : template< size_t M, size_t N, typename T >
1927 : template< typename TT >
1928 : matrix< M, N, T >& matrix< M, N, T >::pre_rotate_y( const TT angle_,
1929 : typename enable_if< M == N && M == 4, TT >::type* )
1930 : {
1931 : const T angle = static_cast< T >( angle_ );
1932 :
1933 : const T sine = std::sin( angle );
1934 : const T cosine = std::cos( angle );
1935 :
1936 : T tmp;
1937 :
1938 : tmp = array[ 0 ];
1939 : array[ 0 ] = array[ 0 ] * cosine - array[ 2 ] * sine;
1940 : array[ 2 ] = tmp * sine + array[ 2 ] * cosine;
1941 :
1942 : tmp = array[ 4 ];
1943 : array[ 4 ] = array[ 4 ] * cosine - array[ 6 ] * sine;
1944 : array[ 6 ] = tmp * sine + array[ 6 ] * cosine;
1945 :
1946 : tmp = array[ 8 ];
1947 : array[ 8 ] = array[ 8 ] * cosine - array[ 10 ] * sine;
1948 : array[ 10 ] = tmp * sine + array[ 10 ] * cosine;
1949 :
1950 : tmp = array[ 12 ];
1951 : array[ 12 ] = array[ 12 ] * cosine - array[ 14 ] * sine;
1952 : array[ 14 ] = tmp * sine + array[ 14 ] * cosine;
1953 :
1954 : return *this;
1955 : }
1956 :
1957 : template< size_t M, size_t N, typename T >
1958 : template< typename TT >
1959 : matrix< M, N, T >& matrix< M, N, T >::pre_rotate_z( const TT angle_,
1960 : typename enable_if< M == N && M == 4, TT >::type* )
1961 : {
1962 : const T angle = static_cast< T >( angle_ );
1963 :
1964 : const T sine = std::sin( angle );
1965 : const T cosine = std::cos( angle );
1966 :
1967 : T tmp;
1968 :
1969 : tmp = array[ 0 ];
1970 : array[ 0 ] = array[ 0 ] * cosine + array[ 1 ] * sine;
1971 : array[ 1 ] = tmp * -sine + array[ 1 ] * cosine;
1972 :
1973 : tmp = array[ 4 ];
1974 : array[ 4 ] = array[ 4 ] * cosine + array[ 5 ] * sine;
1975 : array[ 5 ] = tmp * -sine + array[ 5 ] * cosine;
1976 :
1977 : tmp = array[ 8 ];
1978 : array[ 8 ] = array[ 8 ] * cosine + array[ 9 ] * sine;
1979 : array[ 9 ] = tmp * -sine + array[ 9 ] * cosine;
1980 :
1981 : tmp = array[ 12 ];
1982 : array[ 12 ] = array[ 12 ] * cosine + array[ 13 ] * sine;
1983 : array[ 13 ] = tmp * -sine + array[ 13 ] * cosine;
1984 :
1985 : return *this;
1986 : }
1987 :
1988 : template< size_t M, size_t N, typename T >
1989 : template< typename TT >
1990 : matrix< M, N, T >& matrix< M, N, T >::scale( const TT _scale[3],
1991 : typename enable_if< M == N && M == 4, TT >::type* )
1992 : {
1993 : const T scale0 = static_cast< T >( _scale[ 0 ] );
1994 : const T scale1 = static_cast< T >( _scale[ 1 ] );
1995 : const T scale2 = static_cast< T >( _scale[ 2 ] );
1996 :
1997 : array[0] *= scale0;
1998 : array[1] *= scale0;
1999 : array[2] *= scale0;
2000 : array[3] *= scale0;
2001 : array[4] *= scale1;
2002 : array[5] *= scale1;
2003 : array[6] *= scale1;
2004 : array[7] *= scale1;
2005 : array[8] *= scale2;
2006 : array[9] *= scale2;
2007 : array[10] *= scale2;
2008 : array[11] *= scale2;
2009 :
2010 : return *this;
2011 : }
2012 :
2013 : template< size_t M, size_t N, typename T >
2014 : template< typename TT >
2015 : matrix< M, N, T >& matrix< M, N, T >::scale( const TT x_, const T y_, const T z_,
2016 : typename enable_if< M == N && M == 4, TT >::type* )
2017 : {
2018 : const T _x = static_cast< T >( x_ );
2019 :
2020 : array[0] *= _x;
2021 : array[1] *= _x;
2022 : array[2] *= _x;
2023 : array[3] *= _x;
2024 : array[4] *= y_;
2025 : array[5] *= y_;
2026 : array[6] *= y_;
2027 : array[7] *= y_;
2028 : array[8] *= z_;
2029 : array[9] *= z_;
2030 : array[10] *= z_;
2031 : array[11] *= z_;
2032 :
2033 : return *this;
2034 : }
2035 :
2036 : template< size_t M, size_t N, typename T >
2037 : template< typename TT >
2038 : inline matrix< M, N, T >& matrix< M, N, T >::scale(
2039 : const vector< 3, TT >& scale_,
2040 : typename enable_if< M == N && M == 4, TT >::type* )
2041 : {
2042 : return scale( scale_.array );
2043 : }
2044 :
2045 :
2046 :
2047 : template< size_t M, size_t N, typename T >
2048 : template< typename TT >
2049 : matrix< M, N, T >& matrix< M, N, T >::scale_translation( const TT scale_[3],
2050 : typename enable_if< M == N && M == 4, TT >::type* )
2051 : {
2052 : array[12] *= static_cast< T >( scale_[0] );
2053 : array[13] *= static_cast< T >( scale_[1] );
2054 : array[14] *= static_cast< T >( scale_[2] );
2055 : return *this;
2056 : }
2057 :
2058 : template< size_t M, size_t N, typename T >
2059 : template< typename TT >
2060 : inline matrix< M, N, T >& matrix< M, N, T >::scale_translation(
2061 : const vector< 3, TT >& scale_,
2062 : typename enable_if< M == N && M == 4, TT >::type* )
2063 : {
2064 : return scale_translation( scale_.array );
2065 : }
2066 :
2067 : template< size_t M, size_t N, typename T >
2068 : template< typename TT >
2069 : inline matrix< M, N, T >& matrix< M, N, T >::set_translation(
2070 : const TT x_, const TT y_, const TT z_,
2071 : typename enable_if< M == N && M == 4, TT >::type* )
2072 : {
2073 : array[12] = static_cast< T >( x_ );
2074 : array[13] = static_cast< T >( y_ );
2075 : array[14] = static_cast< T >( z_ );
2076 : return *this;
2077 : }
2078 :
2079 : template< size_t M, size_t N, typename T >
2080 : template< typename TT >
2081 : inline matrix< M, N, T >& matrix< M, N, T >::set_translation( const TT trans[3],
2082 : typename enable_if< M == N && M == 4, TT >::type* )
2083 : {
2084 : array[12] = static_cast< T >( trans[ 0 ] );
2085 : array[13] = static_cast< T >( trans[ 1 ] );
2086 : array[14] = static_cast< T >( trans[ 2 ] );
2087 : return *this;
2088 : }
2089 :
2090 : template< size_t M, size_t N, typename T >
2091 : template< typename TT >
2092 : inline matrix< M, N, T >& matrix< M, N, T >::set_translation(
2093 : const vector< 3, TT >& translation_,
2094 : typename enable_if< M == N && M == 4, TT >::type* )
2095 : {
2096 : return set_translation( translation_.array );
2097 : }
2098 :
2099 : template< size_t M, size_t N, typename T > template< typename TT > inline
2100 : void matrix< M, N, T >::get_translation( vector< N-1, TT >& translation_ )
2101 : const
2102 : {
2103 : for( size_t i = 0; i < N-1; ++i )
2104 : translation_.array[ i ] = array[ i + M * (N - 1) ];
2105 : }
2106 :
2107 :
2108 : template< size_t M, size_t N, typename T >
2109 : inline vector< N-1, T > matrix< M, N, T >::get_translation() const
2110 : {
2111 : vector< N-1, T > result;
2112 : get_translation( result );
2113 : return result;
2114 : }
2115 :
2116 :
2117 :
2118 : template< size_t M, size_t N, typename T >
2119 : size_t
2120 : matrix< M, N, T >::
2121 : size() const
2122 : {
2123 : return M * N;
2124 : }
2125 :
2126 :
2127 :
2128 : template< size_t M, size_t N, typename T >
2129 : typename matrix< M, N, T >::iterator
2130 : matrix< M, N, T >::
2131 : begin()
2132 : {
2133 : return array;
2134 : }
2135 :
2136 :
2137 :
2138 : template< size_t M, size_t N, typename T >
2139 : typename matrix< M, N, T >::iterator
2140 : matrix< M, N, T >::
2141 : end()
2142 : {
2143 : return array + size();
2144 : }
2145 :
2146 :
2147 :
2148 : template< size_t M, size_t N, typename T >
2149 : typename matrix< M, N, T >::const_iterator
2150 : matrix< M, N, T >::
2151 : begin() const
2152 : {
2153 : return array;
2154 : }
2155 :
2156 :
2157 :
2158 : template< size_t M, size_t N, typename T >
2159 : typename matrix< M, N, T >::const_iterator
2160 : matrix< M, N, T >::
2161 : end() const
2162 : {
2163 : return array + size();
2164 : }
2165 :
2166 :
2167 :
2168 : template< size_t M, size_t N, typename T >
2169 : typename matrix< M, N, T >::reverse_iterator
2170 : matrix< M, N, T >::
2171 : rbegin()
2172 : {
2173 : return array + size() - 1;
2174 : }
2175 :
2176 :
2177 :
2178 : template< size_t M, size_t N, typename T >
2179 : typename matrix< M, N, T >::reverse_iterator
2180 : matrix< M, N, T >::
2181 : rend()
2182 : {
2183 : return array - 1;
2184 : }
2185 :
2186 :
2187 :
2188 : template< size_t M, size_t N, typename T >
2189 : typename matrix< M, N, T >::const_reverse_iterator
2190 : matrix< M, N, T >::
2191 : rbegin() const
2192 : {
2193 : return array + size() - 1;
2194 : }
2195 :
2196 :
2197 :
2198 : template< size_t M, size_t N, typename T >
2199 : typename matrix< M, N, T >::const_reverse_iterator
2200 : matrix< M, N, T >::
2201 : rend() const
2202 : {
2203 : return array - 1;
2204 : }
2205 :
2206 :
2207 :
2208 : template< size_t M, size_t N, typename T > template< typename init_functor_t >
2209 : const matrix< M, N, T > matrix< M, N, T >::get_initialized_matrix()
2210 : {
2211 : matrix< M, N, T > matrix_;
2212 : init_functor_t()( matrix_ );
2213 : return matrix_;
2214 : }
2215 :
2216 :
2217 : // it's ugly, but it allows having properly initialized static members
2218 : // without having to worry about static initialization order.
2219 : template< size_t M, size_t N, typename T >
2220 : const matrix< M, N, T >
2221 : matrix< M, N, T >::IDENTITY(
2222 : matrix< M, N, T >::get_initialized_matrix<
2223 : set_to_identity_functor< matrix< M, N, T > > >( ));
2224 :
2225 :
2226 : template< size_t M, size_t N, typename T >
2227 : const matrix< M, N, T >
2228 : matrix< M, N, T >::ZERO(
2229 : matrix< M, N, T >::
2230 : get_initialized_matrix< set_to_zero_functor< matrix< M, N, T > > >()
2231 : );
2232 :
2233 :
2234 :
2235 : template< size_t M, size_t N, typename T >
2236 : double
2237 : matrix< M, N, T >::frobenius_norm( ) const
2238 : {
2239 : double norm = 0.0;
2240 :
2241 : const_iterator it = begin(), it_end = end();
2242 : for( ; it != it_end; ++it )
2243 : {
2244 : norm += *it * *it;
2245 : }
2246 :
2247 : return std::sqrt(norm);
2248 : }
2249 :
2250 : template< size_t M, size_t N, typename T >
2251 : double
2252 : matrix< M, N, T >::p_norm( double p ) const
2253 : {
2254 : double norm = 0.0;
2255 :
2256 : const_iterator it = begin(), it_end = end();
2257 : for( ; it != it_end; ++it )
2258 : {
2259 : norm += std::pow(*it, p);
2260 : }
2261 :
2262 : return std::pow(norm,1./p);
2263 : }
2264 :
2265 :
2266 : template< size_t M, size_t N, typename T >
2267 : template< size_t O >
2268 : void
2269 : matrix< M, N, T >::khatri_rao_product( const matrix< O, N, T >& right_, matrix< M*O, N, T >& prod_ ) const
2270 : {
2271 : //build product for every column
2272 : for (size_t col = 0; col < N; ++col )
2273 : {
2274 : for ( size_t m = 0; m < M; ++m )
2275 : {
2276 : for (size_t o = 0; o < O; ++o )
2277 : {
2278 : prod_.at(O*m + o, col) = at( m, col ) * right_.at( o, col );
2279 : }
2280 : }
2281 : }
2282 : }
2283 :
2284 : template< size_t M, size_t N, typename T >
2285 : template< size_t O, size_t P >
2286 : void
2287 : matrix< M, N, T >::kronecker_product( const matrix< O, P, T >& right_, matrix< M*O, N*P, T >& result_ ) const
2288 : {
2289 : //build product for every column
2290 : for (size_t m = 0; m < M; ++m )
2291 : {
2292 : for ( size_t n = 0; n < N; ++n )
2293 : {
2294 : for (size_t o = 0; o < O; ++o )
2295 : {
2296 : for (size_t p = 0; p < P; ++p )
2297 : {
2298 : result_.at(O*m + o, P*n + p) = at( m, n ) * right_.at( o, p );
2299 : }
2300 : }
2301 : }
2302 : }
2303 : }
2304 :
2305 :
2306 : template< size_t M, size_t N, typename T >
2307 : template< typename TT >
2308 : void
2309 : matrix< M, N, T >::cast_from( const matrix< M, N, TT >& other )
2310 : {
2311 : typedef vmml::matrix< M, N, TT > matrix_tt_type ;
2312 : typedef typename matrix_tt_type::const_iterator tt_const_iterator;
2313 :
2314 : iterator it = begin(), it_end = end();
2315 : tt_const_iterator other_it = other.begin();
2316 : for( ; it != it_end; ++it, ++other_it )
2317 : {
2318 : *it = static_cast< T >( *other_it );
2319 : }
2320 : }
2321 :
2322 :
2323 : template< size_t M, size_t N, typename T >
2324 : T
2325 : matrix< M, N, T >::get_min() const
2326 : {
2327 : T min_value = static_cast<T>(std::numeric_limits<T>::max());
2328 :
2329 : const_iterator it = begin(),
2330 : it_end = end();
2331 : for( ; it != it_end; ++it)
2332 : {
2333 : if ( *it < min_value ) {
2334 : min_value = *it;
2335 : }
2336 : }
2337 : return min_value;
2338 : }
2339 :
2340 : template< size_t M, size_t N, typename T >
2341 : T
2342 : matrix< M, N, T >::get_max() const
2343 : {
2344 : T max_value = static_cast<T>(0);
2345 :
2346 : const_iterator it = begin(),
2347 : it_end = end();
2348 : for( ; it != it_end; ++it)
2349 : {
2350 : if ( *it > max_value ) {
2351 : max_value = *it;
2352 : }
2353 : }
2354 : return max_value;
2355 : }
2356 :
2357 :
2358 : template< size_t M, size_t N, typename T >
2359 : T
2360 : matrix< M, N, T >::get_abs_min() const
2361 : {
2362 : T min_value = static_cast<T>(std::numeric_limits<T>::max());
2363 :
2364 : const_iterator it = begin(),
2365 : it_end = end();
2366 : for( ; it != it_end; ++it)
2367 : {
2368 : if ( fabs(*it) < fabs(min_value) ) {
2369 : min_value = fabs(*it);
2370 : }
2371 : }
2372 : return min_value;
2373 : }
2374 :
2375 : template< size_t M, size_t N, typename T >
2376 : T
2377 : matrix< M, N, T >::get_abs_max() const
2378 : {
2379 : T max_value = static_cast<T>(0);
2380 :
2381 : const_iterator it = begin(),
2382 : it_end = end();
2383 : for( ; it != it_end; ++it)
2384 : {
2385 : if ( fabs(*it) > fabs(max_value) ) {
2386 : max_value = fabs(*it);
2387 : }
2388 : }
2389 : return max_value;
2390 : }
2391 :
2392 :
2393 :
2394 : template< size_t M, size_t N, typename T >
2395 : size_t
2396 : matrix< M, N, T >::nnz() const
2397 : {
2398 : size_t counter = 0;
2399 :
2400 : const_iterator it = begin(),
2401 : it_end = end();
2402 : for( ; it != it_end; ++it)
2403 : {
2404 : if ( *it != 0 ) {
2405 : ++counter;
2406 : }
2407 : }
2408 :
2409 : return counter;
2410 : }
2411 :
2412 : template< size_t M, size_t N, typename T >
2413 : size_t
2414 : matrix< M, N, T >::nnz( const T& threshold_ ) const
2415 : {
2416 : size_t counter = 0;
2417 :
2418 : const_iterator it = begin(),
2419 : it_end = end();
2420 : for( ; it != it_end; ++it)
2421 : {
2422 : if ( fabs(*it) > threshold_ ) {
2423 : ++counter;
2424 : }
2425 : }
2426 :
2427 : return counter;
2428 : }
2429 :
2430 : template< size_t M, size_t N, typename T >
2431 : void
2432 : matrix< M, N, T >::threshold( const T& threshold_value_ )
2433 : {
2434 : iterator it = begin(),
2435 : it_end = end();
2436 : for( ; it != it_end; ++it)
2437 : {
2438 : if ( fabs(*it) <= threshold_value_ ) {
2439 : *it = static_cast<T> (0);
2440 : }
2441 : }
2442 : }
2443 :
2444 :
2445 : template< size_t M, size_t N, typename T >
2446 : template< typename TT >
2447 : void
2448 : matrix< M, N, T >::quantize_to( matrix< M, N, TT >& quantized_, const T& min_value, const T& max_value ) const
2449 : {
2450 : long max_tt_range = long(std::numeric_limits< TT >::max());
2451 : long min_tt_range = long(std::numeric_limits< TT >::min());
2452 : long tt_range = (max_tt_range - min_tt_range);
2453 :
2454 : T t_range = max_value - min_value;
2455 :
2456 : typedef matrix< M, N, TT > m_tt_type ;
2457 : typedef typename m_tt_type::iterator tt_iterator;
2458 : tt_iterator it_quant = quantized_.begin();
2459 : const_iterator it = begin(), it_end = end();
2460 :
2461 : for( ; it != it_end; ++it, ++it_quant )
2462 : {
2463 : if (std::numeric_limits<TT>::is_signed ) {
2464 : *it_quant = TT( std::min( std::max( min_tt_range, long(( *it * tt_range / t_range ) + 0.5)), max_tt_range ));
2465 : } else {
2466 : *it_quant = TT( std::min( std::max( min_tt_range, long(((*it - min_value) * tt_range / t_range) + 0.5)), max_tt_range ));
2467 : }
2468 : }
2469 : }
2470 :
2471 :
2472 : template< size_t M, size_t N, typename T >
2473 : template< typename TT >
2474 : void
2475 : matrix< M, N, T >::quantize( matrix< M, N, TT >& quantized_, T& min_value, T& max_value ) const
2476 : {
2477 : min_value = get_min();
2478 : max_value = get_max();
2479 : quantize_to( quantized_, min_value, max_value );
2480 : }
2481 :
2482 :
2483 :
2484 : template< size_t M, size_t N, typename T >
2485 : template< typename TT >
2486 : void
2487 : matrix< M, N, T >::dequantize( matrix< M, N, TT >& dequantized_, const TT& min_value, const TT& max_value ) const
2488 : {
2489 : long max_t_range = long(std::numeric_limits< T >::max());
2490 : long min_t_range = long(std::numeric_limits< T >::min());
2491 : long t_range = (max_t_range - min_t_range);
2492 :
2493 : TT tt_range = max_value - min_value;
2494 :
2495 : typedef matrix< M, N, TT > m_tt_type ;
2496 : typedef typename m_tt_type::iterator tt_iterator;
2497 : tt_iterator it_dequant = dequantized_.begin();
2498 : const_iterator it = begin(), it_end = end();
2499 : for( ; it != it_end; ++it, ++it_dequant )
2500 : {
2501 : if (std::numeric_limits<T>::is_signed ) {
2502 : *it_dequant = std::min( std::max( min_value, TT((TT(*it) / t_range) * tt_range)), max_value );
2503 : } else {
2504 : *it_dequant = std::min( std::max( min_value, TT((((TT(*it) / t_range)) * tt_range ) + min_value)), max_value );
2505 : }
2506 : }
2507 : }
2508 :
2509 : template< size_t M, size_t N, typename T >
2510 : void
2511 : matrix< M, N, T >::columnwise_sum( vector< N, T>& summed_columns_ ) const
2512 : {
2513 :
2514 : for ( size_t n = 0; n < N; ++n )
2515 : {
2516 : T value = 0;
2517 : for ( size_t m = 0; m < M; ++m )
2518 : {
2519 : value += at( m, n );
2520 : }
2521 : summed_columns_.at( n ) = value;
2522 : }
2523 : }
2524 :
2525 : template< size_t M, size_t N, typename T >
2526 : double
2527 : matrix< M, N, T >::sum_elements( ) const
2528 : {
2529 : double sum = 0.0;
2530 :
2531 : const_iterator it = begin(), it_end = end();
2532 : for( ; it != it_end; ++it )
2533 : {
2534 : sum += *it;
2535 : }
2536 :
2537 : return sum;
2538 : }
2539 :
2540 : template< size_t M, size_t N, typename T >
2541 : template< size_t R>
2542 : typename enable_if< R == M && R == N>::type*
2543 : matrix< M, N, T >::diag( const vector< R, T >& diag_values_ )
2544 : {
2545 : zero();
2546 : for( size_t r = 0; r < R; ++r )
2547 : {
2548 : at(r, r) = static_cast< T >( diag_values_.at(r) );
2549 : }
2550 : return 0;
2551 : }
2552 :
2553 :
2554 : template< size_t M, size_t N, typename T >
2555 : void
2556 : matrix< M, N, T >::set_dct()
2557 : {
2558 : const double num_rows = M;
2559 : double fill_value = 0.0f;
2560 : for( size_t row = 0; row < M; ++row )
2561 : {
2562 : // to receive orthonormality
2563 : const double weight = ( row == 0.0 ) ? std::sqrt(1/num_rows) :
2564 : std::sqrt(2/num_rows);
2565 : for( size_t col = 0; col < N; ++col )
2566 : {
2567 : fill_value = (2 * col + 1) * row * M_PI / (2*M);
2568 : fill_value = std::cos( fill_value );
2569 : fill_value *= weight;
2570 : at( row, col ) = static_cast< T >( fill_value ) ;
2571 : }
2572 : }
2573 : }
2574 :
2575 :
2576 : template< size_t M, size_t N, typename T >
2577 : void
2578 : matrix< M, N, T >::set_random( int seed )
2579 : {
2580 : if ( seed >= 0 )
2581 : srand( seed );
2582 :
2583 : double fillValue = 0.0f;
2584 : for( size_t row = 0; row < M; ++row )
2585 : {
2586 : for( size_t col = 0; col < N; ++col )
2587 : {
2588 : fillValue = rand();
2589 : fillValue /= RAND_MAX;
2590 : at( row, col ) = -1.0 + 2.0 * static_cast< double >( fillValue ) ;
2591 : }
2592 : }
2593 : }
2594 :
2595 : template< size_t M, size_t N, typename T >
2596 : void
2597 : matrix< M, N, T >::write_to_raw( const std::string& dir_, const std::string& filename_ ) const
2598 : {
2599 : int dir_length = dir_.size() -1;
2600 : int last_separator = dir_.find_last_of( "/");
2601 : std::string path = dir_;
2602 : if (last_separator < dir_length ) {
2603 : path.append( "/" );
2604 : }
2605 : path.append( filename_ );
2606 : //check for format
2607 : if( filename_.find( "raw", filename_.size() -3) == std::string::npos )
2608 : {
2609 : path.append( ".");
2610 : path.append( "raw" );
2611 : }
2612 : std::string path_raw = path;
2613 :
2614 : std::ofstream outfile;
2615 : outfile.open( path_raw.c_str() );
2616 : if( outfile.is_open() ) {
2617 : size_t len_slice = sizeof(T) * M*N;
2618 : outfile.write( (char*)&(*this), len_slice );
2619 : outfile.close();
2620 : } else {
2621 : std::cout << "no file open" << std::endl;
2622 : }
2623 : }
2624 :
2625 : template< size_t M, size_t N, typename T >
2626 : void
2627 : matrix< M, N, T >::read_from_raw( const std::string& dir_, const std::string& filename_ )
2628 : {
2629 : int dir_length = dir_.size() -1;
2630 : int last_separator = dir_.find_last_of( "/");
2631 : std::string path = dir_;
2632 : if (last_separator < dir_length ) {
2633 : path.append( "/" );
2634 : }
2635 : path.append( filename_ );
2636 :
2637 : size_t max_file_len = 2147483648u - sizeof(T) ;
2638 : size_t len_data = sizeof(T) * size();
2639 : char* data = new char[ len_data ];
2640 : std::ifstream infile;
2641 : infile.open( path.c_str(), std::ios::in);
2642 :
2643 : if( infile.is_open())
2644 : {
2645 : iterator it = begin(),
2646 : it_end = end();
2647 :
2648 : while ( len_data > 0 )
2649 : {
2650 : size_t len_read = (len_data % max_file_len ) > 0 ?
2651 : len_data % max_file_len : len_data;
2652 : len_data -= len_read;
2653 : infile.read( data, len_read );
2654 :
2655 : T* T_ptr = (T*)&(data[0]);
2656 : for( ; (it != it_end) && (len_read > 0); ++it, len_read -= sizeof(T) )
2657 : {
2658 : *it = *T_ptr; ++T_ptr;
2659 : }
2660 : }
2661 :
2662 : delete[] data;
2663 : infile.close();
2664 : } else {
2665 : std::cout << "no file open" << std::endl;
2666 : }
2667 :
2668 : }
2669 :
2670 :
2671 :
2672 :
2673 : template< size_t M, size_t N, typename T >
2674 : void
2675 : matrix< M, N, T >::write_csv_file( const std::string& dir_, const std::string& filename_ ) const
2676 : {
2677 : int dir_length = dir_.size() -1;
2678 : int last_separator = dir_.find_last_of( "/");
2679 : std::string path = dir_;
2680 : if (last_separator < dir_length ) {
2681 : path.append( "/" );
2682 : }
2683 : path.append( filename_ );
2684 : //check for format
2685 : int suffix_pos = filename_.find( "csv", filename_.size() -3);
2686 : if( suffix_pos == (-1)) {
2687 : path.append( ".");
2688 : path.append( "csv" );
2689 : }
2690 :
2691 : std::ofstream outfile;
2692 : outfile.open( path.c_str() );
2693 : if( outfile.is_open() ) {
2694 : outfile << *this << std::endl;
2695 : outfile.close();
2696 : } else {
2697 : std::cout << "no file open" << std::endl;
2698 : }
2699 :
2700 : }
2701 :
2702 : template< size_t M, size_t N, typename T >
2703 : void
2704 : matrix< M, N, T >::read_csv_file( const std::string& dir_, const std::string& filename_ )
2705 : {
2706 : int dir_length = dir_.size() -1;
2707 : int last_separator = dir_.find_last_of( "/");
2708 : std::string path = dir_;
2709 : if (last_separator < dir_length ) {
2710 : path.append( "/" );
2711 : }
2712 : path.append( filename_ );
2713 : //check for format
2714 : int suffix_pos = filename_.find( "csv", filename_.size() -3);
2715 : if( suffix_pos == (-1)) {
2716 : path.append( ".");
2717 : path.append( "csv" );
2718 : }
2719 :
2720 : std::ifstream infile;
2721 : infile.open( path.c_str(), std::ios::in);
2722 : if( infile.is_open() ) {
2723 : //TODO: not yet implemented
2724 : //infile >> *this >> std::endl;
2725 : infile.close();
2726 : } else {
2727 : std::cout << "no file open" << std::endl;
2728 : }
2729 :
2730 : }
2731 :
2732 :
2733 : template< size_t M, size_t N, typename T >
2734 : void
2735 : matrix< M, N, T >::sum_rows( matrix< M/2, N, T>& other ) const
2736 : {
2737 : typedef vector< N, T > row_type;
2738 :
2739 : row_type* row0 = new row_type;
2740 : row_type* row1 = new row_type;
2741 :
2742 : other.zero();
2743 :
2744 : for ( size_t row = 0; row < M; ++row )
2745 : {
2746 : get_row( row++, *row0 );
2747 : if ( row < M )
2748 : {
2749 : get_row( row, *row1 );
2750 : *row0 += *row1;
2751 : other.set_row( row/2 , *row0 );
2752 : }
2753 : }
2754 :
2755 : delete row0;
2756 : delete row1;
2757 : }
2758 :
2759 : template< size_t M, size_t N, typename T >
2760 : void
2761 : matrix< M, N, T >::sum_columns( matrix< M, N/2, T>& other ) const
2762 : {
2763 : typedef vector< M, T > col_type;
2764 :
2765 : col_type* col0 = new col_type;
2766 : col_type* col1 = new col_type;
2767 :
2768 : other.zero();
2769 :
2770 : for ( size_t col = 0; col< N; ++col )
2771 : {
2772 : get_column( col++, *col0 );
2773 : if ( col < N )
2774 : {
2775 : get_column( col, *col1 );
2776 : *col0 += *col1;
2777 : other.set_column( col/2, *col0 );
2778 : }
2779 : }
2780 :
2781 : delete col0;
2782 : delete col1;
2783 : }
2784 :
2785 :
2786 :
2787 : } // namespace vmml
2788 :
2789 : #endif
|