/******************************************************************************
* 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/                                      *
******************************************************************************/

// speculativesearcher.cpp -- SpeculativeSearcher class methods.

#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
using namespace std;
#include "defines.h"
#include "speculativesearcher.h"

// Public methods.
// ---------------

// Constructor.
SpeculativeSearcher::SpeculativeSearcher(const bool init,
																				 const Description * const des,
																				 Evaluator * eval,
																				 const Parameters * const par)
: Searcher(init, des, eval, par)
{
  direction = NULL;
  trial = NULL;
}

// Destructor.
SpeculativeSearcher::~SpeculativeSearcher()
{
  if (direction != NULL)
    delete [] direction;
  if (trial != NULL)
    delete [] trial;
}

// A speculative search is done after a successful poll.
int SpeculativeSearcher::search(const double delta, const double *,
																const double *, const double *,
																const int sent_from,
																std::vector<AugmentedPoint *> & list_of_points,
																int & term_flag, ofstream & fout,
																ofstream & fgraph, ofstream & history)
{
  int i = 0, max_dimension = description->getDimension(), search_success = 0,
	trial_success = 0;
  std::vector<AugmentedPoint *>::iterator a_point;
	
  if (display_factor >= 7)
    cout << "\nSpeculative search:\n-------------------\n";
	
  while (direction != NULL)
    {
			// First the list of points must be empty.
			if (!list_of_points.empty())
				{
					if (display_factor >= 7)
						cout << "Emptying list...\n";
					for (a_point = list_of_points.begin(); a_point != list_of_points.end(); a_point++)
						delete *a_point;
					list_of_points.clear();
				}
		
			// Then the 'trial' point is inserted in the list.
			AugmentedPoint * ap = new AugmentedPoint(max_dimension, trial);
			list_of_points.push_back(ap);
			// We give the list to Evaluator.
			if (display_factor >= 7)
				cout << "Sending list to Evaluator\n";
			trial_success =  evaluator->processThisList(list_of_points, false, term_flag, fout,
																									fgraph, history, sent_from);
			// Only the most successful try is kept in memory.
			if (trial_success > search_success)
				search_success = trial_success;
		
			a_point = list_of_points.begin();
			
			// If the search was a success...
			if ((trial_success >= 2) && ((*a_point)->getHx() <= parameters->getHmin()))
				{
					if (display_factor >= 5)
						{
							cout << "Speculative search is a success!\n";
							cout << "New trial point generated: ";
						}
			
					// A new point is generated.
					for (i = 0; i < max_dimension; i++)
						{
							// The new 'trial' point is generated by searching further away
							// in the last successful poll direction.
							trial[i] = trial[i] + 3 * direction[i] * delta;
							direction[i] = direction[i] * 2.0;
							if (display_factor >= 5)
								cout << trial[i] << "\t";
						}
				
					if (display_factor >= 5)
						cout << endl << endl;
				}
			else
				{
					if (display_factor >= 5)
						cout << "Speculative search ends.\n";
					delete [] direction;
					direction = NULL;
				}
    }
  return search_success;
}

// 'direction' and 'trial' must be updated.
void SpeculativeSearcher::update(const double delta, std::vector<double> & dir,
																 const AugmentedPoint * new_incumbent)
{
  int i = 0, max_dimension = description->getDimension();
  double * new_inc = new_incumbent->getPoint();
	
  if (display_factor >= 7)
    {
		cout << "\nIn 'SpeculativeSearcher::update(...)'\n";
		cout << "*************************************\n";
		
		cout << "New incumbent = [";
		for (i = 0; i < max_dimension -1; i++)
			cout << new_inc[i] << ", ";
		cout << new_inc[max_dimension -1] << "]\n";
		
		cout << "Successful direction = [";
		for (i = 0; i < max_dimension -1; i++)
			cout << dir[i] * delta << ", ";
		cout << dir[max_dimension -1] * delta << "]\n";
    }
	
	
  // The arrays are initialized on the first update.
  if (direction == NULL)
    direction = new double[max_dimension];
	else
		{
		cout << "Direction = [";
		for (i = 0; i < max_dimension -1; i++)
			cout << direction[i] * delta << ", ";
		cout << direction[max_dimension -1] * delta << "]\n";
		}
	
  if (trial == NULL)
    trial = new double[max_dimension];
	else
		if (display_factor >= 7)
			{
				cout << "Trial = [";
				for (i = 0; i < max_dimension -1; i++)
					cout << trial[i] << ", ";
				cout << trial[max_dimension -1] << "]\n";
			}
	
  for (i = 0; i < max_dimension; i++)
    {
		// First 'dir' is copied into 'direction'.
		direction[i] = dir[i];
		// Now the 'trial' point is generated.
		trial[i] = new_inc[i] + 3 * dir[i] * delta;
    }
	
  if (display_factor >= 7)
    {
		cout << "Trial point generated = [ ";
		for (i = 0; i < max_dimension -1; i++)
			cout << trial[i] << ", ";
		cout << trial[max_dimension -1] << "]" << endl;
    }
}
