private void calculatePCs() {
    // square values in the distance matrix, then double center them
    DoubleMatrix dm = SquaredDoubleMatrixFromDistanceMatrix();
    int n = dm.numberOfRows();

    // double center the matrix
    for (int r = 0; r < n; r++) {
      double mean = dm.rowSum(r) / n;
      for (int c = 0; c < n; c++) {
        dm.set(r, c, dm.get(r, c) - mean);
      }
    }

    for (int c = 0; c < n; c++) {
      double mean = dm.columnSum(c) / n;
      for (int r = 0; r < n; r++) {
        dm.set(r, c, dm.get(r, c) - mean);
      }
    }

    // finally multiply by -1/2
    dm.scalarMultEquals(-0.5);

    // get an eigenvalue decomposition
    eigenDecomp = dm.getEigenvalueDecomposition();

    // calculate PC's for positive eigenvalues
    numberOfPositiveEigenvalues = 0;
    double[] eval = eigenDecomp.getEigenvalues();
    for (int i = 0; i < n; i++) if (eval[i] > tol) numberOfPositiveEigenvalues++;
    eigenVectors = eigenDecomp.getEigenvectors();

    // determine the sort order
    int nEigenvalues = eval.length;
    eigenSort =
        IntStream.range(0, nEigenvalues)
            .boxed()
            .sorted(
                (a, b) -> {
                  if (eval[a] > eval[b]) return -1;
                  if (eval[a] < eval[b]) return 1;
                  return 0;
                })
            .mapToInt(I -> I.intValue())
            .toArray();
    eigenVectors.column(280);
  }
  public double[] getPrincipalCoordinate(int index) {
    if (index > numberOfPositiveEigenvalues - 1) return null;
    double eval = Math.sqrt(eigenDecomp.getEigenvalue(eigenSort[index]));

    int ntaxa = myDistanceMatrix.numberOfTaxa();
    double[] pc = new double[ntaxa];
    for (int i = 0; i < ntaxa; i++) pc[i] = eigenVectors.get(i, eigenSort[index]) * eval;
    return pc;
  }
 public double getEigenvalue(int index) {
   return eigenDecomp.getEigenvalue(eigenSort[index]);
 }