bpp-core3  3.0.0
DualityDiagram.cpp
Go to the documentation of this file.
1 //
2 // File: DualityDiagram.cpp
3 // Authors:
4 // Mathieu Groussin
5 //
6 
7 /*
8  Copyright or © or Copr. Bio++ Development Tools, (November 16, 2004)
9 
10  This software is a computer program whose purpose is to provide classes
11  for phylogenetic data analysis.
12 
13  This software is governed by the CeCILL license under French law and
14  abiding by the rules of distribution of free software. You can use,
15  modify and/ or redistribute the software under the terms of the CeCILL
16  license as circulated by CEA, CNRS and INRIA at the following URL
17  "http://www.cecill.info".
18 
19  As a counterpart to the access to the source code and rights to copy,
20  modify and redistribute granted by the license, users are provided only
21  with a limited warranty and the software's author, the holder of the
22  economic rights, and the successive licensors have only limited
23  liability.
24 
25  In this respect, the user's attention is drawn to the risks associated
26  with loading, using, modifying and/or developing or reproducing the
27  software by the user in light of its specific status of free software,
28  that may mean that it is complicated to manipulate, and that also
29  therefore means that it is reserved for developers and experienced
30  professionals having in-depth computer knowledge. Users are therefore
31  encouraged to load and test the software's suitability as regards their
32  requirements in conditions enabling the security of their systems and/or
33  data to be ensured and, more generally, to use and operate it in the
34  same conditions as regards security.
35 
36  The fact that you are presently reading this means that you have had
37  knowledge of the CeCILL license and that you accept its terms.
38 */
39 
40 #include <cmath>
41 
42 #include "../../../App/ApplicationTools.h"
43 #include "../../Matrix/EigenValue.h"
44 #include "../../Matrix/Matrix.h"
45 #include "../../Matrix/MatrixTools.h"
46 #include "DualityDiagram.h"
47 
48 using namespace bpp;
49 using namespace std;
50 
52  const Matrix<double>& matrix,
53  const vector<double>& rowWeights,
54  const vector<double>& colWeights,
55  unsigned int nbAxes,
56  double tol, bool verbose) :
57  rowWeights_(rowWeights),
58  colWeights_(colWeights),
59  nbAxes_(nbAxes),
60  eigenValues_(),
61  eigenVectors_(),
62  rowCoord_(),
63  colCoord_(),
64  ppalAxes_(),
65  ppalComponents_()
66 {
67  check_(matrix, rowWeights, colWeights, verbose);
68  compute_(matrix, tol, verbose);
69 }
70 
72  const Matrix<double>& matrix,
73  const vector<double>& rowWeights,
74  const vector<double>& colWeights,
75  unsigned int nbAxes)
76 {
77  size_t rowNb = matrix.getNumberOfRows();
78  size_t colNb = matrix.getNumberOfColumns();
79 
80  if (rowWeights.size() != rowNb)
81  throw Exception("DualityDiagram::check_. The number of row weigths has to be equal to the number of rows!");
82  if (colWeights.size() != colNb)
83  throw Exception("DualityDiagram::check_. The number of column weigths has to be equal to the number of columns!");
84 
85  // All row weigths have to be positive
86  for (vector<double>::const_iterator it = rowWeights.begin(); it != rowWeights.end(); it++)
87  {
88  if (*it < 0.)
89  throw Exception("DualityDiagram::check_. All row weights have to be positive");
90  }
91 
92  // All column weigths have to be positive
93  for (vector<double>::const_iterator it = colWeights.begin(); it != colWeights.end(); it++)
94  {
95  if (*it < 0.)
96  throw Exception("DualityDiagram::check_. All column weights have to be positive");
97  }
98 }
99 
100 
102  const Matrix<double>& matrix,
103  const vector<double>& rowWeights,
104  const vector<double>& colWeights,
105  unsigned int nbAxes,
106  double tol, bool verbose)
107 {
108  check_(matrix, rowWeights, colWeights, verbose);
109  rowWeights_ = rowWeights;
110  colWeights_ = colWeights;
111  nbAxes_ = nbAxes;
112  compute_(matrix, tol, verbose);
113 }
114 
116  double tol, bool verbose)
117 {
118  size_t rowNb = matrix.getNumberOfRows();
119  size_t colNb = matrix.getNumberOfColumns();
120 
121  // If there are less rows than columns, the variance-covariance or correlation matrix is obtain differently (see below)
122  bool transpose = (rowNb < colNb);
123 
124  // The initial matrix is multiplied by the square root of the row weigths.
125  vector<double> rW(rowWeights_);
126  for (unsigned int i = 0; i < rowWeights_.size(); i++)
127  {
128  rW[i] = sqrt(rowWeights_[i]);
129  }
130 
131  RowMatrix<double> M1(rowNb, colNb);
132  MatrixTools::hadamardMult(matrix, rW, M1, true);
133 
134  // The resulting matrix is then multiplied by the square root of the column weigths.
135  vector<double> cW(colWeights_);
136  for (unsigned int i = 0; i < colWeights_.size(); i++)
137  {
138  cW[i] = sqrt(colWeights_[i]);
139  }
140 
142  MatrixTools::hadamardMult(M1, cW, M2, false);
143 
144  // The variance-covariance (if the data is centered) or the correlation (if the data is centered and normalized) matrix is calculated
145  RowMatrix<double> tM2;
146  MatrixTools::transpose(M2, tM2);
148  if (!transpose)
149  MatrixTools::mult(tM2, M2, M3);
150  else
151  MatrixTools::mult(M2, tM2, M3);
152 
153  EigenValue<double> eigen(M3);
154  if (!eigen.isSymmetric())
155  throw Exception("DualityDiagram (constructor). The variance-covariance or correlation matrix should be symmetric...");
156 
158  eigenVectors_ = eigen.getV();
159 
160  // How many significant axes have to be conserved?
161  size_t rank = 0;
162  for (size_t i = eigenValues_.size(); i > 0; i--)
163  {
164  if ((eigenValues_[i - 1] / eigenValues_[eigenValues_.size() - 1]) > tol)
165  rank++;
166  }
167 
168  if (nbAxes_ <= 0)
169  {
170  throw Exception("DualityDiagram (constructor). The number of axes to keep must be positive.");
171  }
172  if (nbAxes_ > rank)
173  {
174  if (verbose)
175  ApplicationTools::displayWarning("The number of axes to kept has been reduced to conserve only significant axes");
176  nbAxes_ = rank;
177  }
178 
179  /*The eigen values are initially sorted into ascending order by the 'eigen' function. Here the significant values are sorted
180  in the other way around.*/
181  vector<double> tmpEigenValues(nbAxes_);
182  size_t cpt = 0;
183  for (size_t i = eigenValues_.size(); i > (eigenValues_.size() - nbAxes_); i--)
184  {
185  tmpEigenValues[cpt] = eigenValues_[i - 1];
186  cpt++;
187  }
188  eigenValues_ = tmpEigenValues;
189 
190  for (vector<double>::iterator it = rowWeights_.begin(); it != rowWeights_.end(); it++)
191  {
192  if (*it == 0.)
193  *it = 1.;
194  }
195 
196  for (vector<double>::iterator it = colWeights_.begin(); it != colWeights_.end(); it++)
197  {
198  if (*it == 0.)
199  *it = 1.;
200  }
201 
202  vector<double> dval(nbAxes_);
203  for (size_t i = 0; i < dval.size(); i++)
204  {
205  dval[i] = sqrt(eigenValues_[i]);
206  }
207 
208  vector<double> invDval(nbAxes_);
209  for (size_t i = 0; i < invDval.size(); i++)
210  {
211  invDval[i] = 1. / sqrt(eigenValues_[i]);
212  }
213 
214  // Calculation of the row and column coordinates as well as the principal axes and components:
215  if (!transpose)
216  {
217  vector<double> tmpColWeights(colNb);
218  for (unsigned int i = 0; i < colWeights_.size(); i++)
219  {
220  tmpColWeights[i] = 1. / sqrt(colWeights_[i]);
221  }
222 
223  // The eigen vectors are placed in the same order as their corresponding eigen value in eigenValues_.
224  RowMatrix<double> tmpEigenVectors;
225  tmpEigenVectors.resize(eigenVectors_.getNumberOfRows(), nbAxes_);
226  size_t cpt2 = 0;
227  for (size_t i = eigenVectors_.getNumberOfColumns(); i > (eigenVectors_.getNumberOfColumns() - nbAxes_); i--)
228  {
229  for (unsigned int j = 0; j < eigenVectors_.getNumberOfRows(); j++)
230  {
231  tmpEigenVectors(j, cpt2) = eigenVectors_(j, i - 1);
232  }
233  cpt2++;
234  }
235 
236  // matrix of principal axes
237  MatrixTools::hadamardMult(tmpEigenVectors, tmpColWeights, ppalAxes_, true);
238  // matrix of row coordinates
239  RowMatrix<double> tmpRowCoord_;
240  tmpRowCoord_.resize(rowNb, nbAxes_);
241  MatrixTools::hadamardMult(matrix, colWeights_, tmpRowCoord_, false);
242  MatrixTools::mult(tmpRowCoord_, ppalAxes_, rowCoord_);
243 
244  // matrix of column coordinates
246  // matrix of principal components
248  }
249  else
250  {
251  vector<double> tmpRowWeights(rowNb);
252  for (unsigned int i = 0; i < rowWeights_.size(); i++)
253  {
254  tmpRowWeights[i] = 1. / sqrt(rowWeights_[i]);
255  }
256 
257  // The eigen vectors are placed in the same order as their corresponding eigen value in eigenValues_.
258  RowMatrix<double> tmpEigenVectors;
259  tmpEigenVectors.resize(eigenVectors_.getNumberOfRows(), nbAxes_);
260  size_t cpt2 = 0;
261  for (size_t i = eigenVectors_.getNumberOfColumns(); i > (eigenVectors_.getNumberOfColumns() - nbAxes_); i--)
262  {
263  for (size_t j = 0; j < eigenVectors_.getNumberOfRows(); j++)
264  {
265  tmpEigenVectors(j, cpt2) = eigenVectors_(j, i - 1);
266  }
267  cpt2++;
268  }
269 
270  // matrix of principal components
271  MatrixTools::hadamardMult(tmpEigenVectors, tmpRowWeights, ppalComponents_, true);
272  // matrix of column coordinates
273  RowMatrix<double> tmpColCoord_;
274  tmpColCoord_.resize(colNb, nbAxes_);
275  MatrixTools::hadamardMult(matrix, rowWeights_, tmpColCoord_, true);
276  RowMatrix<double> tTmpColCoord_;
277  MatrixTools::transpose(tmpColCoord_, tTmpColCoord_);
279 
280  // matrix of row coordinates
282  // matrix of principal axes
284  }
285 }
286 
287 /******************************************************************************/
288 
290 
291 /******************************************************************************/
static void displayWarning(const std::string &text)
Print a warning message.
std::vector< double > colWeights_
RowMatrix< double > ppalComponents_
std::vector< double > eigenValues_
RowMatrix< double > ppalAxes_
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.
void compute_(const Matrix< double > &matrix, double tol, bool verbose)
void check_(const Matrix< double > &matrix, const std::vector< double > &rowWeights, const std::vector< double > &colWeights, unsigned int nbAxes)
RowMatrix< double > eigenVectors_
std::vector< double > rowWeights_
RowMatrix< double > colCoord_
RowMatrix< double > rowCoord_
DualityDiagram()
Build an empty DualityDiagram object.
Computes eigenvalues and eigenvectors of a real (non-complex) matrix.
Definition: EigenValue.h:107
bool isSymmetric() const
Definition: EigenValue.h:1096
const RowMatrix< Real > & getV() const
Return the eigenvector matrix.
Definition: EigenValue.h:1168
const std::vector< Real > & getRealEigenValues() const
Return the real parts of the eigenvalues.
Definition: EigenValue.h:1175
Exception base class. Overload exception constructor (to control the exceptions mechanism)....
Definition: Exceptions.h:59
static void mult(const Matrix< Scalar > &A, const Matrix< Scalar > &B, Matrix< Scalar > &O)
Definition: MatrixTools.h:256
static void transpose(const MatrixA &A, MatrixO &O)
Definition: MatrixTools.h:866
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:1055
The matrix template interface.
Definition: Matrix.h:61
virtual size_t getNumberOfColumns() const =0
virtual size_t getNumberOfRows() const =0
size_t getNumberOfRows() const
Definition: Matrix.h:185
size_t getNumberOfColumns() const
Definition: Matrix.h:187
void resize(size_t nRows, size_t nCols)
Resize the matrix.
Definition: Matrix.h:213