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