Evaluation eval(const Evaluation& x, const Evaluation& y) const
    {
        typedef MathToolbox<Evaluation> Toolbox;

#ifndef NDEBUG
        if (!applies(x,y))
        {
            OPM_THROW(NumericalProblem,
                       "Attempt to get tabulated value for ("
                       << x << ", " << y
                       << ") on a table of extend "
                       << xMin() << " to " << xMax() << " times "
                       << yMin() << " to " << yMax());
        };
#endif

        Evaluation alpha = xToI(x);
        Evaluation beta = yToJ(y);

        unsigned i = std::max(0U, std::min(static_cast<unsigned>(numX()) - 2,
                                           static_cast<unsigned>(Toolbox::value(alpha))));
        unsigned j = std::max(0U, std::min(static_cast<unsigned>(numY()) - 2,
                                           static_cast<unsigned>(Toolbox::value(beta))));

        alpha -= i;
        beta -= j;

        // bi-linear interpolation
        const Evaluation& s1 = getSamplePoint(i, j)*(1.0 - alpha) + getSamplePoint(i + 1, j)*alpha;
        const Evaluation& s2 = getSamplePoint(i, j + 1)*(1.0 - alpha) + getSamplePoint(i + 1, j + 1)*alpha;
        return s1*(1.0 - beta) + s2*beta;
    }
void itsHybridEstimationOfDistribution::simplex()
{
  // if no given NMS evaluations number
  if( getSimplexEvaluations() == -1 ) {
    //setSimplexEvaluations( (int)floor( pow( (this->problem->getDimension() + 1 ), 2.0 ) ) );
    setSimplexEvaluations( this->getProblem()->getDimension() + 10 );
  }
  
  for( unsigned int i=0; i < getSampleSizeCurrent(); i++ ) {
    itsNelderMead nms;
  
    // problem optimized
    nms.setProblem( this->getProblem() );
  
    // no ending stopping criteria
    nms.setValueMin(0.0);
    nms.setIterationsMaxNumber( this->getIterationsMaxNumber() );
  
    // used stopping criterion
    nms.setEvaluationsMaxNumber( this->simplexEvaluations );
  
    // edges from sample hypercube
    vector<double> edges = 
      multiply(
        substraction(
          this->getProblem()->boundsMaxima(),
          this->getProblem()->boundsMinima()
        ),
        1 / ( pow( (double)getSampleSizeCurrent(), (double)1.0/this->getProblem()->getDimension() ) - 1 )
      );
      
    // init on current point
    nms.initSimplexFromBasePoint( getSamplePoint(i), edges );
  
    // silent launch
    nms.startSilent();
    
    // change the point to the new local optimum
    setSamplePoint( i, nms.getOptimum() );
  }
}