Vector2<double> GaussianDistribution2D::rand() const
{
  Matrix2x2<double> L;
  choleskyDecomposition(covariance, L, 1E-9*(covariance.trace()));
  Vector2<double> xRaw(randomGauss(), randomGauss());
  return L * xRaw;
}
Example #2
0
/* ******************************************************************************** */
int getSearchDir(double *p, double *Grad, double **Hes, double delta, int numSS) {
  /*
    Computes the search direction using the dogleg method (Nocedal and Wright,
    page 71).  Notation is consistent with that in this reference.

    Due to the construction of the problem, the minimization routine
    to find tau can be solved exactly by solving a quadratic.  There
    can be precision issues with this, so this is checked.  If the
    argument of the square root in the quadratic formula is negative,
    there must be a precision error, as such a situation is not
    possible in the construction of the problem.

    Returns:
      1 if step was a pure Newton step (didn't hit trust region boundary)
      2 if the step was purely Cauchy in nature (hit trust region boundary)
      3 if the step was a dogleg step (part Newton and part Cauchy)
      4 if Cholesky decomposition failed and we had to take a Cauchy step
      5 if Cholesky decompostion failed but we would've taken Cauchy step anyways
      6 if the dogleg calculation failed (should never happen)
  */

  int i,j; // counters
  double a,b,c,sgnb; // Constants used in quadratic formula
  double q,x1,x2; // results from quadratic formula
  double tau; // Multipler in Newtonstep
  double *pB; // Unconstrained minimizer (the regular Newton step)
  double *pU; // Minimizer along steepest descent direction
  double pB2; // pj^2
  double pU2; // pu^2
  double pBpU; // pj . pc
  double *CholDiag; // Diagonal from Cholesky decomposition
  double **HesCopy; // Copy of the upper triangle of the Hessian (don't want to mess
                   // with actual Hessian).
  int CholSuccess; // Whether of not Cholesky decomposition is successful
  double *HGrad; // Hessian dotted with the gradient
  double pUcoeff;  // The coefficient on the Cauchy step
  double delta2; // delta^2
  double mag1;   // temporary variables for vector magnitudes
  double mag2;

  // Initialize pB2 just so compiler doesn't give a warning when optimization is on
  pB2 = 0.0;

  delta2 = pow(delta,2);

  /* ********** Compute the Newton step ************** */
  // Memory allocation for computation of  Newton step
  pB = (double *) malloc(numSS * sizeof(double));
  CholDiag = (double *) malloc(numSS * sizeof(double));
  HesCopy = (double **) malloc(numSS * sizeof(double *));
  for (j = 0; j < numSS; j++) {
    HesCopy[j] = (double *) malloc(numSS * sizeof(double));
  }
 
  // Make a copy of the Hessian because the Cholesky decomposition messes
  // with its entries.  We only have to copy the upper diagonal.
  for (j = 0; j < numSS; j++) {
    for (i = j; i < numSS; i++) {
      HesCopy[i][j] = Hes[i][j];
    }
  }

  CholSuccess = choleskyDecomposition(HesCopy,numSS);

  if (CholSuccess == 1) {
    choleskySolve(HesCopy,numSS,Grad,pB);

    // Free memory from Cholesky computation
    free(CholDiag);
    for (i = 0; i < numSS; i++) {
      free(HesCopy[i]);
    }
    free(HesCopy);

    // Newton step is -H^{-1} Grad
    for (i = 0; i < numSS; i++) {
      pB[i] *= -1.0;
    }

    // If Newton is in trust region, take it
    pB2 = dot(pB,pB,numSS);
    if (pB2 <= delta2) {
      for (i = 0; i < numSS; i++) {
	p[i] = pB[i];
      }
      free(pB);
      return 1; // Signifies we took a pure Newton step
    }
  }
  else { // Free memory from failed Newton step computation
    free(CholDiag);
    for (i = 0; i < numSS; i++) {
      free(HesCopy[i]);
    }
    free(HesCopy);
  }
  /* ************************************************* */


  /* ********** Compute the Cauchy step ************** */
  // Allocate necessary arrays
  HGrad = (double *) malloc(numSS * sizeof(double));
  pU = (double *) malloc(numSS * sizeof(double));

  // The direction of the Cauchy step
  for (i = 0; i < numSS; i++) {
    pU[i] =  -Grad[i];
  }

  // prefactor for the Cauchy step
  MatrixVectorMult(HGrad,Hes,Grad,numSS);
  // Should this be sqrt too?

  mag1 = dot(Grad,Grad,numSS);
  mag2 = dot(Grad,HGrad,numSS);
  pUcoeff = mag1 / mag2;

  for (i = 0; i < numSS; i++) {
    pU[i] = pUcoeff * pU[i];
  }
  free(HGrad); // Don't need this any more

  pU2 = dot(pU,pU,numSS);

  if (pU2 >= delta2) { // In this case we just take the Cauchy step, 0 < tau <= 1
    tau = sqrt(delta2/pU2);
    for (i = 0; i < numSS; i++) {
      p[i] = tau*pU[i];
    }
    free(pU);
    free(pB);
    if (CholSuccess != 1) {
      return 5; // Signifies Cholesky failure, but doesn't matter, would take Cauchy
    }           // regardless
    else {
      return 2; // Signifies that we just took the Cauchy step
    }
  }

  if (CholSuccess != 1) { // We failed computing Newton step and have to take Cauchy
    for (i = 0; i < numSS; i++) {
      p[i] = pU[i];
    }
    free(pU);
    free(pB);
    return 4; // Signifies Cholesky failure and we just took the Cauchy step
  }
  /* ************************************************* */


  /* ************ Take the dogleg step *************** */
  pBpU = dot(pB,pU,numSS); // Need this for dogleg calculation
  
  // Constants for quadratic formula for solving ||pU + (alpha)(pB-pU)||^2 = delta2
  a = pB2 + pU2 - 2.0*pBpU;
  b = 2*(pBpU - pU2);
  c = pU2 - delta2;
  sgnb = 1;

  if(b < 0) {
    sgnb = -1;
  }

  q = -0.5 * (b + sgnb * sqrt(b*b - 4*a*c));
  x1 = q / a;
  x2 = c / q;

  // x2 should be the positive root, x1 should be the negative root.
  if(x2 >= 0 && x2 <= 1.0) {
    for(i = 0; i < numSS; i++) {
      p[i] = pU[i] + x2 * (pB[i] - pU[i]);
    }
    free(pU);
    free(pB);
    return 3; // Signifies we took a dogleg step
  } else if(x1 >= 0 && x1 <= 1.0) {
    for(i = 0; i < numSS; i++) {
      p[i] = pU[i] + x1 * (pB[i] - pU[i]);
    }
    free(pU);
    free(pB);
    return 3;
  } else {
    for (i = 0; i < numSS; i++) {
      p[i] = pU[i];
    }
    free(pU);
    free(pB);
    return 6; // Signifies no root satisfies the dogleg step and we took a Cauchy step
  }
}
// Compute L (lower triangular) such that A = L L^T
void choleskyDecomposition(BlockDiagonalMatrix &A,
                           BlockDiagonalMatrix &L) {
  #pragma omp parallel for schedule(dynamic)
  for (unsigned int b = 0; b < A.blocks.size(); b++)
    choleskyDecomposition(A.blocks[b], L.blocks[b]);
}