All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ejml.dense.row.decomposition.eig.symm.SymmetricQrAlgorithm_DDRM Maven / Gradle / Ivy

/*
 * Copyright (c) 2009-2017, 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 org.ejml.dense.row.decomposition.eig.symm;

import org.ejml.data.DMatrixRMaj;
import org.ejml.dense.row.CommonOps_DDRM;


/**
 * 

* Computes the eigenvalues and eigenvectors of a symmetric tridiagonal matrix using the symmetric QR algorithm. *

*

* This implementation is based on the algorithm is sketched out in:
* David S. Watkins, "Fundamentals of Matrix Computations," Second Edition. page 377-385 *

* @author Peter Abeles */ public class SymmetricQrAlgorithm_DDRM { // performs many of the low level calculations private SymmetricQREigenHelper_DDRM helper; // transpose of the orthogonal matrix private DMatrixRMaj Q; // the eigenvalues previously computed private double eigenvalues[]; private int exceptionalThresh = 15; private int maxIterations = exceptionalThresh*15; // should it ever analytically compute eigenvalues // if this is true then it can't compute eigenvalues at the same time private boolean fastEigenvalues; // is it following a script or not private boolean followingScript; public SymmetricQrAlgorithm_DDRM(SymmetricQREigenHelper_DDRM helper ) { this.helper = helper; } /** * Creates a new SymmetricQREigenvalue class that declares its own SymmetricQREigenHelper. */ public SymmetricQrAlgorithm_DDRM() { this.helper = new SymmetricQREigenHelper_DDRM(); } public void setMaxIterations(int maxIterations) { this.maxIterations = maxIterations; } public DMatrixRMaj getQ() { return Q; } public void setQ(DMatrixRMaj q) { Q = q; } public void setFastEigenvalues(boolean fastEigenvalues) { this.fastEigenvalues = fastEigenvalues; } /** * Returns the eigenvalue at the specified index. * * @param index Which eigenvalue. * @return The eigenvalue. */ public double getEigenvalue( int index ) { return helper.diag[index]; } /** * Returns the number of eigenvalues available. * * @return How many eigenvalues there are. */ public int getNumberOfEigenvalues() { return helper.N; } /** * Computes the eigenvalue of the provided tridiagonal matrix. Note that only the upper portion * needs to be tridiagonal. The bottom diagonal is assumed to be the same as the top. * * @param sideLength Number of rows and columns in the input matrix. * @param diag Diagonal elements from tridiagonal matrix. Modified. * @param off Off diagonal elements from tridiagonal matrix. Modified. * @return true if it succeeds and false if it fails. */ public boolean process( int sideLength, double diag[] , double off[] , double eigenvalues[] ) { if( diag != null ) helper.init(diag,off,sideLength); if( Q == null ) Q = CommonOps_DDRM.identity(helper.N); helper.setQ(Q); this.followingScript = true; this.eigenvalues = eigenvalues; this.fastEigenvalues = false; return _process(); } public boolean process( int sideLength, double diag[] , double off[] ) { if( diag != null ) helper.init(diag,off,sideLength); this.followingScript = false; this.eigenvalues = null; return _process(); } private boolean _process() { while( helper.x2 >= 0 ) { // if it has cycled too many times give up if( helper.steps > maxIterations ) { return false; } if( helper.x1 == helper.x2 ) { // System.out.println("Steps = "+helper.steps); // see if it is done processing this submatrix helper.resetSteps(); if( !helper.nextSplit() ) break; } else if( fastEigenvalues && helper.x2-helper.x1 == 1 ) { // There are analytical solutions to this case. Just compute them directly. // TODO might be able to speed this up by doing the 3 by 3 case also helper.resetSteps(); helper.eigenvalue2by2(helper.x1); helper.setSubmatrix(helper.x2,helper.x2); } else if( helper.steps-helper.lastExceptional > exceptionalThresh ){ // it isn't a good sign if exceptional shifts are being done here helper.exceptionalShift(); } else { performStep(); } helper.incrementSteps(); // helper.printMatrix(); } // helper.printMatrix(); return true; } /** * First looks for zeros and then performs the implicit single step in the QR Algorithm. */ public void performStep() { // check for zeros for( int i = helper.x2-1; i >= helper.x1; i-- ) { if( helper.isZero(i) ) { helper.splits[helper.numSplits++] = i; helper.x1 = i+1; return; } } double lambda; if( followingScript ) { if( helper.steps > 10 ) { followingScript = false; return; } else { // Using the true eigenvalues will in general lead to the fastest convergence // typically takes 1 or 2 steps lambda = eigenvalues[helper.x2]; } } else { // the current eigenvalue isn't working so try something else lambda = helper.computeShift(); } // similar transforms helper.performImplicitSingleStep(lambda,false); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy