void DualityDiagram::check_(
                            const MatrixReal& matrix,
                            const std::vector<double>& rowWeights,
                            const std::vector<double>& colWeights,
                            unsigned int nbAxes) throw (RbException)
{
    size_t rowNb = matrix.getNumberOfRows();
    size_t colNb = matrix.getNumberOfColumns();
    
    if (rowWeights.size() != rowNb)
        throw RbException("DualityDiagram::check_. The number of row weigths has to be equal to the number of rows!");
    if (colWeights.size() != colNb)
        throw RbException("DualityDiagram::check_. The number of column weigths has to be equal to the number of columns!");
    
    // All row weigths have to be positive
    for (std::vector<double>::const_iterator it = rowWeights.begin(); it != rowWeights.end(); it++)
    {
        if (*it < 0.)
            throw RbException("DualityDiagram::check_. All row weights have to be positive");
    }
    
    // All column weigths have to be positive
    for (std::vector<double>::const_iterator it = colWeights.begin(); it != colWeights.end(); it++)
    {
        if (*it < 0.)
            throw RbException("DualityDiagram::check_. All column weights have to be positive");
    }
}
void DualityDiagram::compute_(const MatrixReal& matrix, double tol)
{
    size_t rowNb = matrix.getNumberOfRows();
    size_t colNb = matrix.getNumberOfColumns();
    
    // If there are less rows than columns, the variance-covariance or correlation matrix is obtain differently (see below)
    bool transpose = (rowNb < colNb);
    
    // The initial matrix is multiplied by the square root of the row weigths.
    std::vector<double> rW(rowWeights_);
    for (size_t i = 0; i < rowWeights_.size(); i++)
    {
        rW[i] = sqrt(rowWeights_[i]);
    }
    
    MatrixReal M1(rowNb, colNb);
    RbMath::hadamardMult(matrix, rW, M1, true);
    
    // The resulting matrix is then multiplied by the square root of the column weigths.
    std::vector<double> cW(colWeights_);
    for (unsigned int i = 0; i < colWeights_.size(); i++)
    {
        cW[i] = sqrt(colWeights_[i]);
    }
    
    MatrixReal M2(rowNb,colNb);
    RbMath::hadamardMult(M1, cW, M2, false);
    
    // The variance-covariance (if the data is centered) or the correlation (if the data is centered and normalized) matrix is calculated
    MatrixReal tM2(M2.getNumberOfColumns(),M2.getNumberOfRows());
    RbMath::transposeMatrix(M2, tM2);
    MatrixReal *M3 = new MatrixReal(0,0);
    if (!transpose)
        (*M3) = tM2 * M2;
    else
        (*M3) = M2 * tM2;
    
    EigenSystem eigen(M3);
    eigen.update();
    // @todo: This may be implemented some time ... (Sebastian)
//    if (!eigen.isSymmetric())
//        throw RbException("DualityDiagram (constructor). The variance-covariance or correlation matrix should be symmetric...");
    
    eigenValues_ = eigen.getRealEigenvalues();
    eigenVectors_ = eigen.getEigenvectors();
    
    // How many significant axes have to be conserved?
    size_t rank = 0;
    for (size_t i = eigenValues_.size(); i > 0; i--)
    {
        if ((eigenValues_[i - 1] / eigenValues_[eigenValues_.size() - 1]) > tol)
            rank++;
    }
    
    if (nbAxes_ <=0)
    {
        throw RbException("DualityDiagram (constructor). The number of axes to keep must be positive.");
    }
    if (nbAxes_ > rank)
    {
        nbAxes_ = rank;
    }
    
    /*The eigen values are initially sorted into ascending order by the 'eigen' function. Here the significant values are sorted
     in the other way around.*/
    std::vector<double> tmpEigenValues(nbAxes_);
    size_t cpt = 0;
    for (size_t i = eigenValues_.size(); i > (eigenValues_.size() - nbAxes_); i--)
    {
        tmpEigenValues[cpt] = eigenValues_[i-1];
        cpt++;
    }
    eigenValues_ = tmpEigenValues;
    
    for (std::vector<double>::iterator it = rowWeights_.begin(); it != rowWeights_.end(); it++)
    {
        if (*it == 0.)
            *it = 1.;
    }
    
    for (std::vector<double>::iterator it = colWeights_.begin(); it != colWeights_.end(); it++)
    {
        if (*it == 0.)
            *it = 1.;
    }
    
    std::vector<double> dval(nbAxes_);
    for (size_t i = 0; i < dval.size(); i++)
    {
        dval[i] = sqrt(eigenValues_[i]);
    }
    
    std::vector<double> invDval(nbAxes_);
    for (size_t i = 0; i < invDval.size(); i++)
    {
        invDval[i] = 1. / sqrt(eigenValues_[i]);
    }
    
    // Calculation of the row and column coordinates as well as the principal axes and components:
    if (!transpose)
    {
        std::vector<double> tmpColWeights(colNb);
        for (unsigned int i = 0; i < colWeights_.size(); i++)
        {
            tmpColWeights[i] = 1. / sqrt(colWeights_[i]);
        }
        
        // The eigen vectors are placed in the same order as their corresponding eigen value in eigenValues_.
        MatrixReal tmpEigenVectors(0,0);
        tmpEigenVectors.resize(eigenVectors_.getNumberOfRows(), nbAxes_);
        size_t cpt2 = 0;
        for (size_t i = eigenVectors_.getNumberOfColumns(); i > (eigenVectors_.getNumberOfColumns() - nbAxes_); i--)
        {
            for (unsigned int j = 0; j < eigenVectors_.getNumberOfRows(); j++)
            {
                tmpEigenVectors[j][cpt2] = eigenVectors_[j][i-1];
            }
            cpt2++;
        }
        
        // matrix of principal axes
        RbMath::hadamardMult(tmpEigenVectors, tmpColWeights, ppalAxes_, true);
        // matrix of row coordinates
        MatrixReal tmpRowCoord_(0,0);
        tmpRowCoord_.resize(rowNb, nbAxes_);
        RbMath::hadamardMult(matrix, colWeights_, tmpRowCoord_, false);
        rowCoord_ = tmpRowCoord_ * ppalAxes_;
        
        // matrix of column coordinates
        RbMath::hadamardMult(ppalAxes_, dval, colCoord_, false);
        // matrix of principal components
        RbMath::hadamardMult(rowCoord_, invDval, ppalComponents_, false);
    }
    else
    {
        std::vector<double> tmpRowWeights(rowNb);
        for (unsigned int i = 0; i < rowWeights_.size(); i++)
        {
            tmpRowWeights[i] = 1. / sqrt(rowWeights_[i]);
        }
        
        // The eigen vectors are placed in the same order as their corresponding eigen value in eigenValues_.
        MatrixReal tmpEigenVectors(0,0);
        tmpEigenVectors.resize(eigenVectors_.getNumberOfRows(), nbAxes_);
        size_t cpt2 = 0;
        for (size_t i = eigenVectors_.getNumberOfColumns(); i > (eigenVectors_.getNumberOfColumns() - nbAxes_); i--)
        {
            for (size_t j = 0; j < eigenVectors_.getNumberOfRows(); j++)
            {
                tmpEigenVectors[j][cpt2] = eigenVectors_[j][i-1];
            }
            cpt2++;
        }
        
        // matrix of principal components
        RbMath::hadamardMult(tmpEigenVectors, tmpRowWeights, ppalComponents_, true);
        // matrix of column coordinates
        MatrixReal tmpColCoord_(colNb, nbAxes_);
        RbMath::hadamardMult(matrix, rowWeights_, tmpColCoord_, true);
        MatrixReal tTmpColCoord_(tmpColCoord_.getNumberOfColumns(),tmpColCoord_.getNumberOfRows());
        RbMath::transposeMatrix(tmpColCoord_, tTmpColCoord_);
        colCoord_ = tTmpColCoord_ * ppalComponents_;
        
        // matrix of row coordinates
        RbMath::hadamardMult(ppalComponents_, dval, rowCoord_, false);
        // matrix of principal axes
        RbMath::hadamardMult(colCoord_, invDval, ppalAxes_, false);
    }
}