![JAR search and dependency download from the Maven repository](/logo.png)
org.ojalgo.matrix.decomposition.SingularValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ojalgo Show documentation
Show all versions of ojalgo Show documentation
oj! Algorithms - ojAlgo - is Open Source Java code that has to do with mathematics, linear algebra and optimisation.
/*
* Copyright 1997-2021 Optimatika
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.ojalgo.matrix.decomposition;
import org.ojalgo.ProgrammingError;
import org.ojalgo.array.Array1D;
import org.ojalgo.array.DenseArray;
import org.ojalgo.matrix.store.MatrixStore;
import org.ojalgo.scalar.ComplexNumber;
import org.ojalgo.scalar.Quaternion;
import org.ojalgo.scalar.RationalNumber;
import org.ojalgo.structure.Access2D;
import org.ojalgo.structure.Structure2D;
import org.ojalgo.type.context.NumberContext;
/**
* Singular Value: [A] = [U][D][V]T Decomposes [this] into [U], [D] and [V] where:
*
* - [U] is an orthogonal matrix. The columns are the left, orthonormal, singular vectors of [this]. Its
* columns are the eigenvectors of [A][A]T, and therefore has the same number of rows as [this].
*
* - [D] is a diagonal matrix. The elements on the diagonal are the singular values of [this]. It is either
* square or has the same dimensions as [this]. The singular values of [this] are the square roots of the
* nonzero eigenvalues of [A][A]T and [A]T[A] (they are the same)
* - [V] is an orthogonal matrix. The columns are the right, orthonormal, singular vectors of [this]. Its
* columns are the eigenvectors of [A][A]T, and therefore has the same number of rows as [this] has
* columns.
* - [this] = [U][D][V]T
*
* A singular values decomposition always exists.
*
* @author apete
*/
public interface SingularValue> extends MatrixDecomposition, MatrixDecomposition.Solver, MatrixDecomposition.EconomySize,
MatrixDecomposition.RankRevealing, MatrixDecomposition.Values {
interface Factory> extends MatrixDecomposition.Factory> {
default SingularValue make(final boolean fullSize) {
return this.make(TYPICAL, fullSize);
}
default SingularValue make(final Structure2D typical) {
return this.make(typical, false);
}
SingularValue make(Structure2D typical, boolean fullSize);
}
Factory COMPLEX = (typical, fullSize) -> new SingularValueDecomposition.Complex(fullSize);
Factory PRIMITIVE = (typical, fullSize) -> {
if (fullSize || ((1024L < typical.countColumns()) && (typical.count() <= DenseArray.MAX_ARRAY_SIZE))) {
return new SingularValueDecomposition.Primitive(fullSize);
} else {
return new RawSingularValue();
}
};
Factory QUATERNION = (typical, fullSize) -> new SingularValueDecomposition.Quat(fullSize);
Factory RATIONAL = (typical, fullSize) -> new SingularValueDecomposition.Rational(fullSize);
static > boolean equals(final MatrixStore matrix, final SingularValue decomposition, final NumberContext context) {
final int tmpRowDim = (int) matrix.countRows();
final int tmpColDim = (int) matrix.countColumns();
final MatrixStore tmpQ1 = decomposition.getU();
final MatrixStore tmpD = decomposition.getD();
final MatrixStore tmpQ2 = decomposition.getV();
MatrixStore tmpThis;
MatrixStore tmpThat;
boolean retVal = (tmpRowDim == tmpQ1.countRows()) && (tmpQ2.countRows() == tmpColDim);
// Check that [A][V] == [U][D]
if (retVal) {
tmpThis = matrix.multiply(tmpQ2);
tmpThat = tmpQ1.multiply(tmpD);
retVal &= tmpThis.equals(tmpThat, context);
}
// If Q1 is square, then check if it is orthogonal/unitary.
if (retVal && (tmpQ1.countRows() == tmpQ1.countColumns())) {
tmpThis = tmpQ1.physical().makeEye(tmpRowDim, tmpRowDim);
tmpThat = tmpQ1.conjugate().multiply(tmpQ1);
retVal &= tmpThis.equals(tmpThat, context);
}
// If Q2 is square, then check if it is orthogonal/unitary.
if (retVal && (tmpQ2.countRows() == tmpQ2.countColumns())) {
tmpThis = tmpQ2.physical().makeEye(tmpColDim, tmpColDim);
tmpThat = tmpQ2.multiply(tmpQ2.conjugate());
retVal &= tmpThis.equals(tmpThat, context);
}
// Check the pseudoinverse.
if (retVal) {
final MatrixStore inverse = decomposition.getInverse();
final MatrixStore multiplied = matrix.multiply(inverse.multiply(matrix));
retVal &= matrix.equals(multiplied, context);
}
// Check that the singular values are sorted in descending order
if (retVal) {
final Array1D tmpSV = decomposition.getSingularValues();
for (int i = 1; retVal && (i < tmpSV.size()); i++) {
retVal &= tmpSV.doubleValue(i - 1) >= tmpSV.doubleValue(i);
}
if (retVal && decomposition.isOrdered()) {
for (int ij = 1; retVal && (ij < tmpD.countRows()); ij++) {
retVal &= tmpD.doubleValue(ij - 1, ij - 1) >= tmpD.doubleValue(ij, ij);
}
}
}
return retVal;
}
/**
* @deprecated v48 Use {link #COMPLEX}, {@link #PRIMITIVE}. {@link #QUATERNION} or {@link #RATIONAL}
* innstead.
*/
@Deprecated
@SuppressWarnings("unchecked")
static > SingularValue make(final Access2D typical) {
final N tmpNumber = typical.get(0, 0);
if (tmpNumber instanceof RationalNumber) {
return (SingularValue) RATIONAL.make(typical);
} else if (tmpNumber instanceof ComplexNumber) {
return (SingularValue) COMPLEX.make(typical);
} else if (tmpNumber instanceof Double) {
return (SingularValue) PRIMITIVE.make(typical);
} else if (tmpNumber instanceof Quaternion) {
return (SingularValue) QUATERNION.make(typical);
} else {
throw new IllegalArgumentException();
}
}
/**
* @deprecated v48 Use {@link #reconstruct()} instead
*/
@Deprecated
static > MatrixStore reconstruct(final SingularValue decomposition) {
return decomposition.reconstruct();
}
/**
* The condition number.
*
* @return The largest singular value divided by the smallest singular value.
*/
double getCondition();
/**
* @return [[A]T[A]]-1 Where [A] is the original matrix.
*/
MatrixStore getCovariance();
/**
* @return The diagonal matrix of singular values.
*/
MatrixStore getD();
/**
* Sometimes also called the Schatten 2-norm or Hilbert-Schmidt norm.
*
* @return The square root of the sum of squares of the singular values.
*/
double getFrobeniusNorm();
/**
*
* Ky Fan k-norm.
*
*
* The first Ky Fan k-norm is the operator norm (the largest singular value), and the last is called the
* trace norm (the sum of all singular values).
*
*
* @param k The number of singular values to add up.
* @return The sum of the k largest singular values.
*/
double getKyFanNorm(int k);
/**
* @return 2-norm
*/
double getOperatorNorm();
/**
* @deprecated v48 Use {@link #getU()} instead
*/
@Deprecated
default MatrixStore getQ1() {
return this.getU();
}
/**
* @deprecated v48 Use {@link #getV()} instead
*/
@Deprecated
default MatrixStore getQ2() {
return this.getV();
}
/**
* @return The singular values ordered in descending order.
*/
Array1D getSingularValues();
/**
* @param values An array that will receive the singular values
*/
default void getSingularValues(final double[] values) {
ProgrammingError.throwIfNull(values);
final Array1D singulars = this.getSingularValues();
final int length = values.length;
for (int i = 0; i < length; i++) {
values[i] = singulars.doubleValue(i);
}
}
double getTraceNorm();
/**
* If [A] is m-by-n and its rank is r, then:
*
* - The first r columns of [U] span the column space, range or image of [A].
* - The last m-r columns of [U] span the left nullspace or cokernel of [A].
*
* Calculating the QR decomposition of [A] is a faster alternative.
*/
MatrixStore getU();
/**
* If [A] is m-by-n and its rank is r, then:
*
* - The first r columns of [V] span the row space or coimage of [A].
* - The last n-r columns of [V] span the nullspace or kernel of [A].
*
* Calculating the QR decomposition of [A]T is a faster alternative.
*/
MatrixStore getV();
default MatrixStore reconstruct() {
MatrixStore mtrxQ1 = this.getU();
MatrixStore mtrxD = this.getD();
MatrixStore mtrxQ2 = this.getV();
return mtrxQ1.multiply(mtrxD).multiply(mtrxQ2.conjugate());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy