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

// augmentedpoint.cpp -- AugmentedPoint class methods.

#include <fstream>
#include <iostream>
using namespace std;
#include "augmentedpoint.h"
#include "defines.h"
#include "point.h"

// Initializing the static class members.
int AugmentedPoint::output_dimension = 0;
const int * AugmentedPoint::index = NULL;

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

// This constructor is used at Start-up to build the starting point.
AugmentedPoint::AugmentedPoint(const int dim, const int out,
			       const int * out_index, const double * coord,
			       const double * scales_add,
			       const double * scales_mult)
{
  // The static variables are initialized.
  output_dimension = out;
  index = out_index;

  Hx = 0.0;
  // The outputs are set to INFINITY.
  output_values = new double[output_dimension];
  for (int i = 0; i < output_dimension; i++)
    output_values[i] = INFINIT;
  // The Point object is created (with scaled coordinates).
  p = new Point(dim, coord, scales_add, scales_mult);
}

// This constructor is used to build the points for the Poll and Search.
AugmentedPoint::AugmentedPoint(const int dim, const double * coord)
{
  Hx = 0.0;
  // All outputs are set to INFINITY.
  output_values = new double[output_dimension];
  for (int i = 0; i < output_dimension; i++)
    output_values[i] = INFINIT;
  // The Point object is created.
  p = new Point(dim, coord);
}

// Copy constructor: used to build the list of points in the filter.
AugmentedPoint::AugmentedPoint(const AugmentedPoint & ap)
{
  Hx = ap.Hx;
  output_values = new double[output_dimension];
  for (int i = 0; i < output_dimension; i++)
    output_values[i] = ap.output_values[i];
  p = new Point(*ap.p);
}

// Destructor. The memory allocated for the two arrays is freed.
AugmentedPoint::~AugmentedPoint()
{
  delete [] output_values;
  delete p;
}

// This method overloads the assignment operator.
AugmentedPoint & AugmentedPoint::operator=(const AugmentedPoint & ap)
{
  // If the object is assigned to itself, nothing is done.
  if (this == &ap)
    return *this;

  // The h(x) value is copied.
  Hx = ap.Hx;
  // The output array is copied.
  for (int i = 0; i < output_dimension; i++)
    output_values[i] = ap.output_values[i];
  // We call the assignment operator for the point 'p'.
  *p = *ap.p;

  // A reference to the invoking object is returned.
  return *this;
}

// This method returns the point's surrogate function value.
double AugmentedPoint::getLow() const
{
  int pos = getPosition(Sx);
  if (pos >= 0)
    return output_values[pos];
  else
    return INFINIT;
}

// This method returns the point's array of real numbers.
double * AugmentedPoint::getPoint() const
{
  return p->getPoint();
}

// This method returns the dimension of the point p.
int AugmentedPoint::getDimension() const
{
  return p->getDimension();
}

// This method returns the position in 'index' where the parameter 'val' is
// first encountered.
int AugmentedPoint::getPosition(const int val) const
{
  for (int i = 0; i < output_dimension; i++)
    if (index[i] == val)
      return i;
  return (-1);
}

// This method completes this object's 'output_values' array from the values of
// the array 'outputs'. It's useful when a point is found in the cache: its
// outputs won't be computed (there will be no call to Truth), but copied from
// the point found in the cache.
void AugmentedPoint::complete(const double * outputs)
{
  for (int i = 0; i < output_dimension; i++)
    {
      if ((output_values[i] == INFINIT) && (outputs[i] != INFINIT))
	output_values[i] = outputs[i];
    }
}

// This method sets the gi(x) values in the output array.
void AugmentedPoint::setGxValues(const double * g_x, const int gen_cons_nb)
{
  // cout << "In 'AugmentedPoint::setGxValues(...)'\n";
  // cout << "gen_cons_nb = " << gen_cons_nb << endl;
  int position = getPosition(Gx);
  // cout << "position = " << position << endl;
  for (int i = 0; i < gen_cons_nb; i++)
    output_values[i + position] = g_x[i];
}

// This method sets the point's surrogate function value.
void AugmentedPoint::setLow(const double val)
{
  int pos = getPosition(Sx);
  if (pos >= 0)
    output_values[pos] = val;
}

// This method outputs the augmented point in the history file.
void AugmentedPoint::showHistory(ofstream & fout, const double * scales_add,
				 const double * scales_mult) const
{
  // Check to see if the file is open.
  if (!fout.is_open())
    return;

  // The point's coordinates are written in the history file.
  p->showHistory(fout, scales_add, scales_mult);

  // The point's outputs are written in the history file.
  for (int i = 0; i < output_dimension; i++)
    {
      if (output_values[i] == INFINIT)
	fout << "INFINITY" << "\t";
      else
	fout << output_values[i] << "\t";
    }

  // The h(x) value is written in the history file (if there are general
  // constraints in the problem).
  if (getPosition(Gx) != -1)
    (Hx == INFINIT) ? fout << "INFINITY" : fout << Hx;

  // The augmented point is written: the next point will be written on a new
  // line.
  fout << "\n";
}

// Outputs the augmented point in the results file.
void AugmentedPoint::showResults(ofstream & fout, const double * scales_add,
				 const double * scales_mult) const
{
  if (!fout.is_open())
    return;
  if (output_values[0] == INFINIT)
    fout << "INFINITY   ";
  else
    fout << output_values[0] << "   ";
  if (p != NULL)
    p->showResults(fout, scales_add, scales_mult);
}

// Non-member functions.
// ****************************************************************************

// This method outputs this object's attributes.
ostream & operator<<(ostream & os, const AugmentedPoint & ap)
{	
	os << "[";
	if (ap.getPosition(ap.Gx) != -1)
    {
			if (ap.Hx == INFINIT)
				os << "INFINITY";
			else
				os << ap.Hx;
			os << ", ";
    }

		if (ap.output_values[0] == INFINIT)
			os << "INFINITY]";
		else
			os << ap.output_values[0] << "]";
	
	os << "\t";	
	
	if (ap.p != NULL)
    os << *ap.p;
  os << "\n";

  return os;
}
