void NonGradient::optimize_vertex_positions(PatchData &pd, 
                                            MsqError &err)
{
  MSQ_FUNCTION_TIMER( "NonGradient::optimize_vertex_positions" );
  int numRow = getDimension();
  int numCol = numRow+1;  
  std::vector<double> height(numCol); 

  for(int col = 0; col < numCol; col++)
  {
    height[col] =  evaluate(&simplex[col*numRow], pd, err);//  eval patch stuff
  }
  if(mNonGradDebug > 0)
  {
    printSimplex( simplex, height );
  }

  // standardization
  TerminationCriterion* term_crit=get_inner_termination_criterion();
  int maxNumEval = getMaxNumEval();
  double threshold = getThreshold();
//  double ftol = getTolerance();
  int ilo = 0;  //height[ilo]<=...
  int inhi = 0; //...<=height[inhi]<=
  int ihi = 0;  //<=height[ihi] 
//  double rtol = 2.*ftol;
  double ysave;
  double ytry;
  bool afterEvaluation = false;
  std::vector<double> rowSum(numRow);
  getRowSum( numRow, numCol, simplex, rowSum);
  while( !( term_crit->terminate() ) )
  {

    if(mNonGradDebug > 0)
    {
      printSimplex( simplex, height );
    }
    //std::cout << "rtol " << rtol << " ftol " << ftol << " MesquiteIter " << term_crit->get_iteration_count() << " Done " << term_crit->terminate() << std::endl;

    if( afterEvaluation )   
    {
      // reflect highPt through opposite face
      // height[0] may vanish
/*
      if( !testRowSum( numRow, numCol, &simplex[0], &rowSum[0]) )
      {
        // Before uncommenting here and ... 
        //MSQ_SETERR(err)("Internal check sum test A failed", MsqError::INTERNAL_ERROR);
        //MSQ_ERRRTN(err);
      }
*/
      ytry=amotry(simplex,height,&rowSum[0],ihi,-1.0, pd, err);
/*
      if( !testRowSum( numRow, numCol, &simplex[0], &rowSum[0]) )
      {
         // ... here, determine a maxVal majorizing the previous as well as the current simplex.
         //MSQ_SETERR(err)("Internal check sum test B failed", MsqError::INTERNAL_ERROR);
         //MSQ_ERRRTN(err);
      }   
*/
  
/*
      if( height[0] == 0.)
      {
         MSQ_SETERR(err)("(B) Zero objective function value", MsqError::INTERNAL_ERROR);
         exit(-1);
      }
*/
      if (ytry <= height[ilo])   
      {
        ytry=amotry(simplex,height,&rowSum[0],ihi,-2.0,pd,err);
        if( mNonGradDebug >= 3 ) 
        {      
         std::cout << "Reflect and Expand from highPt " << ytry << std::endl;
        }      
        //MSQ_PRINT(3)("Reflect and Expand from highPt : %e\n",ytry);
      }
      else 
      {
        if (ytry >= height[inhi]) 
        {
          ysave=height[ihi]; // Contract along highPt
          ytry=amotry(simplex,height,&rowSum[0],ihi,0.5,pd,err);
          if (ytry >= ysave)
          { // contract all directions toward lowPt
            for (int col=0;col<numCol;col++)
            {
              if (col != ilo)
              {
                for (int row=0;row<numRow;row++)
                {
                  rowSum[row]=0.5*(simplex[row+col*numRow]+simplex[row+ilo*numRow]);
                  simplex[row+col*numRow]=rowSum[row];
                }
                height[col] = evaluate(&rowSum[0], pd, err); 
                if( mNonGradDebug >= 3 ) 
                {      
                  std::cout << "Contract all directions toward lowPt value( " << col << " ) = " << height[col] << " ilo = " << ilo << std::endl;
                }      
                //MSQ_PRINT(3)("Contract all directions toward lowPt value( %d ) = %e    ilo = %d\n", col, height[col], ilo);
              }
            }
          }
        }   
      } // ytri > h(ilo) 
    } // after evaluation
    ilo=1; // conditional operator or inline if 
    ihi = height[0] > height[1] ? (inhi=1,0) : (inhi=0,1);
    for (int col=0;col<numCol;col++)
    {
      if (height[col] <= height[ilo])
      {
        ilo=col;  // ilo := argmin height
      }
      if (height[col] > height[ihi])
      {
        inhi=ihi;
        ihi=col;
      } 
      else  // height[ihi] >= height[col]
        if (col != ihi && height[col] > height[inhi] ) inhi=col;
    }
//    rtol=2.0*fabs( height[ihi]-height[ilo] )/
//         ( fabs(height[ihi])+fabs(height[ilo])+threshold );
    afterEvaluation = true;
  } //  while not converged 

  // Always set to current best mesh.
  { 
    if( ilo != 0 )
    {
      double yTemp = height[0];
      height[0] = height[ilo]; // height dimension numCol
      height[ilo] = yTemp;
      for (int row=1;row<numRow;row++)
      { 
          yTemp = simplex[row];
          simplex[row] = simplex[row+ilo*numRow];
          simplex[row+ilo*numRow] = yTemp;
      }
    }
  }
  if( pd.num_free_vertices() > 1 )
  {
    MSQ_SETERR(err)("Only one free vertex per patch implemented", MsqError::NOT_IMPLEMENTED);
  }

  Vector3D newPoint( &simplex[0] ); 
  size_t vertexIndex = 0; // fix c.f. freeVertexIndex
  pd.set_vertex_coordinates( newPoint, vertexIndex, err ); 
  pd.snap_vertex_to_domain( vertexIndex, err );
  if( term_crit->terminate() )
  {
    if( mNonGradDebug >= 1 ) 
    {      
         std::cout << "Optimization Termination OptStatus: Max Iter Exceeded" << std::endl;
    }      
    //MSQ_PRINT(1)("Optimization Termination OptStatus: Max Iter Exceeded\n"); 
  }
}
void ML_multi_DownhillSimplex::amoeba(mat_ratep_type& p, 
                                      v_ratep_type& y,
                                      const double ftol,
                                      ptr_eval_func funk,
                                      int& nfunk
                                     )
{
    const double TINY=1.0e-10;
    int i, ihi, ilo, inhi, j;
    double rtol, ysave, ytry;
    int mpts = p.size();
    int ndim = p[0].size();
    v_ratep_type psum(ndim);
    get_psum(p, psum);
    for (;;) {
        ilo = 0;
        ihi = y[0] > y[1] ? (inhi = 1, 0) : (inhi = 0, 1);
        for (i = 0; i < mpts; ++i) {
            if (y[i] <= y[ilo]) ilo = i;
            if (y[i] > y[ihi]) {
                inhi = ihi;
                ihi = i;
            } else if (y[i] > y[inhi] && i != ihi) inhi = i;
        }
        rtol = 2.0 * std::abs(y[ihi] - y[ilo]) / 
               (std::abs(y[ihi]) + std::abs(y[ilo]) + TINY);
        if (rtol < ftol) {
            SWAP(y[0], y[ilo]);
            for (i = 0; i < ndim; ++i) SWAP(p[0][i], p[ilo][i]);
            break;
        }
        if (nfunk >= get_NMAX()) {
            if (CONFIG_DIE_ON_NMAX_EXCEEDED) {
                std::cerr << "amoeba: NMAX " << get_NMAX() << " exceeded "
                          << nfunk << std::endl;
                assert(false);
            }
            // otherwise, put the lowest at vertex 0 and return to try again
            SWAP(y[0], y[ilo]);
            for (i = 0; i < ndim; ++i) SWAP(p[0][i], p[ilo][i]);
            break;
        }
        nfunk += 2;
        ytry = amotry(p, y, psum, funk, ihi, -1.0);
        if (ytry <= y[ilo])
            ytry = amotry(p, y, psum, funk, ihi, 2.0);
        else if (ytry >= y[inhi]) {
            ysave = y[ihi];
            ytry = amotry(p, y, psum, funk, ihi, 0.5);
            if (ytry >= ysave) {
                for (i = 0; i < mpts; ++i) {
                    if (i != ilo) {
                        for (j = 0; j < ndim; ++j)
                            p[i][j] = psum[j] = 0.5*(p[i][j] + p[ilo][j]);
                        if (DEBUG_BOUNDS_TRACE) bounds_trace(p[i], "amoeba");
                        y[i] = (this->*funk)(psum);
                    }
                }
                nfunk += ndim;
                get_psum(p, psum);
            }
        } else --nfunk;
        if (DEBUG_AMOEBA) {
            if (! DEBUG_MONITOR_X10 || (nfunk % 10) == 0) {
                std::cout << "amoeba(): nfunk=" << nfunk;
                std::cout << " y[ilo]=" << y[ilo];
                std::cout << " y[ihi]=" << y[ihi];
                std::cout << std::endl;
            }
        }
    }
}