Package mikera.matrixx.solve.impl.qr

Source Code of mikera.matrixx.solve.impl.qr.QRHouseColSolver

/*
* Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package mikera.matrixx.solve.impl.qr;

import mikera.matrixx.AMatrix;
import mikera.matrixx.Matrix;
import mikera.matrixx.decompose.impl.qr.HouseholderColQR;
import mikera.matrixx.decompose.impl.qr.QRHelperFunctions;
import mikera.matrixx.decompose.impl.qr.QRResult;

/**
* <p>
* QR decomposition can be used to solve for systems.  However, this is not as computationally efficient
* as LU decomposition and costs about 3n<sup>2</sup> flops.
* </p>
* <p>
* It solve for x by first multiplying b by the transpose of Q then solving for the result.
* <br>
* QRx=b<br>
* Rx=Q^T b<br>
* </p>
*
* <p>
* A column major decomposition is used in this solver.
* <p>
*
* @author Peter Abeles
*/
public class QRHouseColSolver {
   
    protected AMatrix A;
    protected int numRows;
    protected int numCols;

    public AMatrix getA() {
        return A;
    }

    protected void _setA(AMatrix A) {
        this.A = A;
        this.numRows = A.rowCount();
        this.numCols = A.columnCount();
    }

    private HouseholderColQR decomposer;

    private Matrix a;
    private Matrix temp;

    protected int maxRows = -1;
    protected int maxCols = -1;

    private double[][] QR; // a column major QR matrix
    private Matrix R;
    private double gammas[];
   
    private QRResult result;

    /**
     * Creates a linear solver that uses QR decomposition.
     */
    public QRHouseColSolver() {
        decomposer = new HouseholderColQR(true);
    }

    public void setMaxSize( int maxRows , int maxCols )
    {
        this.maxRows = maxRows; this.maxCols = maxCols;
    }

    /**
     * Performs QR decomposition on A
     *
     * @param A not modified.
     */
    public boolean setA(AMatrix A) {
        if( A.rowCount() > maxRows || A.columnCount() > maxCols )
            setMaxSize(A.rowCount(),A.columnCount());

        a = Matrix.create(A.rowCount(),1);
        temp = Matrix.create(A.rowCount(),1);

        _setA(A);
        result = decomposer.decompose(A);
        if( result == null )
            return false;

        gammas = decomposer.getGammas();
        QR = decomposer.getQR();
        R = result.getR().toMatrix();
        return true;
    }

    public double quality() {
        return qualityTriangular(true, R);
    }

    /**
     * Solves for X using the QR decomposition.
     *
     * @param B A matrix that is n by m.  Not modified.
     */
    public AMatrix solve(AMatrix B) {
        if( B.rowCount() != numRows)
            throw new IllegalArgumentException("Unexpected dimensions for B");
        Matrix X = Matrix.create(numCols, B.columnCount());

        int BnumCols = B.columnCount();
       
        // solve each column one by one
        for( int colB = 0; colB < BnumCols; colB++ ) {

            // make a copy of this column in the vector
            for( int i = 0; i < numRows; i++ ) {
//                a.data[i] = B.data[i*BnumCols + colB];
                a.data[i] = B.unsafeGet(i, colB);
            }


            // Solve Qa=b
            // a = Q'b
            // a = Q_{n-1}...Q_2*Q_1*b
            //
            // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b)
           
            for( int n = 0; n < numCols; n++ ) {
                double []u = QR[n];

                double vv = u[n];
                u[n] = 1;
                QRHelperFunctions.rank1UpdateMultR(a, u, gammas[n], 0, n, numRows, temp.data);
                u[n] = vv;
            }
            // solve for Rx = b using the standard upper triangular solver
            solveU(R.asDoubleArray(),a.asDoubleArray(),numCols);

            // save the results
            double[]data = X.asDoubleArray();
            for( int i = 0; i < numCols; i++ ) {
//                X.data[i*X.columnCount()+colB] = a.data[i];
                data[i*X.columnCount()+colB] = a.data[i];
            }
        }
        return X;
    }
   
    /**
     * <p>
     * This is a forward substitution solver for non-singular upper triangular matrices.
     * <br>
     * b = U<sup>-1</sup>b<br>
     * <br>
     * where b is a vector, U is an n by n matrix.<br>
     * </p>
     *
     * @param U An n by n non-singular upper triangular matrix. Not modified.
     * @param b A vector of length n. Modified.
     * @param n The size of the matrices.
     */
    private void solveU( double U[] , double []b , int n )
    {
        for( int i =n-1; i>=0; i-- ) {
            double sum = b[i];
            int indexU = i*n+i+1;
            for( int j = i+1; j <n; j++ ) {
                sum -= U[indexU++]* b[j];
            }
            b[i] = sum/U[i*n+i];
        }
    }
   
    /**
     * Computes the quality of a triangular matrix.  In
     * this situation the quality is the absolute value of the product of
     * each diagonal element divided by the magnitude of the largest diagonal element.
     * If all diagonal elements are zero then zero is returned.
     *
     * @param upper if it is upper triangular or not.
     * @param T A matrix.  @return product of the diagonal elements.
     * @return the quality of the system.
     */
    public static double qualityTriangular(boolean upper, AMatrix T)
    {
        int N = Math.min(T.rowCount(),T.columnCount());

        // TODO make faster by just checking the upper triangular portion
        double max = T.absCopy().elementMax();

        if( max == 0.0d )
            return 0.0d;

        double quality = 1.0;
        for( int i = 0; i < N; i++ ) {
            quality *= T.unsafeGet(i,i)/max;
        }

        return Math.abs(quality);
    }
}
TOP

Related Classes of mikera.matrixx.solve.impl.qr.QRHouseColSolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.