// This is core/vnl/algo/vnl_conjugate_gradient.h
#ifndef vnl_conjugate_gradient_h_
#define vnl_conjugate_gradient_h_
//:
//  \file
//  \brief  real function minimization
//  \author Geoffrey Cross, Oxford RRG
//  \date   15 Feb 99
//
// \verbatim
// Modifications
// 990215 Geoff Initial version.
// 000628 David Capel - Major rewrite. Now derived from vnl_nonlinear_minimizer and operates on a vnl_cost_function.
//   Feb.2002 - Peter Vanroose - brief doxygen comment placed on single line
// \endverbatim
//
//-----------------------------------------------------------------------------

#include <iosfwd>
#ifdef _MSC_VER
#  include <vcl_msvc_warnings.h>
#endif
#include <vnl/vnl_vector.h>
#include <vnl/vnl_matrix.h>
#include <vnl/vnl_nonlinear_minimizer.h>
#include <vnl/algo/vnl_algo_export.h>

class vnl_cost_function;

//: real function minimization

class VNL_ALGO_EXPORT vnl_conjugate_gradient : public vnl_nonlinear_minimizer
{
 public:
  // Constructors/Destructors--------------------------------------------------

  //: Initialize with the function object that is to be minimized.
  vnl_conjugate_gradient(vnl_cost_function& f) { init( f); }

  //: Initialize as above, and then run minimization.
  vnl_conjugate_gradient(vnl_cost_function& f, vnl_vector<double>& x) {
    init(f);
    minimize(x);
  }

  //: Initialize all variables
  void init(vnl_cost_function &f);

  //: Destructor.
  ~vnl_conjugate_gradient() override;

  // Operations----------------------------------------------------------------

  void diagnose_outcome(std::ostream&) const;
  void diagnose_outcome(/*std::ostream& = std::cout*/) const;

  // Computations--------------------------------------------------------------

  //: Minimize the function supplied in the constructor until convergence or failure.
  // On return, x is such that f(x) is the lowest value achieved.
  // Returns true for convergence, false for failure.
  bool minimize(vnl_vector<double>& x);

 protected:
  // Data Members--------------------------------------------------------------

  vnl_cost_function *f_;
  double final_step_size_;

  // Helpers-------------------------------------------------------------------

  static double valuecomputer_( double *x, void* userdata);
  static void gradientcomputer_( double *g, double *x, void* userdata);
  static void valueandgradientcomputer_( double *v, double *g, double *x, void* userdata);
  static void preconditioner_( double *out, double *in, void* userdata);

};

#endif // vnl_conjugate_gradient_h_
