/***********************************************************************
* Adaptive Simulated Annealing (ASA)
* Lester Ingber <ingber@ingber.com>
* Copyright (c) 1993-1996 Lester Ingber.  All Rights Reserved.
* The LICENSE file must be included with ASA code.
***********************************************************************/

 /* $Id: asa.h,v 13.5 1996/08/16 10:06:45 ingber Exp ingber $ */

 /* asa.h for Adaptive Simulated Annealing */

#include "asa_user.h"

#define ZERO			((double) 0.0)
#define ONE			((double) 1.0)
#define TWO			((double) 2.0)
#define TEN			((double) 10.0)
#define HALF			((double) 0.5)

#define NORMAL_EXIT			((int) 0)
#define P_TEMP_TOO_SMALL		((int) 1)
#define C_TEMP_TOO_SMALL		((int) 2)
#define COST_REPEATING			((int) 3)
#define TOO_MANY_INVALID_STATES		((int) 4)
#define IMMEDIATE_EXIT			((int) 5)
#define INVALID_USER_INPUT		((int) 7)

#ifndef TIME_STD
#define TIME_STD FALSE
#endif

#if TIME_CALC
#if TIME_STD
#include <sys/syscall.h>
#endif
#include <sys/time.h>
#include <sys/resource.h>
#endif

 /* Set this to TRUE to override the P_TEMP_TOO_SMALL test */
#ifndef NO_PARAM_TEMP_TEST
#define NO_PARAM_TEMP_TEST FALSE
#endif

 /* Set this to TRUE to override the C_TEMP_TOO_SMALL test */
#ifndef NO_COST_TEMP_TEST
#define NO_COST_TEMP_TEST FALSE
#endif

#ifndef SYSTEM_CALL
#define SYSTEM_CALL TRUE
#endif

 /* Printing Options */

#ifndef ASA_PRINT
#define ASA_PRINT TRUE
#endif

#if ASA_PRINT
#else
#if ASA_SAMPLE
#define ASA_PRINT TRUE
#endif
#endif

#ifndef ASA_OUT
#define ASA_OUT "asa_out"
#endif

 /* You can set ASA_PRINT_INTERMED to TRUE to print out
    intermediate data when SELF_OPTIMIZE is set to TRUE */
#ifndef ASA_PRINT_INTERMED
#if SELF_OPTIMIZE
#define ASA_PRINT_INTERMED FALSE
#else
#define ASA_PRINT_INTERMED TRUE
#endif
#endif

#ifndef ASA_PRINT_MORE
#define ASA_PRINT_MORE FALSE
#endif

 /* field-width.precision = G_FIELD.G_PRECISION */
#ifndef G_FIELD
#define G_FIELD 12
#endif
#ifndef G_PRECISION
#define G_PRECISION 7
#endif

 /* The state of the system in terms of parameters and function value */
typedef struct
  {
    double cost;
    double *parameter;
#if ASA_PARALLEL
#if USER_ACCEPTANCE_TEST
    int par_user_accept_flag;
    int par_cost_accept_flag;
#endif
#endif
  }
STATE;

 /* essential MACROS */

#if USER_REANNEAL_PARAMETERS
#else
 /* FUNCTION_REANNEAL_PARAMS(temperature, tangent, max_tangent)
    determines the reannealed temperature. */
#define FUNCTION_REANNEAL_PARAMS(temperature, tangent, max_tangent) \
 (temperature * (max_tangent / tangent))
#endif

 /* IABS(i)
    absolute value for integers, in stdlib.h on _some_ machines */
#define IABS(i) ((i) < 0? -(i) : (i))

 /*  NO_REANNEAL(x)
    can determine whether to calculate derivatives. */
#define NO_REANNEAL(x)	(IABS(parameter_type[x]) == 2)

 /* VFOR
    is a simple macro to iterate on each parameter index. */

#define VFOR(index_v) \
 for (index_v = 0; index_v < *number_parameters; ++index_v)

#if CHECK_EXPONENT
 /* EXPONENT_CHECK
    checks that an exponent x is within a valid range and,
    if not, adjusts its magnitude to fit in the range. */
#define MIN_EXPONENT (0.9 * F_LOG ((double) MIN_DOUBLE))
#define MAX_EXPONENT (0.9 * F_LOG ((double) MAX_DOUBLE))
#define EXPONENT_CHECK(x) \
 ((x) < MIN_EXPONENT ? MIN_EXPONENT : \
 ((x) > MAX_EXPONENT ? MAX_EXPONENT : (x)))
#else
#define EXPONENT_CHECK(x) (x)
#endif /* CHECK_EXPONENT */

 /* PARAMETER_RANGE_TOO_SMALL(x)
    checks if the range of parameter x is too small to work with.
    If user_cost_function changes the parameter ranges,
    this test could be used to adaptively bypass
    some parameters, e.g., depending on constraints. */
#define PARAMETER_RANGE_TOO_SMALL(x) \
 (fabs(parameter_minimum[x] - parameter_maximum[x]) < (double) EPS_DOUBLE)

 /* INTEGER_PARAMETER(x)
    determines if the parameter is an integer type. */
#define INTEGER_PARAMETER(x) (parameter_type[x] > 0)

 /* ROW_COL_INDEX(i, j)
    converts from row i, column j to an index. */
#define ROW_COL_INDEX(i, j) ((i) + *number_parameters * (j))

#if HAVE_ANSI

 /* asa function prototypes */
void accept_new_state (double (*user_random_generator) (LONG_INT *),
		       LONG_INT * seed,
		       double *parameter_minimum,
		       double *parameter_maximum,
		       double *current_cost_temperature,
#if ASA_SAMPLE
		       double *current_user_parameter_temp,
#endif
		       ALLOC_INT * number_parameters,
		       LONG_INT * recent_number_acceptances,
		       LONG_INT * number_accepted,
		       LONG_INT * index_cost_acceptances,
		       LONG_INT * number_acceptances_saved,
		       LONG_INT * recent_number_generated,
		       LONG_INT * number_generated,
		       LONG_INT * index_parameter_generations,
		       STATE * current_generated_state,
		       STATE * last_saved_state,
#if ASA_SAMPLE
		       FILE * ptr_asa_out,
#endif
		       USER_DEFINES * OPTIONS);

void generate_new_state (double (*user_random_generator) (LONG_INT *),
			 LONG_INT * seed,
			 double *parameter_minimum,
			 double *parameter_maximum,
			 double *current_parameter_temperature,
#if USER_GENERATING_FUNCTION
			 double *initial_user_parameter_temp,
			 double *temperature_scale_parameters,
#endif
			 ALLOC_INT * number_parameters,
			 int *parameter_type,
			 STATE * current_generated_state,
			 STATE * last_saved_state,
			 USER_DEFINES * OPTIONS);

void reanneal (double *parameter_minimum,
	       double *parameter_maximum,
	       double *tangents,
	       double *maximum_tangent,
	       double *current_cost_temperature,
	       double *initial_cost_temperature,
	       double *temperature_scale_cost,
	       double *current_user_parameter_temp,
	       double *initial_user_parameter_temp,
	       double *temperature_scale_parameters,
	       ALLOC_INT * number_parameters,
	       int *parameter_type,
	       LONG_INT * index_cost_acceptances,
	       LONG_INT * index_parameter_generations,
	       STATE * last_saved_state,
	       STATE * best_generated_state,
	       USER_DEFINES * OPTIONS);

void cost_derivatives (double (*user_cost_function) (
			   double *, double *, double *, double *, double *,
			  ALLOC_INT *, int *, int *, int *, USER_DEFINES *),
		       double *parameter_minimum,
		       double *parameter_maximum,
		       double *tangents,
		       double *curvature,
		       double *maximum_tangent,
		       ALLOC_INT * number_parameters,
		       int *parameter_type,
		       int *exit_status,
		       int *curvature_flag,
		       int *valid_state_generated_flag,
		       LONG_INT * number_invalid_generated_states,
		       STATE * current_generated_state,
		       STATE * best_generated_state,
		       FILE * ptr_asa_out,
		       USER_DEFINES * OPTIONS);

double generate_asa_state (double (*user_random_generator) (LONG_INT *),
			   LONG_INT * seed,
			   double *temp);

void asa_exit (double (*user_cost_function) (
			   double *, double *, double *, double *, double *,
			  ALLOC_INT *, int *, int *, int *, USER_DEFINES *),
	       double *final_cost,
	       double *parameter_initial_final,
	       double *parameter_minimum,
	       double *parameter_maximum,
	       double *tangents,
	       double *curvature,
	       double *maximum_tangent,
	       double *current_cost_temperature,
	       double *initial_user_parameter_temp,
	       double *current_user_parameter_temp,
	       double *accepted_to_generated_ratio,
	       ALLOC_INT * number_parameters,
	       int *parameter_type,
	       int *valid_state_generated_flag,
	       int *exit_status,
	       ALLOC_INT * index_exit_v,
	       ALLOC_INT * start_sequence,
	       LONG_INT * number_accepted,
	       LONG_INT * best_number_accepted_saved,
	       LONG_INT * index_cost_acceptances,
	       LONG_INT * number_generated,
	       LONG_INT * number_invalid_generated_states,
	       LONG_INT * index_parameter_generations,
	       LONG_INT * best_number_generated_saved,
	       STATE * current_generated_state,
	       STATE * last_saved_state,
	       STATE * best_generated_state,
	       FILE * ptr_asa_out,
	       USER_DEFINES * OPTIONS);

int test_asa_options (LONG_INT * seed,
		      double *parameter_initial_final,
		      double *parameter_minimum,
		      double *parameter_maximum,
		      double *tangents,
		      double *curvature,
		      ALLOC_INT * number_parameters,
		      int *parameter_type,
		      int *valid_state_generated_flag,
		      int *exit_status,
		      FILE * ptr_asa_out,
		      USER_DEFINES * OPTIONS);

void print_string (FILE * ptr_asa_out, char *string);
void print_string_index (FILE * ptr_asa_out, char *string, ALLOC_INT index);

#if ASA_PRINT
void print_state (double *parameter_minimum,
		  double *parameter_maximum,
		  double *tangents,
		  double *curvature,
		  double *current_cost_temperature,
		  double *current_user_parameter_temp,
		  double *accepted_to_generated_ratio,
		  ALLOC_INT * number_parameters,
		  int *curvature_flag,
		  LONG_INT * number_accepted,
		  LONG_INT * index_cost_acceptances,
		  LONG_INT * number_generated,
		  LONG_INT * number_invalid_generated_states,
		  STATE * last_saved_state,
		  STATE * best_generated_state,
		  FILE * ptr_asa_out,
		  USER_DEFINES * OPTIONS);

void print_asa_options (FILE * ptr_asa_out, USER_DEFINES * OPTIONS);


#if TIME_CALC
void aux_print_time (struct timeval *time, char *message,
		     FILE * ptr_asa_out);
#if TIME_STD
int syscall (int sys_option, int who, struct rusage *usage);
#else
int getrusage (int who, struct rusage *usage);
#endif /* TIME_CALC */
#endif /* TIME_STD */
#endif /* ASA_PRINT */

#else /* HAVE_ANSI */

void accept_new_state ();
void generate_new_state ();
void reanneal ();
void cost_derivatives ();
double generate_asa_state ();
void asa_exit ();
int test_asa_options ();
void print_string ();
void print_string_index ();

#if ASA_PRINT
void print_state ();
void print_asa_options ();

#if TIME_CALC
void aux_print_time ();
#if TIME_STD
int syscall ();
#else
int getrusage ();
#endif /* TIME_STD */
#endif /* TIME_CALC */
#endif /* ASA_PRINT */

#endif /* HAVE_ANSI */
