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

org.ejml.dense.row.linsol.svd.SolvePseudoInverseSvd_DDRM Maven / Gradle / Ivy

/*
 * Copyright (c) 2009-2018, 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.linsol.svd;

import org.ejml.UtilEjml;
import org.ejml.data.DMatrixRMaj;
import org.ejml.dense.row.CommonOps_DDRM;
import org.ejml.dense.row.factory.DecompositionFactory_DDRM;
import org.ejml.interfaces.decomposition.SingularValueDecomposition;
import org.ejml.interfaces.decomposition.SingularValueDecomposition_F64;
import org.ejml.interfaces.linsol.LinearSolverDense;


/**
 * 

* The pseudo-inverse is typically used to solve over determined system for which there is no unique solution.
* x=inv(ATA)ATb
* where A ∈ ℜ m × n and m ≥ n. *

* *

* This class implements the Moore-Penrose pseudo-inverse using SVD and should never fail. Alternative implementations * can use Cholesky decomposition, but those will fail if the ATA matrix is singular. * However the Cholesky implementation is much faster. *

* * @author Peter Abeles */ public class SolvePseudoInverseSvd_DDRM implements LinearSolverDense { // Used to compute pseudo inverse private SingularValueDecomposition_F64 svd; // the results of the pseudo-inverse private DMatrixRMaj pinv = new DMatrixRMaj(1,1); // relative threshold used to select singular values private double threshold = UtilEjml.EPS; // Internal workspace private DMatrixRMaj U_t=new DMatrixRMaj(1,1),V=new DMatrixRMaj(1,1); /** * Creates a new solver targeted at the specified matrix size. * * @param maxRows The expected largest matrix it might have to process. Can be larger. * @param maxCols The expected largest matrix it might have to process. Can be larger. */ public SolvePseudoInverseSvd_DDRM(int maxRows, int maxCols) { svd = DecompositionFactory_DDRM.svd(maxRows,maxCols,true,true,true); } /** * Creates a solver targeted at matrices around 100x100 */ public SolvePseudoInverseSvd_DDRM() { this(100,100); } @Override public boolean setA(DMatrixRMaj A) { pinv.reshape(A.numCols,A.numRows,false); if( !svd.decompose(A) ) return false; svd.getU(U_t,true); svd.getV(V,false); double []S = svd.getSingularValues(); int N = Math.min(A.numRows,A.numCols); // compute the threshold for singular values which are to be zeroed double maxSingular = 0; for( int i = 0; i < N; i++ ) { if( S[i] > maxSingular ) maxSingular = S[i]; } double tau = threshold*Math.max(A.numCols,A.numRows)*maxSingular; // computer the pseudo inverse of A if( maxSingular != 0.0 ) { for (int i = 0; i < N; i++) { double s = S[i]; if (s < tau) S[i] = 0; else S[i] = 1.0 / S[i]; } } // V*W for( int i = 0; i < V.numRows; i++ ) { int index = i*V.numCols; for( int j = 0; j < V.numCols; j++ ) { V.data[index++] *= S[j]; } } // V*W*U^T CommonOps_DDRM.mult(V,U_t, pinv); return true; } @Override public /**/double quality() { double []S = svd.getSingularValues(); int N = Math.min(pinv.numRows,pinv.numCols); double min = S[0]; double max = min; for (int i = 0; i < N; i++) { min = Math.min(min,S[i]); max = Math.max(max,S[i]); } return min/max; } @Override public void solve(DMatrixRMaj b, DMatrixRMaj x) { CommonOps_DDRM.mult(pinv,b,x); } @Override public void invert(DMatrixRMaj A_inv) { A_inv.set(pinv); } @Override public boolean modifiesA() { return svd.inputModified(); } @Override public boolean modifiesB() { return false; } @Override public SingularValueDecomposition_F64 getDecomposition() { return svd; } /** * Specify the relative threshold used to select singular values. By default it's UtilEjml.EPS. * @param threshold The singular value threshold */ public void setThreshold(double threshold) { this.threshold = threshold; } public SingularValueDecomposition getDecomposer() { return svd; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy