00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 #ifdef UNITTEST
00091 #include "unit_test.hpp"
00092
00093 #include "matrixutils.h"
00094
00095 using namespace matrix;
00096 using namespace std;
00097
00098 const D EPS=1e-9;
00099 bool comparetoidentity(const Matrix& m, double eps = EPS) {
00100 int worstdiagonal = 0;
00101 D maxunitydeviation = 0.0;
00102 D currentunitydeviation;
00103 for ( unsigned int i = 0; i < m.getM(); i++ ) {
00104 currentunitydeviation = m.val(i,i) - 1.;
00105 if ( currentunitydeviation < 0) currentunitydeviation *= -1.;
00106 if ( currentunitydeviation > maxunitydeviation ) {
00107 maxunitydeviation = currentunitydeviation;
00108 worstdiagonal = i;
00109 }
00110 }
00111 int worstoffdiagonalrow = 0;
00112 int worstoffdiagonalcolumn = 0;
00113 D maxzerodeviation = 0.0;
00114 D currentzerodeviation ;
00115 for ( unsigned int i = 0; i < m.getM(); i++ ) {
00116 for ( unsigned int j = 0; j < m.getN(); j++ ) {
00117 if ( i == j ) continue;
00118 currentzerodeviation = m.val(i,j);
00119 if ( currentzerodeviation < 0) currentzerodeviation *= -1.0;
00120 if ( currentzerodeviation > maxzerodeviation ) {
00121 maxzerodeviation = currentzerodeviation;
00122 worstoffdiagonalrow = i;
00123 worstoffdiagonalcolumn = j;
00124 }
00125
00126 }
00127 }
00128
00129
00130
00131
00132
00133 return (maxunitydeviation < eps && maxzerodeviation < eps);
00134 }
00135
00136 bool comparetozero(const Matrix& m, double eps = EPS) {
00137 D maxdeviation = 0.0;
00138 D currentdeviation;
00139 for ( unsigned int i = 0; i < m.getM(); i++ ) {
00140 for ( unsigned int j = 0; j < m.getN(); j++ ) {
00141 currentdeviation = m.val(i,j);
00142 if ( currentdeviation < 0.0) currentdeviation *= -1.;
00143 if ( currentdeviation > maxdeviation ) {
00144 maxdeviation = currentdeviation;
00145 }
00146 }
00147 }
00148 if(maxdeviation < eps)
00149 return true;
00150 else {
00151 cout << "\tWorst deviation: " << maxdeviation << endl;
00152 return false;
00153 }
00154 }
00155
00156
00157 UNIT_TEST_DEFINES
00158
00159 DEFINE_TEST( check_creation ) {
00160 cout << "\n -[ Creation and Access ]-\n";
00161 Matrix M1(3,3);
00162 D testdata[9]={1,0,0, 0,1,0, 0,0,1};
00163 Matrix M2(3,3);
00164 M2.set(testdata);
00165 M1.toId();
00166 unit_assert( "id=identity_set", M1 == M2 );
00167 D testdata2[12]={1,2,3, 4,5,6, 7,8,9, 10,11,12};
00168 Matrix M3(4,3, testdata2);
00169 unit_assert( "dimension of matrix", M3.getM() == 4 && M3.getN() == 3 );
00170 unit_assert( "field check",
00171 M3.val(0,2) == 3 && M3.val(2,1) == 8 && M3.val(3,0) == 10 );
00172 Matrix M4(M3);
00173 unit_assert( "copy constructor", M3 == M4 );
00174 Matrix M5(1,3,testdata2+3);
00175 unit_assert( "row", M3.row(1) == M5 );
00176
00177 unit_pass();
00178 }
00179
00180 DEFINE_TEST( check_vector_operation ) {
00181 cout << "\n -[ Vector Operations ]-\n";
00182 D testdata[3]={-1,3,2};
00183 const Matrix V1(1,3, testdata);
00184 const Matrix V2(3,1, testdata);
00185 Matrix V3(V1);
00186
00187 V3.toTranspose();
00188 unit_assert( "transpose", V3 == V2 );
00189 V3.toTranspose();
00190 unit_assert( "double transpose", V3 == V1 );
00191 D testdata2[3]={-2,6,4};
00192 Matrix V4(1,3,testdata2);
00193 V3.add(V1,V1);
00194 unit_assert( "add", V3 == V4 );
00195 D testdata3[3]={1,-3,-2};
00196 Matrix V5(1,3,testdata3);
00197 V4.sub(V1,V3);
00198 unit_assert( "sub", V4 == V5 );
00199
00200 D testdata4[3]={3,-9,-6};
00201 V5.set(testdata4);
00202 V4.copy(V1);
00203 V4.toMult(-3.0);
00204 unit_assert( "mult with scalar I", V4 == V5 );
00205 V4.mult(V1,-3.0);
00206 unit_assert( "mult with scalar II", V4 == V5 );
00207
00208 double f = 14;
00209 Matrix V6(1,1,&f);
00210 V3.copy(V1);
00211 V3.toTranspose();
00212 V4.mult(V1,V3);
00213 unit_assert( "scalarproduct", V4 == V6 );
00214 V4.copy(V1);
00215 unit_assert( "scalarproduct with exp(2)", V4.multMT() == V6 );
00216 V4.mult(V3,V1);
00217 unit_assert( "vector^T*vector=matrix", V4.getM() == 3);
00218 unit_assert( "vector^T*vector=exp(2)", V3.multMT().getM() == 3);
00219
00220 unit_pass();
00221 }
00222
00223 DEFINE_TEST( check_matrix_operation ) {
00224 cout << "\n -[ Matrix Operations ]-\n";
00225 D testdata[6]={1,2,3, 4,5,6 };
00226 const Matrix M1(2,3, testdata);
00227 D testdata2[6]={1,4, 2,5, 3,6 };
00228 const Matrix M2(3,2, testdata2);
00229 Matrix M3(M1);
00230
00231 M3.toTranspose();
00232 unit_assert( "transpose", M3 == M2 );
00233 D testdata3[6]={2,4,6, 8,10,12};
00234 Matrix M4(2,3,testdata3);
00235 M3.add(M1,M1);
00236 unit_assert( "add", M3 == M4 );
00237
00238 D testdata4[6]={-0.5, -1, -1.5, -2, -2.5, -3};
00239 M3.set(testdata4);
00240 M4.copy(M1);
00241 M4.toMult(-0.5);
00242 unit_assert( "mult with scalar", M4 == M3 );
00243
00244 D testdata5[6] = {2, -1, 0, 3, 2, -2};
00245 D testdata6[4] = {8, -1, 20, -1};
00246 Matrix M5 (3,2, testdata5);
00247 Matrix M6(2,2,testdata6);
00248 M4.mult(M1,M5);
00249 unit_assert( "mult(matrix, matrix)", M4 == M6 );
00250
00251 M3.copy(M1);
00252 M4.copy(M1);
00253 M4.toExp(1);
00254 unit_assert( "exp(1)", M3 == M4 );
00255 M3.toTranspose();
00256 M4.toExp(T);
00257 unit_assert( "exp(T)=transpose", M3 == M4 );
00258 M3.toId();
00259 M4.toExp(0);
00260 unit_assert( "exp(0)=id", M3 == M4 );
00261
00262 D testdata7[16] = {1,2,3,4, -4,2,1,3, 0.3,-0.9, 4, -3, 1,0.5,0.3,5.0};
00263 Matrix M7(4,4,testdata7);
00264 Matrix M8(M7);
00265 M7.toExp(-1);
00266 M4.mult(M7,M8);
00267 unit_assert( "exp(-1)*exp(1)=id", comparetoidentity(M4) );
00268 M7=M8.pseudoInverse(0);
00269 M4.mult(M7,M8);
00270 unit_assert( "pseudoinverse*exp(1)=id", comparetoidentity(M4) );
00271
00272 D testdata9[6] = {sin(1.0),sin(2.0),sin(3.0), sin(4.0),sin(5.0),sin(6.0) };
00273 Matrix M9(2,3,testdata9);
00274 M4.copy(M1);
00275 M4.toMap(sin);
00276 unit_assert( "map(sin)", M4 == M9 );
00277
00278 D testdata10[6] = {2,4,6, -0.4,-0.5,-0.6 };
00279 D testdata11[2] = {2,-0.1};
00280 Matrix M10(2,3,testdata10);
00281 Matrix M11(2,1,testdata11);
00282 M4.copy(M1);
00283 M4.toMultrowwise(M11);
00284 unit_assert( "multrowwise()", M4 == M10 );
00285 M4 = M1 & M11;
00286 unit_assert( "rowwise (&) ", M4 == M10 );
00287 D testdata12[6] = {2,1,0, 8, 2.5, 0 };
00288 D testdata13[3] = {2, 0.5, 0};
00289 M10.set(2,3,testdata12);
00290 Matrix M12(3,1,testdata13);
00291 M4.copy(M1);
00292 M4.toMultcolwise(M12);
00293 unit_assert( "multcolwise()", M4 == M10 );
00294
00295 M3.copy(M1);
00296 M4.copy(M1);
00297 M4.toTranspose();
00298 M5 = M3.multMT();
00299 M6.mult(M1,M4);
00300 unit_assert( "multMT() ", M5 == M6 );
00301 M5 = M3.multTM();
00302 M6.mult(M4,M1);
00303 unit_assert( "multTM() ", M5 == M6 );
00304
00305 D testdata20[12]={1,2,3, 4,5,6, 1,2,3, 4,5,6 };
00306 const Matrix M20(4,3, testdata20);
00307 const Matrix M21 = M1.above(M1);
00308 unit_assert( "above() ", M20 == M21 );
00309 D testdata22[8]={1,2,3, 7, 4,5,6, 8};
00310 D testdata23[2]={7, 8};
00311 const Matrix M22(2,4, testdata22);
00312 const Matrix M23(2,1, testdata23);
00313 const Matrix M24 = M1.beside(M23);
00314 unit_assert( "beside() ", M24 == M22 );
00315
00316 Matrix M30 = M24;
00317 const Matrix M31 = M30.removeColumns(1);
00318 unit_assert( "removeColumns() ", M31 == M1 );
00319 Matrix M32 = M20;
00320 const Matrix M33 = M32.removeRows(2);
00321 unit_assert( "removeRows() ", M33 == M1 );
00322
00323 unit_pass();
00324 }
00325
00326 DEFINE_TEST( check_matrix_operators ) {
00327 cout << "\n -[ Matrix Operators (+ - * ^)]-\n";
00328 D testdata[6]={1,2,3, 4,5,6 };
00329 const Matrix M1(2,3, testdata);
00330 D testdata2[6]={1,4, 2,5, 3,6 };
00331 const Matrix M2(3,2, testdata2);
00332 unit_assert( "^T ", (M1^T) == M2 );
00333 D testdata3[6]={2,4,6, 8,10,12};
00334 Matrix M4(2,3,testdata3);
00335 unit_assert( "+ ", M1+M1 == M4 );
00336 unit_assert( "- ", M1+M1-M1 == M1 );
00337
00338 D testdata4[6]={-0.5, -1, -1.5, -2, -2.5, -3};
00339 Matrix M3(2,3, testdata4);
00340 unit_assert( "* scalar", M1*(-0.5) == M3 );
00341
00342 D testdata5[6] = {2, -1, 0, 3, 2, -2};
00343 D testdata6[4] = {8, -1, 20, -1};
00344 Matrix M5 (3,2, testdata5);
00345 Matrix M6(2,2,testdata6);
00346 unit_assert( "* ", M1*M5 == M6 );
00347
00348 unit_assert( "^1 ", (M1^1) == M1 );
00349 M3.toId();
00350 unit_assert( "^0=id ", (M1^0) == M3 );
00351
00352 D testdata7[16] = {1,2,3,4, -4,2,1,3, 0.3,-0.9, 4, -3, 1,0.5,0.3,5.0};
00353 Matrix M7(4,4,testdata7);
00354 unit_assert( "^1 * ^-1=id ", comparetoidentity(M7*(M7^-1)) );
00355 unit_pass();
00356 }
00357
00358 DEFINE_TEST( check_matrix_utils ) {
00359 cout << "\n -[ Matrix Utils: Eigenvalues and Eigenvectors ]-\n";
00360 D testdata[9]={1,2,3, 4,5,6, 7,8,9};
00361 const Matrix M1(3,3, testdata);
00362 const Matrix SymM1 = M1.multMT();
00363 Matrix eval, evec;
00364 eval = eigenValuesRealSym(SymM1);
00365 D resultval[3]={1.5*(95+sqrt(8881)), 1.5*(95-sqrt(8881)), 0};
00366 const Matrix resultvalM(3,1, resultval);
00367
00368 unit_assert( "Sym Real Eigenvalues ", comparetozero(eval-resultvalM));
00369 eigenValuesVectorsRealSym(SymM1, eval, evec);
00370 D resultvecs[9]={0.21483723836839594,0.8872306883463704,0.4082482904638631,
00371 0.5205873894647369,0.24964395298829792,-0.816496580927726,
00372 0.826337540561078,-0.3879427823697746,0.4082482904638631};
00373 const Matrix resultvecsM(3,3, resultvecs);
00374
00375
00376 unit_assert( "Sym Real Eigenvalues and Vectors: Vals", comparetozero(eval-resultvalM));
00377 unit_assert( "Sym Real Eigenvalues and Vectors: Vectors", comparetozero(evec-resultvecsM));
00378
00379 D testdata2[16]={-1., 1., -1., 1., -8., 4., -2., 1., 27., 9., 3., 1., 64., 16., 4., 1.};
00380 const Matrix M2(4,4, testdata2);
00381 Matrix eval_r, eval_i;
00382 eigenValues(M2, eval_r, eval_i);
00383 D resultval_r[4]={-6.413911026270929,5.5455534989094595,5.5455534989094595,
00384 2.3228040284520177};
00385 D resultval_i[4]={0,3.0854497586289216,-3.0854497586289216,0};
00386 const Matrix resultvalM_r(4,1, resultval_r);
00387 const Matrix resultvalM_i(4,1, resultval_i);
00388
00389 unit_assert( "NonSym Eigenvalues (Complex) ", comparetozero(eval_r-resultvalM_r)
00390 && comparetozero(eval_i-resultvalM_i));
00391 Matrix evec_r, evec_i;
00392 eigenValuesVectors(M2, eval_r, eval_i, evec_r, evec_i);
00393 D resultvecs_r[16]={
00394 -0.09988217466836526,-0.043500372394264235,-0.043500372394264235, -0.14493294424802267,
00395 -0.11125130967436689,0.06398640593013502, 0.06398640593013502,0.35660144308731107,
00396 0.2925006732813017, -0.5151803514845115,-0.5151803514845115,0.9193688436883699,
00397 0.9445051897206503,-0.8405935042246232,-0.8405935042246232, 0.0811836295983173};
00398 D resultvecs_i[16]={
00399 0,-0.007553928841000267,0.007553928841000267,0,
00400 0,-0.1422404507165189, 0.1422404507165189,0,
00401 0,0.04142240814335418,-0.04142240814335418,0,
00402 0,0.,0.,0};
00403 const Matrix resultvecsM_r(4,4, resultvecs_r);
00404 const Matrix resultvecsM_i(4,4, resultvecs_i);
00405
00406
00407
00408
00409 unit_assert( "NonSym Eigenvalues and Vectors: Vals",
00410 comparetozero(eval_r-resultvalM_r) && comparetozero(eval_i-resultvalM_i) );
00411 unit_assert( "NonSym Eigenvalues and Vectors: Vectors",
00412 comparetozero(evec_r-resultvecsM_r, 0.001) &&
00413 comparetozero(evec_i-resultvecsM_i, 0.002));
00414
00415 unit_pass();
00416 }
00417
00418 DEFINE_TEST( speed ) {
00419 cout << "\n -[ Speed: Inverion ]-\n";
00420 #ifndef NDEBUG
00421 cout << " DEBUG MODE! use -DNDEBUG -O3 (not -g) to get full performance\n";
00422 #endif
00423 Matrix M1;
00424 srand(time(0));
00425 D testdata0[9] = {1,2, -4,2};
00426 Matrix M2(2,2,testdata0);
00427 UNIT_MEASURE_START("2x2 Matrix inversion", 100000)
00428 M1 = (M2^-1);
00429 UNIT_MEASURE_STOP("");
00430 unit_assert( "validation", comparetoidentity(M1*M2));
00431
00432
00433 D testdata1[9] = {1,2,3, -4,2,1, 0.3,-0.9};
00434 Matrix M3(3,3,testdata1);
00435 UNIT_MEASURE_START("3x3 Matrix inversion", 100000)
00436 M1 = (M3^-1);
00437 UNIT_MEASURE_STOP("");
00438 unit_assert( "validation", comparetoidentity(M1*M3));
00439
00440 D testdata2[16] = {1,2,3,4, -4,2,1,3, 0.3,-0.9, 4, -3, 1,0.5,0.3,5.0};
00441 Matrix M4(4,4,testdata2);
00442 UNIT_MEASURE_START("4x4 Matrix inversion", 100000)
00443 M1 = (M4^-1);
00444 UNIT_MEASURE_STOP("");
00445 unit_assert( "validation", comparetoidentity(M1*M4));
00446
00447 Matrix M20(20,20);
00448 for (unsigned int i=0; i < M20.getM(); i++)
00449 for (unsigned int j=0; j < M20.getN(); j++) {
00450 M20.val(i,j) = -22+(100. * rand())/RAND_MAX;
00451 }
00452 UNIT_MEASURE_START("20x20 Matrix inversion",1000)
00453 M1 = (M20^-1);
00454 UNIT_MEASURE_STOP("");
00455 unit_assert( "validation", comparetoidentity(M1*M20));
00456
00457 Matrix M200(200,200);
00458 rand();
00459 for (unsigned int i=0; i < M200.getM(); i++)
00460 for (unsigned int j=0; j < M200.getN(); j++) {
00461 M200.val(i,j) = -22+(100. * rand())/RAND_MAX;
00462 }
00463 UNIT_MEASURE_START("200x200 Matrix inversion",2)
00464 M1 = (M200^-1);
00465 UNIT_MEASURE_STOP("");
00466 unit_assert( "validation", comparetoidentity(M1*M200));
00467
00468 cout << "\n -[ Speed: Other Operations ]-\n";
00469 UNIT_MEASURE_START("20x20 Matrix multiplication with assignment",5000)
00470 M1 = M20*M20;
00471 UNIT_MEASURE_STOP("");
00472 UNIT_MEASURE_START("20x20 Matrix addition with assignment",100000)
00473 M1= (M1 + M20);
00474 UNIT_MEASURE_STOP("");
00475 UNIT_MEASURE_START("20x20 Matrix inplace addition",100000)
00476 M1 += M20;
00477 UNIT_MEASURE_STOP("");
00478 UNIT_MEASURE_START("20x20 Matrix transposition",100000)
00479 M1 += M20;
00480 UNIT_MEASURE_STOP("");
00481 const Matrix& M20Sym = M20.multMT();
00482 UNIT_MEASURE_START("20x20 Matrix Sym Real Eigenvalues",1000)
00483 Matrix eval, evec;
00484 eigenValuesVectorsRealSym(M20Sym, eval, evec);
00485 UNIT_MEASURE_STOP("");
00486
00487
00488 unit_pass();
00489 }
00490
00491
00492 DEFINE_TEST( store_restore ) {
00493 cout << "\n -[ Store and Restore ]-\n";
00494 Matrix M1(32,1);
00495 for(int i =0; i<32; i++){
00496 M1.val(0,0) = (double)rand()/RAND_MAX;
00497 }
00498 Matrix M2(32,2);
00499 for(int i =0; i<64; i++){
00500 M2.val(i%32,i/32) = (double)rand()/RAND_MAX;
00501 }
00502 FILE* f;
00503 f=fopen("test.dat","wb");
00504 M1.store(f);
00505 M2.store(f);
00506 fclose(f);
00507 f=fopen("test.dat","rb");
00508 Matrix M3,M4;
00509 M3.restore(f);
00510 M4.restore(f);
00511 fclose(f);
00512 unit_assert( "validation", (M1-M3).map(fabs).elementSum()==0);
00513 unit_assert( "validation", (M2-M4).map(fabs).elementSum()==0);
00514
00515 unit_pass();
00516 }
00517
00518
00519
00520 double clip(double r,double x){
00521 if(!isnormal(x)) return 0;
00522 return x < -r ? -r : (x>r ? r : x);
00523 }
00524
00525
00526 DEFINE_TEST( invertzero ) {
00527 cout << "\n -[ Inverion of Singular Matrices ]-\n";
00528 Matrix M1;
00529 srand(time(0));
00530 D testdata0[9] = {1.0,0.0, 0.0,0.0};
00531 Matrix M2(2,2,testdata0);
00532 M1 = M2.secureInverse();
00533 cout << M1*M2 <<endl;
00534 unit_assert( "2x2 validation", 1 );
00535
00536 D testdata1[9] = {1,2,3, 1,2,3, 0.3,-0.9,.2};
00537 Matrix M3(3,3,testdata1);
00538 M1 = (M3.secureInverse());
00539 unit_assert( "3x3 validation", 1 );
00540 cout << M3*M1 << endl;
00541
00542 D testdata2[16] = {1,2,3,4, 1,2,3,4, 0.3,-0.9, 4, -3, 1,0.5,0.3,5.0};
00543 Matrix M4(4,4,testdata2);
00544 M1 = M4.secureInverse();
00545 unit_assert( "4x4 validation", 1 );
00546 cout << M4*M1 << endl;
00547
00548 D testdata3[16] = {1,2,3,4, 1,0,3,4, 0.3,-0.9, 4, -3, 1,0.5,0.3,5.0};
00549 Matrix M5(4,4,testdata3);
00550 M1 = M5.secureInverse();
00551 unit_assert( "4x4 validation", 1 );
00552 cout << M1*M5 << endl;
00553 unit_pass();
00554
00555 }
00556
00557 UNIT_TEST_RUN( "Matrix Tests" )
00558 ADD_TEST( check_creation )
00559 ADD_TEST( check_vector_operation )
00560 ADD_TEST( check_matrix_operation )
00561 ADD_TEST( check_matrix_operators )
00562 ADD_TEST( check_matrix_utils )
00563 ADD_TEST( speed )
00564 ADD_TEST( store_restore )
00565 ADD_TEST( invertzero )
00566
00567 UNIT_TEST_END
00568
00569 #endif // UNITTEST