Program: 57379
Project: 57379
Buggy source:
/** 
 * Decompose a matrix A as A.P = Q.R using Householder transforms. <p>As suggested in the P. Lascaux and R. Theodor book <i>Analyse num&eacute;rique matricielle appliqu&eacute;e &agrave; l'art de l'ing&eacute;nieur</i> (Masson, 1986), instead of representing the Householder transforms with u<sub>k</sub> unit vectors such that: <pre> H<sub>k</sub> = I - 2u<sub>k</sub>.u<sub>k</sub><sup>t</sup> </pre> we use <sub>k</sub> non-unit vectors such that: <pre> H<sub>k</sub> = I - beta<sub>k</sub>v<sub>k</sub>.v<sub>k</sub><sup>t</sup> </pre> where v<sub>k</sub> = a<sub>k</sub> - alpha<sub>k</sub> e<sub>k</sub>. The beta<sub>k</sub> coefficients are provided upon exit as recomputing them from the v<sub>k</sub> vectors would be costly.</p> <p>This decomposition handles rank deficient cases since the tranformations are performed in non-increasing columns norms order thanks to columns pivoting. The diagonal elements of the R matrix are therefore also in non-increasing absolute values order.</p>
 * @exception OptimizationException if the decomposition cannot be performed
 */
private void qrDecomposition() throws OptimizationException {
  for (int k=0; k < cols; ++k) {
    permutation[k]=k;
    double norm2=0;
    for (int i=0; i < jacobian.length; ++i) {
      double akk=jacobian[i][k];
      norm2+=akk * akk;
    }
    jacNorm[k]=Math.sqrt(norm2);
  }
  for (int k=0; k < cols; ++k) {
    int nextColumn=-1;
    double ak2=Double.NEGATIVE_INFINITY;
    for (int i=k; i < cols; ++i) {
      double norm2=0;
      for (int j=k; j < jacobian.length; ++j) {
        double aki=jacobian[j][permutation[i]];
        norm2+=aki * aki;
      }
      if (Double.isInfinite(norm2) || Double.isNaN(norm2)) {
        throw new OptimizationException("String_Node_Str",rows,cols);
      }
      if (norm2 > ak2) {
        nextColumn=i;
        ak2=norm2;
      }
    }
    if (ak2 == 0) {
      rank=k;
      return;
    }
    int pk=permutation[nextColumn];
    permutation[nextColumn]=permutation[k];
    permutation[k]=pk;
    double akk=jacobian[k][pk];
    double alpha=(akk > 0) ? -Math.sqrt(ak2) : Math.sqrt(ak2);
    double betak=1.0 / (ak2 - akk * alpha);
    beta[pk]=betak;
    diagR[pk]=alpha;
    jacobian[k][pk]-=alpha;
    for (int dk=cols - 1 - k; dk > 0; --dk) {
      double gamma=0;
      for (int j=k; j < jacobian.length; ++j) {
        gamma+=jacobian[j][pk] * jacobian[j][permutation[k + dk]];
      }
      gamma*=betak;
      for (int j=k; j < jacobian.length; ++j) {
        jacobian[j][permutation[k + dk]]-=gamma * jacobian[j][pk];
      }
    }
  }
  rank=solvedCols;
}

Fixed version (ground truth):
/** 
 * Decompose a matrix A as A.P = Q.R using Householder transforms. <p>As suggested in the P. Lascaux and R. Theodor book <i>Analyse num&eacute;rique matricielle appliqu&eacute;e &agrave; l'art de l'ing&eacute;nieur</i> (Masson, 1986), instead of representing the Householder transforms with u<sub>k</sub> unit vectors such that: <pre> H<sub>k</sub> = I - 2u<sub>k</sub>.u<sub>k</sub><sup>t</sup> </pre> we use <sub>k</sub> non-unit vectors such that: <pre> H<sub>k</sub> = I - beta<sub>k</sub>v<sub>k</sub>.v<sub>k</sub><sup>t</sup> </pre> where v<sub>k</sub> = a<sub>k</sub> - alpha<sub>k</sub> e<sub>k</sub>. The beta<sub>k</sub> coefficients are provided upon exit as recomputing them from the v<sub>k</sub> vectors would be costly.</p> <p>This decomposition handles rank deficient cases since the tranformations are performed in non-increasing columns norms order thanks to columns pivoting. The diagonal elements of the R matrix are therefore also in non-increasing absolute values order.</p>
 * @exception OptimizationException if the decomposition cannot be performed
 */
private void qrDecomposition() throws OptimizationException {
  for (int k=0; k < cols; ++k) {
    permutation[k]=k;
    double norm2=0;
    for (int i=0; i < jacobian.length; ++i) {
      double akk=jacobian[i][k];
      norm2+=akk * akk;
    }
    jacNorm[k]=Math.sqrt(norm2);
  }
  for (int k=0; k < cols; ++k) {
    int nextColumn=-1;
    double ak2=Double.NEGATIVE_INFINITY;
    for (int i=k; i < cols; ++i) {
      double norm2=0;
      for (int j=k; j < jacobian.length; ++j) {
        double aki=jacobian[j][permutation[i]];
        norm2+=aki * aki;
      }
      if (Double.isInfinite(norm2) || Double.isNaN(norm2)) {
        throw new OptimizationException("String_Node_Str",rows,cols);
      }
      if (norm2 > ak2) {
        nextColumn=i;
        ak2=norm2;
      }
    }
    if (ak2 < 1.0e-66) {
      rank=k;
      return;
    }
    int pk=permutation[nextColumn];
    permutation[nextColumn]=permutation[k];
    permutation[k]=pk;
    double akk=jacobian[k][pk];
    double alpha=(akk > 0) ? -Math.sqrt(ak2) : Math.sqrt(ak2);
    double betak=1.0 / (ak2 - akk * alpha);
    beta[pk]=betak;
    diagR[pk]=alpha;
    jacobian[k][pk]-=alpha;
    for (int dk=cols - 1 - k; dk > 0; --dk) {
      double gamma=0;
      for (int j=k; j < jacobian.length; ++j) {
        gamma+=jacobian[j][pk] * jacobian[j][permutation[k + dk]];
      }
      gamma*=betak;
      for (int j=k; j < jacobian.length; ++j) {
        jacobian[j][permutation[k + dk]]-=gamma * jacobian[j][pk];
      }
    }
  }
  rank=solvedCols;
}