[eigen] [RFC] Test helper to make a matrix with exact rank. |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen <eigen@xxxxxxxxxxxxxxxxxxx>
- Subject: [eigen] [RFC] Test helper to make a matrix with exact rank.
- From: Keir Mierle <mierle@xxxxxxxxx>
- Date: Sun, 1 Feb 2009 20:13:45 -0800
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:date:message-id:subject :from:to:content-type; bh=2WL5BspWgvHN3cuQWJOn2RxunuoVe6QOTh/jg0tBR94=; b=jX7xJ5pcIHLq1ob5P3IH56VWizrtd+/uWjav8rSRAIyDjB25Om43103upKOahUB3Jp 3G2vH4VRhTYyf4dJ+W/D15d/BklE/JGjBGIxtuJLO8EEHcgeXHet1iGxh3SPtZZP5O/l 45haj92d5KJbg3B4VEVoB9XnshrrRmxAGOUVM=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=RDjPML5c2QfnA+bMSIxIcHt/7wJAPa0R1iMzcBkhJDsfvZO6Ij21lKtQCw/cKTV1B9 c6Hgs57G9nhsb98+jUbyD38geYOkOlWgSg7TnVrj8C3za3FhBLaMs81zcH/f3T5Dc2U8 5PuRB9Qx/mruLQmd+qQgcoGb2rfW80swY94dM=
Here's a test routine to make a matrix with exact size and rank. It uses the SVD though, so may be too slow, and doesn't work on complex matrices (because SVD doesn't). Nevertheless, it is probably better than the current method of generating random matrices when it applies because the matrix will have excellent conditioning (i.e. the singular values will be 1, 1, 1, 1 ... (up to rank), 0, 0, 0, 0, 0).
It works by making a random (tall) matrix of the desired size, then setting the first 'rank' singular values to 1.0, and the remaining singular values to zero. Then the matrix is reconstituted by multiplying it back together, creating a matrix with the desired rows, columns, and rank.
Comments?
Keir
#include <Eigen/Core>
#include <Eigen/Cholesky>
#include <Eigen/LU>
#include <Eigen/QR>
#include <Eigen/SVD>
#include <Eigen/Array>
using namespace Eigen;
using namespace std;
// Make a well-conditioned matrix with precise rank. Must have rank <= cols <=
// rows. Takes a rows * cols SVD; this routine is not fast.
template<typename TMatrix>
void makeTallMatrix(int rows, int cols, int rank, TMatrix *matrix) {
typedef typename TMatrix::Scalar Scalar;
matrix->resize(rows, cols);
matrix->setRandom();
SVD<TMatrix> svd(*matrix);
Matrix<Scalar, Dynamic, 1> s = svd.singularValues();
int maxrank = std::min(rows, cols);
assert(rank <= maxrank);
for (int i = 0; i < rank; ++i) s(i) = 1.0;
for (int i = rank; i < maxrank; ++i) s(i) = 0.0;
Matrix<Scalar, Dynamic, Dynamic> S(maxrank, maxrank);
S.fill(0);
S.block(0, 0, maxrank, maxrank).diagonal() = s;
*matrix = svd.matrixU() * S * svd.matrixV().transpose();
}
template<typename TMatrix>
void makeMatrix(int rows, int cols, int rank, TMatrix *matrix) {
if (rows < cols) {
// Unfortunately a copy is necessary.
TMatrix transposed = matrix->transpose();
makeTallMatrix(cols, rows, rank, &transposed);
*matrix = transposed.transpose();
} else {
makeTallMatrix(rows, cols, rank, matrix);
}
}
template<typename TMatrix>
void makeMatrixWithRandomRank(TMatrix *matrix) {
int rows = ei_random<int>(10,200);
int cols = ei_random<int>(10,200);
int rank = ei_random<int>(1, std::min(rows, cols));
makeMatrix(rows, cols, rank, matrix);
}
int main() {
MatrixXd m;
makeMatrix(6, 4, 3, &m); cout << "m: \n" << m << endl;
makeMatrix(23, 20, 6, &m); cout << "rank: " << m.lu().rank() << endl;
makeMatrix(23, 20, 2, &m); cout << "rank: " << m.lu().rank() << endl;
makeMatrix(20, 20, 11, &m); cout << "rank: " << m.lu().rank() << endl;
makeMatrix(20, 23, 5, &m); cout << "rank: " << m.lu().rank() << endl;
MatrixXf M;
makeMatrix(23, 20, 6, &M); cout << "rank: " << M.lu().rank() << endl;
makeMatrix(23, 20, 2, &M); cout << "rank: " << M.lu().rank() << endl;
makeMatrix(20, 20, 11, &M); cout << "rank: " << M.lu().rank() << endl;
makeMatrix(20, 23, 5, &M); cout << "rank: " << M.lu().rank() << endl;
makeMatrixWithRandomRank(&M); cout << "rank: " << M.lu().rank() << " rows: " << M.rows() << " cols: " << M.cols() << endl;
/*
* Fails; SVD doesn't work for complex.
MatrixXcf C;
makeMatrix(23, 20, 6, &C); cout << "rank: " << C.lu().rank() << endl;
makeMatrix(23, 20, 2, &C); cout << "rank: " << C.lu().rank() << endl;
makeMatrix(20, 20, 11, &C); cout << "rank: " << C.lu().rank() << endl;
makeMatrix(20, 23, 5, &C); cout << "rank: " << C.lu().rank() << endl;
*/
}