bpp-core3  3.0.0
DualityDiagram.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 #include <cmath>
6 
7 #include "../../../App/ApplicationTools.h"
8 #include "../../Matrix/EigenValue.h"
9 #include "../../Matrix/Matrix.h"
10 #include "../../Matrix/MatrixTools.h"
11 #include "DualityDiagram.h"
12 
13 using namespace bpp;
14 using namespace std;
15 
17  const Matrix<double>& matrix,
18  const vector<double>& rowWeights,
19  const vector<double>& colWeights,
20  unsigned int nbAxes,
21  double tol, bool verbose) :
22  rowWeights_(rowWeights),
23  colWeights_(colWeights),
24  nbAxes_(nbAxes),
25  eigenValues_(),
26  eigenVectors_(),
27  rowCoord_(),
28  colCoord_(),
29  ppalAxes_(),
30  ppalComponents_()
31 {
32  check_(matrix, rowWeights, colWeights, verbose);
33  compute_(matrix, tol, verbose);
34 }
35 
37  const Matrix<double>& matrix,
38  const vector<double>& rowWeights,
39  const vector<double>& colWeights,
40  unsigned int nbAxes)
41 {
42  size_t rowNb = matrix.getNumberOfRows();
43  size_t colNb = matrix.getNumberOfColumns();
44 
45  if (rowWeights.size() != rowNb)
46  throw Exception("DualityDiagram::check_. The number of row weigths has to be equal to the number of rows!");
47  if (colWeights.size() != colNb)
48  throw Exception("DualityDiagram::check_. The number of column weigths has to be equal to the number of columns!");
49 
50  // All row weigths have to be positive
51  for (vector<double>::const_iterator it = rowWeights.begin(); it != rowWeights.end(); it++)
52  {
53  if (*it < 0.)
54  throw Exception("DualityDiagram::check_. All row weights have to be positive");
55  }
56 
57  // All column weigths have to be positive
58  for (vector<double>::const_iterator it = colWeights.begin(); it != colWeights.end(); it++)
59  {
60  if (*it < 0.)
61  throw Exception("DualityDiagram::check_. All column weights have to be positive");
62  }
63 }
64 
65 
67  const Matrix<double>& matrix,
68  const vector<double>& rowWeights,
69  const vector<double>& colWeights,
70  unsigned int nbAxes,
71  double tol, bool verbose)
72 {
73  check_(matrix, rowWeights, colWeights, verbose);
74  rowWeights_ = rowWeights;
75  colWeights_ = colWeights;
76  nbAxes_ = nbAxes;
77  compute_(matrix, tol, verbose);
78 }
79 
81  double tol, bool verbose)
82 {
83  size_t rowNb = matrix.getNumberOfRows();
84  size_t colNb = matrix.getNumberOfColumns();
85 
86  // If there are less rows than columns, the variance-covariance or correlation matrix is obtain differently (see below)
87  bool transpose = (rowNb < colNb);
88 
89  // The initial matrix is multiplied by the square root of the row weigths.
90  vector<double> rW(rowWeights_);
91  for (unsigned int i = 0; i < rowWeights_.size(); i++)
92  {
93  rW[i] = sqrt(rowWeights_[i]);
94  }
95 
96  RowMatrix<double> M1(rowNb, colNb);
97  MatrixTools::hadamardMult(matrix, rW, M1, true);
98 
99  // The resulting matrix is then multiplied by the square root of the column weigths.
100  vector<double> cW(colWeights_);
101  for (unsigned int i = 0; i < colWeights_.size(); i++)
102  {
103  cW[i] = sqrt(colWeights_[i]);
104  }
105 
107  MatrixTools::hadamardMult(M1, cW, M2, false);
108 
109  // The variance-covariance (if the data is centered) or the correlation (if the data is centered and normalized) matrix is calculated
110  RowMatrix<double> tM2;
111  MatrixTools::transpose(M2, tM2);
113  if (!transpose)
114  MatrixTools::mult(tM2, M2, M3);
115  else
116  MatrixTools::mult(M2, tM2, M3);
117 
118  EigenValue<double> eigen(M3);
119  if (!eigen.isSymmetric())
120  throw Exception("DualityDiagram (constructor). The variance-covariance or correlation matrix should be symmetric...");
121 
123  eigenVectors_ = eigen.getV();
124 
125  // How many significant axes have to be conserved?
126  size_t rank = 0;
127  for (size_t i = eigenValues_.size(); i > 0; i--)
128  {
129  if ((eigenValues_[i - 1] / eigenValues_[eigenValues_.size() - 1]) > tol)
130  rank++;
131  }
132 
133  if (nbAxes_ <= 0)
134  {
135  throw Exception("DualityDiagram (constructor). The number of axes to keep must be positive.");
136  }
137  if (nbAxes_ > rank)
138  {
139  if (verbose)
140  ApplicationTools::displayWarning("The number of axes to keep has been reduced to conserve only significant axes");
141  nbAxes_ = rank;
142  }
143 
144  /*The eigen values are initially sorted into ascending order by the 'eigen' function. Here the significant values are sorted
145  in the other way around.*/
146  vector<double> tmpEigenValues(nbAxes_);
147  size_t cpt = 0;
148  for (size_t i = eigenValues_.size(); i > (eigenValues_.size() - nbAxes_); i--)
149  {
150  tmpEigenValues[cpt] = eigenValues_[i - 1];
151  cpt++;
152  }
153  eigenValues_ = tmpEigenValues;
154 
155  for (vector<double>::iterator it = rowWeights_.begin(); it != rowWeights_.end(); it++)
156  {
157  if (*it == 0.)
158  *it = 1.;
159  }
160 
161  for (vector<double>::iterator it = colWeights_.begin(); it != colWeights_.end(); it++)
162  {
163  if (*it == 0.)
164  *it = 1.;
165  }
166 
167  vector<double> dval(nbAxes_);
168  for (size_t i = 0; i < dval.size(); i++)
169  {
170  dval[i] = sqrt(eigenValues_[i]);
171  }
172 
173  vector<double> invDval(nbAxes_);
174  for (size_t i = 0; i < invDval.size(); i++)
175  {
176  invDval[i] = 1. / sqrt(eigenValues_[i]);
177  }
178 
179  // Calculation of the row and column coordinates as well as the principal axes and components:
180  if (!transpose)
181  {
182  vector<double> tmpColWeights(colNb);
183  for (unsigned int i = 0; i < colWeights_.size(); i++)
184  {
185  tmpColWeights[i] = 1. / sqrt(colWeights_[i]);
186  }
187 
188  // The eigen vectors are placed in the same order as their corresponding eigen value in eigenValues_.
189  RowMatrix<double> tmpEigenVectors;
190  tmpEigenVectors.resize(eigenVectors_.getNumberOfRows(), nbAxes_);
191  size_t cpt2 = 0;
192  for (size_t i = eigenVectors_.getNumberOfColumns(); i > (eigenVectors_.getNumberOfColumns() - nbAxes_); i--)
193  {
194  for (unsigned int j = 0; j < eigenVectors_.getNumberOfRows(); j++)
195  {
196  tmpEigenVectors(j, cpt2) = eigenVectors_(j, i - 1);
197  }
198  cpt2++;
199  }
200 
201  // matrix of principal axes
202  MatrixTools::hadamardMult(tmpEigenVectors, tmpColWeights, ppalAxes_, true);
203  // matrix of row coordinates
204  RowMatrix<double> tmpRowCoord_;
205  tmpRowCoord_.resize(rowNb, nbAxes_);
206  MatrixTools::hadamardMult(matrix, colWeights_, tmpRowCoord_, false);
207  MatrixTools::mult(tmpRowCoord_, ppalAxes_, rowCoord_);
208 
209  // matrix of column coordinates
211  // matrix of principal components
213  }
214  else
215  {
216  vector<double> tmpRowWeights(rowNb);
217  for (unsigned int i = 0; i < rowWeights_.size(); i++)
218  {
219  tmpRowWeights[i] = 1. / sqrt(rowWeights_[i]);
220  }
221 
222  // The eigen vectors are placed in the same order as their corresponding eigen value in eigenValues_.
223  RowMatrix<double> tmpEigenVectors;
224  tmpEigenVectors.resize(eigenVectors_.getNumberOfRows(), nbAxes_);
225  size_t cpt2 = 0;
226  for (size_t i = eigenVectors_.getNumberOfColumns(); i > (eigenVectors_.getNumberOfColumns() - nbAxes_); i--)
227  {
228  for (size_t j = 0; j < eigenVectors_.getNumberOfRows(); j++)
229  {
230  tmpEigenVectors(j, cpt2) = eigenVectors_(j, i - 1);
231  }
232  cpt2++;
233  }
234 
235  // matrix of principal components
236  MatrixTools::hadamardMult(tmpEigenVectors, tmpRowWeights, ppalComponents_, true);
237  // matrix of column coordinates
238  RowMatrix<double> tmpColCoord_;
239  tmpColCoord_.resize(colNb, nbAxes_);
240  MatrixTools::hadamardMult(matrix, rowWeights_, tmpColCoord_, true);
241  RowMatrix<double> tTmpColCoord_;
242  MatrixTools::transpose(tmpColCoord_, tTmpColCoord_);
244 
245  // matrix of row coordinates
247  // matrix of principal axes
249  }
250 }
251 
252 /******************************************************************************/
253 
255 
256 /******************************************************************************/
The matrix template interface.
Definition: Matrix.h:22
void setData(const Matrix< double > &matrix, const std::vector< double > &rowWeights, const std::vector< double > &colWeights, unsigned int nbAxes, double tol=0.0000001, bool verbose=true)
Set the data and perform computations.
static void displayWarning(const std::string &text)
Print a warning message.
bool isSymmetric() const
Definition: EigenValue.h:1059
RowMatrix< double > eigenVectors_
RowMatrix< double > colCoord_
std::vector< double > colWeights_
STL namespace.
RowMatrix< double > rowCoord_
RowMatrix< double > ppalAxes_
std::vector< double > eigenValues_
virtual size_t getNumberOfColumns() const =0
const RowMatrix< Real > & getV() const
Return the eigenvector matrix.
Definition: EigenValue.h:1131
void resize(size_t nRows, size_t nCols)
Resize the matrix.
Definition: Matrix.h:176
void check_(const Matrix< double > &matrix, const std::vector< double > &rowWeights, const std::vector< double > &colWeights, unsigned int nbAxes)
static void mult(const Matrix< Scalar > &A, const Matrix< Scalar > &B, Matrix< Scalar > &O)
Definition: MatrixTools.h:221
Computes eigenvalues and eigenvectors of a real (non-complex) matrix.
Definition: EigenValue.h:69
std::vector< double > rowWeights_
static void transpose(const MatrixA &A, MatrixO &O)
Definition: MatrixTools.h:828
Exception base class. Overload exception constructor (to control the exceptions mechanism). Destructor is already virtual (from std::exception)
Definition: Exceptions.h:20
size_t getNumberOfRows() const
Definition: Matrix.h:148
static void hadamardMult(const Matrix< Scalar > &A, const Matrix< Scalar > &B, Matrix< Scalar > &O)
Compute the Hadamard product of two row matrices with same dimensions.
Definition: MatrixTools.h:1017
const std::vector< Real > & getRealEigenValues() const
Return the real parts of the eigenvalues.
Definition: EigenValue.h:1138
RowMatrix< double > ppalComponents_
virtual size_t getNumberOfRows() const =0
DualityDiagram()
Build an empty DualityDiagram object.
size_t getNumberOfColumns() const
Definition: Matrix.h:150
void compute_(const Matrix< double > &matrix, double tol, bool verbose)