/************************************************************************/
/*
opt-criterion: optimization criterion

The random seed is used to control when noise is repeated.
Each trial 1..N gets a different seed. When the trial is repeated
on the next optimization pass, the same seed is used.
*/
/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "main.h"
#include "main2.h"

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/

extern SIM sim;

/*****************************************************************************/
/*****************************************************************************/
/* double, zero-based indexing */

double func_core( double *x )
{
  double cost = 0;

  sim.func_calls++;

  dvector_to_sim( x, sim.n_parameters, sim.params );
  reinit_sim( &sim );

  for( ; sim.time < sim.duration; )
    {
      controller( &sim );
      if ( sim.status == CRASHED )
	break;
      integrate_one_time_step( &sim );
    }

  cost = get_score( &sim );

  return cost;
}

/***************************************************************************/
/* Version for Numerical Recipes version 1 and 2. float, 1-based indexing */

float call_many_func( float *x )
{
  float cost = 0;
  float c;
  int i;
  static int count = 1;
  double p[MAX_N_PARAMETERS];

  printf( "call_many_func %d\n", count++ );

  for( i = 0; i < sim.n_parameters; i++ )
    p[i] = x[i+1];

  for( i = 0; i < sim.n_func_calls_per_eval; i++ )
    {
      sim.rand_seed = i + 1;
      c = func_core( p );
      cost += c;
      if ( sim.debug_criterion )
	printf( "%d: %g\n", i, c );
    }

  if ( cost < sim.all_time_low_cost )
    {
      printf( "ALL TIME LOW COST: %g\n", cost );
      for ( i = 1; i <= sim.n_parameters; i++ )
	printf( "p[%d] = %18.12f;\n", i-1, x[i] );
      if ( cost < sim.all_time_low_cost )
	sim.all_time_low_cost = cost;
      write_param_file( sim.output_file, sim.params );
    }

  if ( sim.debug_criterion )
    {
      printf( "%d %d: cost %g\n", sim.iter, sim.func_calls, cost );
      for( i = 1; i <= sim.n_parameters; i++ )
	printf( "%g ", x[i] );
      printf( "\n\n" );
    }

  return cost;
}

/***************************************************************************/
/* Version for Numerical Recipes 3. double, 0-based indexing */

double call_many_func_d( double *x )
{
  double cost = 0;
  double c;
  int i;
  static int count = 1;

  printf( "call_many_func_d %d\n", count++ );

  for( i = 0; i < sim.n_func_calls_per_eval; i++ )
    {
      sim.rand_seed = i + 1;
      c = func_core( x );
      cost += c;
      printf( "%d: %g\n", i, c );
    }

  if ( cost < sim.all_time_low_cost )
    {
      printf( "ALL TIME LOW COST: %g\n", cost );
      for ( i = 0; i < sim.n_parameters; i++ )
	printf( "p[%d] = %18.12f;\n", i, x[i] );
      if ( cost < sim.all_time_low_cost )
	sim.all_time_low_cost = cost;
      write_param_file( sim.output_file, sim.params );
    }

  if ( sim.debug_criterion )
    {
      printf( "%d %d: cost %g\n", sim.iter, sim.func_calls, cost );
      for( i = 0; i < sim.n_parameters; i++ )
	printf( "%g ", x[i] );
      printf( "\n\n" );
    }

  return cost;
}

/***************************************************************************/
