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

org.ejml.alg.dense.linsol.svd.SolvePseudoInverseSvd Maven / Gradle / Ivy

Go to download

A fast and easy to use dense matrix linear algebra library written in Java.

There is a newer version: 0.25
Show newest version
/*
 * Copyright (c) 2009-2012, Peter Abeles. All Rights Reserved.
 *
 * This file is part of Efficient Java Matrix Library (EJML).
 *
 * EJML is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * EJML is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EJML.  If not, see .
 */

package org.ejml.alg.dense.linsol.svd;

import org.ejml.UtilEjml;
import org.ejml.data.DenseMatrix64F;
import org.ejml.factory.DecompositionFactory;
import org.ejml.factory.LinearSolver;
import org.ejml.factory.SingularValueDecomposition;
import org.ejml.ops.CommonOps;


/**
 * 

* 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 implements LinearSolver { // Used to compute pseudo inverse private SingularValueDecomposition svd; // the results of the pseudo-inverse private DenseMatrix64F pinv = new DenseMatrix64F(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(int maxRows, int maxCols) { svd = DecompositionFactory.svd(maxRows,maxCols,true,true,true); } /** * Creates a solver targeted at matrices around 100x100 */ public SolvePseudoInverseSvd() { this(100,100); } @Override public boolean setA(DenseMatrix64F A) { pinv.reshape(A.numCols,A.numRows,false); if( !svd.decompose(A) ) return false; DenseMatrix64F U_t = svd.getU(null,true); DenseMatrix64F V = svd.getV(null,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 = UtilEjml.EPS*Math.max(A.numCols,A.numRows)*maxSingular; // computer the pseudo inverse of A 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.mult(V,U_t, pinv); return true; } @Override public double quality() { throw new IllegalArgumentException("Not supported by this solver."); } @Override public void solve( DenseMatrix64F b, DenseMatrix64F x) { CommonOps.mult(pinv,b,x); } @Override public void invert(DenseMatrix64F A_inv) { A_inv.set(pinv); } @Override public boolean modifiesA() { return svd.inputModified(); } @Override public boolean modifiesB() { return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy