Exemple #1
0
double _ConstOptimizer::do_optimize(unsigned int n) {
  for (unsigned int i = 0; i < n; ++i) {
    get_scoring_function()->evaluate(false);
    update_states();
  }
  return get_scoring_function()->evaluate(false);
}
Exemple #2
0
double MonteCarlo::do_optimize(unsigned int max_steps) {
    IMP_OBJECT_LOG;
    IMP_CHECK_OBJECT(this);
    if (get_number_of_movers() == 0) {
        IMP_THROW("Running MonteCarlo without providing any"
                  << " movers isn't very useful.",
                  ValueException);
    }

    ParticleIndexes movable = get_movable_particles();

    // provide a way of feeding in this value
    last_energy_ = do_evaluate(movable);
    if (return_best_) {
        best_ = new Configuration(get_model());
        best_energy_ = last_energy_;
    }
    reset_statistics();
    update_states();

    IMP_LOG_TERSE("MC Initial energy is " << last_energy_ << std::endl);

    for (unsigned int i = 0; i < max_steps; ++i) {
        if (get_stop_on_good_score() &&
                get_scoring_function()->get_had_good_score()) {
            break;
        }
        do_step();
        if (best_energy_ < get_score_threshold()) break;
    }

    IMP_LOG_TERSE("MC Final energy is " << last_energy_ << std::endl);
    if (return_best_) {
        // std::cout << "Final score is " << get_model()->evaluate(false)
        //<< std::endl;
        best_->swap_configuration();
        IMP_LOG_TERSE("MC Returning energy " << best_energy_ << std::endl);
        IMP_IF_CHECK(USAGE) {
            IMP_LOG_TERSE("MC Got " << do_evaluate(get_movable_particles())
                          << std::endl);
            /*IMP_INTERNAL_CHECK((e >= std::numeric_limits<double>::max()
                                && best_energy_ >= std::numeric_limits<double>::max())
                               || std::abs(best_energy_ - e)
                               < .01+.1* std::abs(best_energy_ +e),
                               "Energies do not match "
                               << best_energy_ << " vs " << e << std::endl);*/
        }

        return do_evaluate(movable);
    } else {
        return last_energy_;
double GSLOptimizer::optimize(unsigned int iter,
                              const gsl_multimin_fminimizer_type*t,
                              double ms, double mxs) {
  fis_= get_optimized_attributes();
  best_score_=std::numeric_limits<double>::max();
  unsigned int n= get_dimension();
  if (n ==0) {
    IMP_LOG(TERSE, "Nothing to optimize" << std::endl);
    return get_scoring_function()->evaluate(false);
  }
  gsl_multimin_fminimizer *s=gsl_multimin_fminimizer_alloc (t, n);

  gsl_vector *x= gsl_vector_alloc(get_dimension());
  update_state(x);
  gsl_vector *ss= gsl_vector_alloc(get_dimension());
  gsl_vector_set_all(ss, mxs);

  gsl_multimin_function f= internal::create_f_function_data(this);
  gsl_multimin_fminimizer_set (s, &f, x, ss);
  try {
    int status;
    do {
      --iter;
      //update_state(x);
      status = gsl_multimin_fminimizer_iterate(s);
      if (status) {
        IMP_LOG(TERSE, "Ending optimization because of state " << s
                << std::endl);
        break;
      }
      double sz= gsl_multimin_fminimizer_size(s);
      status= gsl_multimin_test_size(sz, ms);
      update_states();
      if (status == GSL_SUCCESS) {
        IMP_LOG(TERSE, "Ending optimization because of small size " << sz
                << std::endl);
        break;
      }
    } while (status == GSL_CONTINUE && iter >0);
  } catch (AllDone){
  }
  gsl_vector *ret=gsl_multimin_fminimizer_x (s);
  best_score_=gsl_multimin_fminimizer_minimum (s);
  write_state(ret);
  gsl_multimin_fminimizer_free (s);
  gsl_vector_free (x);
  return best_score_;
}
Exemple #4
0
bool MonteCarlo::do_accept_or_reject_move(double score, double last,
        double proposal_ratio) {
    bool ok = false;
    if (score < last) {
        ++stat_downward_steps_taken_;
        ok = true;
        if (score < best_energy_ && return_best_) {
            best_ = new Configuration(get_model());
            best_energy_ = score;
        }
    } else {
        double diff = score - last;
        double e = std::exp(-diff / temp_);
        double r = rand_(random_number_generator);
        IMP_LOG_VERBOSE(diff << " " << temp_ << " " << e << " " << r << std::endl);
        if (e * proposal_ratio > r) {
            ++stat_upward_steps_taken_;
            ok = true;
        } else {
            ok = false;
        }
    }
    if (ok) {
        IMP_LOG_TERSE("Accept: " << score << " previous score was " << last
                      << std::endl);
        last_energy_ = score;
        update_states();
        for (int i = get_number_of_movers() - 1; i >= 0; --i) {
            get_mover(i)->accept();
        }
        return true;
    } else {
        IMP_LOG_TERSE("Reject: " << score << " current score stays " << last
                      << std::endl);
        for (int i = get_number_of_movers() - 1; i >= 0; --i) {
            get_mover(i)->reject();
        }
        ++stat_num_failures_;
        if (isf_) {
            isf_->reset_moved_particles();
        }
        return false;
    }
}
Exemple #5
0
double Simulator::do_simulate(double time) {
  IMP_FUNCTION_LOG;
  set_was_used(true);
  ParticleIndexes ps = get_simulation_particle_indexes();

  setup(ps);
  double target = current_time_ + time;
  boost::scoped_ptr<boost::progress_display> pgs;
  if (get_log_level() == PROGRESS) {
    pgs.reset(new boost::progress_display(time / max_time_step_));
  }
  while (current_time_ < target) {
    last_time_step_ = do_step(ps, max_time_step_);
    current_time_ += last_time_step_;
    update_states();
    if (get_log_level() == PROGRESS) {
      ++(*pgs);
    }
  }
  return Optimizer::get_scoring_function()->evaluate(false);
}
void calc_jacobian(MeshCTX* meshctx, PropCTX* propctx) {

	int myid = propctx->myid, numprocs = propctx->numproc;

	HashTable* El_Table = meshctx->el_table;
	HashTable* NodeTable = meshctx->nd_table;

	TimeProps* timeprops_ptr = propctx->timeprops;
	MapNames* mapname_ptr = propctx->mapnames;
	MatProps* matprops_ptr = propctx->matprops;

	HashEntryPtr* buck = El_Table->getbucketptr();
	HashEntryPtr currentPtr;
	DualElem* Curr_El = NULL;

	int iter = timeprops_ptr->iter;
	double tiny = GEOFLOW_TINY;

#ifdef DEBUGFILE
	ofstream myfile;
	myfile.open("debug.txt",ios::app);
#endif

	for (int i = 0; i < El_Table->get_no_of_buckets(); i++) {
		if (*(buck + i)) {
			currentPtr = *(buck + i);
			while (currentPtr) {
				Curr_El = (DualElem*) (currentPtr->value);

				if (Curr_El->get_adapted_flag() > 0) {

					double *prev_state_vars = Curr_El->get_prev_state_vars();
					double *state_vars = Curr_El->get_state_vars();
					double *d_state_vars = Curr_El->get_d_state_vars();
					double *gravity = Curr_El->get_gravity();
					double *d_gravity = Curr_El->get_d_gravity();
					double *curvature = Curr_El->get_curvature();
					Curr_El->calc_stop_crit(matprops_ptr); //this function updates bedfric properties
					double bedfrict = Curr_El->get_effect_bedfrict();
					double *dx = Curr_El->get_dx();

					if (timeprops_ptr->iter < 51)
						matprops_ptr->frict_tiny = 0.1;
					else
						matprops_ptr->frict_tiny = 0.000000001;

					double flux[4][NUM_STATE_VARS];
					get_flux(El_Table, NodeTable, Curr_El->pass_key(), matprops_ptr, myid, flux);

					double dt = timeprops_ptr->dt.at(iter - 1);	//at final time step we do not need the computation of adjoint and we always compute it for the previouse time so we need iter.
					double dtdx = dt / dx[0];
					double dtdy = dt / dx[1];

					int stop[DIMENSION] = { 0, 0 };
					double orgSrcSgn[4] = { 0., 0., 0., 0. };

					update_states(state_vars, prev_state_vars, flux[0], flux[1], flux[2], flux[3], dtdx, dtdy,
					    dt, d_state_vars, (d_state_vars + NUM_STATE_VARS), curvature, matprops_ptr->intfrict,
					    bedfrict, gravity, d_gravity, *(Curr_El->get_kactxy()), matprops_ptr->frict_tiny,
					    stop, orgSrcSgn);

					Vec_Mat<9>& jacobian = Curr_El->get_jacobian();

					for (int effelement = 0; effelement < EFF_ELL; effelement++) { //0 for the element itself, and the rest id for neighbour elements

#ifdef DEBUG
						char filename[] = "jacobian";
						int bb = 1, aa = 0;

						if (fabs(*(Curr_El->get_coord()) - 161.3) < .04
								&& fabs(*(Curr_El->get_coord() + 1) - 539.58) < .04 && (iter == 545 || iter == 546))
						bb = aa;

						/*Curr_El->get_ithelem() == 8255 && effelement == 0) {/**(Curr_El->pass_key()) == KEY0
						 && *(Curr_El->pass_key() + 1) == KEY1 && iter == ITER
						 && effelement == EFFELL
						 Curr_El->write_elem_info(NodeTable, filename, timeprops_ptr->iter, dt);*/

#endif

						if ((effelement == 0 && prev_state_vars[0] == 0.) || //this is a void element so the residual vector does not change by changing it's values
						    (effelement > 4 && *(Curr_El->get_neigh_proc() + (effelement - 1)) == -2) || //one neighbor in this side
						    (effelement != 0 && void_neigh_elem(El_Table, Curr_El, effelement)) || //this is a void neighbor element so the residual of the curr_el does not depend on this neighbor
						    (effelement > 0 && *(Curr_El->get_neigh_proc() + (effelement - 1)) == INIT)) {

							Curr_El->set_jacobianMat_zero(effelement);

						} else {
							const Mat3x3 *jac_flux_n_x, *jac_flux_p_x, *jac_flux_n_y, *jac_flux_p_y;
							double dh_sens[2];

							set_fluxes_hsens(Curr_El, jac_flux_n_x, jac_flux_p_x, jac_flux_n_y, jac_flux_p_y,
							    dh_sens, effelement);

							calc_jacobian_elem(jacobian(effelement), *jac_flux_n_x, *jac_flux_p_x, *jac_flux_n_y,
							    *jac_flux_p_y, prev_state_vars, d_state_vars, (d_state_vars + NUM_STATE_VARS),
							    curvature, gravity, d_gravity, dh_sens, matprops_ptr->intfrict, bedfrict,
							    *(Curr_El->get_kactxy()), effelement, dtdx, dtdy, dt, stop, orgSrcSgn);

						}
					}
				}
				currentPtr = currentPtr->next;
			}
		}
	}

//	cout<<"max jacobian:  "<<max_jac<<endl;

#ifdef DEBUGFILE
	myfile.close();
#endif

}
Exemple #7
0
double Simulator::do_simulate_wave(double time, double max_time_step_factor,
                                   double base) {
  IMP_FUNCTION_LOG;
  set_was_used(true);
  ParticleIndexes ps = get_simulation_particle_indexes();

  setup(ps);
  double target = current_time_ + time;
  IMP_USAGE_CHECK(max_time_step_factor > 1.0,
                  "simulate wave time step factor must be >1.0");

  // build wave into cur_ts
  double wave_max_ts = max_time_step_factor * max_time_step_;
  std::vector<double> ts_seq;
  {
    int n_half = 2;  // subwave length
    bool max_reached = false;
    double raw_wave_time = 0.0;
    do {
      double cur_ts = max_time_step_;
      // go up
      for (int i = 0; i < n_half; i++) {
        ts_seq.push_back(cur_ts);
        raw_wave_time += cur_ts;
        cur_ts *= base;
        if (cur_ts > wave_max_ts) {
          max_reached = true;
          break;
        }
      }
      // go down
      for (int i = 0; i < n_half; i++) {
        cur_ts /= base;
        ts_seq.push_back(cur_ts);
        raw_wave_time += cur_ts;
        if (cur_ts < max_time_step_) {
          break;
        }
      }
      n_half++;
    } while (!max_reached && raw_wave_time < time);
    // adjust to fit into time precisely
    unsigned int n = (unsigned int)std::ceil(time / raw_wave_time);
    double wave_time = time / n;
    double adjust = wave_time / raw_wave_time;
    IMP_LOG(PROGRESS, "Wave time step seq: ");
    for (unsigned int i = 0; i < ts_seq.size(); i++) {
      ts_seq[i] *= adjust;
      IMP_LOG(PROGRESS, ts_seq[i] << ", ");
    }
    IMP_LOG(PROGRESS, std::endl);
  }

  unsigned int i = 0;
  unsigned int k = ts_seq.size();  // n waves of k frames
  int orig_nf_left = (int)(time / max_time_step_);
  while (current_time_ < target) {
    last_time_step_ = do_step(ps, ts_seq[i++ % k]);
    current_time_ += last_time_step_;
    // emulate state updating by frames for the origin max_time_step
    // (for periodic optimizers)
    int nf_left = (int)((target - current_time_) / max_time_step_);
    while (orig_nf_left >= nf_left) {
      IMP_LOG(PROGRESS, "Updating states: " << orig_nf_left << "," << nf_left
                                            << " target time " << target
                                            << " current time " << current_time_
                                            << std::endl);
      update_states();  // needs to move
      orig_nf_left--;
    }
  }
  IMP_LOG(PROGRESS, "Simulated for " << i << " actual frames with waves of "
                                     << k << " frames each" << std::endl);
  IMP_USAGE_CHECK(current_time_ >= target - 0.001 * max_time_step_,
                  "simulations did not advance to target time for some reason");
  return Optimizer::get_scoring_function()->evaluate(false);
}
double SteepestDescent::do_optimize(unsigned int max_steps) {
  IMP_OBJECT_LOG;
  Float last_score, new_score = 0.0;

  // set up the indexes

  FloatIndexes float_indexes = get_optimized_attributes();

  Float current_step_size = step_size_;

  // ... and space for the old values
  algebra::VectorKD temp_derivs =
      algebra::get_zero_vector_kd(float_indexes.size());
  algebra::VectorKD temp_values =
      algebra::get_zero_vector_kd(float_indexes.size());

  for (unsigned int step = 0; step < max_steps; step++) {
    // model.show(std::cout);
    int cnt = 0;

    // evaluate the last model state
    last_score = get_scoring_function()->evaluate(true);
    IMP_LOG_TERSE("start score: " << last_score << std::endl);

    // store the old values
    for (unsigned int i = 0; i < temp_derivs.get_dimension(); i++) {
      temp_derivs[i] = get_derivative(float_indexes[i]);
      temp_values[i] = get_value(float_indexes[i]);
    }

    bool constant_score = false;
    while (true) {
      cnt++;
      // try new values based on moving down the gradient at the current
      // step size

      IMP_LOG_VERBOSE("step: " << temp_derivs * current_step_size << std::endl);
      for (unsigned int i = 0; i < float_indexes.size(); i++) {
        set_value(float_indexes[i],
                  temp_values[i] - temp_derivs[i] * current_step_size);
      }

      // check the new model
      new_score = get_scoring_function()->evaluate(false);
      IMP_LOG_TERSE("last score: " << last_score << "  new score: " << new_score
                                   << "  step size: " << current_step_size
                                   << std::endl);

      // if the score got better, we'll take it
      if (new_score < last_score) {
        IMP_LOG_TERSE("Accepting step of size " << current_step_size);
        update_states();
        if (new_score <= threshold_) {
          IMP_LOG_TERSE("Below threshold, returning." << std::endl);
          return new_score;
        }
        current_step_size = std::min(current_step_size * 1.4, max_step_size_);
        break;
      }

      // if the score is the same, keep going one more time
      if (std::abs(new_score - last_score) < .0000001) {
        if (constant_score) {
          break;
        }

        current_step_size *= 0.9;
        constant_score = true;
      } else {
        constant_score = false;
        current_step_size *= .7;
      }
      if (cnt > 200) {
        // stuck
        for (unsigned int i = 0; i < float_indexes.size(); i++) {
          set_value(float_indexes[i], temp_values[i]);
        }
        IMP_LOG_TERSE("Unable to find a good step. Returning" << std::endl);
        return last_score;
      }
      if (current_step_size < .00000001) {
        // here is as good as any place we found
        update_states();
        IMP_LOG_TERSE("Unable to make progress, returning." << std::endl);
        return new_score;
      }
    }
  }

  return new_score;
}
Exemple #9
0
void Game_Loop::run() {
  const float interval = 1.0 / target_fps;
  double time = SDL_GetTicks() / 1000.0;
  running = true;
  update_state_stack();
  while (running) {
    double current_time = SDL_GetTicks() / 1000.0;

    // Failsafe in case updates keep taking more time than interval and the
    // loop keeps falling back.
    int max_updates = 16;
    if (current_time - time >= interval) {
      while (current_time - time >= interval) {
        running = update_states(interval);
        if (!running)
          break;
        time += interval;
        if (max_updates-- <= 0) {
          // Forget about catching up.
          time = current_time;
          break;
        }
      }

      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      auto dim = get_dim();
      glViewport(0, 0, dim[0], dim[1]);
      for (auto& state : states)
        state->draw();
      SDL_GL_SwapBuffers();
    } else {
      // Don't busy wait.
      SDL_Delay(10);
    }
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      Game_State *top = top_state();
      switch (event.type) {
      case SDL_KEYDOWN:
        if (top)
          top->key_event(event.key.keysym.sym, event.key.keysym.unicode);
        break;
      case SDL_KEYUP:
        if (top)
          top->key_event(-event.key.keysym.sym, -1);
        break;
      case SDL_MOUSEBUTTONDOWN:
      case SDL_MOUSEBUTTONUP:
        if (top)
          top->mouse_event(event.button.x, event.button.y, mouse_button_mask());
        break;
      case SDL_MOUSEMOTION:
        if (top)
          top->mouse_event(event.motion.x, event.motion.y, mouse_button_mask());
        break;
      case SDL_QUIT:
        quit();
        break;
      }
    }
  }
  SDL_Quit();
}
Exemple #10
0
Float ConjugateGradients::do_optimize(unsigned int max_steps) {
  IMP_OBJECT_LOG;
  IMP_USAGE_CHECK(get_model(),
                  "Must set the model on the optimizer before optimizing");
  clear_range_cache();
  Vector<NT> x, dx;
  int i;
  // ModelData* model_data = get_model()->get_model_data();

  FloatIndexes float_indices = get_optimized_attributes();

  int n = float_indices.size();
  if (n == 0) {
    IMP_THROW("There are no optimizable degrees of freedom.", ModelException);
  }

  x.resize(n);
  dx.resize(n);
  // get initial state in x(n):
  for (i = 0; i < n; i++) {
#ifdef IMP_CG_SCALE
    x[i] = get_scaled_value(float_indices[i]);  // scaled
#else
    x[i] = get_value(float_indices[i]);            // scaled
#endif
    IMP_USAGE_CHECK(
        !IMP::isnan(x[i]) && std::abs(x[i]) < std::numeric_limits<NT>::max(),
        "Bad input to CG");
  }

  // Initialize optimization variables
  int ifun = 0;
  int nrst;
  NT dg1, xsq, dxsq, alpha, step, u1, u2, u3, u4;
  NT f = 0., dg = 1., w1 = 0., w2 = 0., rtst, bestf;
  bool gradient_direction;

  // dx holds the gradient at x
  // search holds the search vector
  // estimate holds the best current estimate to the minimizer
  // destimate holds the gradient at the best current estimate
  // resy holds the restart Y vector
  // ressearch holds the restart search vector
  Vector<NT> search, estimate, destimate, resy, ressearch;
  search.resize(n);
  estimate.resize(n);
  destimate.resize(n);
  resy.resize(n);
  ressearch.resize(n);

/* Calculate the function and gradient at the initial
   point and initialize nrst,which is used to determine
   whether a Beale restart is being done. nrst=n means that this
   iteration is a restart iteration. */
g20:
  f = get_score(float_indices, x, dx);
  if (get_stop_on_good_score() &&
      get_scoring_function()->get_had_good_score()) {
    estimate = x;
    goto end;
  }
  ifun++;
  nrst = n;
  // this is a gradient, not restart, direction:
  gradient_direction = true;

  /* Calculate the initial search direction, the norm of x squared,
     and the norm of dx squared. dg1 is the current directional
     derivative, while xsq and dxsq are the squared norms. */
  dg1 = xsq = 0.;

  for (i = 0; i < n; i++) {
    search[i] = -dx[i];
    xsq += x[i] * x[i];
    dg1 -= dx[i] * dx[i];
  }
  dxsq = -dg1;

  /* Test if the initial point is the minimizer. */
  if (dxsq <= cg_eps * cg_eps * std::max(NT(1.0), xsq)) {
    goto end;
  }

/* Begin the major iteration loop. */
g40:
  update_states();
  /* Begin linear search. alpha is the steplength. */

  if (gradient_direction) {
    /* This results in scaling the initial search vector to unity. */
    alpha = 1.0 / sqrt(dxsq);
  } else if (nrst == 1) {
    /* Set alpha to 1.0 after a restart. */
    alpha = 1.0;
  } else {
    /* Set alpha to the nonrestart conjugate gradient alpha. */
    alpha = alpha * dg / dg1;
  }

  /* Store current best estimate for the score */
  estimate = x;
  destimate = dx;

  /* Try to find a better score by linear search */
  if (!line_search(x, dx, alpha, float_indices, ifun, f, dg, dg1, max_steps,
                   search, estimate)) {
    /* If the line search failed, it was either because the maximum number
       of iterations was exceeded, or the minimum could not be found */
    if (static_cast<unsigned int>(ifun) > max_steps) {
      goto end;
    } else if (gradient_direction) {
      goto end;
    } else {
      goto g20;
    }
  }

  /* THE LINE SEARCH HAS CONVERGED. TEST FOR CONVERGENCE OF THE ALGORITHM. */
  dxsq = xsq = 0.0;
  for (i = 0; i < n; i++) {
    dxsq += dx[i] * dx[i];
    xsq += x[i] * x[i];
  }
  if (dxsq < threshold_) {
    goto end;
  }

  /* Search continues. Set search(i)=alpha*search(i),the full step vector. */
  for (i = 0; i < n; i++) {
    search[i] *= alpha;
  }

  /* COMPUTE THE NEW SEARCH VECTOR;
     TEST IF A POWELL RESTART IS INDICATED. */
  rtst = 0.;
  for (i = 0; i < n; ++i) {
    rtst += dx[i] * destimate[i];
  }

  if (std::abs(rtst / dxsq) > .2) {
    nrst = n;
  }

  /* If a restart is indicated, save the current d and y
     as the Beale restart vectors and save d'y and y'y
     in w1 and w2. */
  if (nrst == n) {
    ressearch = search;
    w1 = w2 = 0.;
    for (i = 0; i < n; i++) {
      resy[i] = dx[i] - destimate[i];
      w1 += resy[i] * resy[i];
      w2 += search[i] * resy[i];
    }
  }

  /* CALCULATE THE RESTART HESSIAN TIMES THE CURRENT GRADIENT. */
  u1 = u2 = 0.0;
  for (i = 0; i < n; i++) {
    u1 -= ressearch[i] * dx[i] / w1;
    u2 += ressearch[i] * dx[i] * 2.0 / w2 - resy[i] * dx[i] / w1;
  }
  u3 = w2 / w1;
  for (i = 0; i < n; i++) {
    estimate[i] = -u3 * dx[i] - u1 * resy[i] - u2 * ressearch[i];
  }

  /* If this is a restart iteration, estimate contains the new search vector. */
  if (nrst != n) {

    /* NOT A RESTART ITERATION. CALCULATE THE RESTART HESSIAN
       TIMES THE CURRENT Y. */
    u1 = u2 = u3 = 0.0;
    for (i = 0; i < n; i++) {
      u1 -= (dx[i] - destimate[i]) * ressearch[i] / w1;
      u2 = u2 - (dx[i] - destimate[i]) * resy[i] / w1 +
           2.0 * ressearch[i] * (dx[i] - destimate[i]) / w2;
      u3 += search[i] * (dx[i] - destimate[i]);
    }
    step = u4 = 0.;
    for (i = 0; i < n; i++) {
      step =
          (w2 / w1) * (dx[i] - destimate[i]) + u1 * resy[i] + u2 * ressearch[i];
      u4 += step * (dx[i] - destimate[i]);
      destimate[i] = step;
    }

    /* CALCULATE THE DOUBLY UPDATED HESSIAN TIMES THE CURRENT
       GRADIENT TO OBTAIN THE SEARCH VECTOR. */
    u1 = u2 = 0.0;
    for (i = 0; i < n; i++) {
      u1 -= search[i] * dx[i] / u3;
      u2 +=
          (1.0 + u4 / u3) * search[i] * dx[i] / u3 - destimate[i] * dx[i] / u3;
    }
    for (i = 0; i < n; i++) {
      estimate[i] = estimate[i] - u1 * destimate[i] - u2 * search[i];
    }
  }

  /* CALCULATE THE DERIVATIVE ALONG THE NEW SEARCH VECTOR. */
  search = estimate;
  dg1 = 0.0;
  for (i = 0; i < n; i++) {
    dg1 += search[i] * dx[i];
  }

  /* IF THE NEW DIRECTION IS NOT A DESCENT DIRECTION,STOP. */
  if (dg1 <= 0.0) {

    /* UPDATE NRST TO ASSURE AT LEAST ONE RESTART EVERY N ITERATIONS. */
    if (nrst == n) {
      nrst = 0;
    }
    nrst++;
    gradient_direction = false;
    goto g40;
  }

/* ROUNDOFF HAS PRODUCED A BAD DIRECTION. */

end:
  // If the 'best current estimate' is better than the current state, return
  // that:
  bestf = get_score(float_indices, estimate, destimate);
  if (bestf < f) {
    f = bestf;
  } else {
    // Otherwise, restore the current state x (note that we already have the
    // state x and its derivatives dx, so it's rather inefficient to
    // recalculate the score here, but it's cleaner)
    f = get_score(float_indices, x, dx);
  }
  update_states();
  return f;
}