Thanks, Greg, for looking more at this.  Apologies I've not been able to
focus on this too much recently.

Yes, the approach above works, however the solvers also require a change so
that they don't unexpectedly solve for a permuted matrix.  Additionally, a
getRank() method can now be implemented much more efficiently than the
getRank() from SingularValueDecomposition.

I submitted an initial patch at *********** with these bits working, however
this patch introduces a new RRQRDecomposition interface extending
QRDecomposition.  In light of the insights above from the team, I'll
implement it instead within the existing class structure and re-submit.

If the pivoting code is to be included in QRDecomposition, then perhaps an
extra constructor is required to perform column pivoting since the RRQR
decomposition of matrix A produces Q, R and P such A = QRP^T and would break
any existing code that expects a plain decomposition of A=QR.

Chris.

On 6 August 2011 21:34, Greg Sterijevski <gsterijev...@gmail.com> wrote:

> Hello All,
>
> Not sure if this is stepping on toes, but here is what I thought of to deal
> with pivoting. I would only need to modify the constructor of the
> QRDecompImpl class:
>
>  public QRDecompositionPivotImpl(RealMatrix matrix) {
>
>        final int m = matrix.getRowDimension();
>        final int n = matrix.getColumnDimension();
>        final int mn = FastMath.min(m, n);
>
>        qrt = matrix.transpose().getData();
>        rDiag = new double[FastMath.min(m, n)];
>        cachedQ = null;
>        cachedQT = null;
>        cachedR = null;
>        cachedH = null;
>
>
>        /*
>         * The QR decomposition of a matrix A is calculated using
> Householder
>         * reflectors by repeating the following operations to each minor
>         * A(minor,minor) of A:
>         */
>
>        pivots = new int[n];
>        for (int i = 0; i < n; i++) {
>            pivots[i] = i;
>        }
>
>        int pivotIdx = -1;
>        double bestNorm = 0.0;
>        for (int minor = 0; minor < mn; minor++) {
>            bestNorm = 0.0;
>            pivotIdx = 0;
>            for (int i = minor; i < n; i++) {
>                final double[] qrtMinor = qrt[i];
>                double xNormSqr = 0.0;
>                for (int row = minor; row < m; row++) {
>                    final double c = qrtMinor[row];
>                    xNormSqr += c * c;
>                }
>                if (xNormSqr > bestNorm) {
>                    bestNorm = xNormSqr;
>                    pivotIdx = i;
>                }
>            }
>
>
>            if( pivotIdx != minor){
>                int pvt = pivots[minor];
>                pivots[minor] = pivots[pivotIdx];
>                double[] qswp = qrt[minor];
>                qrt[minor] = qrt[pivotIdx];
>                for( int i = minor + 1; i < n; i++){
>                    if( i <= pivotIdx ){
>                        final int itmp = pivots[i];
>                        pivots[i] = pvt;
>                        pvt = itmp;
>                        final double[] tmp = qrt[i];
>                        qrt[i] = qswp;
>                        qswp=tmp;
>                    }
>                }
>            }
>
>            final double[] qrtMinor = qrt[minor];
>            /*
>             * Let x be the first column of the minor, and a^2 = |x|^2.
>             * x will be in the positions qr[minor][minor] through
> qr[m][minor].
>             * The first column of the transformed minor will be (a,0,0,..)'
>             * The sign of a is chosen to be opposite to the sign of the
> first
>             * component of x. Let's find a:
>             */
>            final double a = (qrtMinor[minor] > 0) ?
> -FastMath.sqrt(bestNorm) : FastMath.sqrt(bestNorm);
>            rDiag[minor] = a;
>
>            if (a != 0.0) {
>
>                /*
>                 * Calculate the normalized reflection vector v and
> transform
>                 * the first column. We know the norm of v beforehand: v =
> x-ae
>                 * so |v|^2 = <x-ae,x-ae> = <x,x>-2a<x,e>+a^2<e,e> =
>                 * a^2+a^2-2a<x,e> = 2a*(a - <x,e>).
>                 * Here <x, e> is now qr[minor][minor].
>                 * v = x-ae is stored in the column at qr:
>                 */
>                qrtMinor[minor] -= a; // now |v|^2 = -2a*(qr[minor][minor])
>
>                /*
>                 * Transform the rest of the columns of the minor:
>                 * They will be transformed by the matrix H = I-2vv'/|v|^2.
>                 * If x is a column vector of the minor, then
>                 * Hx = (I-2vv'/|v|^2)x = x-2vv'x/|v|^2 = x - 2<x,v>/|v|^2
> v.
>                 * Therefore the transformation is easily calculated by
>                 * subtracting the column vector (2<x,v>/|v|^2)v from x.
>                 *
>                 * Let 2<x,v>/|v|^2 = alpha. From above we have
>                 * |v|^2 = -2a*(qr[minor][minor]), so
>                 * alpha = -<x,v>/(a*qr[minor][minor])
>                 */
>                for (int col = minor + 1; col < n; col++) {
>                    final double[] qrtCol = qrt[col];
>                    double alpha = 0;
>                    for (int row = minor; row < m; row++) {
>                        alpha -= qrtCol[row] * qrtMinor[row];
>                    }
>                    alpha /= a * qrtMinor[minor];
>
>                    // Subtract the column vector alpha*v from x.
>                    for (int row = minor; row < m; row++) {
>                        qrtCol[row] -= alpha * qrtMinor[row];
>                    }
>                }
>            }
>        }
>    }
>
>
> All I am doing is looking forward and taking the next column with the
> largest norm. Then I rearrange the Q's. Is this what you had in mind Chris?
> The result will be Q,R and the pivot array for which we can implement a
> getter?
>
> -Greg
>

Reply via email to