code: public final Result solve(GradientSolver gslvr, double [] beta, GradientInfo ginfo, ProgressMonitor pm) {
      if(_hist == null)
        _hist = new History(_historySz, beta.length);
      int iter = 0;
      double rel_improvement = 1;
      final double [] pk = new double[beta.length];
      double minStep = 1e-16;
      LineSearchSolver lineSearch = new MoreThuente(gslvr,beta,ginfo);
      while(!ArrayUtils.hasNaNsOrInfs(beta) && (ArrayUtils.linfnorm(ginfo._gradient,false) > _gradEps  && rel_improvement > _objEps) && iter != _maxIter) {
        ++iter;
        _hist.getSearchDirection(ginfo._gradient,pk);
        if(!lineSearch.evaluate(pk))
          break;
        lineSearch.setInitialStep(Math.max(minStep, lineSearch.step()));
        GradientInfo newGinfo = lineSearch.ginfo();
        _hist.update(pk, newGinfo._gradient, ginfo._gradient);
        rel_improvement = (ginfo._objVal - newGinfo._objVal)/ginfo._objVal;
        ginfo = newGinfo;
        if(!pm.progress(lineSearch.getX(), ginfo))break;
      }
      return new Result((ArrayUtils.linfnorm(ginfo._gradient,false) <= _gradEps  || rel_improvement <= _objEps),iter,lineSearch.getX(), lineSearch.ginfo(),rel_improvement);
    }
docs: public final Result solve(GradientSolver gslvr, double [] beta, GradientInfo ginfo, ProgressMonitor pm) {return solve(gslvr,beta,beta.clone(),ginfo,pm);}