init
This commit is contained in:
+2053
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,223 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Basics.hpp
|
||||
/// \brief Basic functions of Eigen matrix manipulation and verification.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include <cmath> // Ceil
|
||||
#include <type_traits> // Template type
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Enumeration of Standardization method for features matrix data. </summary>
|
||||
enum class EStandardization
|
||||
{
|
||||
None, ///< No change.
|
||||
Center, ///< Standardize data by removing the mean (on each feature separately).
|
||||
StandardScale ///< Standardize data by removing the mean and scaling to unit variance (on each feature separately).
|
||||
};
|
||||
|
||||
//************************************************
|
||||
//******************** Matrix ********************
|
||||
//************************************************
|
||||
|
||||
/// <summary> Apply an affine transformation and return the result (The last transpose is useless if matrix is SPD).
|
||||
/// \f[
|
||||
/// B = R^{-1/2} * A * {R^{-1/2}}^{\mathsf{T}}
|
||||
/// \f]
|
||||
/// </summary>
|
||||
/// <param name="ref"> The reference matrix which transforms. </param>
|
||||
/// <param name="matrix"> the matrix to transform. </param>
|
||||
/// <returns> The transformed matrix </returns>
|
||||
Eigen::MatrixXd AffineTransformation(const Eigen::MatrixXd& ref, const Eigen::MatrixXd& matrix);
|
||||
|
||||
|
||||
/// <summary> Standardize data row by row with selected method (destructive operation). </summary>
|
||||
/// <param name="matrix"> The matrix to standardize. </param>
|
||||
/// <param name="standard"> Standard method. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MatrixStandardization(Eigen::MatrixXd& matrix, EStandardization standard = EStandardization::None);
|
||||
|
||||
/// <summary> Standardize data row by row with selected method (non destructive operation). </summary>
|
||||
/// <param name="in"> The matrix to standardize. </param>
|
||||
/// <param name="out"> The matrix standardized. </param>
|
||||
/// <param name="standard"> Standard method. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MatrixStandardization(const Eigen::MatrixXd& in, Eigen::MatrixXd& out, EStandardization standard = EStandardization::None);
|
||||
|
||||
/// <summary> Removes the mean of each row at the matrix (destructive operation).\n
|
||||
/// So \f$\mu=0\f$. </summary>
|
||||
/// <param name="matrix"> The Matrix to center. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MatrixCenter(Eigen::MatrixXd& matrix);
|
||||
|
||||
/// <summary> Removes the mean of each row at the matrix (non destructive operation).\n
|
||||
/// So \f$\mu=0\f$. </summary>
|
||||
/// <param name="in"> The Matrix to center. </param>
|
||||
/// <param name="out"> The Matrix centered. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MatrixCenter(const Eigen::MatrixXd& in, Eigen::MatrixXd& out);
|
||||
|
||||
/// <summary> Removes the mean of each row at the matrix and divide by the variance (destructive operation with scale return).\n
|
||||
/// So \f$\mu=0\f$ and \f$\sigma=1\f$. </summary>
|
||||
/// <param name="matrix"> The Matrix to standardize. </param>
|
||||
/// <param name="scale"> The scale vector. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Adaptation of <a href="http://scikit-learn.org">sklearn</a> <a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html">StandardScaler</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>). </remarks>
|
||||
bool MatrixStandardScaler(Eigen::MatrixXd& matrix, Eigen::RowVectorXd& scale);
|
||||
|
||||
/// <summary> Removes the mean of each row at the matrix and divide by the variance (destructive operation).\n
|
||||
/// So \f$\mu=0\f$ and \f$\sigma=1\f$. </summary>
|
||||
/// <param name="matrix"> The Matrix to standardize. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Adaptation of <a href="http://scikit-learn.org">sklearn</a> <a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html">StandardScaler</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>). </remarks>
|
||||
bool MatrixStandardScaler(Eigen::MatrixXd& matrix);
|
||||
|
||||
/// <summary> Removes the mean of each row at the matrix and divide by the variance (non destructive operation with scale return).\n
|
||||
/// So \f$\mu=0\f$ and \f$\sigma=1\f$. </summary>
|
||||
/// <param name="in"> The Matrix to standardize. </param>
|
||||
/// <param name="out"> The Matrix standardized. </param>
|
||||
/// <param name="scale"> The scale vector. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Adaptation of <a href="http://scikit-learn.org">sklearn</a> <a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html">StandardScaler</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>). </remarks>
|
||||
bool MatrixStandardScaler(const Eigen::MatrixXd& in, Eigen::MatrixXd& out, Eigen::RowVectorXd& scale);
|
||||
|
||||
/// <summary> Removes the mean of each row at the matrix and divide by the variance (non destructive operation).\n
|
||||
/// So \f$\mu=0\f$ and \f$\sigma=1\f$. </summary>
|
||||
/// <param name="in"> The Matrix to standardize. </param>
|
||||
/// <param name="out"> The Matrix standardized. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Adaptation of <a href="http://scikit-learn.org">sklearn</a> <a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html">StandardScaler</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>). </remarks>
|
||||
bool MatrixStandardScaler(const Eigen::MatrixXd& in, Eigen::MatrixXd& out);
|
||||
|
||||
/// <summary> Give the string format of Matrix. </summary>
|
||||
/// <param name="matrix"> The Matrix to display. </param>
|
||||
/// <returns> The string format. </returns>
|
||||
std::string MatrixPrint(const Eigen::MatrixXd& matrix);
|
||||
|
||||
/// <summary> Check first the size, then if not empty matrix and then if they are almost equal. </summary>
|
||||
/// <param name="matrix1"> First Matrix. </param>
|
||||
/// <param name="matrix2"> Second Matrix. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance), <c>False</c> otherwise. </returns>
|
||||
bool AreEquals(const Eigen::MatrixXd& matrix1, const Eigen::MatrixXd& matrix2, double precision = 1e-6);
|
||||
|
||||
//*************************************************************
|
||||
//******************** Index Manipulations ********************
|
||||
//*************************************************************
|
||||
/// <summary> Gets the items selected by the index. </summary>
|
||||
/// <param name="row"> the original row. </param>
|
||||
/// <param name="index"> Elements to select. </param>
|
||||
/// <returns> Row with selected elements. </returns>
|
||||
Eigen::RowVectorXd GetElements(const Eigen::RowVectorXd& row, const std::vector<size_t>& index);
|
||||
|
||||
/// <summary> <a href="https://numpy.org/doc/stable/reference/generated/numpy.arange.html">Numpy arange</a> implementation in C++. </summary>
|
||||
/// <typeparam name="T"> Generic numeric type parameter. </typeparam>
|
||||
/// <param name="start"> The start. </param>
|
||||
/// <param name="stop"> The stop. </param>
|
||||
/// <param name="step"> (Optional) Amount to increment by. </param>
|
||||
/// <returns> vector<T> </returns>
|
||||
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
|
||||
std::vector<T> ARange(const T start, const T stop, const T step = 1)
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.reserve(size_t(ceil(1.0 * (stop - start) / step)));
|
||||
for (T i = start; i < stop; i += step) { result.push_back(i); }
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Turn vector of vector into vector. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="in"> vector of vector. </param>
|
||||
/// <returns> <c>vector<T></c> </returns>
|
||||
template <typename T>
|
||||
std::vector<T> Vector2DTo1D(const std::vector<std::vector<T>>& in)
|
||||
{
|
||||
std::vector<T> result;
|
||||
size_t sum = 0;
|
||||
for (const auto& v : in) { sum += v.size(); }
|
||||
result.reserve(sum);
|
||||
for (const auto& v : in) { for (const auto& e : v) { result.push_back(e); } }
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Turn vector into vector of vector with position repartition. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="in"> vector of vector. </param>
|
||||
/// <param name="position"> position of element (size of position is the number of row the values are the number of element on each row). </param>
|
||||
/// <returns> <c>vector<T></c> </returns>
|
||||
template <typename T>
|
||||
std::vector<std::vector<T>> Vector1DTo2D(const std::vector<T>& in, const std::vector<size_t>& position)
|
||||
{
|
||||
const size_t n = position.size();
|
||||
std::vector<std::vector<T>> result(n);
|
||||
size_t idx = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const size_t nbSample = position[i];
|
||||
result[i].resize(nbSample);
|
||||
for (size_t j = 0; j < nbSample; ++j) { result[i][j] = in[idx++]; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
//******************** Validates ********************
|
||||
//***************************************************
|
||||
/// <summary> Validate if value is in [min;max]. </summary>
|
||||
/// <param name="value"> The value. </param>
|
||||
/// <param name="min"> The minimum. </param>
|
||||
/// <param name="max"> The maximum. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool InRange(const double value, const double min, const double max);
|
||||
|
||||
/// <summary> Validate if the vector is not empty and the matrices are validate. </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool AreNotEmpty(const std::vector<Eigen::MatrixXd>& matrices);
|
||||
|
||||
/// <summary> Validates if matrix is not empty. </summary>
|
||||
/// <param name="matrix"> Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool IsNotEmpty(const Eigen::MatrixXd& matrix);
|
||||
|
||||
/// <summary> Validates if two matrix have same size. </summary>
|
||||
/// <param name="a"> Matrix A. </param>
|
||||
/// <param name="b"> Matrix B. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool HaveSameSize(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Validate if the vector is not empty and the matrices have same size. </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool HaveSameSize(const std::vector<Eigen::MatrixXd>& matrices);
|
||||
|
||||
/// <summary> Validates if matrix is square matrix and not empty. </summary>
|
||||
/// <param name="matrix"> Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool IsSquare(const Eigen::MatrixXd& matrix);
|
||||
|
||||
/// <summary> Validate if the vector is not empty and the matrices are square matrix and not empty. </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool AreSquare(const std::vector<Eigen::MatrixXd>& matrices);
|
||||
|
||||
//********************************************************
|
||||
//******************** CSV MANAGEMENT ********************
|
||||
//********************************************************
|
||||
/// <summary>Return the string split by the \p sep parameter. </summary>
|
||||
/// <param name="s"> The string to split. </param>
|
||||
/// <param name="sep"> the separator string which splits. </param>
|
||||
/// <returns> Vector of string part. </returns>
|
||||
std::vector<std::string> Split(const std::string& s, const std::string& sep);
|
||||
|
||||
} // namespace Geometry
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Classification.hpp
|
||||
/// \brief All functions to help Matrix Classifiers.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks
|
||||
/// - LSQR inspired by <a href="http://scikit-learn.org">sklearn</a> <a href="https://scikit-learn.org/stable/modules/generated/sklearn.discriminant_analysis.LinearDiscriminantAnalysis.html">LinearDiscriminantAnalysis</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>).
|
||||
/// - FgDA inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Compute the weight of Linear Discriminant Analysis with Least squares (LSQR) Solver. </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the class, second dimension the trial as Feature Vector). </param>
|
||||
/// <param name="weight"> The weight to apply. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Inspired by <a href="http://scikit-learn.org">sklearn</a> <a href="https://scikit-learn.org/stable/modules/generated/sklearn.discriminant_analysis.LinearDiscriminantAnalysis.html">LinearDiscriminantAnalysis</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>). </remarks>
|
||||
bool LSQR(const std::vector<std::vector<Eigen::RowVectorXd>>& dataset, Eigen::MatrixXd& weight);
|
||||
|
||||
/// <summary> Compute Least squares (LSQR) Weight and transform to FgDA Weight. \n
|
||||
/// \f[ W_{\text{FgDA}} = W^{\mathsf{T}} \times (W \times W^{\mathsf{T}})^{-1} \times W \f]
|
||||
/// </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the class, second dimension is the trial as Feature Vector). </param>
|
||||
/// <param name="weight"> The Weight to apply. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Method inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>). </remarks>
|
||||
bool FgDACompute(const std::vector<std::vector<Eigen::RowVectorXd>>& dataset, Eigen::MatrixXd& weight);
|
||||
|
||||
/// <summary> Apply the weight on the vector. (just a matrix product) </summary>
|
||||
/// <param name="in"> Sample to transform. </param>
|
||||
/// <param name="out"> Transformed Sample. </param>
|
||||
/// <param name="weight"> The Weight to apply. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> Method inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>). </remarks>
|
||||
bool FgDAApply(const Eigen::RowVectorXd& in, Eigen::RowVectorXd& out, const Eigen::MatrixXd& weight);
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,224 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Covariance.hpp
|
||||
/// \brief All functions to estimate the Covariance Matrix.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks
|
||||
/// - List of Estimator inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
|
||||
/// - <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.LedoitWolf.html">Ledoit and Wolf Estimator</a> inspired by <a href="http://scikit-learn.org">sklearn</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>).
|
||||
/// - <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.OAS.html">Oracle Approximating Shrinkage (OAS) Estimator</a> Inspired by <a href="http://scikit-learn.org">sklearn</a> (<a href="https://github.com/scikit-learn/scikit-learn/blob/master/COPYING">License</a>).
|
||||
/// - <b>Minimum Covariance Determinant (MCD) Estimator isn't implemented. </b>
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/Basics.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
//***************************************************
|
||||
//******************** CONSTANTS ********************
|
||||
//***************************************************
|
||||
/// <summary> Enumeration of the covariance matrix estimator. Inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a>. </summary>
|
||||
enum class EEstimator
|
||||
{
|
||||
COV, ///< The Simple Covariance Estimator.
|
||||
SCM, ///< The Normalized Spatial Covariance Matrix (SCM) Estimator.
|
||||
LWF, ///< The Ledoit and Wolf Estimator.
|
||||
OAS, ///< The Oracle Approximating Shrinkage (OAS) Estimator.
|
||||
MCD, ///< The Minimum Covariance Determinant (MCD) Estimator.
|
||||
COR, ///< The Pearson Correlation Estimator.
|
||||
IDE ///< The Identity Matrix.
|
||||
};
|
||||
|
||||
/// <summary> Convert estimators to string. </summary>
|
||||
/// <param name="estimator"> The estimator. </param>
|
||||
/// <returns> <c>std::string</c> </returns>
|
||||
inline std::string toString(const EEstimator estimator)
|
||||
{
|
||||
switch (estimator)
|
||||
{
|
||||
case EEstimator::COV: return "Covariance";
|
||||
case EEstimator::SCM: return "Normalized Spatial Covariance Matrix (SCM)";
|
||||
case EEstimator::LWF: return "Ledoit and Wolf";
|
||||
case EEstimator::OAS: return "Oracle Approximating Shrinkage (OAS)";
|
||||
case EEstimator::MCD: return "Minimum Covariance Determinant (MCD)";
|
||||
case EEstimator::COR: return "Pearson Correlation";
|
||||
case EEstimator::IDE: return "Identity";
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
/// <summary> Convert string to estimators. </summary>
|
||||
/// <param name="estimator"> The estimator. </param>
|
||||
/// <returns> <see cref="EEstimator"/> </returns>
|
||||
inline EEstimator StringToEstimator(const std::string& estimator)
|
||||
{
|
||||
if (estimator == "Covariance") { return EEstimator::COV; }
|
||||
if (estimator == "Normalized Spatial Covariance Matrix (SCM)") { return EEstimator::SCM; }
|
||||
if (estimator == "Ledoit and Wolf") { return EEstimator::LWF; }
|
||||
if (estimator == "Oracle Approximating Shrinkage (OAS)") { return EEstimator::OAS; }
|
||||
if (estimator == "Minimum Covariance Determinant (MCD)") { return EEstimator::MCD; }
|
||||
if (estimator == "Pearson Correlation") { return EEstimator::COR; }
|
||||
return EEstimator::IDE;
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
//******************** COVARIANCES BASES ********************
|
||||
//***********************************************************
|
||||
/// <summary> Calculation of the Variance of a double dataset \f$\vec{X}\f$.\n
|
||||
/// \f[ V(X) = \left(\frac{1}{n} \sum_{i=1}^{N}x_{i}^{2}\right) - \left(\frac{1}{n} \sum_{i=1}^{N}x_{i}\right)^{2} \f]
|
||||
/// </summary>
|
||||
/// <param name="x"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Samples. </param>
|
||||
/// <returns> The Variance. </returns>
|
||||
double Variance(const Eigen::RowVectorXd& x);
|
||||
|
||||
/// <summary> Calculation of the Covariance between two double dataset \f$\vec{X}, \vec{Y}\f$.\n
|
||||
/// \f[ \operatorname{Cov}\left(x,y\right) = \frac{\sum_{i=1}^{N}{x_{i}y_{i}} - \left(\sum_{i=1}^{N}{x_{i}}\sum_{i=1}^{N}{y_{i}}\right)/N}{N}\f]
|
||||
/// </summary>
|
||||
/// <param name="x"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Samples. </param>
|
||||
/// <param name="y"> The dataset \f$\vec{Y}\f$. With \f$ N \f$ Samples. </param>
|
||||
/// <returns> The Covariance. </returns>
|
||||
double Covariance(const Eigen::RowVectorXd& x, const Eigen::RowVectorXd& y);
|
||||
|
||||
/// <summary> Shrunks the Covariance Matrix \f$ M \f$ (destructive operation).\n
|
||||
/// \f[ (1 - \text{shrinkage}) \times M_{\operatorname{Cov}} + \frac{\text{shrinkage} \times \operatorname{trace}(M_{Cov})}{N} \times I_N \f]
|
||||
/// </summary>
|
||||
/// <param name="cov"> The Covariance Matrix to shrink. </param>
|
||||
/// <param name="shrinkage"> (Optional) The shrinkage coefficient : \f$ 0\leq \text{shrinkage} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool ShrunkCovariance(Eigen::MatrixXd& cov, double shrinkage = 0.1);
|
||||
|
||||
/// <summary> Shrunks the Covariance Matrix \f$ M \f$ (non destructive operation).\n
|
||||
/// \f[ (1 - \text{shrinkage}) \times M_{\operatorname{Cov}} + \frac{\text{shrinkage} \times \operatorname{trace}(M_{Cov})}{N} \times I_N \f]
|
||||
/// </summary>
|
||||
/// <param name="in"> The covariance matrix to shrink. </param>
|
||||
/// <param name="out"> The shrunk covariance matrix. </param>
|
||||
/// <param name="shrinkage"> (Optional) The shrinkage coefficient : \f$ 0\leq \text{shrinkage} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool ShrunkCovariance(const Eigen::MatrixXd& in, Eigen::MatrixXd& out, double shrinkage = 0.1);
|
||||
|
||||
/// <summary> Select the function to call for the covariance matrix.\n
|
||||
/// - centralizing the data is useless for <c><see cref="EEstimator::COV"/></c> and <c><see cref="EEstimator::COR"/></c>.\n
|
||||
/// - centralizing the data is not usual for <c><see cref="EEstimator::SCM"/></c>.
|
||||
/// </summary>
|
||||
/// <param name="in"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="out"> The Covariance Matrix. </param>
|
||||
/// <param name="estimator"> (Optional) The selected estimator (see <see cref="EEstimator"/>). </param>
|
||||
/// <param name="standard"> (Optional) Standardize the data (see <see cref="EStandardization"/>). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrix(const Eigen::MatrixXd& in, Eigen::MatrixXd& out, EEstimator estimator = EEstimator::COV,
|
||||
EStandardization standard = EStandardization::Center);
|
||||
|
||||
//***********************************************************
|
||||
//******************** COVARIANCES TYPES ********************
|
||||
//***********************************************************
|
||||
/// <summary> Calculation of the covariance matrix.\n
|
||||
/// \f[ M_{\operatorname{Cov}} =
|
||||
/// \begin{pmatrix}
|
||||
/// V\left(x_1\right) & \operatorname{Cov}\left(x_1,x_2\right) &\cdots & \operatorname{Cov}\left(x_1,x_N\right)\\
|
||||
/// \operatorname{Cov}\left(x_2,x_1\right) &\ddots & \ddots & \vdots \\
|
||||
/// \vdots & \ddots & \ddots & \vdots \\
|
||||
/// \operatorname{Cov}\left(x_N,x_1\right) &\cdots & \cdots & V\left(x_N\right)
|
||||
/// \end{pmatrix}
|
||||
/// \quad\quad \text{with } x_i \text{ the feature } i
|
||||
/// \f]\n
|
||||
/// With the <see cref="Variance"/> and <see cref="Covariance"/> function.
|
||||
/// </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrixCOV(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
/// <summary> Calculation of the covariance matrix by the method : Normalized Spatial Covariance Matrix (SCM).\n
|
||||
/// \f[ M_{\operatorname{Cov_{SCM}}} = \frac{XX^{\mathsf{T}}}{\operatorname{trace}{\left(XX^{\mathsf{T}}\right)}} \f]
|
||||
/// </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrixSCM(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
/// <summary> Calculation of the covariance matrix and shrinkage by the method : Ledoit and Wolf.\n
|
||||
/// -# Compute the Covariance Matrix (see <see cref="CovarianceMatrixCOV"/>) \f$ M_{\operatorname{Cov}} \f$
|
||||
/// -# Compute the Ledoit and Wolf Shrinkage
|
||||
/// -# Shrunk the Matrix (see <see cref="ShrunkCovariance"/>)
|
||||
///
|
||||
/// Ledoit and Wolf Shrinkage (from <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.LedoitWolf.html">Sklearn LedoitWolf Estimator</a>)
|
||||
/// described in "A Well-Conditioned Estimator for Large-Dimensional Covariance Matrices", Ledoit and Wolf, Journal of Multivariate Analysis, Volume 88, Issue 2, February 2004, pages 365-411. : \n
|
||||
/// \f[
|
||||
/// \begin{aligned}
|
||||
/// \vec{X}^2 &= \begin{pmatrix}x_{0,0}^2 & \cdots & x_{0,S}^2 \\ \vdots & \ddots &\vdots \\ x_{N,0}^2 & \cdots & x_{N,S}^2\end{pmatrix} \quad \text{with } x_{i,j} \in \vec{X}\\
|
||||
/// M_{\mu} &= \mu\times I_N = \begin{pmatrix} \mu & 0 & \cdots & 0 \\ 0 & \ddots &\ddots & \vdots \\ \vdots & \ddots &\ddots & 0 \\ 0 & \cdots & 0 & \mu\end{pmatrix}
|
||||
/// \quad \text{with } \mu = \frac{\operatorname{trace}(M_{\operatorname{Cov}})}{N}\\
|
||||
/// M_{\delta} &= M_{\operatorname{Cov}}-M_{\mu}\\
|
||||
/// M_{\delta}^2 &= M_{\delta} * M_{\delta}\\
|
||||
/// M_{\beta} &= \frac{1}{S} \times \left(\vec{X}^2 * \vec{X}^{2\mathsf{T}}\right) - M_{Cov} * M_{Cov}\\
|
||||
/// \Sigma\left( M \right) &=\text{ the sum of the elements of the matrix } M\\
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// \f[ \text{Shrinkage}_\text{LWF} = \frac{\beta}{\delta} \quad \text{with } \delta = \frac{\Sigma\left( M_{\delta}^2 \right)}{N} \quad\text{and}\quad
|
||||
/// \beta = \operatorname{min}\left(\frac{\Sigma\left( M_{\beta}^2 \right)}{N \times S},~ \delta\right)\f]
|
||||
/// </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrixLWF(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
/// <summary> Calculation of the covariance matrix and shrinkage by the method : Oracle Approximating Shrinkage (OAS).\n
|
||||
/// -# Compute the Covariance Matrix (see <see cref="CovarianceMatrixCOV"/>) \f$ M_{\operatorname{Cov}} \f$
|
||||
/// -# Compute the Oracle Approximating Shrinkage
|
||||
/// -# Shrunk the Matrix (see <see cref="ShrunkCovariance"/>)
|
||||
///
|
||||
/// Oracle Approximating Shrinkage (from <a href="http://scikit-learn.org/stable/modules/generated/sklearn.covariance.OAS.html">Sklearn Oracle Approximating Shrinkage Estimator</a>)
|
||||
/// describe in "Shrinkage Algorithms for MMSE Covariance Estimation" Chen et al., IEEE Trans. on Sign. Proc., Volume 58, Issue 10, October 2010. : \n
|
||||
/// \f[
|
||||
/// \begin{aligned}
|
||||
/// \mu &= \frac{\operatorname{trace}(M_{\operatorname{Cov}})}{N}\\
|
||||
/// \mu \left( M \right) &=\text{ the mean of the elements of the matrix } M\\
|
||||
/// \alpha &= \mu \left( M_{\operatorname{Cov}} * M_{\operatorname{Cov}} \right)\\
|
||||
/// \text{num} &= \alpha + \mu^2\\
|
||||
/// \text{den} &= (S + 1) \times \frac{\alpha - \mu^2}{N}\\
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// \f[
|
||||
/// \text{Shrinkage}_\text{OAS} = \begin{cases}
|
||||
/// 1, & \text{if}\ \text{den} = 0 \text{ or num} > \text{den} \\
|
||||
/// \frac{\text{num}}{\text{den}}, & \text{otherwise}
|
||||
/// \end{cases}
|
||||
/// \f]
|
||||
/// </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrixOAS(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
/// <summary>Calculation of the covariance matrix and shrinkage by the method : Minimum Covariance Determinant (MCD). </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// \todo Not implemented.
|
||||
bool CovarianceMatrixMCD(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
/// <summary> Calculation of the covariance matrix by the method : Pearson Correlation.\n
|
||||
/// \f[
|
||||
/// M_{\operatorname{Cov_{COR}}}\left(i,j\right)
|
||||
/// = \frac{ M_{\operatorname{Cov}}\left(i,j\right) } { \sqrt{ M_{\operatorname{Cov}}\left(i,i\right) * M_{\operatorname{Cov}}\left(j,j\right) } }
|
||||
/// \f]
|
||||
/// </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrixCOR(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
/// <summary> Return the Identity matrix \f$ I_N \f$. </summary>
|
||||
/// <param name="samples"> The dataset \f$\vec{X}\f$. With \f$ N \f$ Rows (features) and \f$ S \f$ columns (samples). </param>
|
||||
/// <param name="cov"> The Covariance Matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool CovarianceMatrixIDE(const Eigen::MatrixXd& samples, Eigen::MatrixXd& cov);
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,87 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Distance.hpp
|
||||
/// \brief All functions to estimate the Distance between two Covariance Matrix.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks
|
||||
/// - List of Metrics inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/Metrics.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Compute the distance between two matrix with the selected \p metric. </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <param name="metric"> (Optional) The metric (see <see cref="EMetric"/>). </param>
|
||||
/// <returns> The Distance between A and B. </returns>
|
||||
double Distance(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b, EMetric metric = EMetric::Riemann);
|
||||
|
||||
/// <summary> Compute the Riemannian Distance between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{R}}(A,B) = \sqrt{\left( \sum_i \log\left(\lambda_i\right)^2 \right)} \f]
|
||||
/// with : \f$\lambda_i\f$ the joint eigenvalues of \f$A\f$ and \f$B\f$.
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Riemannian Distance between A and B. </returns>
|
||||
double DistanceRiemann(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Compute the Euclidian Distance between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{E}}(A,B) = \left\lVert B - A \right\rVert\f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Eclidean Distance between A and B. </returns>
|
||||
double DistanceEuclidian(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Compute the Log Euclidian Distance between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{lE}}(A,B) = \left\lVert \log\left(B\right) - \log\left(A\right) \right\rVert\f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Log Eclidean Distance between A and B. </returns>
|
||||
double DistanceLogEuclidian(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Compute the Log-det Distance between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{lD}}(A,B) = \sqrt{\log\left(\left\lvert\frac{A + B}{2}\right\rvert\right) - 0.5 \times \log\left( \left\lvert A \right\rvert \times \left\lvert B \right\rvert \right)} \f]
|
||||
/// with : \f$\left\lvert A \right\rvert\f$ the determinant of \f$A\f$.
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Log-det Distance between A and B. </returns>
|
||||
double DistanceLogDet(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Compute the Kullback Leibler Divergence between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{K}}(A,B) = 0.5 \times \left( \operatorname{trace}\left(B^{-1} ~ A\right) - N + \log\left( \frac{\left\lvert B \right\rvert }{\left\lvert A \right\rvert} \right) \right) \f]
|
||||
/// with : \f$\left\lvert A \right\rvert\f$ the determinant of \f$A\f$.
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Kullback Leibler Divergence Distance between A and B. </returns>
|
||||
double DistanceKullback(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Compute the Symetric Kullback Leibler Divergence between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{sK}}(A,B) = d_\text{K}(A, B) + d_\text{K}(B, A) \f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Symetric Kullback Leibler Divergence Distance between A and B. </returns>
|
||||
double DistanceKullbackSym(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
/// <summary> Compute the Wasserstein Distance between two covariance matrices A and B.\n
|
||||
/// \f[ d_{\text{W}}(A,B) = \sqrt{ \operatorname{trace}\left(A + B - 2 \times \left(A^{1/2} ~ B ~ A^{1/2}\right)^{1/2}\right) } \f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <returns> The Wasserstein Distance between A and B. </returns>
|
||||
double DistanceWasserstein(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b);
|
||||
|
||||
} // namespace Geometry
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Featurization.hpp
|
||||
/// \brief All functions to transform Covariance matrix to feature vector.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Compute the features vector of covariance matrix with the selected method. </summary>
|
||||
/// <param name="in"> The covariance in. </param>
|
||||
/// <param name="out"> The Feature Vector. </param>
|
||||
/// <param name="tangent"> (Optional) True to use tangent space featurization, Upper Triangle Squeeze if false. </param>
|
||||
/// <param name="ref"> The reference Matrix (usefull for Tangent Space Featurization). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool Featurization(const Eigen::MatrixXd& in, Eigen::RowVectorXd& out, bool tangent = true, const Eigen::MatrixXd& ref = Eigen::MatrixXd());
|
||||
|
||||
/// <summary> Compute the covariance matrix of features vector with the selected method. </summary>
|
||||
/// <param name="in"> The Feature Vector. </param>
|
||||
/// <param name="out"> The covariance out. </param>
|
||||
/// <param name="tangent"> (Optional) True to use tangent space featurization, Upper Triangle Squeeze if false. </param>
|
||||
/// <param name="ref"> The reference Matrix (usefull for Tangent Space Featurization). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool UnFeaturization(const Eigen::RowVectorXd& in, Eigen::MatrixXd& out, bool tangent = true, const Eigen::MatrixXd& ref = Eigen::MatrixXd());
|
||||
|
||||
/// <summary> Squeeze the upper triangle of \f$N \times N\f$ square matrix to a \f$\frac{N\left(N+1\right)}{2}\f$ Vector.
|
||||
/// <table align="center" border="0">
|
||||
/// <tr><th>Upper Triangle Matrix</th><th></th><th>Row Major Upper Triangle Squeeze</th> <th></th> <th>Diagonal Major Upper Triangle Squeeze</th></tr>
|
||||
/// <tr><td>\f[ \begin{pmatrix} a&b&c\\d&e&f\\g&h&i \end{pmatrix} \Rightarrow \begin{pmatrix} a&b&c\\0&e&f\\0&0&i \end{pmatrix} \f]</td>
|
||||
/// <td><pre> </pre></td>
|
||||
/// <td>\f[ \begin{pmatrix} a&b&c\\d&e&f\\g&h&i \end{pmatrix} \Rightarrow \begin{pmatrix} a&b&c&e&f&i \end{pmatrix} \f]</td>
|
||||
/// <td><pre> </pre></td>
|
||||
/// <td>\f[\begin{pmatrix} a&b&c\\d&e&f\\g&h&i \end{pmatrix} \Rightarrow \begin{pmatrix} a&e&i&b&f&c \end{pmatrix} \f]</td></tr>
|
||||
/// </table>
|
||||
/// </summary>
|
||||
/// <param name="in"> The \f$N \times N\f$ square matrix. </param>
|
||||
/// <param name="out"> The \f$\frac{N\left(N+1\right)}{2}\f$ Vector. </param>
|
||||
/// <param name="rowMajor"> Get the values row by row if true, diagonal by diagonal if false. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool SqueezeUpperTriangle(const Eigen::MatrixXd& in, Eigen::RowVectorXd& out, bool rowMajor = true);
|
||||
|
||||
/// <summary> Compute the upper triangle of \f$\frac{N\left(N+1\right)}{2}\f$ Vector to a \f$N \times N\f$ square matrix.
|
||||
/// <table align="center" border="0">
|
||||
/// <tr><th>Row Major Method</th> <th></th> <th>Diagonal Major Method</th></tr>
|
||||
/// <tr><td>\f[ \begin{pmatrix} a&b&c&d&e&f \end{pmatrix} \Rightarrow \begin{pmatrix} a&b&c\\0&d&e\\0&0&f \end{pmatrix} \f]</td>
|
||||
/// <td><pre> </pre></td>
|
||||
/// <td>\f[ \begin{pmatrix} a&b&c&d&e&f \end{pmatrix} \Rightarrow \begin{pmatrix} a&d&f\\0&b&e\\0&0&c \end{pmatrix} \f]</td></tr>
|
||||
/// </table>
|
||||
/// </summary>
|
||||
/// <param name="in"> The \f$\frac{N\left(N+1\right)}{2}\f$ Vector. </param>
|
||||
/// <param name="out"> The \f$N \times N\f$ square matrix. </param>
|
||||
/// <param name="rowMajor"> Get the values row by row if true, diagonal by diagonal if false. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool UnSqueezeUpperTriangle(const Eigen::RowVectorXd& in, Eigen::MatrixXd& out, bool rowMajor = true);
|
||||
|
||||
/// <summary> Project a covariance matrices (\f$M\f$) in the tangent space (\f$\mathcal{T}\f$) according to the given reference point (\f$M_\text{Ref}\f$). <br/>
|
||||
///
|
||||
/// - Compute the transformation matrix for the covariance matrix \f$M\f$ with the reference matrix \f$M_\text{Ref}\f$ and squeeze ths matrix (see <see cref="SqueezeUpperTriangle"/>).
|
||||
/// \f[
|
||||
/// \begin{aligned}
|
||||
/// J &= \log{\left(M_\text{Ref}^{-1/2} \times M \times M_\text{Ref}^{-1/2}\right)}\\
|
||||
/// V_J &= \operatorname{SqueezeUpperTriangle}(J)
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// - Compute a coefficient Vector to apply to transformation vector.
|
||||
/// \f[
|
||||
/// \begin{aligned}
|
||||
/// M_\text{Coeffs} &= \begin{pmatrix}
|
||||
/// 1 & \sqrt{2} & \cdots & \sqrt{2} \\
|
||||
/// 0 & 1 & \ddots & \sqrt{2} \\
|
||||
/// \vdots & \ddots & \ddots & \vdots\\
|
||||
/// 0 & \cdots & \cdots & 1
|
||||
/// \end{pmatrix}\\
|
||||
/// V_\text{Coeffs} &= \operatorname{SqueezeUpperTriangle}(M_\text{Coeffs})\\
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// - Compute the element wise product of the two vectors to have the tangent space Projection \f$\zeta_M\f$
|
||||
/// \f[ \zeta_M = V_J \odot V_\text{Coeffs} \f]
|
||||
/// </summary>
|
||||
/// <param name="in"> The \f$N \times N\f$ covariance matrix. </param>
|
||||
/// <param name="out"> The \f$\frac{N\left(N+1\right)}{2}\f$ row. </param>
|
||||
/// <param name="ref"> (Optional) The \f$N \times N\f$ reference in (use the identity Matrix if empty). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool TangentSpace(const Eigen::MatrixXd& in, Eigen::RowVectorXd& out, const Eigen::MatrixXd& ref = Eigen::MatrixXd());
|
||||
|
||||
/// <summary> Project a Tangent space vectors in the manifold according to the given reference point. <br/>
|
||||
/// \f[
|
||||
/// \begin{aligned}
|
||||
/// \text{With : } M_\text{Ts} &= \operatorname{UnSqueezeUpperTriangle}(V_\text{Ts}) \quad \text{ and } \quad \mathsf{U}_{M}\text{ the upper triangular out.}\\
|
||||
/// M_\text{Coeffs} &= \operatorname{diag}\left(M_\text{Ts}\right) + \frac{\mathsf{U}_{M_\text{Ts}} + \mathsf{U}_{M_\text{Ts}}^{\mathsf{T}}}{\sqrt{2}}\\
|
||||
/// \Rightarrow M &= M_\text{Ref}^{1/2} ~ \exp{\left(M_\text{Coeffs}\right)} ~ M_\text{Ref}^{1/2}
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// </summary>
|
||||
/// <param name="in"> The \f$\frac{N\left(N+1\right)}{2}\f$ row. </param>
|
||||
/// <param name="out"> The \f$N \times N\f$ covariance matrix. </param>
|
||||
/// <param name="ref"> (Optional) The \f$N \times N\f$ reference out (use the identity Matrix if empty). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool UnTangentSpace(const Eigen::RowVectorXd& in, Eigen::MatrixXd& out, const Eigen::MatrixXd& ref = Eigen::MatrixXd());
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,72 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Geodesic.hpp
|
||||
/// \brief All functions to estimate the Geodesic position of two Covariance Matrix.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks
|
||||
/// - List of Metrics inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/Metrics.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Compute the matrix at the position alpha on the geodesic between A and B with the selected \p metric.\n
|
||||
/// - Allowed Metrics : <c>Riemann</c>, <c>Euclidian</c>, <c>LogEuclidian</c>, <c>Identity</c>
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <param name="g"> The Geodesic. </param>
|
||||
/// <param name="metric"> (Optional) The metric (see <see cref="EMetric"/>). </param>
|
||||
/// <param name="alpha"> (Optional) Position on the Geodesic : \f$ 0\leq \text{alpha} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool Geodesic(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b, Eigen::MatrixXd& g, EMetric metric = EMetric::Riemann, double alpha = 0.5);
|
||||
|
||||
/// <summary> Compute the matrix at the position alpha on the Riemannian geodesic between A and B. \n
|
||||
/// \f[ \gamma_\text{R} = A^{1/2} ~ \left( A^{-1/2} ~ B ~ A^{-1/2} \right)^\alpha ~ A^{1/2} \f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <param name="g"> The Geodesic. </param>
|
||||
/// <param name="alpha"> (Optional) Position on the Geodesic : \f$ 0\leq \text{alpha} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool GeodesicRiemann(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b, Eigen::MatrixXd& g, double alpha = 0.5);
|
||||
|
||||
/// <summary> Compute the matrix at the position alpha on the Euclidean geodesic between A and B.\n
|
||||
/// \f[ \gamma_\text{E} = \left(1 - \alpha \right) \times A + \alpha \times B \f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <param name="g"> The Geodesic. </param>
|
||||
/// <param name="alpha"> (Optional) Position on the Geodesic : \f$ 0\leq \text{alpha} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool GeodesicEuclidian(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b, Eigen::MatrixXd& g, double alpha = 0.5);
|
||||
|
||||
/// <summary> Compute the matrix at the position alpha on the Log Euclidean geodesic between A and B. \n
|
||||
/// \f[ \gamma_\text{LogE} = \exp\left(\left(1 - \alpha \right) \times \log\left(A\right) + \alpha \times \log\left(B\right) \right)\f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <param name="g"> The Geodesic. </param>
|
||||
/// <param name="alpha"> (Optional) Position on the Geodesic : \f$ 0\leq \text{alpha} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool GeodesicLogEuclidian(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b, Eigen::MatrixXd& g, double alpha = 0.5);
|
||||
|
||||
/// <summary> Compute the matrix at the position alpha on the Identity geodesic. \n
|
||||
/// \f[ \gamma_\text{I} = I_N \f]
|
||||
/// </summary>
|
||||
/// <param name="a"> The First Covariance matrix. </param>
|
||||
/// <param name="b"> The Second Covariance matrix. </param>
|
||||
/// <param name="g"> The Geodesic. </param>
|
||||
/// <param name="alpha"> (Optional) Position on the Geodesic : \f$ 0\leq \text{alpha} \leq 1\f$. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool GeodesicIdentity(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b, Eigen::MatrixXd& g, double alpha = 0.5);
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,163 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Mean.hpp
|
||||
/// \brief All functions to estimate the mean of Vector of Covariance Matrix.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks
|
||||
/// - List of Metrics inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
|
||||
/// - The Approximate joint diagonalization based on pham's algorithm is not implemented.
|
||||
/// - The Approximate joint diagonalization based log-Euclidean (ALE) Mean doesn't work => Need to implement <see cref="AJDPham"/> and check if it works next.
|
||||
/// - The Wasserstein Mean Doesn't work so good (after \f$10^{-3}\f$ precision with the pyriemann library).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/Metrics.hpp"
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Compute the mean of vector of covariance matrix with the selected \p metric. </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The computed mean. </param>
|
||||
/// <param name="metric"> (Optional) The metric (see <see cref="EMetric"/>). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool Mean(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean, EMetric metric = EMetric::Riemann);
|
||||
|
||||
/// <summary> Approximate Joint Diagonalization based on pham's algorithm.\n
|
||||
/// \f[ C_\text{AJD} = \cdots \f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="ajd"> The computed Approximate Joint Diagonalization. </param>
|
||||
/// <param name="epsilon"> (Optional) The epsilon. </param>
|
||||
/// <param name="maxIter"> (Optional) The maximum iterator. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// \todo Not implemented.
|
||||
bool AJDPham(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& ajd, double epsilon = 0.0001, int maxIter = 15);
|
||||
|
||||
/// <summary> Compute the Mean with the Riemannian Mean.\n
|
||||
/// -# Compute the Classical Mean \f$ C_{\mu_\text{E}} \f$ (see <see cref="MeanEuclidian"/>)
|
||||
/// -# Update with an iterative procedure that stops after 50 iterations or when one of two criterions is under \f$ 10^{-4}\f$
|
||||
///
|
||||
/// \f[ C_{\mu_\text{R}} = C_{\mu_\text{E}} \\ \nu=1.0 \\ \tau=+\infty \f]
|
||||
/// Iterative process with \f$J\f$ while \f$ \text{iteration} < 50 \f$ and \f$ 10^{-4} < \left\lVert J \right\rVert \f$ and \f$ 10^{-4} < \nu \f$
|
||||
/// \f[ \begin{aligned}
|
||||
/// J &= \frac{1}{N} \sum_i \log\left(C_{\mu_\text{R}}^{-1/2} + C_i ~ C_{\mu_\text{R}}^{-1/2}\right)\\
|
||||
/// C_{\mu_\text{R}} &= C_{\mu_\text{R}}^{1/2} ~ \exp(\nu \times J) ~ C_{\mu_\text{R}}^{1/2}\\
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// \f[ \begin{cases}
|
||||
/// \text{if } \nu \times \left\lVert J \right\rVert < \tau & \nu = 0.95 \times \nu,~\tau = \nu \times \left\lVert J \right\rVert\\
|
||||
/// \text{otherwise } & \nu = 0.5 \times \nu
|
||||
/// \end{cases}
|
||||
/// \f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanRiemann(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Euclidian Mean.\n
|
||||
/// \f[ C_{\mu_\text{E}} =\frac{1}{N} \sum_i{C_i}\f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanEuclidian(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Log Euclidiean Mean.\n
|
||||
/// \f[ C_{\mu_\text{lE}} =\exp\left(\frac{1}{N} \sum_i{\log\left(C_i\right)}\right)\f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanLogEuclidian(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Log Determinant Mean.\n
|
||||
/// -# Compute the Classical Mean \f$ C_{\mu_\text{E}} \f$ (see <see cref="MeanEuclidian"/>)
|
||||
/// -# Update with an iterative procedure that stops after 50 iterations or when criterion is under \f$ 10^{-4}\f$
|
||||
///
|
||||
/// \f[ C_{\mu_\text{lD}} = C_{\mu_\text{E}}\f]
|
||||
/// Iterative process with \f$J\f$ while \f$ \text{iteration} < 50 \f$ and \f$ 10^{-4} < \left\lVert J-C_\mu \right\rVert \f$
|
||||
/// \f[ \begin{aligned}
|
||||
/// J &= \left(\frac{1}{N} \sum_i \left( 0.5 \times\left(C_{\mu_\text{lD}} + C_i \right)\right)^{-1} \right)^{-1}\\
|
||||
/// C_{\mu_\text{lD}} &= J
|
||||
/// \end{aligned}\f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanLogDet(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Kullback Mean.\n
|
||||
/// The mean is the Geodesic center between the Euclidian and the Harmonic Mean.\n
|
||||
/// \f[ C_{\mu_\text{K}} = \gamma \left( C_{\mu_{\text{E}}}, C_{\mu_{\text{H}}} \right) \f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanKullback(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Wasserstein Mean.\n
|
||||
/// -# Compute the Classical Mean \f$ C_{\mu_\text{E}} \f$ (see <see cref="MeanEuclidian"/>)
|
||||
/// -# Update with an iterative procedure that stops after 50 iterations or when criterion is under \f$ 10^{-4}\f$
|
||||
///
|
||||
/// \f[ C_{\mu_\text{W}} = C_{\mu_{\text{E}}}\f]
|
||||
/// Iterative process with \f$J\f$ while \f$ \text{iteration} < 50 \f$ and \f$ 10^{-4} < \left\lVert J-J_{-1} \right\rVert \f$
|
||||
/// \f[ \begin{aligned}
|
||||
/// J &= C_{\mu_\text{W}}^{1/2}\\
|
||||
/// J &= \left(\frac{1}{N} \sum_i \left( J C_i J \right)^{1/2} \right)^{1/2}\\
|
||||
/// \end{aligned}\f]
|
||||
/// After the Iterative process : \f$ C_{\mu_\text{W}} = J*J \f$
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// \todo Doesn't work so good (after \f$10^{-3}\f$ precision with the pyriemann library).
|
||||
bool MeanWasserstein(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Approximate joint diagonalization based log-Euclidean (ALE) Mean. \n
|
||||
/// -# Compute the Approximate Joint Diagonalization \f$ C_\text{AJD} \f$ (see <see cref="AJDPham"/>)
|
||||
/// -# Update with an iterative procedure that stops after 50 iterations or when criterion is under \f$ 10^{-4}\f$
|
||||
///
|
||||
/// \f[ C_{\mu_\text{ALE}} = C_\text{AJD}\f]
|
||||
/// Iterative process with \f$J\f$ (and \f$U = \operatorname{diag}(\operatorname{diag}(\exp(J))\f$) while \f$ \text{iteration} < 50 \f$ and \f$ 10^{-4} < d_\text{R}(I_N,U) \f$
|
||||
/// \f[ \begin{aligned}
|
||||
/// J &= \frac{1}{N} \log\left(\sum_i \left( C_{\mu_\text{ALE}}^{\mathsf{T}} C_i C_{\mu_\text{ALE}} \right) \right)\\
|
||||
/// U &= \operatorname{diag}(\operatorname{diag}(\exp(J))\\
|
||||
/// C_{\mu_\text{ALE}} &= C_{\mu_\text{ALE}} * U^{-1/2}\\
|
||||
/// \end{aligned}\f]
|
||||
/// After the Iterative process :
|
||||
/// \f[ \begin{aligned}
|
||||
/// J &= \frac{1}{N} \log\left(\sum_i \left( C_{\mu_\text{ALE}}^{\mathsf{T}} C_i C_{\mu_\text{ALE}} \right) \right)\\
|
||||
/// C_{\mu_\text{ALE}} &= \left(C_{\mu_\text{ALE}}^{-1}\right)^{\mathsf{T}} ~ \exp(J) ~ C_{\mu_\text{ALE}}^{-1}
|
||||
/// \end{aligned}\f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// \todo Doesn't work => Need to implement <see cref="AJDPham"/> and check if it works next.
|
||||
bool MeanALE(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Compute the Harmonic Mean.\n
|
||||
/// \f[ C_{\mu_\text{H}} = (\frac{1}{N} \sum_i{C_i}^{-1})^{-1} \f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanHarmonic(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
/// <summary> Give the Identity Matrix.\n
|
||||
/// \f[ C_{\mu_\text{I}} = I_N \f]
|
||||
/// </summary>
|
||||
/// <param name="covs"> Vector of Covariance Matrix. </param>
|
||||
/// <param name="mean"> The mean. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MeanIdentity(const std::vector<Eigen::MatrixXd>& covs, Eigen::MatrixXd& mean);
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,108 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Median.hpp
|
||||
/// \brief All Median functions for array or matrix.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 29/07/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks This algortihms is inspired by the plugin clean_rawdata in <a href="https://sccn.ucsd.edu/eeglab/index.php">EEGLAB</a> (<a href="https://github.com/sccn/clean_rawdata/blob/master/LICENSE">License</a>).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include "geometry/Metrics.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//------------------------------ Matrix Median ------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Find the median of stl vector. </summary>
|
||||
/// <typeparam name="T"> The type of the values (only arithmetic type). </typeparam>
|
||||
/// <param name="v"> the vector of values. </param>
|
||||
/// <returns> The median of vector. </returns>
|
||||
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
|
||||
T Median(const std::vector<T>& v)
|
||||
{
|
||||
std::vector<T> tmp = v;
|
||||
const size_t n = tmp.size() / 2; // Where is the middle (if odd number of value the decimal part is floor by cast)
|
||||
std::stable_sort(tmp.begin(), tmp.end()); // We sort all because nth_element doesn't have same behaviour in Windows and Unix
|
||||
return (tmp.size() % 2 == 0) ? (tmp[n] + tmp[n - 1]) / 2 : tmp[n]; // For Even number of value we take the mean of the two middle value
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Find the median of values of the Eigen Matrix. </summary>
|
||||
/// <param name="m"> the matrix. </param>
|
||||
/// <returns> The median of matrix. </returns>
|
||||
double Median(const Eigen::MatrixXd& m);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Compute the median of vector of matrix with the Weiszfeld's algorithm. <br/>
|
||||
/// To compute this median, we start by computing the initial median of the dataset by taking each element of the matrices independently.
|
||||
/// That is to say that for the element at position i, j(a_i, j) of the matrices, we computes the median of the elements a_i, j of all the matrices of the dataset.
|
||||
/// We thus have an initial median for our dataset. <br/>
|
||||
/// Then, we refine our median by the iterative algorithm of Weiszfeld:
|
||||
/// - We remove the median in our dataset.
|
||||
/// - For each new matrices, we compute the norm.
|
||||
/// - We sum the the matrices in initial dataset (divided by their own norm) and we normalize the result by the sum of inverse norms.
|
||||
/// - We iterate this previous step until we have a difference between the old and new median is under an epsilon or that the number of iterations is above the limit.
|
||||
/// </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <param name="median"> The computed median. </param>
|
||||
/// <param name="epsilon"> (Optional) The epsilon value to stop algorithm. </param>
|
||||
/// <param name="maxIter"> (Optional) The maximum iteration allowed to find best Median. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> it's an iterative algorithm, so we have a limit of iterations and an epsilon value to consider the calculation as satisfactory. </remarks>
|
||||
bool MedianEuclidian(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median, const double epsilon = 0.0001, const size_t maxIter = 50);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Compute the median of vector of matrix with the Riemman Barycentre. <br/>
|
||||
/// - Initialize the median with the euclidian mean of matrices.
|
||||
/// - Iterate until the stop criterion (<c>iteration</c> over <c>maxIter</c> or \f$\text{gain}\f$ under <c>epsilon</c>).
|
||||
/// - Compute the tangent space projection of each matrices with median as reference.
|
||||
/// - Compute the sum (\f$\mathcal{S}\f$) of euclidian distance of each tangent space projection. <br/>
|
||||
/// \f[ \delta_E=\sqrt{\sum_{i \in N}{x_i^2}} \quad \text{with } x_i \text{ the feature } i \text{ of the tangent space projection}\f]
|
||||
/// - Compare with previous sum and stop if \f$\text{gain} < \varepsilon\f$. <br/>
|
||||
/// \f[ \text{gain} = \left|\frac{\mathcal{S} - \mathcal{S}_\text{prev}}{\mathcal{S}_\text{prev}}\right| \f]
|
||||
/// - Compute Median of each feature \f$i\f$ of tangent space projection.
|
||||
/// - Transform this tangent space projection median to riemann space with previous median as reference and update the median by this new matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <param name="median"> The computed median. </param>
|
||||
/// <param name="epsilon"> (Optional) The epsilon value to stop algorithm. </param>
|
||||
/// <param name="maxIter"> (Optional) The maximum iteration allowed to find best Median. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MedianRiemann(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median, const double epsilon = 0.0001, const size_t maxIter = 50);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Give the identity matrix has median. </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <param name="median"> The computed median. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool MedianIdentity(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Compute the median of vector of matrix with the Weiszfeld's algorithm for Euclidian Metric and Riemman Barycentre. </summary>
|
||||
/// <param name="matrices"> Vector of Matrix. </param>
|
||||
/// <param name="median"> The computed median. </param>
|
||||
/// <param name="epsilon"> (Optional) The epsilon value to stop algorithm. </param>
|
||||
/// <param name="maxIter"> (Optional) The maximum iteration allowed to find best Median. </param>
|
||||
/// <param name="metric"> (Optional) THe metric to use. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> it's an iterative algorithm, so we have a limit of iterations and an epsilon value to consider the calculation as satisfactory. </remarks>
|
||||
bool Median(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median,
|
||||
const double epsilon = 0.0001, const size_t maxIter = 50, const EMetric& metric = EMetric::Euclidian);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,69 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Metrics.hpp
|
||||
/// \brief All Metrics.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 26/10/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks
|
||||
/// - List of Metrics inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a> (<a href="https://github.com/alexandrebarachant/pyRiemann/blob/master/LICENSE">License</a>).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Enumeration of metrics. Inspired by the work of Alexandre Barachant : <a href="https://github.com/alexandrebarachant/pyRiemann">pyRiemann</a>. </summary>
|
||||
enum class EMetric
|
||||
{
|
||||
Riemann, ///< The Riemannian Metric.
|
||||
Euclidian, ///< The Euclidian Metric.
|
||||
LogEuclidian, ///< The Log Euclidian Metric.
|
||||
LogDet, ///< The Log Determinant Metric.
|
||||
Kullback, ///< The Kullback Metric.
|
||||
ALE, ///< The AJD-based log-Euclidean (ALE) Metric.
|
||||
Harmonic, ///< The Harmonic Metric.
|
||||
Wasserstein, ///< The Wasserstein Metric.
|
||||
Identity ///< The Identity Metric.
|
||||
};
|
||||
|
||||
/// <summary> Convert metric to string. </summary>
|
||||
/// <param name="metric"> The metric. </param>
|
||||
/// <returns> <c>std::string</c> </returns>
|
||||
inline std::string toString(const EMetric metric)
|
||||
{
|
||||
switch (metric)
|
||||
{
|
||||
case EMetric::Riemann: return "Riemann";
|
||||
case EMetric::Euclidian: return "Euclidian";
|
||||
case EMetric::LogEuclidian: return "Log Euclidian";
|
||||
case EMetric::LogDet: return "Log Determinant";
|
||||
case EMetric::Kullback: return "Kullback";
|
||||
case EMetric::ALE: return "AJD-based log-Euclidean";
|
||||
case EMetric::Harmonic: return "Harmonic";
|
||||
case EMetric::Wasserstein: return "Wasserstein";
|
||||
case EMetric::Identity: return "Identity";
|
||||
}
|
||||
return "Invalid Metric";
|
||||
}
|
||||
|
||||
/// <summary> Convert string to metric. </summary>
|
||||
/// <param name="metric"> The metric. </param>
|
||||
/// <returns> <see cref="EMetric"/> </returns>
|
||||
inline EMetric StringToMetric(const std::string& metric)
|
||||
{
|
||||
if (metric == "Riemann") { return EMetric::Riemann; }
|
||||
if (metric == "Euclidian") { return EMetric::Euclidian; }
|
||||
if (metric == "Log Euclidian") { return EMetric::LogEuclidian; }
|
||||
if (metric == "Log Determinant") { return EMetric::LogDet; }
|
||||
if (metric == "Kullback") { return EMetric::Kullback; }
|
||||
if (metric == "AJD-based log-Euclidean") { return EMetric::ALE; }
|
||||
if (metric == "Harmonic") { return EMetric::Harmonic; }
|
||||
if (metric == "Wasserstein") { return EMetric::Wasserstein; }
|
||||
return EMetric::Identity;
|
||||
}
|
||||
|
||||
} // namespace Geometry
|
||||
@@ -0,0 +1,104 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file Misc.hpp
|
||||
/// \brief All misc functions.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 29/07/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
/// \remarks This algortihms is inspired by the plugin clean_rawdata in <a href="https://sccn.ucsd.edu/eeglab/index.php">EEGLAB</a> (<a href="https://github.com/sccn/clean_rawdata/blob/master/LICENSE">License</a>).
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include "geometry/Metrics.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//------------------------------ Range ------------------------------
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Create a range of double value. </summary>
|
||||
/// <param name="begin"> Beginning of the range. </param>
|
||||
/// <param name="end"> End of the range. </param>
|
||||
/// <param name="step"> Step of the range. </param>
|
||||
/// <param name="closed"> Authorize the end in range if <c>True</c>. </param>
|
||||
/// <returns> The range vector. </returns>
|
||||
/// <remarks>Use [std::iota](https://en.cppreference.com/w/cpp/algorithm/iota) function and a struct for this specific used. </remarks>
|
||||
std::vector<double> doubleRange(const double begin, const double end, const double step = 1.0, const bool closed = true);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Create a range of index with double value rounded. </summary>
|
||||
/// <param name="begin"> Beginning of the range. </param>
|
||||
/// <param name="end"> End of the range. </param>
|
||||
/// <param name="step"> Step of the range. </param>
|
||||
/// <param name="closed"> Authorize the end in range if <c>True</c>. </param>
|
||||
/// <param name="unique"> Remove duplicate value if <c>True</c>. </param>
|
||||
/// <returns> The range vector. </returns>
|
||||
/// <remarks>Use [std::iota](https://en.cppreference.com/w/cpp/algorithm/iota) function and a struct for this specific used. </remarks>
|
||||
std::vector<size_t> RoundIndexRange(const double begin, const double end, const double step, const bool closed = true, const bool unique = true);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------ Fit Distribution ------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Commputes histogram of dataset extended in <c>n</c> bins, bins are computed from \f$[0;max]\f$ (values) to \f$[0;n]\f$ (bins). </summary>
|
||||
/// <param name="dataset"> Input vector (all datas are positive). </param>
|
||||
/// <param name="n"> Number of bin of the final histogram. </param>
|
||||
std::vector<size_t> BinHist(const std::vector<double>& dataset, const size_t n);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Get a Fit distribution. </summary>
|
||||
/// <param name="values"> The values. </param>
|
||||
/// <param name="mu"> The mu. </param>
|
||||
/// <param name="sigma"> The sigma. </param>
|
||||
/// <param name="betas"> List of wanted \f$\beta\f$ shapes. </param>
|
||||
/// <param name="minQuant"> Minimum of wanted quantile (in range [0, 1]). </param>
|
||||
/// <param name="maxQuant"> Maximum of wanted quantile (in range [0, 1]). </param>
|
||||
/// <param name="minClean"> Minimum of estimated clean datas (only positive value). </param>
|
||||
/// <param name="maxDropout"> Maximum of estimated artifact datas (only positive value). </param>
|
||||
/// <param name="stepBound"> Step used to select beginning of datas subset (in range [0.0001, 0.1]). </param>
|
||||
/// <param name="stepScale"> Step used to select size of datas subset (in range [0.0001, 0.1]). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool FitDistribution(const std::vector<double>& values, double& mu, double& sigma,
|
||||
const std::vector<double>& betas = doubleRange(1.7, 3.5, 0.15),
|
||||
const double minQuant = 0.022, const double maxQuant = 0.60,
|
||||
const double minClean = 0.250, const double maxDropout = 0.10,
|
||||
const double stepBound = 0.010, const double stepScale = 0.01);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
//------------------------------ Riemannian Eigen Values ------------------------------
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Compute sorted eigen vector of the matrix. </summary>
|
||||
/// <param name="matrix"> the input matrix. </param>
|
||||
/// <param name="vectors"> Sorted eigen vectors. </param>
|
||||
/// <param name="values"> Sorted eigen values. </param>
|
||||
/// <param name="metric"> metric used for vectors. </param>
|
||||
/// <remarks> Actually only euclidian method is implemented. <br/>
|
||||
/// For Riemmanian metric, we must have some optimisation algorithm. </remarks>
|
||||
void sortedEigenVector(const Eigen::MatrixXd& matrix, Eigen::MatrixXd& vectors, std::vector<double>& values, const EMetric metric = EMetric::Euclidian);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Compute the eigen vector of the input matrix. </summary>
|
||||
/// <param name="matrix"> input Matrix. </param>
|
||||
/// <param name="vectors"> Sorted eigen vectors. </param>
|
||||
/// <param name="values"> Sorted eigen values. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> This algorithm is in <a href="https://sccn.ucsd.edu/eeglab/index.php">EEGLAB</a> plugin and inspired by the paper "A Riemannian Newton Algorithm for Nonlinear Eigenvalue Problems", Zhi Zhao, Zheng - Jian Bai, and Xiao - Qing Jin, SIAM Journal on Matrix Analysisand Applications, 36(2), 752 - 774, 2015. </remarks>
|
||||
//bool RiemannianNonLinearEigenVector(const Eigen::MatrixXd& matrix, Eigen::MatrixXd& vectors, std::vector<double>& values);
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
} // namespace Geometry
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CASR.hpp
|
||||
/// \brief Class used to use Artifact Subspace Reconstruction Algorithm.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 27/08/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include "geometry/Basics.hpp"
|
||||
#include "geometry/Metrics.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class For Artifact Subspace Reconstruction (ASR) Algorithm. </summary>
|
||||
class CASR
|
||||
{
|
||||
public:
|
||||
|
||||
CASR() = default; ///< Initializes a new instance of the <see cref="CASR"/> class.
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CASR"/> class with specified <c>metric</c>. </summary>
|
||||
/// <remarks> Only Euclidian and Riemmann metrics are implemented If other is selected, Euclidian is used. </remarks>
|
||||
explicit CASR(const EMetric& metric) { setMetric(metric); }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CASR"/> class with specified <c>metric</c> and train with the specified <c>dataset</c>. </summary>
|
||||
/// <remarks> Only Euclidian and Riemmann metrics are implemented If other is selected, Euclidian is used. </remarks>
|
||||
explicit CASR(const EMetric& metric, const std::vector<Eigen::MatrixXd>& dataset)
|
||||
{
|
||||
setMetric(metric);
|
||||
train(dataset);
|
||||
}
|
||||
|
||||
~CASR() = default; ///< Finalizes an instance of the <see cref="CASR"/> class.
|
||||
|
||||
/// <summary> Trains the specified dataset. </summary>
|
||||
/// <param name="dataset"> The dataset (Vector of signal window). </param>
|
||||
/// <param name="rejectionLimit"> The rejection limit. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool train(const std::vector<Eigen::MatrixXd>& dataset, const double rejectionLimit = 5);
|
||||
|
||||
/// <summary> Apply the ASR algorithm to the input signal. </summary>
|
||||
/// <param name="in"> The input signal. </param>
|
||||
/// <param name="out"> The corrected signal. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool process(const Eigen::MatrixXd& in, Eigen::MatrixXd& out);
|
||||
|
||||
//***************************
|
||||
//***** Getter / Setter *****
|
||||
//***************************
|
||||
|
||||
/// <summary> Set the metric to use (only Riemann and euclidian is used). </summary>
|
||||
/// <param name="metric">The metric. </param>
|
||||
/// <remarks> If invalid metric is used Euclidian is selected. </remarks>
|
||||
void setMetric(const EMetric& metric) { m_metric = (metric == EMetric::Riemann) ? EMetric::Riemann : EMetric::Euclidian; }
|
||||
|
||||
/// <summary> Sets the number of channel (dimension) to reconstruct in fraction, 0 for nothing 1 for all. </summary>
|
||||
/// <param name="max"> The maximum ratio. </param>
|
||||
/// <remarks> If value isn't in [0;1], this function does nothing. </remarks>
|
||||
void setMaxChannel(const double max) { if (InRange(max, 0.0, 1.0)) { m_maxChannel = max; } }
|
||||
|
||||
/// <summary> Sets the differents matrices : median matrix, trheshold matrix, reconstruction matrix and covariance matrix. </summary>
|
||||
/// <param name="median"> The median matrix. </param>
|
||||
/// <param name="threshold"> The threshold matrix. </param>
|
||||
/// <param name="reconstruct"> (Optional) The reconstruct matrix. </param>
|
||||
/// <param name="covariance"> (Optional) The covariance matrix. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> All matrices must be square with same size (or empty for reconstruct and covariance matrix).
|
||||
/// Trivial trigger is set to true. </remarks>
|
||||
bool setMatrices(const Eigen::MatrixXd& median, const Eigen::MatrixXd& threshold,
|
||||
const Eigen::MatrixXd& reconstruct = Eigen::MatrixXd(), const Eigen::MatrixXd& covariance = Eigen::MatrixXd());
|
||||
|
||||
EMetric getMetric() const { return m_metric; } ///< Get the metric.
|
||||
size_t getChannelNumber() const { return m_nChannel; } ///< Get the matrices number of channel.
|
||||
double getMaxChannel() const { return m_maxChannel; } ///< Get the number of channel (dimension) to reconstruct in fraction.
|
||||
bool getTrivial() const { return m_trivial; } ///< Get is last reconstruct was trivial (first time or if previous doesn't need reconstruct).
|
||||
Eigen::MatrixXd getMedian() const { return m_median; } ///< Get the median matrix.
|
||||
Eigen::MatrixXd getThresholdMatrix() const { return m_threshold; } ///< Get the threshold matrix.
|
||||
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Saves the ASR information in an XML file. </summary>
|
||||
/// <param name="filename"> Filename. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveXML(const std::string& filename) const;
|
||||
|
||||
/// <summary> Loads the ASR information from an XML file. </summary>
|
||||
/// <param name="filename"> Filename. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadXML(const std::string& filename);
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance), <c>False</c> otherwise. </returns>
|
||||
bool isEqual(const CASR& obj, const double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const CASR& obj);
|
||||
|
||||
/// <summary> Get the ASR information for output. </summary>
|
||||
/// <returns> The ASR print in stringstream. </returns>
|
||||
std::stringstream print() const;
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CASR& operator=(const CASR& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CASR"/> are equals. </returns>
|
||||
bool operator==(const CASR& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CASR"/> are diffrents. </returns>
|
||||
bool operator!=(const CASR& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CASR& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
EMetric m_metric = EMetric::Euclidian; ///< Metric Used to compute (only euclidian and Riemann are implemented
|
||||
size_t m_nChannel = 0; ///< Number of channels (dimension)
|
||||
double m_maxChannel = 1; ///< Maximum number of channels (dimension) to reconstruct if needed (in fraction, 0 for nothing 1 for all).
|
||||
bool m_trivial = true; ///< Define if previous sample was trivial to reconstruct
|
||||
Eigen::MatrixXd m_median; ///< Median computed with train dataset
|
||||
Eigen::MatrixXd m_threshold; ///< Threshold matrix computed with train dataset
|
||||
Eigen::MatrixXd m_r; ///< Last Reconstruction matrix
|
||||
Eigen::MatrixXd m_cov; ///< Last Covariance matrix
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CBias.hpp
|
||||
/// \brief Class used to add Rebias to Other Classifier.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 27/08/2019.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include "geometry/Metrics.hpp"
|
||||
#include "geometry/3rd-party/tinyxml2.h"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class For Bias Algorithm for covariance matrices. </summary>
|
||||
class CBias
|
||||
{
|
||||
public:
|
||||
/// <summary> Initializes a new instance of the <see cref="CBias"/> class. </summary>
|
||||
CBias() = default;
|
||||
/// <summary> Finalizes an instance of the <see cref="CBias"/> class. </summary>
|
||||
~CBias() = default;
|
||||
|
||||
/// <summary> Computes the Bias matrix and reset the number of classification. </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as matrix). </param>
|
||||
/// <param name="metric"> The metric. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool computeBias(const std::vector<std::vector<Eigen::MatrixXd>>& dataset, const EMetric metric = EMetric::Riemann);
|
||||
|
||||
/// <summary> Computes the Bias matrix and reset the number of classification. </summary>
|
||||
/// <param name="dataset"> The dataset is a vector of trial as matrix. </param>
|
||||
/// <param name="metric"> The metric. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool computeBias(const std::vector<Eigen::MatrixXd>& dataset, const EMetric metric = EMetric::Riemann);
|
||||
|
||||
/// <summary> Applies the Bias on 2D vector of Matrix. </summary>
|
||||
/// <param name="in"> The input 2D vector of matrix. </param>
|
||||
/// <param name="out"> The output 2D vector of matrix. </param>
|
||||
void applyBias(const std::vector<std::vector<Eigen::MatrixXd>>& in, std::vector<std::vector<Eigen::MatrixXd>>& out);
|
||||
/// <summary> Applies the Bias on vector of Matrix. </summary>
|
||||
/// <param name="in"> The input vector of matrix. </param>
|
||||
/// <param name="out"> The output vector of matrix. </param>
|
||||
void applyBias(const std::vector<Eigen::MatrixXd>& in, std::vector<Eigen::MatrixXd>& out);
|
||||
/// <summary> Applies the Bias on Matrix. </summary>
|
||||
/// <param name="in"> The input matrix. </param>
|
||||
/// <param name="out"> The output matrix. </param>
|
||||
void applyBias(const Eigen::MatrixXd& in, Eigen::MatrixXd& out);
|
||||
|
||||
/// <summary> Updates the Bias. </summary>
|
||||
/// <param name="sample"> The sample. </param>
|
||||
/// <param name="metric"> The metric. </param>
|
||||
void updateBias(const Eigen::MatrixXd& sample, const EMetric metric = EMetric::Riemann);
|
||||
|
||||
const Eigen::MatrixXd& getBias() const { return m_bias; } ///< Get the bias matrix.
|
||||
void setBias(const Eigen::MatrixXd& bias); ///< Set the bias matrix and the inverse square root of biais.
|
||||
|
||||
size_t getClassificationNumber() const { return m_n; } ///< Get the Number of classification (used for update).
|
||||
void setClassificationNumber(const size_t& n) { m_n = n; } ///< Set the Number of classification (used for update).
|
||||
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Saves the Bias information in an XML file. </summary>
|
||||
/// <param name="filename"> Filename. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveXML(const std::string& filename) const;
|
||||
|
||||
/// <summary> Loads the Bias information from an XML file. </summary>
|
||||
/// <param name="filename"> Filename. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadXML(const std::string& filename);
|
||||
|
||||
/// <summary> Save informations in xml element (Bias and number of classification). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveAdditional(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* data) const;
|
||||
|
||||
/// <summary> Load informations in xml element (Bias and number of classification). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadAdditional(tinyxml2::XMLElement* data);
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance), <c>False</c> otherwise. </returns>
|
||||
bool isEqual(const CBias& obj, const double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const CBias& obj);
|
||||
|
||||
/// <summary> Get the Classifier information for output. </summary>
|
||||
/// <returns> The Classifier print in stringstream. </returns>
|
||||
std::stringstream print() const;
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CBias& operator=(const CBias& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CBias"/> are equals. </returns>
|
||||
bool operator==(const CBias& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CBias"/> are diffrents. </returns>
|
||||
bool operator!=(const CBias& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CBias& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
size_t m_n = 0; ///< Number of classification launched (used for update).
|
||||
Eigen::MatrixXd m_bias; ///< Bias Matrix.
|
||||
Eigen::MatrixXd m_biasIS; ///< Inverse squared root bias matrix (stored and pre-computed for application of bias).
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CMatrixClassifierFgMDM.hpp
|
||||
/// \brief Class of Minimum Distance to Mean with geodesic filtering (FgMDM) Classifier.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 10/12/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/classifier/CMatrixClassifierFgMDMRT.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class of Minimum Distance to Mean with geodesic filtering (FgMDM) Classifier. </summary>
|
||||
/// <seealso cref="CMatrixClassifierMDM" />
|
||||
class CMatrixClassifierFgMDM final : public CMatrixClassifierFgMDMRT
|
||||
{
|
||||
public:
|
||||
//***********************
|
||||
//***** Constructor *****
|
||||
//***********************
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierFgMDM"/> class. </summary>
|
||||
CMatrixClassifierFgMDM() = default;
|
||||
|
||||
/// <summary> Default Copy constructor. Initializes a new instance of the <see cref="CMatrixClassifierFgMDM"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
CMatrixClassifierFgMDM(const CMatrixClassifierFgMDM& obj) { *this = obj; }
|
||||
|
||||
/// <summary> Copy constructor with parent class. Initializes a new instance of the <see cref="CMatrixClassifierFgMDM"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
explicit CMatrixClassifierFgMDM(const CMatrixClassifierFgMDMRT& obj) { copy(obj); }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierFgMDM"/> class and set base members. </summary>
|
||||
/// <param name="nbClass"> The number of classes. </param>
|
||||
/// <param name="metric"> Metric to use to calculate means (see also <see cref="EMetric" />). </param>
|
||||
explicit CMatrixClassifierFgMDM(const size_t nbClass, const EMetric metric) : CMatrixClassifierFgMDMRT(nbClass, metric) { }
|
||||
|
||||
/// <summary> Finalizes an instance of the <see cref="CMatrixClassifierFgMDM"/> class. </summary>
|
||||
/// <remarks> clear the <see cref="m_means"/> vector of Matrix and the <see cref="m_dataset"/> member. </remarks>
|
||||
~CMatrixClassifierFgMDM() override;
|
||||
|
||||
//***************************
|
||||
//***** Getter / Setter *****
|
||||
//***************************
|
||||
void setDataset(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) { m_dataset = dataset; } ///< Set dataset.
|
||||
const std::vector<std::vector<Eigen::MatrixXd>>& getDataset() const { return m_dataset; } ///< Get dataset.
|
||||
|
||||
//**********************
|
||||
//***** Classifier *****
|
||||
//**********************
|
||||
/// <summary> Train the classifier with the dataset.
|
||||
/// -# Compute the Riemann mean of all trials as reference and store this in <see cref="m_ref"/> member.
|
||||
/// -# Set the good number of classes
|
||||
/// -# Trasnform data to the Tangent Space with the reference
|
||||
/// -# Compute the FgDA Weight (<see cref="FgDACompute" />).
|
||||
/// -# Apply the FgDA Weight and return to Original Manifold.
|
||||
/// -# Apply the train function of MDM Classifier (see <see cref="CMatrixClassifierMDM::train"/>)
|
||||
/// </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as covariance matrix). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <remarks> the dataset is saved. </remarks>
|
||||
bool train(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) override;
|
||||
|
||||
/// <summary> Classify the matrix and return the class id, the distance and the probability of each class.\n
|
||||
/// -# Transform the sample to the Tangent Space.\n
|
||||
/// -# Apply the FgDA weight.\n
|
||||
/// -# Return to the original Manifold.\n
|
||||
/// -# Apply the classify function of MDM Classifier (see <see cref="CMatrixClassifierMDM::classify"/>)
|
||||
/// </summary>
|
||||
/// <remarks> The classifier is train with the new sample. </remarks>
|
||||
/// \copydetails IMatrixClassifier::classify(const Eigen::MatrixXd&, size_t&, std::vector<double>&, std::vector<double>&, const EAdaptations, const size_t&)
|
||||
bool classify(const Eigen::MatrixXd& sample, size_t& classId, std::vector<double>& distance, std::vector<double>& probability,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max()) override;
|
||||
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
|
||||
/// <summary> Get the type of the classifier. </summary>
|
||||
/// <returns> Minimum Distance to Mean with geodesic filtering (FgMDM). </returns>
|
||||
std::string getType() const override { return toString(EMatrixClassifiers::FgMDM); }
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CMatrixClassifierFgMDM& operator=(const CMatrixClassifierFgMDM& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CMatrixClassifierFgMDM& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
///<summary> train with the actual dataset (<see cref="m_dataset"/>). </summary>
|
||||
bool train() { return CMatrixClassifierFgMDMRT::train(m_dataset); }
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
std::vector<std::vector<Eigen::MatrixXd>> m_dataset; ///< Data set for train and adaptation (it can quickly rise).
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CMatrixClassifierFgMDMRT.hpp
|
||||
/// \brief Class of Minimum Distance to Mean with geodesic filtering (FgMDM) Classifier RT (adaptation is Real Time Assumed)
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 10/12/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/classifier/CMatrixClassifierMDM.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class of Minimum Distance to Mean with geodesic filtering (FgMDM) Classifier RT (adaptation is Real Time Assumed). </summary>
|
||||
/// <seealso cref="CMatrixClassifierMDM" />
|
||||
class CMatrixClassifierFgMDMRT : public CMatrixClassifierMDM
|
||||
{
|
||||
public:
|
||||
//***********************
|
||||
//***** Constructor *****
|
||||
//***********************
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierFgMDMRT"/> class. </summary>
|
||||
CMatrixClassifierFgMDMRT() = default;
|
||||
|
||||
/// <summary> Default Copy constructor. Initializes a new instance of the <see cref="CMatrixClassifierFgMDMRT"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
CMatrixClassifierFgMDMRT(const CMatrixClassifierFgMDMRT& obj) { *this = obj; }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierFgMDMRT"/> class and set base members. </summary>
|
||||
/// <param name="nbClass"> The number of classes. </param>
|
||||
/// <param name="metric"> Metric to use to calculate means (see also <see cref="EMetric" />). </param>
|
||||
explicit CMatrixClassifierFgMDMRT(const size_t nbClass, const EMetric metric) : CMatrixClassifierMDM(nbClass, metric) { }
|
||||
|
||||
/// <summary> Finalizes an instance of the <see cref="CMatrixClassifierFgMDMRT"/> class. </summary>
|
||||
/// <remarks> clear the <see cref="m_means"/> vector of Matrix. </remarks>
|
||||
~CMatrixClassifierFgMDMRT() override = default;
|
||||
|
||||
//***************************
|
||||
//***** Getter / Setter *****
|
||||
//***************************
|
||||
const Eigen::MatrixXd& getRef() const { return m_ref; } ///< Get reference of tangent space.
|
||||
void setRef(const Eigen::MatrixXd& ref) { m_ref = ref; } ///< Set reference of tangent space.
|
||||
|
||||
const Eigen::MatrixXd& getWeight() const { return m_weight; } ///< Get weight matrix of geodesic filter.
|
||||
void setWeight(const Eigen::MatrixXd& weight) { m_weight = weight; } ///< Set weight matrix of geodesic filter.
|
||||
|
||||
//**********************
|
||||
//***** Classifier *****
|
||||
//**********************
|
||||
/// <summary> Train the classifier with the dataset.
|
||||
/// -# Compute the Riemann mean of all trials as reference and store this in <see cref="m_ref"/> member.
|
||||
/// -# Set the good number of classes
|
||||
/// -# Trasnform data to the Tangent Space with the reference
|
||||
/// -# Compute the FgDA Weight (<see cref="FgDACompute" />).
|
||||
/// -# Apply the FgDA Weight and return to Original Manifold.
|
||||
/// -# Apply the train function of MDM Classifier (see <see cref="CMatrixClassifierMDM::train"/>)
|
||||
/// </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as covariance matrix). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool train(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) override;
|
||||
|
||||
/// <summary> Classify the matrix and return the class id, the distance and the probability of each class.\n
|
||||
/// -# Transform the sample to the Tangent Space.\n
|
||||
/// -# Apply the FgDA weight.\n
|
||||
/// -# Return to the original Manifold.\n
|
||||
/// -# Apply the classify function of MDM Classifier (see <see cref="CMatrixClassifierMDM::classify"/>)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Remark</b> : We use the MDM classification whatever the adaptation method chosen.
|
||||
/// Thus the MDM part evolves but the geodesic filtering does not evolve to keep an execution online.
|
||||
/// A version allowing the adaptation of the Filter will be implemented for offline execution.
|
||||
/// </remarks>
|
||||
/// \copydetails IMatrixClassifier::classify(const Eigen::MatrixXd&, size_t&, std::vector<double>&, std::vector<double>&, const EAdaptations, const size_t&)
|
||||
bool classify(const Eigen::MatrixXd& sample, size_t& classId, std::vector<double>& distance, std::vector<double>& probability,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max()) override;
|
||||
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance). </returns>
|
||||
bool isEqual(const CMatrixClassifierFgMDMRT& obj, double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const CMatrixClassifierFgMDMRT& obj);
|
||||
|
||||
/// <summary> Get the type of the classifier. </summary>
|
||||
/// <returns> Minimum Distance to Mean with geodesic filtering (FgMDM). </returns>
|
||||
std::string getType() const override { return toString(EMatrixClassifiers::FgMDM_RT); }
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CMatrixClassifierFgMDMRT& operator=(const CMatrixClassifierFgMDMRT& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierFgMDMRT"/> are equals. </returns>
|
||||
bool operator==(const CMatrixClassifierFgMDMRT& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierFgMDMRT"/> are diffrents. </returns>
|
||||
bool operator!=(const CMatrixClassifierFgMDMRT& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CMatrixClassifierFgMDMRT& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Save Additionnal informations (Reference and LDA Weight). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveAdditional(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* data) const override;
|
||||
|
||||
/// <summary> Load Additionnal informations (Reference and LDA Weight). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadAdditional(tinyxml2::XMLElement* data) override;
|
||||
|
||||
/// <summary> Prints the Additional informations (Reference and LDA Weight). </summary>
|
||||
/// <returns> Additional informations in stringstream. </returns>
|
||||
std::stringstream printAdditional() const override;
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
Eigen::MatrixXd m_ref; ///< Reference matrix of tanget space.
|
||||
Eigen::MatrixXd m_weight; ///< Weght matrix of Filter Geodesic Discriminant Analysis.
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CMatrixClassifierFgMDMRTRebias.hpp
|
||||
/// \brief Class of Minimum Distance to Mean with geodesic filtering (FgMDM) Classifier RT (adaptation is Real Time Assumed)
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 10/12/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/classifier/CMatrixClassifierFgMDMRT.hpp"
|
||||
#include "geometry/classifier/CBias.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class of Minimum Distance to Mean with geodesic filtering (FgMDM) Classifier RT (adaptation is Real Time Assumed). </summary>
|
||||
/// <seealso cref="CMatrixClassifierFgMDMRT" />
|
||||
class CMatrixClassifierFgMDMRTRebias final : public CMatrixClassifierFgMDMRT
|
||||
{
|
||||
public:
|
||||
//***********************
|
||||
//***** Constructor *****
|
||||
//***********************
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierFgMDMRTRebias"/> class. </summary>
|
||||
CMatrixClassifierFgMDMRTRebias() = default;
|
||||
|
||||
/// <summary> Default Copy constructor. Initializes a new instance of the <see cref="CMatrixClassifierFgMDMRTRebias"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
CMatrixClassifierFgMDMRTRebias(const CMatrixClassifierFgMDMRTRebias& obj) { *this = obj; }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierFgMDMRTRebias"/> class and set base members. </summary>
|
||||
/// <param name="nbClass"> The number of classes. </param>
|
||||
/// <param name="metric"> Metric to use to calculate means (see also <see cref="EMetric" />). </param>
|
||||
explicit CMatrixClassifierFgMDMRTRebias(const size_t nbClass, const EMetric metric) : CMatrixClassifierFgMDMRT(nbClass, metric) { }
|
||||
|
||||
/// <summary> Finalizes an instance of the <see cref="CMatrixClassifierFgMDMRTRebias"/> class. </summary>
|
||||
/// <remarks> clear the <see cref="m_means"/> vector of Matrix. </remarks>
|
||||
~CMatrixClassifierFgMDMRTRebias() override = default;
|
||||
|
||||
//***************************
|
||||
//***** Getter / Setter *****
|
||||
//***************************
|
||||
const CBias& getBias() const { return m_bias; } ///< Get Rebias Method.
|
||||
void setBias(const CBias& bias) { m_bias = bias; } ///< Set Rebias Method.
|
||||
|
||||
//**********************
|
||||
//***** Classifier *****
|
||||
//**********************
|
||||
/// <summary> Train the classifier with the dataset.
|
||||
/// -# Compute the Riemann mean of all trials as reference and store this in <see cref="m_ref"/> member.
|
||||
/// -# Set the good number of classes
|
||||
/// -# Trasnform data to the Tangent Space with the reference
|
||||
/// -# Compute the FgDA Weight (<see cref="FgDACompute" />).
|
||||
/// -# Apply the FgDA Weight and return to Original Manifold.
|
||||
/// -# Apply the train function of MDM Classifier (see <see cref="CMatrixClassifierMDM::train"/>)
|
||||
/// </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as covariance matrix). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool train(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) override;
|
||||
|
||||
/// <summary> Classify the matrix and return the class id, the distance and the probability of each class.\n
|
||||
/// -# Transform the sample to the Tangent Space.\n
|
||||
/// -# Apply the FgDA weight.\n
|
||||
/// -# Return to the original Manifold.\n
|
||||
/// -# Apply the classify function of MDM Classifier (see <see cref="CMatrixClassifierMDM::classify"/>)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Remark</b> : We use the MDM classification whatever the adaptation method chosen.
|
||||
/// Thus the MDM part evolves but the geodesic filtering does not evolve to keep an execution online.
|
||||
/// A version allowing the adaptation of the Filter will be implemented for offline execution.
|
||||
/// </remarks>
|
||||
/// \copydetails IMatrixClassifier::classify(const Eigen::MatrixXd&, size_t&, std::vector<double>&, std::vector<double>&, const EAdaptations, const size_t&)
|
||||
bool classify(const Eigen::MatrixXd& sample, size_t& classId, std::vector<double>& distance, std::vector<double>& probability,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max()) override;
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance). </returns>
|
||||
bool isEqual(const CMatrixClassifierFgMDMRTRebias& obj, double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const CMatrixClassifierFgMDMRTRebias& obj);
|
||||
|
||||
/// <summary> Get the type of the classifier. </summary>
|
||||
/// <returns> Minimum Distance to Mean with geodesic filtering (FgMDM). </returns>
|
||||
std::string getType() const override { return toString(EMatrixClassifiers::FgMDM_RT_Rebias); }
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CMatrixClassifierFgMDMRTRebias& operator=(const CMatrixClassifierFgMDMRTRebias& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierFgMDMRTRebias"/> are equals. </returns>
|
||||
bool operator==(const CMatrixClassifierFgMDMRTRebias& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierFgMDMRTRebias"/> are diffrents. </returns>
|
||||
bool operator!=(const CMatrixClassifierFgMDMRTRebias& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CMatrixClassifierFgMDMRTRebias& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Save Additionnal informations (Reference and LDA Weight). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveAdditional(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* data) const override;
|
||||
|
||||
/// <summary> Load Additionnal informations (Reference and LDA Weight). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadAdditional(tinyxml2::XMLElement* data) override;
|
||||
|
||||
/// <summary> Prints the Additional informations (Reference and LDA Weight). </summary>
|
||||
/// <returns> Additional informations in stringstream. </returns>
|
||||
std::stringstream printAdditional() const override;
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
CBias m_bias; ///< Rebias Method.
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CMatrixClassifierMDM.hpp
|
||||
/// \brief Class of Minimum Distance to Mean (MDM) Classifier
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 10/12/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/classifier/IMatrixClassifier.hpp"
|
||||
#include "geometry/Metrics.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class of Minimum Distance to Mean (MDM) Classifier. </summary>
|
||||
/// <seealso cref="IMatrixClassifier" />
|
||||
class CMatrixClassifierMDM : public IMatrixClassifier
|
||||
{
|
||||
public:
|
||||
//***********************
|
||||
//***** Constructor *****
|
||||
//***********************
|
||||
/// <summary> Default constructor. Initializes a new instance of the <see cref="CMatrixClassifierMDM"/> class. </summary>
|
||||
CMatrixClassifierMDM() { CMatrixClassifierMDM::setClassCount(m_nbClass); }
|
||||
|
||||
/// <summary> Default Copy constructor. Initializes a new instance of the <see cref="CMatrixClassifierMDM"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
CMatrixClassifierMDM(const CMatrixClassifierMDM& obj) { *this = obj; }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierMDM"/> class and set base members. </summary>
|
||||
/// <param name="nbClass"> The number of classes. </param>
|
||||
/// <param name="metric"> Metric to use to calculate means (see also <see cref="EMetric" />). </param>
|
||||
explicit CMatrixClassifierMDM(size_t nbClass, EMetric metric);
|
||||
|
||||
/// <summary> Finalizes an instance of the <see cref="CMatrixClassifierMDM"/> class. </summary>
|
||||
/// <remarks> clear the <see cref="m_means"/> vector of Matrix. </remarks>
|
||||
~CMatrixClassifierMDM() override;
|
||||
|
||||
//***************************
|
||||
//***** Getter / Setter *****
|
||||
//***************************
|
||||
const std::vector<Eigen::MatrixXd>& getMeans() const { return m_means; } ///< Get Means of classes.
|
||||
void setMeans(const std::vector<Eigen::MatrixXd>& means) { m_means = means; } ///< Set Means of classes.
|
||||
|
||||
const std::vector<size_t>& getTrialNumbers() const { return m_nbTrials; } ///< Get the number of trial used for train.
|
||||
void setTrialNumbers(const std::vector<size_t>& nbTrials) { m_nbTrials = nbTrials; } ///< Set the number of trial used for train.
|
||||
|
||||
//**********************
|
||||
//***** Classifier *****
|
||||
//**********************
|
||||
/// <summary> Set the class count. </summary>
|
||||
/// <remarks> resize the <see cref="m_means"/> vector of Matrix. </remarks>
|
||||
void setClassCount(size_t nbClass) override;
|
||||
|
||||
/// <summary> Train the classifier with the dataset.
|
||||
/// -# Set the good number of classes
|
||||
/// -# Compute the mean of each class (row) with the metric (<see cref="EMetric" />) in <see cref="m_metric"/> member.
|
||||
/// -# Set the number of trials for each class.
|
||||
/// </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as covariance matrix). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool train(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) override;
|
||||
|
||||
/// <summary> Classify the matrix and return the class id, the distance and the probability of each class.\n
|
||||
/// - Compute the distance between the sample and each mean matrix.\n
|
||||
/// - The class with the closest mean is the predicted class.\n
|
||||
/// - The distances are returned.\n
|
||||
/// - The probability \f$ \mathcal{P}_i \f$ to be the class \f$ i \f$ is compute as :
|
||||
/// \f[
|
||||
/// \begin{aligned}
|
||||
/// p_i &= \frac{d_{\text{min}}}{d_i}\\
|
||||
/// \mathcal{P}_i &= \frac{p_i}{\sum{\left(p_i\right)}}
|
||||
/// \end{aligned}
|
||||
/// \f]
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Remark</b> : The probability is normalized \f$ \sum{\left(\mathcal{P}_i\right)} = 1 \f$\n
|
||||
/// If the classfier is adapted, launch adaptation method (expected class if supervised, predicted class if unsupervised).\n
|
||||
/// With \f$ C_k \f$ the prototype (mean) of the Class \f$ k \f$, \f$ \gamma_m \f$ the Geodesic (<see cref="Geodesic" />) with the metric \f$ m \f$ (<see cref="EMetric" />),
|
||||
/// \f$ S \f$ the current trial (sample) and \f$ N_k \f$ the number of trials for the class \f$ k \f$ (with the current trial).
|
||||
/// \f[
|
||||
/// C_k = \gamma_m\left( C_k,S,\frac{1}{N_k}\right)
|
||||
/// \f]
|
||||
/// </remarks>
|
||||
/// \copydetails IMatrixClassifier::classify(const Eigen::MatrixXd&, size_t&, std::vector<double>&, std::vector<double>&, const EAdaptations, const size_t&)
|
||||
bool classify(const Eigen::MatrixXd& sample, size_t& classId, std::vector<double>& distance, std::vector<double>& probability,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max()) override;
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance). </returns>
|
||||
bool isEqual(const CMatrixClassifierMDM& obj, double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const CMatrixClassifierMDM& obj);
|
||||
|
||||
/// <summary> Get the type of the classifier. </summary>
|
||||
/// <returns> Minimum Distance to Mean. </returns>
|
||||
std::string getType() const override { return toString(EMatrixClassifiers::MDM); }
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CMatrixClassifierMDM& operator=(const CMatrixClassifierMDM& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierMDM"/> are equals. </returns>
|
||||
bool operator==(const CMatrixClassifierMDM& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierMDM"/> are diffrents. </returns>
|
||||
bool operator!=(const CMatrixClassifierMDM& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CMatrixClassifierMDM& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Save Classes informations (Mean and number of trials of each class). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveClasses(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* data) const override;
|
||||
|
||||
/// <summary> Load Classes informations (Mean and number of trials of each class). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadClasses(tinyxml2::XMLElement* data) override;
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
std::stringstream printClasses() const override;
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
std::vector<Eigen::MatrixXd> m_means; ///< Mean Matrix of each class.
|
||||
std::vector<size_t> m_nbTrials; ///< Number of trials of each class.
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CMatrixClassifierMDMRebias.hpp
|
||||
/// \brief Class of Minimum Distance to Mean (MDM) Classifier with Rebias.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 10/12/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "geometry/classifier/CMatrixClassifierMDM.hpp"
|
||||
#include "geometry/Metrics.hpp"
|
||||
#include "geometry/classifier/CBias.hpp"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
/// <summary> Class of Minimum Distance to Mean (MDM) Classifier with Rebias. </summary>
|
||||
/// <seealso cref="IMatrixClassifier" />
|
||||
class CMatrixClassifierMDMRebias final : public CMatrixClassifierMDM
|
||||
{
|
||||
public:
|
||||
//***********************
|
||||
//***** Constructor *****
|
||||
//***********************
|
||||
/// <summary> Default constructor. Initializes a new instance of the <see cref="CMatrixClassifierMDMRebias"/> class. </summary>
|
||||
CMatrixClassifierMDMRebias() = default;
|
||||
|
||||
/// <summary> Default Copy constructor. Initializes a new instance of the <see cref="CMatrixClassifierMDMRebias"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
CMatrixClassifierMDMRebias(const CMatrixClassifierMDMRebias& obj) { *this = obj; }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="CMatrixClassifierMDMRebias"/> class and set base members. </summary>
|
||||
/// <param name="nbClass"> The number of classes. </param>
|
||||
/// <param name="metric"> Metric to use to calculate means (see also <see cref="EMetric" />). </param>
|
||||
explicit CMatrixClassifierMDMRebias(const size_t nbClass, const EMetric metric) : CMatrixClassifierMDM(nbClass, metric) { }
|
||||
|
||||
/// <summary> Finalizes an instance of the <see cref="CMatrixClassifierMDMRebias"/> class. </summary>
|
||||
~CMatrixClassifierMDMRebias() override = default;
|
||||
|
||||
//***************************
|
||||
//***** Getter / Setter *****
|
||||
//***************************
|
||||
const CBias& getBias() const { return m_bias; } ///< Get Rebias Method.
|
||||
void setBias(const CBias& bias) { m_bias = bias; } ///< Set Rebias Method.
|
||||
|
||||
//**********************
|
||||
//***** Classifier *****
|
||||
//**********************
|
||||
|
||||
/// <summary> Train the classifier with the dataset.
|
||||
/// -# Compute the mean of all trials with the metric (<see cref="EMetric" />) in <see cref="m_metric"/> member as reference and store this in <see cref="m_bias"/> member.
|
||||
/// -# Set the good number of classes
|
||||
/// -# Apply an affine transformation on each trials with the reference : \f$ S_\text{new} = R^{-1/2} * S * {R^{-1/2}}^{\mathsf{T}} \f$
|
||||
/// -# Compute the mean of each class (row), on transformed trials, with the metric (<see cref="EMetric" />) in <see cref="m_metric"/> member.
|
||||
/// -# Set the number of trials for each class.
|
||||
/// </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as covariance matrix). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool train(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) override;
|
||||
|
||||
/// <summary> Classify the matrix and return the class id, the distance and the probability of each class.
|
||||
/// -# Apply an affine transformation on the trial (sample) with the reference : \f$ S_\text{new} = R^{-1/2} * S * {R^{-1/2}}^{\mathsf{T}} \f$
|
||||
/// -# Update the reference with the current sample the first time and next with the Geodesic between the reference and the current sample.\n
|
||||
/// With \f$ \gamma_m \f$ the Geodesic (<see cref="Geodesic" />) with the metric \f$ m \f$ (<see cref="EMetric" />) and \f$ N_c \f$ the number of classification : \f$ R = \gamma_\text{m}\left( R,S,\frac{1}{N_c} \right) \f$
|
||||
/// -# Apply the classify function of MDM Classifier (see <see cref="CMatrixClassifierMDM::classify"/>)
|
||||
/// </summary>
|
||||
/// \copydetails IMatrixClassifier::classify(const Eigen::MatrixXd&, size_t&, std::vector<double>&, std::vector<double>&, const EAdaptations, const size_t&)
|
||||
bool classify(const Eigen::MatrixXd& sample, size_t& classId, std::vector<double>& distance, std::vector<double>& probability,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max()) override;
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance). </returns>
|
||||
bool isEqual(const CMatrixClassifierMDMRebias& obj, double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const CMatrixClassifierMDMRebias& obj);
|
||||
|
||||
/// <summary> Get the type of the classifier. </summary>
|
||||
/// <returns> Minimum Distance to Mean REBIAS. </returns>
|
||||
std::string getType() const override { return toString(EMatrixClassifiers::MDM_Rebias); }
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
CMatrixClassifierMDMRebias& operator=(const CMatrixClassifierMDMRebias& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierMDMRebias"/> are equals. </returns>
|
||||
bool operator==(const CMatrixClassifierMDMRebias& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="CMatrixClassifierMDMRebias"/> are diffrents. </returns>
|
||||
bool operator!=(const CMatrixClassifierMDMRebias& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const CMatrixClassifierMDMRebias& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary> Save Additionnal informations (reference and number of classification). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool saveAdditional(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement* data) const override;
|
||||
|
||||
/// <summary> Load Additionnal informations (reference and number of classification). </summary>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
bool loadAdditional(tinyxml2::XMLElement* data) override;
|
||||
|
||||
/// <summary> Prints the Additional informations (reference and number of classification). </summary>
|
||||
/// <returns> Additional informations in stringstream. </returns>
|
||||
std::stringstream printAdditional() const override;
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
CBias m_bias; ///< Rebias Method.
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file IMatrixClassifier.hpp
|
||||
/// \brief Abstract class of Matrix Classifier
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 10/12/2018.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include "geometry/Metrics.hpp"
|
||||
#include "geometry/3rd-party/tinyxml2.h"
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Enumeration of Adaptation Methods for classifier. </summary>
|
||||
enum class EAdaptations
|
||||
{
|
||||
None, ///< No Adaptation.
|
||||
Supervised, ///< Supervised Adaptation.
|
||||
Unsupervised ///< Unsupervised Adaptation.
|
||||
};
|
||||
|
||||
/// <summary> Convert adaptations to string. </summary>
|
||||
/// <param name="type"> The type of adaptation. </param>
|
||||
/// <returns> <c>std::string</c> </returns>
|
||||
inline std::string toString(const EAdaptations type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EAdaptations::None: return "No";
|
||||
case EAdaptations::Supervised: return "Supervised";
|
||||
case EAdaptations::Unsupervised: return "Unsupervised";
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
/// <summary> Convert string to adaptations. </summary>
|
||||
/// <param name="type"> The type of adaptation. </param>
|
||||
/// <returns> <see cref="EAdaptations"/> </returns>
|
||||
inline EAdaptations StringToAdaptation(const std::string& type)
|
||||
{
|
||||
if (type == "No") { return EAdaptations::None; }
|
||||
if (type == "Supervised") { return EAdaptations::Supervised; }
|
||||
return EAdaptations::Unsupervised;
|
||||
}
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Enumeration of Matrix Classifiers. </summary>
|
||||
enum class EMatrixClassifiers
|
||||
{
|
||||
MDM, ///< Minimum Distance To Mean (MDM) Classifier.
|
||||
MDM_Rebias, ///< Minimum Distance To Mean Rebias (MDM Rebias) Classifier.
|
||||
FgMDM_RT, ///< Minimum Distance to Mean with geodesic filtering (FgMDM) (Real Time adaptation assumed).
|
||||
FgMDM, ///< Minimum Distance to Mean with geodesic filtering (FgMDM).
|
||||
FgMDM_RT_Rebias, ///< Minimum Distance to Mean with geodesic filtering & Rebias adaptation (FgMDM Rebias) (Real Time adaptation assumed).
|
||||
FgMDM_Rebias ///< Minimum Distance to Mean with geodesic filtering & Rebias adaptation (FgMDM Rebias).
|
||||
};
|
||||
|
||||
|
||||
/// <summary> Convert Matrix Classifiers to string. </summary>
|
||||
/// <param name="type"> The type of classifier. </param>
|
||||
/// <returns> <c>std::string</c> </returns>
|
||||
inline std::string toString(const EMatrixClassifiers type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EMatrixClassifiers::MDM: return "Minimum Distance to Mean (MDM)";
|
||||
case EMatrixClassifiers::MDM_Rebias: return "Minimum Distance to Mean Rebias (MDM Rebias)";
|
||||
case EMatrixClassifiers::FgMDM_RT: return "Minimum Distance to Mean with geodesic filtering (FgMDM) (Real Time adaptation assumed)";
|
||||
case EMatrixClassifiers::FgMDM: return "Minimum Distance to Mean with geodesic filtering (FgMDM)";
|
||||
case EMatrixClassifiers::FgMDM_RT_Rebias: return "Minimum Distance to Mean with geodesic filtering Rebias (FgMDM Rebias) (Real Time adaptation assumed)";
|
||||
case EMatrixClassifiers::FgMDM_Rebias: return "Minimum Distance to Mean with geodesic filtering Rebias (FgMDM Rebias)";
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
/// <summary> Convert string to Matrix Classifiers. </summary>
|
||||
/// <param name="type"> The type of classifier. </param>
|
||||
/// <returns> <see cref="EMatrixClassifiers"/> </returns>
|
||||
inline EMatrixClassifiers StringToMatrixClassifier(const std::string& type)
|
||||
{
|
||||
if (type == "Minimum Distance to Mean (MDM)") { return EMatrixClassifiers::MDM; }
|
||||
if (type == "Minimum Distance to Mean Rebias (MDM Rebias)") { return EMatrixClassifiers::MDM_Rebias; }
|
||||
if (type == "Minimum Distance to Mean with geodesic filtering (FgMDM) (Real Time adaptation assumed)") { return EMatrixClassifiers::FgMDM_RT; }
|
||||
if (type == "Minimum Distance to Mean with geodesic filtering (FgMDM)") { return EMatrixClassifiers::FgMDM; }
|
||||
if (type == "Minimum Distance to Mean with geodesic filtering Rebias (FgMDM Rebias) (Real Time adaptation assumed)")
|
||||
{
|
||||
return EMatrixClassifiers::FgMDM_RT_Rebias;
|
||||
}
|
||||
return EMatrixClassifiers::FgMDM_Rebias;
|
||||
}
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary> Format the Eigen matrix with Full Precision. </summary>
|
||||
#define MATRIX_FORMAT Eigen::IOFormat(-2, 0, " ", "\n", "", "", "", "")
|
||||
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
/// <summary> Abstract class of Matrix Classifier. </summary>
|
||||
class IMatrixClassifier
|
||||
{
|
||||
public:
|
||||
//****************************
|
||||
//***** Static Functions *****
|
||||
//****************************
|
||||
/// <summary> Format the Matrix for XML Saving. </summary>
|
||||
/// <param name="in"> Matrix. </param>
|
||||
/// <param name="out"> Stringstream. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
static bool convertMatrixToXMLFormat(const Eigen::MatrixXd& in, std::stringstream& out);
|
||||
|
||||
/// <summary> Fill the Matrix From XML Format. </summary>
|
||||
/// <param name="in"> Stringstream. </param>
|
||||
/// <param name="out"> Matrix. </param>
|
||||
/// <param name="rows"> Number of rows. </param>
|
||||
/// <param name="cols"> Number of cols. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
static bool convertXMLFormatToMatrix(std::stringstream& in, Eigen::MatrixXd& out, size_t rows, size_t cols);
|
||||
|
||||
/// <summary> Saves matrix. </summary>
|
||||
/// <param name="element"> Matrix Node. </param>
|
||||
/// <param name="matrix"> Matrix to save. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
static bool saveMatrix(tinyxml2::XMLElement* element, const Eigen::MatrixXd& matrix);
|
||||
|
||||
/// <summary> Load matrix. </summary>
|
||||
/// <param name="element"> Matrix Node. </param>
|
||||
/// <param name="matrix"> Matrix to load. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
static bool loadMatrix(tinyxml2::XMLElement* element, Eigen::MatrixXd& matrix);
|
||||
|
||||
//***********************
|
||||
//***** Constructor *****
|
||||
//***********************
|
||||
/// <summary> Default constructor. Initializes a new instance of the <see cref="IMatrixClassifier"/> class. </summary>
|
||||
IMatrixClassifier() = default;
|
||||
|
||||
/// <summary> Default Copy constructor. Initializes a new instance of the <see cref="IMatrixClassifier"/> class. </summary>
|
||||
/// <param name="obj"> Initial object. </param>
|
||||
IMatrixClassifier(const IMatrixClassifier& obj) { *this = obj; }
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="IMatrixClassifier"/> class and set members. </summary>
|
||||
/// <param name="nbClass"> The number of classes. </param>
|
||||
/// <param name="metric"> Metric to use to calculate means (see also <see cref="EMetric" />). </param>
|
||||
explicit IMatrixClassifier(size_t nbClass, EMetric metric);
|
||||
|
||||
/// <summary> Finalizes an instance of the <see cref="IMatrixClassifier"/> class. </summary>
|
||||
virtual ~IMatrixClassifier() = default;
|
||||
|
||||
//**********************
|
||||
//***** Classifier *****
|
||||
//**********************
|
||||
virtual size_t getClassCount() const { return m_nbClass; } ///< Get the class count.
|
||||
virtual void setClassCount(size_t nbClass); ///< Set the class count.
|
||||
|
||||
/// <summary> Train the classifier with the dataset. </summary>
|
||||
/// <param name="dataset"> The dataset (first dimension is the classes, second dimension is the trials as covariance matrix). </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
virtual bool train(const std::vector<std::vector<Eigen::MatrixXd>>& dataset) = 0;
|
||||
|
||||
/// <summary> Classify the matrix and return the class id (override of same function with all argument). </summary>
|
||||
/// <param name="sample"> The sample to classify. </param>
|
||||
/// <param name="classId"> The predicted class. </param>
|
||||
/// <param name="adaptation"> Adaptation method for the classfier <see cref="EAdaptations" />. </param>
|
||||
/// <param name="realClassId"> The expected class id if supervised adaptation. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
/// <seealso cref="classify(const Eigen::MatrixXd&, size_t&, std::vector<double>&, std::vector<double>&, EAdaptations, const size_t&)"/>
|
||||
virtual bool classify(const Eigen::MatrixXd& sample, size_t& classId,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max());
|
||||
|
||||
/// <summary> Classify the matrix and return the class id, the distance and the probability of each class. </summary>
|
||||
/// <param name="sample"> The sample to classify. </param>
|
||||
/// <param name="classId"> The predicted class. </param>
|
||||
/// <param name="distance"> The distance of the sample with each class. </param>
|
||||
/// <param name="probability"> The probability of the sample with each class. </param>
|
||||
/// <param name="adaptation"> Adaptation method for the classfier <see cref="EAdaptations" />. </param>
|
||||
/// <param name="realClassId"> The expected class id if supervised adaptation. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
virtual bool classify(const Eigen::MatrixXd& sample, size_t& classId, std::vector<double>& distance, std::vector<double>& probability,
|
||||
EAdaptations adaptation = EAdaptations::None, const size_t& realClassId = std::numeric_limits<size_t>::max()) = 0;
|
||||
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Saves the classifier information in an XML file. </summary>
|
||||
/// <param name="filename"> Filename. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
virtual bool saveXML(const std::string& filename) const;
|
||||
|
||||
/// <summary> Loads the classifier information from an XML file. </summary>
|
||||
/// <param name="filename"> Filename. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
virtual bool loadXML(const std::string& filename);
|
||||
|
||||
|
||||
//*****************************
|
||||
//***** Override Operator *****
|
||||
//*****************************
|
||||
|
||||
/// <summary> Check if object are equals (with a precision tolerance). </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <param name="precision"> Precision for matrix comparison. </param>
|
||||
/// <returns> <c>True</c> if the two elements are equals (with a precision tolerance). </returns>
|
||||
bool isEqual(const IMatrixClassifier& obj, double precision = 1e-6) const;
|
||||
|
||||
/// <summary> Copy object value. </summary>
|
||||
/// <param name="obj"> The object to copy. </param>
|
||||
void copy(const IMatrixClassifier& obj);
|
||||
|
||||
/// <summary> Get the type of the classifier. </summary>
|
||||
/// <returns> The type in string. </returns>
|
||||
virtual std::string getType() const = 0;
|
||||
|
||||
/// <summary> Get the Classifier information for output. </summary>
|
||||
/// <returns> The Classifier print in stringstream. </returns>
|
||||
virtual std::stringstream print() const;
|
||||
|
||||
/// <summary> Override the affectation operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> The copied object. </returns>
|
||||
IMatrixClassifier& operator=(const IMatrixClassifier& obj)
|
||||
{
|
||||
copy(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary> Override the equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two <see cref="IMatrixClassifier"/> are equals. </returns>
|
||||
bool operator==(const IMatrixClassifier& obj) const { return isEqual(obj); }
|
||||
|
||||
/// <summary> Override the not equal operator. </summary>
|
||||
/// <param name="obj"> The second object. </param>
|
||||
/// <returns> <c>True</c> if the two objects are diffrents. </returns>
|
||||
bool operator!=(const IMatrixClassifier& obj) const { return !isEqual(obj); }
|
||||
|
||||
/// <summary> Override the ostream operator. </summary>
|
||||
/// <param name="os"> The ostream. </param>
|
||||
/// <param name="obj"> The object. </param>
|
||||
/// <returns> Return the modified ostream. </returns>
|
||||
friend std::ostream& operator <<(std::ostream& os, const IMatrixClassifier& obj)
|
||||
{
|
||||
os << obj.print().str();
|
||||
return os;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// <summary> Prints the header informations. </summary>
|
||||
/// <returns> Header informations in stringstream. </returns>
|
||||
virtual std::stringstream printHeader() const;
|
||||
|
||||
/// <summary> Prints the Additional informations. </summary>
|
||||
/// <returns> Additional informations in stringstream. </returns>
|
||||
virtual std::stringstream printAdditional() const { return std::stringstream(); }
|
||||
|
||||
/// <summary> Prints the Classes informations. </summary>
|
||||
/// <returns> Classes informations in stringstream. </returns>
|
||||
virtual std::stringstream printClasses() const { return std::stringstream(); }
|
||||
|
||||
//***********************
|
||||
//***** XML Manager *****
|
||||
//***********************
|
||||
/// <summary> Add the attribute on the first node (general informations as classifier type, number of class...).
|
||||
///
|
||||
/// -# The type of the classifier : <see cref="getType"/>
|
||||
/// -# The number of classes : <see cref="m_nbClass"/>
|
||||
/// -# The metric to use : <see cref="m_metric"/>
|
||||
/// </summary>
|
||||
/// <param name="data"> Node to modify. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
virtual bool saveHeader(tinyxml2::XMLElement* data) const;
|
||||
|
||||
/// <summary> Loads the attribute on the first node (general informations as classifier type, number of class...).
|
||||
///
|
||||
/// -# Check the type : <see cref="getType"/>
|
||||
/// -# The number of classes : <see cref="m_nbClass"/>
|
||||
/// -# The metric to use : <see cref="m_metric"/>
|
||||
/// </summary>
|
||||
/// <param name="data"> Node to read. </param>
|
||||
/// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
|
||||
virtual bool loadHeader(tinyxml2::XMLElement* data);
|
||||
|
||||
/// <summary> Save Additionnal informations (none at this level). </summary>
|
||||
/// <returns> <c>True</c>. </returns>
|
||||
virtual bool saveAdditional(tinyxml2::XMLDocument& /*doc*/, tinyxml2::XMLElement* /*data*/) const { return true; }
|
||||
|
||||
/// <summary> Load Additionnal informations (none at this level). </summary>
|
||||
/// <returns> <c>True</c>. </returns>
|
||||
virtual bool loadAdditional(tinyxml2::XMLElement* /*data*/) { return true; }
|
||||
|
||||
/// <summary> Save Classes informations (none at this level). </summary>
|
||||
/// <returns> <c>True</c>. </returns>
|
||||
virtual bool saveClasses(tinyxml2::XMLDocument& /*doc*/, tinyxml2::XMLElement* /*data*/) const { return true; }
|
||||
|
||||
/// <summary> Load Classes informations (none at this level). </summary>
|
||||
/// <returns> <c>True</c>. </returns>
|
||||
virtual bool loadClasses(tinyxml2::XMLElement* /*data*/) { return true; }
|
||||
|
||||
|
||||
//*********************
|
||||
//***** Variables *****
|
||||
//*********************
|
||||
size_t m_nbClass = 2; ///< Number of classes to classify.
|
||||
EMetric m_metric = EMetric::Riemann; ///< Metric to use to calculate means and distances (see also <see cref="EMetric" />).
|
||||
};
|
||||
|
||||
} // namespace Geometry
|
||||
Reference in New Issue
Block a user