Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
optimizer.h 2.95 KiB
#ifndef __LIB_MATH_OPTIMIZER__
#define __LIB_MATH_OPTIMIZER__

#include <iostream>
#include <limits>
#include <gsl/gsl_multimin.h>
#include "math/gsl_vector.h"
#include "util/flags.h"

using std::cout;
using std::endl;

DEFINE_double(multimin_convergence_threshold,
	      1e-5,
	      "Convergence threshold for conjugate gradient.");
DEFINE_size(max_multimin_iterations,
	    40,
	    "Maximum number of conjugate gradient iterations to perform.");

class Optimizer {
 public:
  Optimizer(size_t size) : size_(size) {  
  }
  
  void Optimize() {
    gsl_multimin_function_fdf my_func;
    my_func.n = size_;
    my_func.f = &MultiminObjectiveWrapper;
    my_func.df = &MultiminGradientWrapper;
    my_func.fdf = &MultiminObjectiveGradientWrapper;
    my_func.params = this;
    
    gsl_multimin_fdfminimizer* s =  
      gsl_multimin_fdfminimizer_alloc(gsl_multimin_fdfminimizer_conjugate_fr, size_);
    GslVector initial_guess(size_);
    MultiminInitialGuess(initial_guess.mutable_ptr());

    // step_size, tol
    //    gsl_multimin_fdfminimizer_set(s, &my_func, initial_guess.ptr(), 0.1, 1.0);
    gsl_multimin_fdfminimizer_set(s, &my_func, initial_guess.ptr(), 0.01, 0.01);
    
    size_t iter = 0;
    int status;
    
    double value = std::numeric_limits<double>::infinity();
    double prev_value;
    do {
      prev_value = value;
      iter++;
      status = gsl_multimin_fdfminimizer_iterate(s);
      if (status) {
	cout << "Error: " << gsl_strerror(status) << endl;
	break;
      }
      status = gsl_multimin_test_gradient(s->gradient, 1e-3);	
      if (status == GSL_SUCCESS) {
	cout << "Minimum found." << endl;
      }
      value = s->f;
      cout << "Iteration: " << iter << " Value: " << 
	value << " dValue:" << (prev_value - value)/fabs(value) << " " <<
	gsl_strerror(status) << endl;
    } while (status == GSL_CONTINUE &&
	       iter < FLAGS_max_multimin_iterations &&
	     (prev_value - value) / fabs(value) > FLAGS_multimin_convergence_threshold);    
    MultiminResult(s->x);
    gsl_multimin_fdfminimizer_free(s);
  }

  virtual void MultiminObjectiveGradient(const gsl_vector* x, 
					 double* objective, 
					 gsl_vector* gradient) = 0;

  virtual void MultiminInitialGuess(gsl_vector* v) = 0;
  
  virtual void MultiminResult(gsl_vector* x) = 0;

  virtual ~Optimizer() { }
 protected:
  static double MultiminObjectiveWrapper(const gsl_vector* x, void* params) {
    double objective;
    reinterpret_cast<Optimizer*>(params)->MultiminObjectiveGradient(x, &objective, NULL);
    return objective;
  }
  
  static void MultiminGradientWrapper(const gsl_vector* x, void* params, gsl_vector* g) {
    reinterpret_cast<Optimizer*>(params)->MultiminObjectiveGradient(x, NULL, g);
  }
  
  static void MultiminObjectiveGradientWrapper(const gsl_vector* x,
					       void* params,
					       double* f,
					       gsl_vector* g) {
    reinterpret_cast<Optimizer*>(params)->MultiminObjectiveGradient(x, f, g);
  }
  
 private:
  size_t size_;
};
#endif  // __LIB_MATH_OPTIMIZER__