Accuracy.java
/*
* Copyright (C) 2018 Alberto Irurueta Carro (alberto@irurueta.com)
*
* 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 com.irurueta.geometry;
import com.irurueta.algebra.AlgebraException;
import com.irurueta.algebra.Matrix;
import com.irurueta.algebra.NonSymmetricPositiveDefiniteMatrixException;
import com.irurueta.algebra.SingularValueDecomposer;
import com.irurueta.statistics.NormalDist;
import java.io.Serializable;
/**
* Base class representing the confidence of provided accuracy from a covariance matrix
* expressed in the distance unit of such matrix.
* This class contains utility methods to convert covariance matrices into geometric figures
* with the requested confidence.
*/
public abstract class Accuracy implements Serializable {
/**
* Default standard deviation factor to account for a given accuracy confidence.
* Typically, a factor of 2.0 will be used, which means that accuracy of position will
* be drawn as an ellipse of size equal to one time the standard deviation. Assuming a
* Gaussian distribution this is equivalent to providing a 95.44% of confidence on provided
* accuracy.
*/
private static final double DEFAULT_STANDARD_DEVIATION_FACTOR = 2.0;
/**
* Covariance matrix representing the accuracy of an estimated position.
*/
private Matrix covarianceMatrix;
/**
* Standard deviation factor to account for a given accuracy confidence.
* Typically, a factor of 2.0 will be used, which means that accuracy of a point or
* measure will be drawn as a geometric figure (either an ellipse in 2D or an
* ellipsoid in 3D) equal to two times the standard deviation. Assuming a
* Gaussian distribution this is equivalent to providing a 95.44% of confidence on
* provided accuracy.
*/
protected double standardDeviationFactor = DEFAULT_STANDARD_DEVIATION_FACTOR;
/**
* Confidence of provided accuracy of a point for a value located up to the standard
* deviation factor distance from the mean.
* This is expressed as a value between 0 and 1, where 1 indicates a 100% confidence that
* the real position is within provided accuracy.
*/
protected double confidence = 2.0 * NormalDist.cdf(DEFAULT_STANDARD_DEVIATION_FACTOR, 0.0, 1.0) - 1.0;
/**
* Square root of singular values of decomposed covariance matrix.
*/
protected double[] sqrtSingularValues;
/**
* Orthonormal matrix representing a rotation after decomposing covariance matrix.
*/
protected Matrix u;
/**
* Minimum square root of singular value of decomposed covariance matrix. Can be used to
* determine the smallest accuracy on a geometric figure (i.e. the shortest semi-axis on
* an ellipse or an ellipsoid).
*/
private double minSqrtSingularValue = Double.POSITIVE_INFINITY;
/**
* Maximum square root of singular value of decomposed covariance matrix. Can be used to
* determine the largest accuracy on a geometric figure (i.e. the largest semi-axis on
* an ellipse or an ellipsoid).
*/
private double maxSqrtSingularValue = Double.POSITIVE_INFINITY;
/**
* Average square root of singular value of decomposed covariance matrix. Can be used to
* determine the average accuracy on a geometric figure (i.e. the average semi-axis on
* an ellipse or an ellipsoid).
*/
private double avgSqrtSingularValue = Double.POSITIVE_INFINITY;
/**
* Constructor.
*/
protected Accuracy() {
}
/**
* Constructor.
*
* @param covarianceMatrix covariance matrix to be set. Must be NxN where N
* is the number of dimensions and positive definite.
* @throws IllegalArgumentException if provided matrix is not square (it must also be
* positive definite to be properly converted to a geometric figure - e.g. an ellipse or
* an ellipsoid).
* @throws NonSymmetricPositiveDefiniteMatrixException if provided matrix is not symmetric and
* positive definite.
*/
protected Accuracy(final Matrix covarianceMatrix) throws NonSymmetricPositiveDefiniteMatrixException {
setCovarianceMatrix(covarianceMatrix);
}
/**
* Constructor.
*
* @param confidence confidence of provided accuracy of an estimated position.
* @throws IllegalArgumentException if provided value is not within 0 and 1.
*/
protected Accuracy(final double confidence) {
setConfidence(confidence);
}
/**
* Constructor.
*
* @param covarianceMatrix covariance matrix to be set. Must be NxN where N
* is the number of dimensions and positive definite.
* @param confidence confidence of provided accuracy of an estimated position.
* @throws IllegalArgumentException if provided matrix is not square (it must also be
* positive definite to be properly converted to a geometric figure - e.g. an ellipse or
* an ellipsoid), or if provided confidence value is not within 0 and 1.
* @throws NonSymmetricPositiveDefiniteMatrixException if provided matrix is not symmetric and
* positive definite.
*/
protected Accuracy(final Matrix covarianceMatrix, final double confidence)
throws NonSymmetricPositiveDefiniteMatrixException {
setCovarianceMatrix(covarianceMatrix);
setConfidence(confidence);
}
/**
* Gets covariance matrix representing the accuracy of an estimated point or measure.
*
* @return covariance matrix representing the accuracy of an estimated point or measure.
*/
public Matrix getCovarianceMatrix() {
return covarianceMatrix;
}
/**
* Sets covariance matrix representing the accuracy of an estimated point or measure.
*
* @param covarianceMatrix covariance matrix representing the accuracy of an estimated
* point or measure.
* @throws IllegalArgumentException if provided matrix is not square (it must also be
* positive definite to be properly converted to a geometric figure - e.g. an ellipse
* or an ellipsoid).
* @throws NonSymmetricPositiveDefiniteMatrixException if provided matrix is not symmetric and
* positive definite.
*/
public void setCovarianceMatrix(final Matrix covarianceMatrix) throws NonSymmetricPositiveDefiniteMatrixException {
final var dims = getNumberOfDimensions();
if (covarianceMatrix.getRows() != dims || covarianceMatrix.getColumns() != dims) {
throw new IllegalArgumentException();
}
try {
final var svdDecomposer = new SingularValueDecomposer();
svdDecomposer.setInputMatrix(covarianceMatrix);
svdDecomposer.decompose();
final var singularValues = svdDecomposer.getSingularValues();
final var sqrtSingularValues = new double[dims];
var minSqrtSingularValue = Double.MAX_VALUE;
var maxSqrtSingularValue = -Double.MAX_VALUE;
var avgSqrtSingularValue = 0.0;
var i = 0;
for (final var singularValue : singularValues) {
if (singularValue < 0.0) {
// matrix is not positive definite
throw new NonSymmetricPositiveDefiniteMatrixException();
}
final var sqrtSingularValue = Math.sqrt(singularValue);
if (sqrtSingularValue < minSqrtSingularValue) {
minSqrtSingularValue = sqrtSingularValue;
}
if (sqrtSingularValue > maxSqrtSingularValue) {
maxSqrtSingularValue = sqrtSingularValue;
}
avgSqrtSingularValue += sqrtSingularValue / dims;
sqrtSingularValues[i] = sqrtSingularValue;
i++;
}
this.sqrtSingularValues = sqrtSingularValues;
u = svdDecomposer.getU();
this.minSqrtSingularValue = minSqrtSingularValue;
this.maxSqrtSingularValue = maxSqrtSingularValue;
this.avgSqrtSingularValue = avgSqrtSingularValue;
this.covarianceMatrix = covarianceMatrix;
} catch (final AlgebraException e) {
throw new NonSymmetricPositiveDefiniteMatrixException(e);
}
}
/**
* Gets standard deviation factor to account for a given accuracy confidence.
* Typically, a factor of 2.0 will be used, which means that accuracy can be drawn as
* a geometric figure of size equal to 2 times the standard deviation. Assuming a
* Gaussian distribution this is equivalent to providing a 95.44% confidence on provided
* accuracy.
*
* @return standard deviation factor.
*/
public double getStandardDeviationFactor() {
return standardDeviationFactor;
}
/**
* Sets standard deviation factor to account for a given accuracy confidence.
* Typically, a factor of 2.0 will be used, which means that accuracy can be drawn as
* a geometric figure of size equal to 2 times the standard deviation. Assuming a
* Gaussian distribution this is equivalent to providing a 95.44% confidence on provided
* accuracy.
*
* @param standardDeviationFactor standard deviation factor to be set.
* @throws IllegalArgumentException if provided value is zero or negative.
*/
public void setStandardDeviationFactor(final double standardDeviationFactor) {
if (standardDeviationFactor <= 0.0) {
throw new IllegalArgumentException();
}
this.standardDeviationFactor = standardDeviationFactor;
confidence = 2.0 * NormalDist.cdf(this.standardDeviationFactor, 0.0, 1.0) - 1.0;
}
/**
* Gets confidence of provided accuracy of estimated point or measure.
* This is expressed as a value between 0 and 1, where 1 indicates a 100% confidence
* that the real point or measure is within provided accuracy.
*
* @return confidence of provided accuracy of estimated point or measure.
*/
public double getConfidence() {
return confidence;
}
/**
* Sets confidence of provided accuracy of estimated point or measure.
* This is expressed as a value between 0 and 1, where 1 indicates a 100% confidence
* that the real point or measure is within provided accuracy.
*
* @param confidence confidence of provided accuracy of estimated point or measure.
* @throws IllegalArgumentException if provided value is not within 0 and 1.
*/
public void setConfidence(final double confidence) {
if (confidence < 0.0 || confidence > 1.0) {
throw new IllegalArgumentException();
}
this.confidence = confidence;
standardDeviationFactor = NormalDist.invcdf((confidence + 1.0) / 2.0, 0.0, 1.0);
}
/**
* Gets smallest (best) accuracy in any direction (i.e. either 2D or 3D).
* This value is represented by the smallest semi axis representing the ellipse or ellipsoid of accuracy.
*
* @return smallest accuracy in any direction.
*/
public double getSmallestAccuracy() {
return minSqrtSingularValue * standardDeviationFactor;
}
/**
* Gets largest (worse) accuracy in any direction (i.e. either 2D or 3D).
* This value is represented by the largest semi axis representing the ellipse or ellipsoid of accuracy.
*
* @return largest accuracy in any direction.
*/
public double getLargestAccuracy() {
return maxSqrtSingularValue * standardDeviationFactor;
}
/**
* Gets average accuracy among all directions.
* This value is equal to the average value of all semi axes representing the ellipse or ellipsoid of
* accuracy.
*
* @return average accuracy among all directions.
*/
public double getAverageAccuracy() {
return avgSqrtSingularValue * standardDeviationFactor;
}
/**
* Gets number of dimensions.
* This is equal to 2 for 2D, and to 3 for 3D.
*
* @return number of dimensions.
*/
public abstract int getNumberOfDimensions();
}