// Compute a single eigenvector, which amounts to computing column c // of matrix Q. The reflections and rotations are applied incrementally. // This is useful when you want only a small number of the eigenvectors. public void GetEigenvector(int c, double[] eigenvector) { if (0 <= c && c < mSize) { // y = H*x, then x and y are swapped for the next H double[] x = eigenvector; double[] y = mPVector; // Start with the Euclidean basis vector. Array.Clear(x, 0, mSize); if (mPermutation[c] >= 0) { x[mPermutation[c]] = 1; } else { x[c] = 1; } // Apply the Givens rotations. // [RMS] C# doesn't support reverse iterator so I replaced w/ loop...right? //typename std::vector < GivensRotation >::const_reverse_iterator givens = mGivens.rbegin(); //for (/**/; givens != mGivens.rend(); ++givens) { for (int i = mGivens.Count - 1; i >= 0; --i) { GivensRotation givens = mGivens[i]; double xr = x[givens.index]; double xrp1 = x[givens.index + 1]; double tmp0 = givens.cs * xr + givens.sn * xrp1; double tmp1 = -givens.sn * xr + givens.cs * xrp1; x[givens.index] = tmp0; x[givens.index + 1] = tmp1; } // Apply the Householder reflections. for (int i = mSize - 3; i >= 0; --i) { // Get the Householder vector v. //double const* column = &mMatrix[i]; ArrayAlias <double> column = new ArrayAlias <double>(mMatrix, i); double twoinvvdv = column[mSize * (i + 1)]; int r; for (r = 0; r < i + 1; ++r) { y[r] = x[r]; } // Compute s = Dot(x,v) * 2/v^T*v. double s = x[r]; // r = i+1, v[i+1] = 1 for (int j = r + 1; j < mSize; ++j) { s += x[j] * column[mSize * j]; } s *= twoinvvdv; y[r] = x[r] - s; // v[i+1] = 1 // Compute the remaining components of y. for (++r; r < mSize; ++r) { y[r] = x[r] - s * column[mSize * r]; } //std::swap(x, y); var tmp = x; x = y; y = tmp; } // The final product is stored in x. if (x != eigenvector) { Array.Copy(x, eigenvector, mSize); } } }
// Accumulate the Householder reflections and Givens rotations to produce // the orthogonal matrix Q for which Q^T*A*Q = D. The input // 'eigenvectors' must be NxN and stored in row-major order. public void GetEigenvectors(double[] eigenvectors) { if (eigenvectors != null && mSize > 0) { // Start with the identity matrix. Array.Clear(eigenvectors, 0, mSize * mSize); for (int d = 0; d < mSize; ++d) { eigenvectors[d + mSize * d] = 1; } // Multiply the Householder reflections using backward accumulation. int r, c; for (int i = mSize - 3, rmin = i + 1; i >= 0; --i, --rmin) { // Copy the v vector and 2/Dot(v,v) from the matrix. //double const* column = &mMatrix[i]; ArrayAlias <double> column = new ArrayAlias <double>(mMatrix, i); double twoinvvdv = column[mSize * (i + 1)]; for (r = 0; r < i + 1; ++r) { mVVector[r] = 0; } mVVector[r] = 1; for (++r; r < mSize; ++r) { mVVector[r] = column[mSize * r]; } // Compute the w vector. for (r = 0; r < mSize; ++r) { mWVector[r] = 0; for (c = rmin; c < mSize; ++c) { mWVector[r] += mVVector[c] * eigenvectors[r + mSize * c]; } mWVector[r] *= twoinvvdv; } // Update the matrix, Q <- Q - v*w^T. for (r = rmin; r < mSize; ++r) { for (c = 0; c < mSize; ++c) { eigenvectors[c + mSize * r] -= mVVector[r] * mWVector[c]; } } } // Multiply the Givens rotations. foreach (GivensRotation givens in mGivens) { for (r = 0; r < mSize; ++r) { int j = givens.index + mSize * r; double q0 = eigenvectors[j]; double q1 = eigenvectors[j + 1]; double prd0 = givens.cs * q0 - givens.sn * q1; double prd1 = givens.sn * q0 + givens.cs * q1; eigenvectors[j] = prd0; eigenvectors[j + 1] = prd1; } } mIsRotation = 1 - (mSize & 1); if (mPermutation[0] >= 0) { // Sorting was requested. Array.Clear(mVisited, 0, mVisited.Length); for (int i = 0; i < mSize; ++i) { if (mVisited[i] == 0 && mPermutation[i] != i) { // The item starts a cycle with 2 or more elements. mIsRotation = 1 - mIsRotation; int start = i, current = i, j, next; for (j = 0; j < mSize; ++j) { mPVector[j] = eigenvectors[i + mSize * j]; } while ((next = mPermutation[current]) != start) { mVisited[current] = 1; for (j = 0; j < mSize; ++j) { eigenvectors[current + mSize * j] = eigenvectors[next + mSize * j]; } current = next; } mVisited[current] = 1; for (j = 0; j < mSize; ++j) { eigenvectors[current + mSize * j] = mPVector[j]; } } } } } }