00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <limits>
00026 #include <iostream>
00027
00028 #include <qvmath.h>
00029 #include <qvdefines.h>
00030 #include <qvmatrixalgebra.h>
00031
00032 #include <QString>
00033 #include <QVMatrix>
00034
00036
00037
00038 QVMatrix::QVMatrix():
00039 cols(1), rows(1), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00040 {
00041 operator()(0,0) = 1;
00042 }
00043
00044 QVMatrix::QVMatrix(const QVMatrix &matrix):
00045 cols(matrix.cols), rows(matrix.rows), type(matrix.type), transposed(matrix.type), data(matrix.data)
00046 { }
00047
00048 QVMatrix::QVMatrix(const int rows, const int cols, const double *data):
00049 cols(cols), rows(rows), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00050 {
00051 if (data != NULL)
00052 {
00053 const int n = cols*rows;
00054 double *matrixData = getWriteData();
00055 for(int i = 0; i < n; i++)
00056 matrixData[i] = data[i];
00057 }
00058
00059
00060
00061 }
00062
00063 QVMatrix::QVMatrix(const int rows, const int cols, const QVVector &data):
00064 cols(cols), rows(rows), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00065 {
00066 const int n = cols*rows;
00067 double *matrixData = getWriteData();
00068 for(int i = 0; i < n; i++)
00069 matrixData[i] = data[i];
00070 }
00071
00072
00073 QVMatrix::QVMatrix(const int rows, const int cols, const double value):
00074 cols(cols), rows(rows), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00075 {
00076 set(value);
00077 }
00078
00079 QVMatrix::QVMatrix(const QVQuaternion &quaternion)
00080 {
00081 *this = quaternion.toRotationMatrix();
00082 }
00083
00084 QVMatrix::QVMatrix(const QVVector &vector, const bool rowVector):
00085 cols(rowVector?vector.size():1), rows(rowVector?1:vector.size()), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00086 {
00087 if (rowVector)
00088 setRow(0, vector);
00089 else
00090 setCol(0, vector);
00091 }
00092
00093 QVMatrix::QVMatrix(const QList<QVVector> &vectorList): cols(vectorList.at(0).size()), rows(vectorList.size()), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00094 {
00095 for (int n = 0; n < getRows(); n++)
00096 {
00097 Q_ASSERT(vectorList.at(n).size() == getCols());
00098 setRow(n, vectorList.at(n));
00099 }
00100 }
00101
00102 QVMatrix::QVMatrix(const QList< QVector<double> > &vectorList): cols(vectorList.at(0).size()), rows(vectorList.size()), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00103 {
00104 for (int n = 0; n < getRows(); n++)
00105 {
00106 Q_ASSERT(vectorList.at(n).size() == getCols());
00107 setRow(n, vectorList.at(n));
00108 }
00109 }
00110
00111 #ifdef GSL_AVAILABLE
00112 QVMatrix::QVMatrix(const gsl_matrix *matrix): cols(matrix->size2), rows(matrix->size1), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00113 {
00114 for(int i = 0; i < rows; i++)
00115 for(int j = 0; j < cols; j++)
00116 operator()(i, j) = gsl_matrix_get(matrix, i, j);
00117 }
00118
00119 QVMatrix::operator gsl_matrix * () const
00120 {
00121 gsl_matrix *result = gsl_matrix_alloc(rows, cols);
00122 for(int i = 0; i < rows; i++)
00123 for(int j = 0; j < cols; j++)
00124 gsl_matrix_set(result, i, j, operator()(i, j));
00125 return result;
00126 }
00127 #endif
00128
00129 QVMatrix::QVMatrix(const QList<QPointF> &pointList): cols(2), rows(pointList.size()), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00130 {
00131 for (int n = 0; n < getRows(); n++)
00132 setRow(n, pointList.at(n));
00133 }
00134
00135 #ifdef QVOPENCV
00136 QVMatrix::QVMatrix(const CvMat *cvMatrix): cols(cvMatrix->cols), rows(cvMatrix->rows), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00137 {
00138 for (int i = 0; i < rows; i++)
00139 for (int j = 0; j < cols; j++)
00140 this->operator()(i,j) = cvmGet(cvMatrix, i, j);
00141 }
00142
00143 CvMat *QVMatrix::toCvMat(const int cvMatType) const
00144 {
00145 Q_ASSERT( (cvMatType == CV_32F) || (cvMatType == CV_64F) );
00146
00147 CvMat *result = cvCreateMat(rows, cols, cvMatType);
00148
00149 for (int i = 0; i < rows; i++)
00150 for (int j = 0; j < cols; j++)
00151 cvmSet(result, i, j, this->operator()(i,j));
00152 return result;
00153 }
00154 #endif
00155
00156 #ifdef QVOCTAVE
00157 QVMatrix::QVMatrix(const Matrix octMatrix): cols(octMatrix.columns()), rows(octMatrix.rows()), type(General), transposed(false), data(new QBlasDataBuffer(cols*rows))
00158 {
00159 for (int i = 0; i < rows; i++)
00160 for(int j = 0; j < cols; j++)
00161 operator()(i,j) = octMatrix(i,j);
00162 }
00163
00164 Matrix QVMatrix::toOctaveMat() const
00165 {
00166 Matrix result(rows, cols);
00167
00168 for (int i = 0; i < rows; i++)
00169 for(int j = 0; j < cols; j++)
00170 result(i,j) = operator()(i,j);
00171 return result;
00172 }
00173 #endif
00174
00176 QVMatrix & QVMatrix::operator=(const QVMatrix &matrix)
00177 {
00178 cols = matrix.cols;
00179 rows = matrix.rows;
00180 type = matrix.type;
00181 transposed = matrix.transposed;
00182 data = matrix.data;
00183
00184 return *this;
00185 }
00186
00188
00189
00190
00191
00192
00193
00194
00195
00197
00198 bool QVMatrix::equals(const QVMatrix &matrix) const
00199 {
00200
00201 if (cols != matrix.cols || rows != matrix.rows)
00202 return false;
00203
00204
00205 const double *data1 = getReadData(),
00206 *data2 = matrix.getReadData();
00207
00208 for (int i = 0; i < getDataSize(); i++)
00209 if (data1[i] != data2[i])
00210 return false;
00211
00212 return true;
00213 }
00214
00215 #ifdef BLAS_AVAILABLE
00216 QVVector QVMatrix::dotProduct(const QVVector &vector, const bool transposeMatrix) const
00217 {
00218 const int m = transposeMatrix? cols: rows,
00219 n = transposeMatrix? rows: cols,
00220 n_ = vector.size();
00221
00222 if (n != n_)
00223 {
00224 std::cout << "ERROR: tried to multiply a matrix with a vector of incompatible sizes at QVMatrix::dotProduct(const QVVector &v)." << std::endl
00225 << "\tMatrix dimensions:\t" << m << "x" << n << std::endl
00226 << "\tVector dimension:\t" << n_ << std::endl;
00227 exit(1);
00228 }
00229
00230 QVVector result(m);
00231 cblas_dgemv(CblasRowMajor, transposeMatrix?CblasTrans:CblasNoTrans, rows, cols, 1.0, getReadData(), cols, vector.data(), 1, 0.0, result.data(), 1);
00232 return result;
00233 }
00234
00235 QVMatrix QVMatrix::dotProduct(const QVMatrix &matrix, const bool transposeFirstOperand, const bool transposeSecondOperand) const
00236 {
00237
00238 const int cols1 = cols, rows1 = rows, cols2 = matrix.cols, rows2 = matrix.rows;
00239
00240
00241 const int m = transposeFirstOperand? cols1: rows1,
00242 k = transposeFirstOperand? rows1: cols1,
00243 k_ = transposeSecondOperand? cols2: rows2,
00244 n = transposeSecondOperand? rows2: cols2;
00245
00246 QVMatrix result(m, n);
00247
00248
00249 Q_ASSERT(k == k_);
00250
00251 if (k != k_)
00252 {
00253 std::cout << "ERROR: tried to multiply matrices with incompatible sizes at QVMatrix::dotProduct(const QVMatrix &matrix)." << std::endl
00254 << "\tMatrix 1 dimensions:\t" << m << "x" << k << std::endl
00255 << "\tMatrix 2 dimensions:\t" << k_ << "x" << n << std::endl;
00256 exit(1);
00257 }
00258
00259 cblas_dgemm(CblasRowMajor,
00260 transposeFirstOperand?CblasTrans:CblasNoTrans,
00261 transposeSecondOperand?CblasTrans:CblasNoTrans,
00262 m, n, k, 1.0,
00263 getReadData(), cols1,
00264 matrix.getReadData(), cols2, 0.0,
00265 result.getWriteData(), n);
00266
00267 return result;
00268 }
00269 #else
00270 QVMatrix QVMatrix::dotProduct(const QVMatrix &matrix, const bool transposeFirstOperand, const bool transposeSecondOperand) const
00271 {
00272 std::cout << "[QVMatrix::dotProduct] --------------------------------- Not blas! --------------------" << std::endl;
00273 const QVMatrix op1 = transposeFirstOperand? this->transpose():(*this),
00274 op2 = transposeSecondOperand? matrix.transpose():matrix;
00275
00276 const int m = op1.getRows(), o = op1.getCols(), o_ = op2.getRows(), n = op2.getCols();
00277
00278
00279 Q_ASSERT(o == o_);
00280
00281 if (o != o_)
00282 {
00283 std::cout << "ERROR: tried to multiply matrices with incompatible sizes at QVMatrix::dotProduct(const QVMatrix &matrix)." << std::endl
00284 << "\tMatrix 1 dimensions:\t" << m << "x" << o << std::endl
00285 << "\tMatrix 2 dimensions:\t" << o_ << "x" << n << std::endl;
00286 exit(1);
00287 }
00288
00289 QVMatrix result(m, n, 0.0);
00290
00291 for(int i = 0; i < m; i++)
00292 for(int j = 0; j < n; j++)
00293 for(int k = 0; k < o; k++)
00294 result(i,j) += op1(i,k) * op2(k, j);
00295 return result;
00296 }
00297
00298 QVVector QVMatrix::dotProduct(const QVVector &vector, const bool transposeMatrix) const
00299 {
00300 std::cout << "[QVMatrix::dotProduct] --------------------------------- Not blas! --------------------" << std::endl;
00301
00302 const QVMatrix op1 = transposeMatrix? this->transpose() : (*this);
00303 const int m = op1.getRows(), o = op1.getCols(), o_ = vector.size();
00304
00305 if (o != o_)
00306 {
00307 std::cout << "ERROR: tried to multiply a matrix with a vector of incompatible sizes at QVMatrix::dotProduct(const QVVector &v)." << std::endl
00308 << "\tMatrix dimensions:\t" << m << "x" << o << std::endl
00309 << "\tVector dimension:\t" << o_ << std::endl;
00310 exit(1);
00311 }
00312
00313 QVVector result(m, 0.0);
00314
00315 for(int i = 0; i < m; i++)
00316 for(int k = 0; k < o; k++)
00317 result[i] += op1(i,k) * vector[k];
00318
00319 return result;
00320 }
00321 #endif
00322
00323 QVMatrix QVMatrix::elementProduct(const QVMatrix &matrix) const
00324 {
00325 const int cols1 = cols, rows1 = rows, cols2 = matrix.cols, rows2 = matrix.rows;
00326
00327 Q_ASSERT(rows1 == rows2);
00328 Q_ASSERT(cols1 == cols2);
00329
00330 if (cols1 != cols2 || rows1 != rows2)
00331 {
00332 std::cout << "ERROR: tried to multiply matrices with incompatible sizes at QVMatrix::dotProduct(const QVMatrix &matrix)." << std::endl
00333 << "\tMatrix 1 dimensions:\t" << rows1 << "x" << cols1 << std::endl
00334 << "\tMatrix 2 dimensions:\t" << rows2 << "x" << cols2 << std::endl;
00335 exit(1);
00336 }
00337
00338 QVMatrix result(rows1, cols2);
00339
00341 for (int i = 0; i < cols1; i++)
00342 for (int j = 0; j < cols1; j++)
00343 result(i,j) = this->operator()(i,j) * matrix(i,j);
00344
00345 return result;
00346 }
00347
00348 #ifdef QVMATRIXALGEBRA_AVAILABLE
00349 QVMatrix QVMatrix::matrixDivide(const QVMatrix &matrix) const
00350 {
00351 Q_ASSERT(matrix.getCols() >= matrix.getRows());
00352 Q_ASSERT(matrix.getCols() == (*this).getCols());
00353
00354 QVMatrix result(matrix.getRows(), (*this).getRows());
00355
00356
00357
00358
00359 solveBySingularValueDecomposition(matrix.transpose(), result, (*this).transpose());
00360
00361 return result.transpose();
00362 }
00363
00364 void QVMatrix::triangularSolve(const QVVector &b, QVVector &x, bool transposed, bool unit_diagonal) const
00365 {
00366 x = b;
00367
00368
00369
00370 switch(this->getType()) {
00371 case UpperTriangular:
00372
00373 cblas_dtrsv(CblasRowMajor, CblasUpper,transposed?CblasTrans:CblasNoTrans,unit_diagonal?CblasUnit:CblasNonUnit,
00374 this->getRows(),this->getReadData(),this->getRows(),x.data(),1);
00375 break;
00376 case LowerTriangular:
00377
00378 cblas_dtrsv(CblasRowMajor, CblasLower,transposed?CblasTrans:CblasNoTrans,unit_diagonal?CblasUnit:CblasNonUnit,
00379 this->getRows(),this->getReadData(),this->getRows(),x.data(),1);
00380 break;
00381 default:
00382 qFatal("QVMatrix::triangularSolve() method called with non-triangular matrix\n");
00383 }
00384
00385
00386
00387
00388
00389
00390 }
00391
00392 void QVMatrix::triangularSolve(const QVMatrix &B, QVMatrix &X, bool transposed, bool unit_diagonal, bool left) const
00393 {
00394 X = B;
00395
00396
00397
00398 switch(this->getType()) {
00399 case UpperTriangular:
00400
00401 cblas_dtrsm(CblasRowMajor, left?CblasLeft:CblasRight, CblasUpper, transposed?CblasTrans:CblasNoTrans,
00402 unit_diagonal?CblasUnit:CblasNonUnit,
00403 this->getRows(),X.getCols(),1.0,this->getReadData(),this->getRows(),X.getWriteData(),X.getCols());
00404 break;
00405 case LowerTriangular:
00406
00407 cblas_dtrsm(CblasRowMajor, left?CblasLeft:CblasRight, CblasLower, transposed?CblasTrans:CblasNoTrans,
00408 unit_diagonal?CblasUnit:CblasNonUnit,
00409 this->getRows(),X.getCols(),1.0,this->getReadData(),this->getRows(),X.getWriteData(),X.getCols());
00410 break;
00411 default:
00412 qFatal("QVMatrix::triangularSolve() method called with non-triangular matrix\n");
00413 }
00414
00415
00416
00417
00418
00419 }
00420
00421 QVMatrix QVMatrix::inverse() const
00422 {
00424 return pseudoInverse(*this);
00425 }
00426
00427 double QVMatrix::det() const
00428 {
00429 return determinant(*this);
00430 }
00431 #endif
00432
00433 QVMatrix QVMatrix::transpose() const
00434 {
00435 const int rows = getRows(), cols = getCols();
00436
00437 QVMatrix result(cols, rows);
00438
00439 const double *matrixData = getReadData();
00440 double *resultData = result.getWriteData();
00441
00443 for (int i = 0; i < rows; i++)
00444 for (int j = 0; j < cols; j++)
00445 resultData[j*rows+i] = matrixData[i*cols+j];
00446
00447 return result;
00448 }
00449
00450 void QVMatrix::set(const double value)
00451 {
00452 double *resultData = getWriteData();
00453 const int dataSize = getDataSize();
00454
00456 for (int i = 0; i < dataSize; i++)
00457 resultData[i] = value;
00458 }
00459
00460 QVMatrix QVMatrix::addition(const QVMatrix &matrix) const
00461 {
00462 Q_ASSERT(cols == matrix.cols || rows == matrix.rows);
00463
00464 QVMatrix result = *this;
00465
00466 const double *matrixData = matrix.getReadData();
00467 double *resultData = result.getWriteData();
00468 const int dataSize = matrix.getDataSize();
00469
00471 for (int i = 0; i < dataSize; i++)
00472 resultData[i] += matrixData[i];
00473
00474 return result;
00475 }
00476
00477
00478 void QVMatrix::inlineAddition(const QVMatrix &matrix)
00479 {
00480 Q_ASSERT(cols == matrix.cols || rows == matrix.rows);
00481
00482 QVMatrix result = *this;
00483
00484 const double *matrixData = matrix.getReadData();
00485 double *resultData = getWriteData();
00486 const int dataSize = matrix.getDataSize();
00487
00489 for (int i = 0; i < dataSize; i++)
00490 resultData[i] += matrixData[i];
00491 }
00492
00493 QVMatrix QVMatrix::substract(const QVMatrix &matrix) const
00494 {
00495
00496 Q_ASSERT(cols == matrix.cols || rows == matrix.rows);
00497
00498 QVMatrix result = *this;
00499
00500 const double *matrixData = matrix.getReadData();
00501 double *resultData = result.getWriteData();
00502 const int dataSize = matrix.getDataSize();
00503
00505
00506 for (int i = 0; i < dataSize; i++)
00507 resultData[i] -= matrixData[i];
00508
00509 return result;
00510 }
00511
00512 QVMatrix QVMatrix::scalarProduct(const double value) const
00513 {
00514 QVMatrix result = *this;
00515
00516 double *resultData = result.getWriteData();
00517 const int dataSize = getDataSize();
00518
00520
00521 for (int i = 0; i < dataSize; i++)
00522 resultData[i] *= value;
00523
00524 return result;
00525 }
00526
00527 QVMatrix QVMatrix::scalarDivide(const double value) const
00528 {
00529 QVMatrix result = *this;
00530
00531 double *resultData = result.getWriteData();
00532 const int dataSize = getDataSize();
00533
00535
00536 for (int i = 0; i < dataSize; i++)
00537 resultData[i] /= value;
00538
00539 return result;
00540 }
00541
00542 QVMatrix QVMatrix::scalarAdd(const double value) const
00543 {
00544 QVMatrix result = *this;
00545
00546 double *resultData = result.getWriteData();
00547 const int dataSize = getDataSize();
00548
00550
00551 for (int i = 0; i < dataSize; i++)
00552 resultData[i] += value;
00553
00554 return result;
00555 }
00556
00557 QVMatrix QVMatrix::scalarSubstract(const double value) const
00558 {
00559 QVMatrix result = *this;
00560
00561 double *resultData = result.getWriteData();
00562 const int dataSize = getDataSize();
00563
00565
00566 for (int i = 0; i < dataSize; i++)
00567 resultData[i] -= value;
00568
00569 return result;
00570 }
00571
00572 QVMatrix QVMatrix::horizontalAppend(const QVMatrix &matrix) const
00573 {
00574 const int cols1 = cols, rows1 = rows, cols2 = matrix.cols, rows2 = matrix.rows;
00575
00576 Q_ASSERT(rows1 == rows2);
00577
00578 if (rows1 != rows2)
00579 {
00580 std::cout << "ERROR: tried to append horizontally matrices with different row number at QVMatrix::horizontalAppend(const QVMatrix &matrix)."
00581 << std::endl
00582 << "\tMatrix 1 dimensions:\t" << rows1 << "x" << cols1 << std::endl
00583 << "\tMatrix 2 dimensions:\t" << rows2 << "x" << cols2 << std::endl;
00584 exit(1);
00585 }
00586
00587 QVMatrix result(rows1, cols1 + cols2);
00588
00589 for (int i = 0; i < cols1; i++)
00590 result.setCol(i, getCol(i));
00591
00592 for (int i = 0; i < cols2; i++)
00593 result.setCol(cols1 + i, matrix.getCol(i));
00594
00595 return result;
00596 }
00597
00598 QVMatrix QVMatrix::verticalAppend(const QVMatrix &matrix) const
00599 {
00600 const int cols1 = cols, rows1 = rows, cols2 = matrix.cols, rows2 = matrix.rows;
00601
00602 Q_ASSERT(cols1 == cols2);
00603
00604 if (cols1 != cols2)
00605 {
00606 std::cout << "ERROR: tried to append vertically matrices with different row number at QVMatrix::horizontalAppend(const QVMatrix &matrix)."
00607 << std::endl
00608 << "\tMatrix 1 dimensions:\t" << rows1 << "x" << cols1 << std::endl
00609 << "\tMatrix 2 dimensions:\t" << rows2 << "x" << cols2 << std::endl;
00610 exit(1);
00611 }
00612
00613 QVMatrix result(rows1 + rows2, cols2);
00614
00615 for (int i = 0; i < rows1; i++)
00616 result.setRow(i, getRow(i));
00617
00618 for (int i = 0; i < rows2; i++)
00619 result.setRow(rows1 + i, matrix.getRow(i));
00620
00621 return result;
00622 }
00623
00625
00626 double QVMatrix::norm2() const
00627 {
00628 #ifdef BLAS_AVAILABLE
00629 return cblas_dnrm2(getDataSize(), getReadData(), 1);
00630 #else
00631 std::cout << "[QVMatrix::dotProduct] --------------------------------- Not blas! --------------------" << std::endl;
00632 double accum = 0.0;
00633 const int cols = getCols(), rows = getRows();
00634
00635 for (int i = 0; i < rows; i++)
00636 for (int j = 0; j < cols; j++)
00637 {
00638 const double actualValue = operator()(i,j);
00639 accum += actualValue * actualValue;
00640 }
00641 return sqrt(accum);
00642 #endif
00643 };
00644
00645 double QVMatrix::trace() const
00646 {
00647 const int n = MIN(getCols(), getRows());
00648 double accum = 0.0;
00649 for (int i = 0; i < n; i++)
00650 accum += operator()(i,i);
00651 return accum;
00652 }
00653
00654 bool QVMatrix::isDiagonal() const
00655 {
00656 const double *data = getReadData();
00657
00658
00659 for (int i = 0; i < rows; i++)
00660 for (int j = 0; j < cols; j++)
00661 if ( (i != j) and (data[i*cols+j] != 0.0) )
00662 return false;
00663
00664 return true;
00665 }
00666
00667 bool QVMatrix::containsNaN() const
00668 {
00669 const double *data = getReadData();
00670 const int dataSize = getDataSize();
00671
00672 for (int i = 0; i < dataSize; i++)
00673 if (isnan(data[i]))
00674 return true;
00675
00676 return false;
00677 }
00678
00679 bool QVMatrix::containsInf() const
00680 {
00681 const double *data = getReadData();
00682 const int dataSize = getDataSize();
00683
00684 for (int i = 0; i < dataSize; i++)
00685 if (isinf(data[i]))
00686 return true;
00687
00688 return false;
00689 }
00690
00691 QVMatrix QVMatrix::rowHomogeneousNormalize() const
00692 {
00693 const int cols = getCols(), rows = getRows();
00694 QVMatrix result(rows, cols);
00695
00696 for (int i = 0; i < rows; i++)
00697 for (int j = 0; j < cols; j++)
00698 result(i,j) = operator()(i,j) / operator()(i,cols-1);
00699 return result;
00700 }
00701
00702 const QVVector QVMatrix::getRow(const int row) const
00703 {
00704 Q_ASSERT(row < getRows());
00705
00706 const int cols = getCols();
00707 QVVector result(cols);
00708 for (int col= 0; col < cols; col++)
00709 result[col] = operator()(row,col);
00710
00711 return result;
00712 }
00713
00714 void QVMatrix::setRow(const int row, QVVector vector)
00715 {
00716 Q_ASSERT(row < getRows());
00717 Q_ASSERT(getCols() == vector.size());
00718
00719 const int cols = getCols();
00720 for (int col= 0; col < cols; col++)
00721 operator()(row,col) = vector[col];
00722 }
00723
00724 void QVMatrix::setRow(const int row, QVector<double> vector)
00725 {
00726 Q_ASSERT(row < getRows());
00727 Q_ASSERT(getCols() == vector.size());
00728
00729 const int cols = getCols();
00730 for (int col= 0; col < cols; col++)
00731 operator()(row,col) = vector[col];
00732 }
00733
00734 const QVVector QVMatrix::getCol(const int col) const
00735 {
00736 Q_ASSERT(col < getCols());
00737
00738 const int rows = getRows();
00739 QVVector result(rows);
00740 for (int row= 0; row < rows; row++)
00741 result[row] = operator()(row,col);
00742
00743 return result;
00744 }
00745
00746 void QVMatrix::setCol(const int col, QVVector vector)
00747 {
00748 Q_ASSERT(col < getCols());
00749 Q_ASSERT(getRows() == vector.size());
00750
00751 const int rows = getRows();
00752 for (int row= 0; row < rows; row++)
00753 operator()(row,col) = vector[row];
00754 }
00755
00756
00757 const QVVector QVMatrix::diagonal() const
00758 {
00759 Q_ASSERT(getRows() == getCols());
00760 QVVector result(getRows());
00761 for(int i = 0; i < getRows(); i++)
00762 result[i] = operator()(i,i);
00763
00764 return result;
00765 }
00766
00768 const QVMatrix QVMatrix::getSubmatrix(const int firstRow, const int lastRow, const int firstCol, const int lastCol) const
00769 {
00770 Q_ASSERT(firstRow >= 0);
00771 Q_ASSERT(firstCol >= 0);
00772 Q_ASSERT(firstRow <= lastRow);
00773 Q_ASSERT(firstCol <= lastCol);
00774 Q_ASSERT(lastRow < getRows());
00775 Q_ASSERT(lastCol < getCols());
00776
00777 QVMatrix result(lastRow - firstRow +1, lastCol - firstCol +1);
00778
00779 for (int row = firstRow; row <= lastRow; row++)
00780 result.setRow(row-firstRow, getRow(row).mid(firstCol, lastCol - firstCol +1));
00781
00782 return result;
00783 }
00784
00785 void QVMatrix::setSubmatrix(const int row, const int col, const QVMatrix &M)
00786 {
00787 Q_ASSERT(col >= 0);
00788 Q_ASSERT(row >= 0);
00789 Q_ASSERT(M.getCols() + col <= getCols());
00790 Q_ASSERT(M.getRows() + row <= getRows());
00791
00792 for (int r = 0; r < M.getRows(); r++)
00793 for (int c = 0; c < M.getCols(); c++)
00794 operator()(r + row, c + col) = M(r, c);
00795 }
00796
00797 QVMatrix QVMatrix::reversedRows() const
00798 {
00799 int m = getRows(), n = getCols();
00800 QVMatrix result(m,n);
00801
00802 for(int i=0;i<m;i++)
00803 for(int j=0;j<n;j++)
00804 result(i,j) = operator()(m-1-i,j);
00805
00806 return result;
00807 }
00808
00809 QVMatrix QVMatrix::reversedCols() const
00810 {
00811 int m = getRows(), n = getCols();
00812 QVMatrix result(m,n);
00813
00814 for(int i=0;i<m;i++)
00815 for(int j=0;j<n;j++)
00816 result(i,j) = operator()(i,n-1-j);
00817
00818 return result;
00819 }
00820
00822
00823
00824 QVMatrix QVMatrix::identity(const int size)
00825 {
00826 QVMatrix result(size, size);
00827 result.set(0);
00828 for (int i= 0; i < size; i++)
00829 result(i,i) = 1;
00830 return result;
00831 }
00832
00833 QVMatrix QVMatrix::cameraCalibrationMatrix(const double focal, const double aspectRatio, const double cx, const double cy, const double skew)
00834 {
00835 const double dataK[9] = { focal, skew, cx, 0.0, aspectRatio*focal, cy, 0.0, 0.0, 1.0 };
00836 return QVMatrix(3,3, dataK);
00837 }
00838
00839 QVMatrix QVMatrix::zeros(const int rows, const int cols)
00840 {
00841 QVMatrix result(rows, cols);
00842 result.set(0);
00843 return result;
00844 }
00845
00846 QVMatrix QVMatrix::random(const int rows, const int cols)
00847 {
00848 QVMatrix result(rows, cols);
00849 for (int col = 0; col < cols; col++)
00850 for (int row = 0; row < rows; row++)
00851 result(row,col) = (double)ABS(rand()) / (double)RAND_MAX;
00852 return result;
00853 }
00854
00855 QVMatrix QVMatrix::diagonal(const QVVector &diagonalVector)
00856 {
00857 const int size = diagonalVector.size();
00858 QVMatrix result(size, size);
00859 result.set(0);
00860 for (int i= 0; i < size; i++)
00861 result(i,i) = diagonalVector[i];
00862 return result;
00863 }
00864
00865 QVMatrix QVMatrix::rotationMatrix(const double delta)
00866 {
00867
00868 QVMatrix result = QVMatrix::identity(3);
00869
00870 result(0,0) = cos(delta); result(0,1) = sin(delta);
00871 result(1,0) = -sin(delta); result(1,1) = cos(delta);
00872
00873 return result;
00874 }
00875
00876 QVMatrix QVMatrix::rotationMatrix(const QPointF center, const double angle)
00877 {
00878 return QVMatrix::translationMatrix(center.x(), center.y()) * QVMatrix::rotationMatrix(angle) *
00879 QVMatrix::translationMatrix(-center.x(), -center.y());
00880 }
00881
00882 QVMatrix QVMatrix::translationMatrix(const double x, const double y)
00883
00884 {
00885 QVMatrix result = QVMatrix::identity(3);
00886
00887 result(0,2) = x;
00888 result(1,2) = y;
00889
00890 return result;
00891 }
00892
00893 QVMatrix QVMatrix::scaleMatrix(const double zoom)
00894 {
00895 QVMatrix result = QVMatrix::identity(3);
00896
00897 result(0,0) = zoom;
00898 result(1,1) = zoom;
00899
00900 return result;
00901 }
00902
00903 QVMatrix QVMatrix::rotationMatrix3dZAxis(const double angle)
00904 {
00905 QVMatrix result = identity(4);
00906
00907 result(0,0) = cos(angle);
00908 result(0,1) = sin(angle);
00909
00910 result(1,0) = -sin(angle);
00911 result(1,1) = cos(angle);
00912
00913 return result;
00914 }
00915
00916 QVMatrix QVMatrix::rotationMatrix3dXAxis(const double angle)
00917 {
00918 QVMatrix result = identity(4);
00919
00920 result(1,1) = cos(angle);
00921 result(1,2) = sin(angle);
00922
00923 result(2,1) = -sin(angle);
00924 result(2,2) = cos(angle);
00925
00926 return result;
00927 }
00928
00929 QVMatrix QVMatrix::rotationMatrix3dYAxis(const double angle)
00930 {
00931 QVMatrix result = identity(4);
00932
00933 result(0,0) = cos(angle);
00934 result(0,2) = -sin(angle);
00935
00936 result(2,0) = sin(angle);
00937 result(2,2) = cos(angle);
00938
00939 return result;
00940 }
00941
00942 QVMatrix QVMatrix::translationMatrix3d(const double x, const double y, const double z)
00943 {
00944 QVMatrix result = identity(4);
00945
00946 result(0,3) = x;
00947 result(1,3) = y;
00948 result(2,3) = z;
00949
00950 return result;
00951 }
00952
00953 QVVector QVMatrix::meanCol() const
00954 {
00955 QVVector result = getCol(0);
00956 for (int i = 1; i < getCols(); i++)
00957 result += getCol(i);
00958 return result / getCols();
00959 }
00960
00962
00963 std::ostream& operator << ( std::ostream &os, const QVMatrix &matrix )
00964 {
00965 const int cols = matrix.getCols(), rows = matrix.getRows(), precision = os.precision();
00966
00967 os << "QVMatrix (" << rows << ", " << cols << ")" << std::endl;
00968
00969 const double *data = matrix.getReadData();
00970 os << "[" << std::endl;
00971 for (int i=0; i < rows; i++)
00972 {
00973 os << " [ ";
00974 for (int j = 0; j < cols; j++)
00975 {
00976 const double value = data[i*cols + j];
00977 os << qPrintable(QString("%1").arg(value, -(2+precision), 'f', precision)) << " ";
00978 }
00979 os << "]" << std::endl;
00980 }
00981 os << "]" << std::endl;
00982 return os;
00983 }
00984
00985 std::istream& operator >> ( std::istream &is, QVMatrix &matrix )
00986 {
00987 matrix = QVMatrix();
00988
00989 int cols, rows;
00990 double value;
00991
00992 is.ignore(256, '(');
00993 if (is.eof())
00994 return is;
00995
00996 is >> rows;
00997
00998 is.ignore(256, ',');
00999 if (is.eof())
01000 return is;
01001
01002 is >> cols;
01003
01004 is.ignore(256, '[');
01005 if (is.eof())
01006 return is;
01007
01008 QVMatrix maux(rows, cols);
01009
01010 for (int i = 0; i < rows; i++)
01011 {
01012 is.ignore(256, '[');
01013 if (is.eof())
01014 return is;
01015
01016 for (int j = 0; j < cols; j++)
01017 {
01018 is >> value;
01019 maux(i, j) = value;
01020 }
01021 }
01022
01023 matrix = maux;
01024
01025 return is;
01026 }
01027
01028
01029 uint qHash(const QVMatrix &matrix)
01030 {
01031 const int cols = matrix.getCols(), rows = matrix.getRows();
01032
01033 double accum = 0;
01034 for (int i = 0; i < cols; i++)
01035 for (int j = 0; j < rows; j++)
01036 accum += matrix(i,j) / matrix(cols-i-1, rows-j-1);
01037
01038 return (uint) ((100000 * accum) / ((double) (cols + rows)));
01039 }
01040
01041
01042 #include <iostream>
01043 #include <fstream>
01044 #include <iomanip>
01045
01046 bool writeQVMatrixToFile(const QString fileName, const QVMatrix &matrix, const int precission)
01047 {
01048 std::ofstream stream;
01049 stream.open(qPrintable(fileName));
01050
01051 if ( stream.fail() )
01052 return false;
01053
01054 stream << std::setprecision (precission);
01055 stream << matrix;
01056 stream.close();
01057 return true;
01058 }
01059
01060 bool readQVMatrixFromFile(const QString fileName, QVMatrix &matrix)
01061 {
01062 std::ifstream stream;
01063 stream.open(qPrintable(fileName));
01064
01065 if ( stream.fail() )
01066 return false;
01067
01068 stream >> matrix;
01069 stream.close();
01070 return true;
01071 }
01072
01073 QVMatrix operator*(const double value, const QVMatrix &matrix)
01074 {
01075 return matrix.scalarProduct(value);
01076 }
01077
01078 QVMatrix operator+(const double value, const QVMatrix &matrix)
01079 {
01080 return matrix.scalarAdd(value);
01081 }
01082
01083 QVMatrix operator-(const double value, const QVMatrix &matrix)
01084 {
01085 return matrix.scalarSubstract(value);
01086 }
01087
01088
01089 #ifndef DOXYGEN_IGNORE_THIS
01090
01091
01092 void rodrigues_so3_exp(const QV3DPointF &w, const double A, const double B, QVMatrix &R)
01093 {
01094 const double wx2 = w[0]*w[0],
01095 wy2 = w[1]*w[1],
01096 wz2 = w[2]*w[2],
01097 a1 = A*w[2],
01098 a2 = A*w[1],
01099 a3 = A*w[0],
01100 b1 = B*(w[0]*w[1]),
01101 b2 = B*(w[0]*w[2]),
01102 b3 = B*(w[1]*w[2]);
01103
01104 R(0,0) = 1.0 - B*(wy2 + wz2);
01105 R(1,1) = 1.0 - B*(wx2 + wz2);
01106 R(2,2) = 1.0 - B*(wx2 + wy2);
01107 R(0,1) = b1 - a1;
01108 R(1,0) = b1 + a1;
01109 R(0,2) = b2 + a2;
01110 R(2,0) = b2 - a2;
01111 R(1,2) = b3 - a3;
01112 R(2,1) = b3 + a3;
01113 }
01114 #endif // DOXYGEN_IGNORE_THIS
01115
01116
01117 QVMatrix expSO3(const QV3DPointF& w)
01118 {
01119 static const double one_6th = 1.0/6.0, one_20th = 1.0/20.0;
01120 const double theta_sq = w*w,
01121 theta = sqrt(theta_sq),
01122 inv_theta = 1.0/theta;
01123
01124 QVMatrix result(3,3,0.0);
01125 if (theta_sq < 1e-8)
01126 rodrigues_so3_exp(w, 1.0 - one_6th * theta_sq, 0.5, result);
01127 else {
01128 if (theta_sq < 1e-6)
01129 rodrigues_so3_exp(w, 1.0 - theta_sq * one_6th*(1.0 - one_20th * theta_sq),
01130 0.5 - 0.25 * one_6th * theta_sq, result);
01131 else
01132 rodrigues_so3_exp(w, sin(theta) * inv_theta,
01133 (1 - cos(theta)) * (inv_theta * inv_theta),
01134 result);
01135 }
01136 return result;
01137 }
01138
01139
01140
01141 QV3DPointF lnSO3(const QVMatrix &R)
01142 {
01143 QV3DPointF result( (R(2,1)-R(1,2))/2, (R(0,2)-R(2,0))/2, (R(1,0)-R(0,1))/2 );
01144
01145 const double cos_angle = (R(0,0) + R(1,1) + R(2,2) - 1.0) * 0.5;
01146
01147 double sin_angle_abs = result.norm2();
01148 if (cos_angle > M_SQRT1_2)
01149
01150 {
01151 if(sin_angle_abs > 0)
01152 result = result * asin(sin_angle_abs) / sin_angle_abs;
01153 }
01154 else if( cos_angle > -M_SQRT1_2)
01155
01156 result = result * acos(cos_angle) / sin_angle_abs;
01157 else
01158 {
01159
01160 const double d0 = R(0,0) - cos_angle,
01161 d1 = R(1,1) - cos_angle,
01162 d2 = R(2,2) - cos_angle;
01163
01164 const QV3DPointF r2 = (fabs(d0) > fabs(d1) && fabs(d0) > fabs(d2))?
01165
01166 QV3DPointF(d0, (R(1,0)+R(0,1))/2, (R(0,2)+R(2,0))/2):
01167 (fabs(d1) > fabs(d2))?
01168
01169 QV3DPointF((R(1,0)+R(0,1))/2, d1, (R(2,1)+R(1,2))/2):
01170
01171 QV3DPointF((R(0,2)+R(2,0))/2, (R(2,1)+R(1,2))/2, d2);
01172
01173
01174 result = r2 * ((r2 * result < 0)?-1.0:1.0) * (M_PI - asin(sin_angle_abs)) / r2.norm2();
01175 }
01176 return result;
01177 }