/******************************************************************************
* NOMAD -  Nonlinear Optimization for Mixed vAriables and Derivatives.        *
* Copyright (C) 2001-2004  Gilles Couture - Ecole Polytechnique,              *
*                          Charles Audet - Ecole Polytechnique,               *
*		           John Dennis - Rice University.                     *
*                                                                             *
* Author: Gilles Couture                                                      *
* École Polytechnique de Montréal - GERAD                                     *
* C.P. 6079, Succ. Centre-ville, Montréal (Québec) H3C 3A7 Canada             *
* Tel:  (514) 340-6053 x6928                                                  *
* Email: Gilles.Couture@gerad.ca                                              *
* Fax: (514) 340-5665                                                         *
*                                                                             *
* This program is free software; you can redistribute it and/or               *
* modify it under the terms of the GNU General Public License                 *
* as published by the Free Software Foundation. You can find the              *
* GNU General Public License at:                                              *
*             http://www.gnu.org/copyleft/gpl.html                            *
*                                                                             *
* This program is distributed in the hope that it will be useful,             *
* but WITHOUT ANY WARRANTY; without even the implied warranty of              *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
* GNU General Public License for more details.                                *
*                                                                             *
* You should have received a copy of the GNU General Public License           *
* along with this program; if not, write to the Free Software                 *
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. *
*                                                                             *
* You can find information on the NOMAD software at:                          *
*             http://www.gerad.ca/NOMAD/                                      *
******************************************************************************/

// parameters.cpp -- class methods for Parameters.

#include <fstream>
#include <iostream>
using namespace std;
#include "parameters.h"

// Private methods
// ****************************************************************************

// This method reads the parameters file, capturing its variables in the
// process.
void Parameters::readParameterFile(ifstream & fin)
{
  char ch;
  char line[80];
  bool check_speculative = false, check_relative = false,
    check_init_comp = false, check_iter_comp = false, check_poll_comp = false,
    check_poll_order = false, check_poll_size = false,
    check_poll_size_term = false, check_hmax = false, check_poll_basis = false,
    check_frame_center_trigger = false, check_surr_tol = false,
    check_truth_term = false, check_iter_nb = false, check_last_term = false,
    check_refine = false, check_new_truth_term = false, check_coarsen = false,
    check_norm = false, check_ini_pts = false, check_ini_type = false,
    check_iter_pts = false, check_iter_type = false, check_poll_dirs = false,
    check_rand_seed = false, check_hmin = false, check_max_poll_size = false,
    check_secondary = false;
  // The file is read line by line in this loop.
  while (!fin.eof())
    {
      // We look at the first character, without putting it in the input buffer
      ch = fin.peek();
      fin >> line;
      // If the first character is '#', it means that we have a comment line.
      // Nothing is done in that case.
      if (ch != '#')
	{
	  // The initial poll size is extracted:
	  if (!check_poll_size && (strcmp(line, "INITIAL_POLL_SIZE") == 0))
	    {
	      fin >> poll_size;
	      check_poll_size = true;
	    }
	  // The maximum poll size is extracted:
	  if (!check_max_poll_size && (strcmp(line, "MAX_POLL_SIZE") == 0))
	    {
	      fin >> max_poll_size;
	      check_max_poll_size = true;
	    }
	  // The poll size basis is extracted:
	  else if (!check_poll_basis && (strcmp(line, "POLL_BASIS") == 0))
	    {
	      fin >> poll_basis;
	      check_poll_basis = true;
	    }
	  // The frame center trigger is extracted:
	  else if (!check_frame_center_trigger &&
		   (strcmp(line, "FRAME_CENTER_TRIGGER") == 0))
	    {
	      fin >> frame_center_trigger;
	      check_frame_center_trigger = true;
	    }
	  // The coarsening exponent is extracted:
	  else if (!check_coarsen && (strcmp(line,"COARSENING_EXPONENT") == 0))
	    {
	      fin >> coarsening_exponent;
	      check_coarsen = true;
	    }
	  // The refining exponent is extracted:
	  else if (!check_refine && (strcmp(line, "REFINING_EXPONENT") == 0))
	    {
	      fin >> refining_exponent;
	      check_refine = true;
	    }
	  // The random seed is extracted:
	  else if (!check_rand_seed && (strcmp(line, "RANDOM_SEED") == 0))
	    {
	      fin >> random_seed;
	      check_rand_seed = true;
	    }
	  // The poll order is extracted:
	  else if (!check_poll_order && (strcmp(line, "POLL_ORDER") == 0))
	    {
	      fin >> poll_order;
	      check_poll_order = true;
	    }
	  // The variable that indicates if the poll is complete is extracted:
	  else if (!check_poll_comp && (strcmp(line, "POLL_COMPLETE") == 0))
	    {
	      fin >> poll_complete;
	      check_poll_comp = true;
	    }
	  // The poll directions variable is extracted:
	  else if (!check_poll_dirs && (strcmp(line, "POLL_DIRECTIONS") == 0))
	    {
	      fin >> poll_directions;
	      check_poll_dirs = true;
	    }
	  // The number of secondary poll directions is extracted.
	  else if (!check_secondary && (strcmp(line, "SECONDARY_POLLDIRS") == 0))
	    {
	      fin >> secondary_polldirs;
	      check_secondary = true;
	    }
	  // The initial search type is extracted:
	  else if (!check_ini_type && (strcmp(line, "INITIAL_SEARCH") == 0))
	    {
	      fin >> initial;
	      check_ini_type = true;
	    }
	  /* The variable that indicates if the initial search is complete is
	     extracted: */
	  else if (!check_init_comp && (strcmp(line,"INITIAL_COMPLETE") == 0))
	    {
	      fin >> initial_complete;
	      check_init_comp = true;
	    }
	  // The number of points of the initial search is extracted:
	  else if (!check_ini_pts && (strcmp(line, "INITIAL_POINTS") == 0))
	    {
	      fin >> initial_points;
	      check_ini_pts = true;
	    }
	  // The iterative search type is extracted:
	  else if (!check_iter_type && (strcmp(line, "ITERATIVE_SEARCH") == 0))
	    {
	      fin >> iterative;
	      check_iter_type = true;
	    }
	  /* The variable that indicates if the iterative search is complete is
	     extracted: */
	  else if (!check_iter_comp && (strcmp(line,"ITERATIVE_COMPLETE")== 0))
	    {
	      fin >> iterative_complete;
	      check_iter_comp = true;
	    }
	  // The number of points of the iterative search is extracted:
	  else if (!check_iter_pts && (strcmp(line, "ITERATIVE_POINTS") == 0))
	    {
	      fin >> iterative_points;
	      check_iter_pts = true;
	    }
	  // The presence of a speculative search is extracted:
	  else if (!check_speculative &&
		   (strcmp(line, "SPECULATIVE_SEARCH") == 0))
	    {
	      fin >> speculative_search;
	      check_speculative = true;
	    }
	  // The poll size termination criterion is extracted:
	  else if (!check_poll_size_term &&
		   (strcmp(line, "POLL_SIZE_TERM") == 0))
	    {
	      fin >> poll_size_term;
	      check_poll_size_term = true;
	    }
	  // The number of function evaluations criterion is extracted:
	  else if (!check_truth_term && (strcmp(line, "TRUTH_EVALS") == 0))
	    {
	      fin >> truth_evals;
	      check_truth_term = true;
	    }
	  // The criterion for the number of iterations is extracted.
	  else if (!check_iter_nb && (strcmp(line, "ITERATIONS") == 0))
	    {
	      fin >> iterations;
	      check_iter_nb = true;
	    }
	  // The number of new truth evaluations criterion is extracted:
	  else if (!check_new_truth_term &&
		   (strcmp(line, "NEW_TRUTH_EVALS") == 0))
	    {
	      fin >> new_truth_evals;
	      check_new_truth_term = true;
	    }
	  // The 'consecutive failures' criterion is extracted:
	  else if (!check_last_term &&
		   (strcmp(line, "CONSECUTIVE_FAILS") == 0))
	    {
	      fin >> consecutive_fails;
	      check_last_term = true;
	    }
	  /* The variable indicating if 'hmax' is relative to the starting
	     point's h(x) value is extracted: */
	  else if (!check_relative && (strcmp(line, "FILTER_RELATIVE") == 0))
	    {
	      fin >> filter_relative;
	      check_relative = true;
	    }
	  // The hmax value is extracted:
	  else if (!check_hmax && (strcmp(line, "HMAX") == 0))
	    {
	      fin >> hmax;
	      check_hmax = true;
	    }
	  // The hmin value is extracted.
	  else if (!check_hmin && (strcmp(line,"HMIN")== 0))
	    {
	      fin >> hmin;
	      check_hmin = true;
	    }
	  // The filter norm is extracted:
	  else if (!check_norm && (strcmp(line, "FILTER_NORM") == 0))
	    {
	      fin >> filter_norm;
	      check_norm = true;
	    }
	  // The surrogate tolerance is extracted:
	  else if (!check_surr_tol && (strcmp(line,"SURROGATE_TOLERANCE")== 0))
	    {
	      fin >> surrogate_tolerance;
	      check_surr_tol = true;
	    }
	}
    }
}

// Public methods:
// ****************************************************************************

// Class constructor.
Parameters::Parameters(const char * file)
{
  // All the variables are initialized to default parameters, just in case
  // the user forgets to include a given variable in the parameters file.
  // Boolean variables.
  filter_relative = true, initial_complete = false, iterative_complete = false,
    poll_complete = false, poll_order = true, speculative_search = false;
  // String variable.
  parameters_file = NULL;
  // Real variables.
  hmax = 2.0, hmin = 0.0001, max_poll_size = 100000, poll_basis = 2.0,
    frame_center_trigger = 0.1, poll_size = 1.0, poll_size_term = 0.0,
    surrogate_tolerance = 10.0;
  // The integer variables are initialized.
  coarsening_exponent = 1, consecutive_fails = -1, filter_norm = 2,
    initial = 0, initial_points = 0, iterations = -1, iterative = 0,
    iterative_points = 0, new_truth_evals = -1, poll_directions = 0,
    random_seed = 1, refining_exponent = -1, secondary_polldirs = 0,
    truth_evals = 50;

  // The problem file must be loaded.
  if (file != NULL)
    load(file);
  else   // The user didn't provide a parameters file.
    {
      // A default path is given for the parameters file.
      setFile("LIBRARY/parameters.dat");
      // The parameters are written to file.
      write();
    }
}

// Destructor.
Parameters::~Parameters()
{}

// This method checks if the problem is ready to solve.
bool Parameters::readyToSolve() const
{
  // First we check the mesh parameters.
  if (((poll_size <= 0.0) || (poll_basis <= 1.0) || (max_poll_size <= 0.0)) ||
      // The choice of poll directions is checked.	       
      (poll_directions > 4)                            ||
      // The poll center trigger must be strictly positive.
      (frame_center_trigger <= 0.0)                      ||
      // The choice of initial search is checked.	       
      (initial > 2)                                    ||
      // The choice of iterative search is checked.	       
      (iterative > 2)                                  ||
      // At least one termination criterion must be set.
      !((poll_size_term > 0.0) || (consecutive_fails > 0) ||
	(truth_evals > 0) || (iterations > 0) || (new_truth_evals > 0)))
    // Something is wrong with the parameters.
    return false;
  else
    // Everything is ok: we're ready to solve the problem.
    return true;
}

// The mesh parameters are captured.
void Parameters::enterMesh(const double delta_p, const double basis,
			   const double max_delta_p, const int coarsen,
			   const int refine)
{
  poll_size = delta_p;
  poll_basis = basis;
  max_poll_size = max_delta_p;
  coarsening_exponent = coarsen;
  refining_exponent = refine;
}

// The poll parameters are captured.
void Parameters::enterPoll(bool fixed, const bool complete, int choice,
			   const int secondary)
{
  // Choices #3 and #4 are for 'MADS - 2*n' and 'MADS - n+1' poll directions.
  // If MADS poll directions are used, the poll directions are recreated every
  // iteration, thus they can't be ordered by success.
  poll_order = (choice > 2) ? true : fixed;
  poll_complete = complete;
  poll_directions = choice;
  // If we have MADS poll directions we can have secondary poll directions,
  // else the variable is just set to zero.
  secondary_polldirs = (choice > 2) ? secondary : 0;
}

// The progressive barrier parameters are captured.
void Parameters::enterProgressiveBarrier(const bool choice, const double h_max,
																				 const double h_min, const double trigger, const int norm)
{
  filter_relative = choice;
  hmax = h_max;
  hmin = h_min;
  frame_center_trigger = trigger;
  filter_norm = norm;
}

// The random seed is captured.
void Parameters::enterRandomSeed(const int seed)
{
  random_seed = seed;
}

// The search parameters are captured.
void Parameters::enterSearch(const int ini_type, const bool ini_complete,
			     const int ini_pts, const int iter_type,
			     const bool iter_complete, const int iter_pts,
			     const bool speculative)
{
  initial = ini_type;
  initial_complete = ini_complete;
  initial_points = ini_pts;
  iterative = iter_type;
  iterative_complete = iter_complete;
  iterative_points = iter_pts;
  speculative_search = speculative;
}

// The surrogate parameters are captured.
void Parameters::enterSurrogate(const double surr_tol)
{
  surrogate_tolerance = surr_tol;
}

// The termination criteria are captured.
void Parameters::enterTerminationCriteria(const double poll_size_criterion,
					  const int consecutive_failures,
					  const int truth_evaluations,
					  const int iter_number,
					  const int new_truth_evaluations)
{
  poll_size_term = poll_size_criterion;
  consecutive_fails = consecutive_failures;
  truth_evals = truth_evaluations;
  iterations = iter_number;
  new_truth_evals = new_truth_evaluations;
}

// This method opens the parameters file and loads them in memory.
void Parameters::load(const char * file)
{
  // First the 'problem_file' variable is reset.
  setFile(file);
  // We open the problem data file.
  ifstream fin(file);
  // If the file has been opened ('file' is a correct path)...
  if (fin.is_open())
    {
      // ...we read the file's data with this method.
      readParameterFile(fin);
      // The file is closed.
      fin.close();
    }
  else
    {
      // We alert the user that something is wrong with the path.
      cerr << "Couldn't open parameter file '" << file << "'\n\n";
      exit(0);
    }
}

// This method resets the 'parameters_file' variable to 'file'.
void Parameters::setFile(const char * file)
{
  if (parameters_file != NULL)
    delete [] parameters_file;
  // The memory is reserved for 'parameters_file'.
  parameters_file = new char[strlen(file) + 1];
  // 'file' is copied into 'parameters_file'.
  strcpy(parameters_file, file);
}

// This method prints the object's attributes to standard output.
void Parameters::show(ostream & fout, const bool filter_use,
		      const bool surrogate_use) const
{
  fout << "************\n";
  fout << "*PARAMETERS*\n";
  fout << "************\n\n";

  // The mesh parameters are shown.
  fout << "Mesh parameters:\n----------------\n";
  fout << "Initial poll size: " << poll_size;
  fout << "\nMaximum poll size: " << max_poll_size;
  fout << "\nPoll size basis: " << poll_basis;
  fout << "\nCoarsening exponent: " << coarsening_exponent;
  fout << "\nRefining exponent: " << refining_exponent << "\n\n";

  // The random seed is shown.
  fout << "Random seed: " << random_seed << "\n";
  fout << "------------\n\n";

  // The poll parameters are shown.
  fout << "Poll parameters:\n----------------\n";
  fout << "Poll order: " << poll_order;
  (poll_order == true) ? fout << " (Fixed)\n" : fout << " (Dynamic)\n";
  fout << "Complete poll: " << poll_complete;
  (poll_complete == true) ? fout << " (Complete)\n" : fout << " (Opportunistic)\n";
  fout << "Poll directions: ";
  switch (poll_directions)
    {
      case 0  :  fout << "GPS 2*n\n";
	         break;
      case 1  :  fout << "GPS n+1\n";
	         break;
      case 2  :  fout << "GPS uniform\n";
	         break;
      case 3  :  fout << "MADS 2*n\n";
	         break;
      case 4  :  fout << "MADS n+1\n";
	         break;
      default :  fout << "That's not a choice!\n";
    }
  fout << "Secondary directions: " << secondary_polldirs << "\n\n";

  // The search parameters are shown.
  fout << "Search parameters:\n------------------\n";
  switch (initial)
    {
      case 0  : fout << "No initial search.\n";
	        break;
      case 1  : fout << "Initial search: Random, ";
	        break;
      case 2  : fout << "Initial search: Latin hypercube sampling, ";
	        break;
      default : fout << "This is not an initial search type!\n";
    }
  if (initial > 0)
    {
      (initial_complete > 0) ? fout << "complete, " : fout << "incomplete, ";
      fout << initial_points << " points.\n";
    }
  switch (iterative)
    {
      case 0  : fout << "No iterative searches.\n";
	        break;
      case 1  : fout << "Iterative searches: Random, ";
	        break;
      case 2  : fout << "Iterative searches: Latin hypercube sampling, ";
	        break;
      default : fout << "This is not an iterative search type!\n";
    }
  if (iterative > 0)
    {
      (iterative_complete > 0) ? fout << "complete, " : fout << "incomplete, ";
      fout << iterative_points << " points.\n";
    }
  if (speculative_search)
    fout << "Speculative search executed after a successful iteration.\n";

  // The termination parameters are shown.
  fout << "\nTermination parameters:\n-----------------------\n";
  if (poll_size_term > 0.0)
    fout << "Poll size: " << poll_size_term << "\n";
  if (iterations > 0)
    fout << "Number of iterations: " << iterations << "\n";
  if (truth_evals > 0)
    fout << "Number of truth evaluations: " << truth_evals << "\n";
  if (new_truth_evals > 0)
    fout << "Number of new truth evaluations: " << new_truth_evals << "\n";
  if (consecutive_fails > 0)
    fout << "Number of consecutive failures: " << consecutive_fails << "\n";
  fout << "\n";

  // If there are general constraints in the problem, the filter parameters are
  // shown.
  if (filter_use)
    {
      fout << "Filter parameters:\n------------------\n";
      fout << "hmax relative to starting point's h(x) value? ";
      (filter_relative == true) ? fout << "True\n" : fout << "False\n";
      if (filter_relative)
	fout << "Multiplication factor for determining hmax: ";
      else
	fout << "hmax set by the user: ";
      fout << hmax << "\n";
      fout << "hmin: " << hmin << "\n";
      fout << "Frame center trigger: " << frame_center_trigger << "\n";
      fout << "Constraint violation norm: ";
      switch (filter_norm)
	{
	  case 0  : fout << "L-infinity\n\n";
	            break;
	  case 1  : fout << "L-one\n\n";
	            break;
	  case 2  : fout << "L-two squared\n\n";
	            break;
	  default : fout << "That's not a norm!\n\n";
	}
    }

  // If the problem uses a surrogate, the surrogate parameters are shown.
  if (surrogate_use)
    fout << "Surrogate tolerance factor: " << surrogate_tolerance << "\n";
}

// This method writes the object's attributes in the parameters file.
void Parameters::write() const
{
  // First we open the parameters file.
  ofstream fout(parameters_file);
  if (!fout.is_open())
    {
      cerr << "Couldn't open parameters file " << parameters_file << "!!!\n";
      exit(0);
    }
  else   // The file is open; the attributes are written in the file.
    {
      /********************/
      /* Mesh parameters. */
      /********************/
      fout << "#MESH PARAMETERS\n#---------------\n";
      fout << "INITIAL_POLL_SIZE\t" << poll_size << "\n";
      fout << "MAX_POLL_SIZE\t\t" << max_poll_size << "\n";
      fout << "POLL_BASIS\t\t" << poll_basis << "\n";
      fout << "COARSENING_EXPONENT\t" << coarsening_exponent << "\n";
      fout << "REFINING_EXPONENT\t" << refining_exponent << "\n";

      /****************/
      /* Random seed. */
      /****************/
      fout << "#\n#RANDOM SEED PARAMETER\n#---------------------\n";
      fout << "RANDOM_SEED\t\t" << random_seed << "\n";

      /********************/
      /* Poll parameters. */
      /********************/
      fout << "#\n#POLL PARAMETERS\n#---------------\n";
      fout << "POLL_ORDER\t\t" << poll_order << "\n";
      fout << "POLL_COMPLETE\t\t" << poll_complete << "\n";
      fout << "POLL_DIRECTIONS\t\t" << poll_directions << "\n";
      fout << "SECONDARY_POLLDIRS\t\t" << secondary_polldirs << "\n";

      /**********************/
      /* Search parameters. */
      /**********************/
      fout << "#\n#SEARCH PARAMETERS\n#-----------------\n";
      fout << "INITIAL_SEARCH\t\t" << initial << "\n";
      fout << "INITIAL_COMPLETE\t" << initial_complete << "\n";
      fout << "INITIAL_POINTS\t\t" << initial_points << "\n";
      fout << "ITERATIVE_SEARCH\t" << iterative << "\n";
      fout << "ITERATIVE_COMPLETE\t" << iterative_complete << "\n";
      fout << "ITERATIVE_POINTS\t" << iterative_points << "\n";
      fout << "SPECULATIVE_SEARCH\t" << speculative_search << "\n";

      /***************************/
      /* Termination parameters. */
      /***************************/
      fout << "#\n#TERMINATION PARAMETERS\n#----------------------\n";
      fout << "POLL_SIZE_TERM\t\t" << poll_size_term << "\n";
      fout << "CONSECUTIVE_FAILS\t" << consecutive_fails << "\n";
      fout << "TRUTH_EVALS\t\t" << truth_evals << "\n";
      fout << "ITERATIONS\t\t" << iterations << "\n";
      fout << "NEW_TRUTH_EVALS\t\t" << new_truth_evals << "\n";

      /**********************/
      /* Filter parameters. */
      /**********************/
      fout << "#\n#FILTER PARAMETERS\n#-----------------\n";
      fout << "FILTER_RELATIVE\t\t" << filter_relative << "\n";
      fout << "HMAX\t\t\t" << hmax << "\n";
      fout << "HMIN\t\t\t" << hmin << "\n";
      fout << "FRAME_CENTER_TRIGGER\t" << frame_center_trigger << "\n";
      fout << "FILTER_NORM\t\t" << filter_norm << "\n";

      /*************************/
      /* Surrogate parameters. */
      /*************************/
      fout << "#\n#SURROGATE PARAMETERS\n#--------------------\n";
      fout << "SURROGATE_TOLERANCE\t" << surrogate_tolerance << "\n";

      // We close the parameters file.
      fout.close();
    }
}
