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

#define ASA_ID \
"/* $Id: asa.c,v 13.5 1996/08/16 10:06:33 ingber Exp ingber $ */"

#include "asa.h"

/***********************************************************************
* asa
*       This procedure implements the full ASA function optimization.
***********************************************************************/
#if HAVE_ANSI
double
asa (double (*user_cost_function) (
			   double *, double *, double *, double *, double *,
			  ALLOC_INT *, int *, int *, int *, USER_DEFINES *),
     double (*user_random_generator) (LONG_INT *),
     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,
     USER_DEFINES * OPTIONS)
#else
double
asa (user_cost_function,
     user_random_generator,
     seed,
     parameter_initial_final,
     parameter_minimum,
     parameter_maximum,
     tangents,
     curvature,
     number_parameters,
     parameter_type,
     valid_state_generated_flag,
     exit_status,
     OPTIONS)
     double (*user_cost_function) ();
     double (*user_random_generator) ();
     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;
     USER_DEFINES *OPTIONS;
#endif /* HAVE_ANSI */
{
#if USER_INITIAL_COST_TEMP
#if USER_REANNEAL_COST
#else
  int index_cost_constraint;	/* index cost functions averaged */
#endif /* USER_REANNEAL_COST */
#else /* USER_INITIAL_COST_TEMP */
  int index_cost_constraint;	/* index cost functions averaged */
#endif /* USER_INITIAL_COST_TEMP */

  int index_cost_repeat,	/* test OPTIONS->Cost_Precision when =
				   OPTIONS->Maximum_Cost_Repeat */
    tmp_var_int, tmp_var_int1, tmp_var_int2;	/* temporary integers */

  ALLOC_INT index_v,		/* iteration index */
   *start_sequence;		/* initial OPTIONS->Sequential_Parameters
				   used if >= 0 */
  double final_cost,		/* best cost to return to user */
    tmp_var_db, tmp_var_db1, tmp_var_db2;	/* temporary doubles */
  int *curvature_flag;
  FILE *ptr_asa_out;		/* file ptr to output file */

  /* The 3 states that are kept track of during the annealing process */
  STATE *current_generated_state, *last_saved_state, *best_generated_state;

#if ASA_PARALLEL
  /* parallel generated states */
  STATE *gener_block_state;
#endif

#if ASA_SAVE
  FILE *ptr_save;
  int asa_read;
#endif

  /* The array of tangents (absolute value of the numerical derivatives),
     and the maximum |tangent| of the array */
  double *maximum_tangent;

  /* ratio of acceptances to generated points - determines when to
     test/reanneal */
  double *accepted_to_generated_ratio;

  /* temperature parameters */
  double temperature_scale, *temperature_scale_parameters;
  /* relative scalings of cost and parameters to temperature_scale */
  double *temperature_scale_cost;
  double *current_user_parameter_temp;
  double *initial_user_parameter_temp;
  double *current_cost_temperature;
  double *initial_cost_temperature;
  double log_new_temperature_ratio;	/* current *temp = initial *temp *
					   exp(log_new_temperature_ratio) */
  ALLOC_INT *index_exit_v;	/* information for asa_exit */

  /* counts of generated states and acceptances */
  LONG_INT *index_parameter_generations;
  LONG_INT *number_generated, *best_number_generated_saved;
  LONG_INT *recent_number_generated, *number_accepted;
  LONG_INT *recent_number_acceptances, *index_cost_acceptances;
  LONG_INT *number_acceptances_saved, *best_number_accepted_saved;

  /* Flag indicates that the parameters generated were
     invalid according to the cost function validity criteria. */
  LONG_INT *number_invalid_generated_states;
  LONG_INT repeated_invalid_states;

#if ASA_QUEUE
  int queue_new;		/* flag to add new entry */
  int *save_queue_flag;		/* save valid_state_generated_flag */
  LONG_INT queue;		/* index of queue */
  LONG_INT queue_v;		/* index of parameters in queue */
  LONG_INT save_queue_test;	/* test if all parameters are present */
  LONG_INT save_queue;		/* last filled position in queue */
  LONG_INT save_queue_indx;	/* current position in queue */
  double *save_queue_cost, *save_queue_param;	/* saved states */
#endif

#if ASA_PARALLEL
  LONG_INT index_parallel;	/* count of parallel generated states */
  LONG_INT parallel_generated;	/* saved *recent_number_generated */
  LONG_INT parallel_block_max;	/* saved OPTIONS->Gener_Block_Max */
#endif

  /* used to index repeated and recursive calls to asa */
  /* This assumes that multiple calls (>= 1) _or_ recursive
     calls are being made to asa */
  static int asa_open = FALSE;
  static int number_asa_open = 0;
  static int recursive_asa_open = 0;

  /* initializations */

  if ((curvature_flag =
       (int *) mycxalloc (1, sizeof (int))) == NULL)
      exit (9);
  if ((maximum_tangent =
       (double *) mycxalloc (1, sizeof (double))) == NULL)
      exit (9);
  if ((accepted_to_generated_ratio =
       (double *) mycxalloc (1, sizeof (double))) == NULL)
      exit (9);
  if ((temperature_scale_cost =
       (double *) mycxalloc (1, sizeof (double))) == NULL)
      exit (9);
  if ((current_cost_temperature =
       (double *) mycxalloc (1, sizeof (double))) == NULL)
      exit (9);
  if ((initial_cost_temperature =
       (double *) mycxalloc (1, sizeof (double))) == NULL)
      exit (9);
  if ((index_exit_v =
       (ALLOC_INT *) mycxalloc (1, sizeof (ALLOC_INT))) == NULL)
    exit (9);
  if ((start_sequence =
       (ALLOC_INT *) mycxalloc (1, sizeof (ALLOC_INT))) == NULL)
    exit (9);
  if ((number_generated =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((best_number_generated_saved =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((recent_number_generated =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((number_accepted =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((recent_number_acceptances =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((index_cost_acceptances =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((number_acceptances_saved =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((best_number_accepted_saved =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);
  if ((number_invalid_generated_states =
       (LONG_INT *) mycxalloc (1, sizeof (LONG_INT))) == NULL)
    exit (9);

  if ((current_generated_state =
       (STATE *) mycxalloc (1, sizeof (STATE))) == NULL)
    exit (9);
  if ((last_saved_state =
       (STATE *) mycxalloc (1, sizeof (STATE))) == NULL)
    exit (9);
  if ((best_generated_state =
       (STATE *) mycxalloc (1, sizeof (STATE))) == NULL)
    exit (9);
#if ASA_PARALLEL
  if ((gener_block_state =
       (STATE *) mycxalloc (OPTIONS->Gener_Block_Max, sizeof (STATE))) == NULL)
    exit (9);
#endif

#if ASA_PRINT
  ;
#else
  ptr_asa_out = (FILE *) NULL;
#endif

  OPTIONS->Immediate_Exit = FALSE;

  if (asa_open == FALSE)
    {
      asa_open = TRUE;
      ++number_asa_open;
#if ASA_PRINT
      if (number_asa_open == 1)
	{
	  /* open the output file */
#if USER_ASA_OUT
	  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
#if ASA_SAVE
	      ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
	      ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
	    }
#else /* USER_ASA_OUT */
	  if (!strcmp (ASA_OUT, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
#if ASA_SAVE
	      ptr_asa_out = fopen (ASA_OUT, "a");
#else
	      ptr_asa_out = fopen (ASA_OUT, "w");
#endif
	    }
#endif /* USER_ASA_OUT */
	}
      else
	{
#if USER_ASA_OUT
	  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
	    }
#else
	  if (!strcmp (ASA_OUT, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (ASA_OUT, "a");
	    }
#endif
	  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
		   number_asa_open);
	}
#endif /* ASA_PRINT */
    }
  else
    {
      ++recursive_asa_open;
#if ASA_PRINT
      if (recursive_asa_open == 1)
	{
	  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
	  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
	    }
#else
	  if (!strcmp (ASA_OUT, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (ASA_OUT, "a");
	    }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
	  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
	    }
#else
	  if (!strcmp (ASA_OUT, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (ASA_OUT, "w");
	    }
#endif
#endif /* ASA_SAVE */
	}
      else
	{
#if USER_ASA_OUT
	  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
	    }
#else
	  if (!strcmp (ASA_OUT, "STDOUT"))
	    {
	      ptr_asa_out = stdout;
	    }
	  else
	    {
	      ptr_asa_out = fopen (ASA_OUT, "a");
	    }
#endif
	  fprintf (ptr_asa_out, "\n\n\t\t recursive_asa_open = %d\n",
		   recursive_asa_open);
	}
#endif /* ASA_PRINT */
    }

#if ASA_PRINT
  /* print header information as defined by user */
  print_asa_options (ptr_asa_out, OPTIONS);

#if TIME_CALC
  /* print starting time */
  print_time ("start_asa", ptr_asa_out);
#endif
  fflush (ptr_asa_out);
#endif /* ASA_PRINT */

  /* set indices and counts to 0 */
  *best_number_generated_saved =
    *number_generated =
    *recent_number_generated =
    *recent_number_acceptances = 0;
  *index_cost_acceptances =
    *best_number_accepted_saved =
    *number_accepted =
    *number_acceptances_saved = 0;
  index_cost_repeat = 0;

  OPTIONS->N_Accepted = *number_accepted;
  OPTIONS->N_Generated = *number_generated;

#if ASA_SAMPLE
  OPTIONS->N_Generated = 0;
  OPTIONS->Average_Weights = 1.0;
#endif

  /* do not calculate curvatures initially */
  *curvature_flag = FALSE;

  /* allocate storage for all parameters */
  if ((current_generated_state->parameter =
       (double *) mycxalloc (*number_parameters, sizeof (double))
      ) == NULL)
      exit (9);
  if ((last_saved_state->parameter =
       (double *) mycxalloc (*number_parameters, sizeof (double))
      ) == NULL)
      exit (9);
  if ((best_generated_state->parameter =
       (double *) mycxalloc (*number_parameters, sizeof (double))
      ) == NULL)
      exit (9);
#if ASA_PARALLEL
  parallel_block_max = OPTIONS->Gener_Block_Max;
  parallel_generated = OPTIONS->Gener_Block;

  for (index_parallel = 0; index_parallel < parallel_block_max;
       ++index_parallel)
    {
      if ((gener_block_state[index_parallel].parameter =
	   (double *) mycxalloc (*number_parameters, sizeof (double))
	  ) == NULL)
	  exit (9);
    }
#endif

  if ((initial_user_parameter_temp =
       (double *) mycxalloc (*number_parameters, sizeof (double))
      ) == NULL)
      exit (9);
  if ((index_parameter_generations =
       (LONG_INT *) mycxalloc (*number_parameters, sizeof (LONG_INT))
      ) == NULL)
    exit (9);

  /* set all temperatures */
  if ((current_user_parameter_temp =
       (double *) mycxalloc (*number_parameters, sizeof (double))
      ) == NULL)
      exit (9);
#if USER_INITIAL_PARAMETERS_TEMPS
  VFOR (index_v)
    current_user_parameter_temp[index_v] =
    initial_user_parameter_temp[index_v] =
    OPTIONS->User_Parameter_Temperature[index_v];
#else
  VFOR (index_v)
    current_user_parameter_temp[index_v] =
    initial_user_parameter_temp[index_v] =
    OPTIONS->Initial_Parameter_Temperature;
#endif

  if ((temperature_scale_parameters =
       (double *) mycxalloc (*number_parameters, sizeof (double))
      ) == NULL)
      exit (9);

#if USER_INITIAL_COST_TEMP
#if USER_ACCEPTANCE_TEST
  OPTIONS->Cost_Temp_Curr =
    OPTIONS->Cost_Temp_Init =
#endif
    *initial_cost_temperature = *current_cost_temperature =
    OPTIONS->User_Cost_Temperature[0];
#endif

  /* set parameters to the initial parameter values */
  VFOR (index_v)
    last_saved_state->parameter[index_v] =
    current_generated_state->parameter[index_v] =
    parameter_initial_final[index_v];
#if USER_ACCEPTANCE_TEST
  OPTIONS->Random_Seed = seed;
  OPTIONS->Random_Seed[0] = *seed;
  OPTIONS->User_Acceptance_Flag = TRUE;
  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif

#if ASA_PRINT
#if INT_LONG
  fprintf (ptr_asa_out, "Initial Random Seed = %ld\n\n", *seed);
#else
  fprintf (ptr_asa_out, "Initial Random Seed = %d\n\n", *seed);
#endif
#endif /* ASA_PRINT */

  /* save initial user value of OPTIONS->Sequential_Parameters */
  *start_sequence = OPTIONS->Sequential_Parameters;

#if ASA_PRINT
  fprintf (ptr_asa_out,
#if INT_ALLOC
	   "*number_parameters = %d\n\n", *number_parameters);
#else
#if INT_LONG
	   "*number_parameters = %ld\n\n", *number_parameters);
#else
	   "*number_parameters = %d\n\n", *number_parameters);
#endif
#endif

  /* print the min, max, current values, and types of parameters */
  fprintf (ptr_asa_out,
	   "index_v parameter_minimum parameter_maximum\
 parameter_value parameter_type \n");

#if ASA_PRINT_INTERMED
  VFOR (index_v)
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     " %-8d %-*.*g \t\t %-*.*g \t %-*.*g %-7d\n",
#else
#if INT_LONG
	     " %-8ld %-*.*g \t\t %-*.*g \t %-*.*g %-7d\n",
#else
	     " %-8d %-*.*g \t\t %-*.*g \t %-*.*g %-7d\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, parameter_minimum[index_v],
	     G_FIELD, G_PRECISION, parameter_maximum[index_v],
	  G_FIELD, G_PRECISION, current_generated_state->parameter[index_v],
	     parameter_type[index_v]);

  fprintf (ptr_asa_out, "\n\n");
#endif /* ASA_PRINT_INTERMED */
  /* Print out user-defined OPTIONS */

#if DELTA_PARAMETERS
  VFOR (index_v)
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "OPTIONS->User_Delta_Parameter[%d] = %*.*g\n",
#else
#if INT_LONG
	     "OPTIONS->User_Delta_Parameter[%ld] = %*.*g\n",
#else
	     "OPTIONS->User_Delta_Parameter[%d] = %*.*g\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, OPTIONS->User_Delta_Parameter[index_v]);
#endif /* DELTA_PARAMETERS */

#if QUENCH_PARAMETERS
  VFOR (index_v)
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "OPTIONS->User_Quench_Param_Scale[%d] = %*.*g\n",
#else
#if INT_LONG
	     "OPTIONS->User_Quench_Param_Scale[%ld] = %*.*g\n",
#else
	     "OPTIONS->User_Quench_Param_Scale[%d] = %*.*g\n",
#endif
#endif
	     index_v,
	   G_FIELD, G_PRECISION, OPTIONS->User_Quench_Param_Scale[index_v]);
#endif /* QUENCH_PARAMETERS */

#if QUENCH_COST
  fprintf (ptr_asa_out,
	   "\nOPTIONS->User_Quench_Cost_Scale = %*.*g\n\n",
	   G_FIELD, G_PRECISION, OPTIONS->User_Quench_Cost_Scale[0]);
#endif /* QUENCH_COST */

#if USER_INITIAL_PARAMETERS_TEMPS
  VFOR (index_v)
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "OPTIONS->User_Parameter_Temperature[%d] = %*.*g\n",
#else
#if INT_LONG
	     "OPTIONS->User_Parameter_Temperature[%ld] = %*.*g\n",
#else
	     "OPTIONS->User_Parameter_Temperature[%d] = %*.*g\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, initial_user_parameter_temp[index_v]);
#endif /* USER_INITIAL_PARAMETERS_TEMPS */

#if RATIO_TEMPERATURE_SCALES
  VFOR (index_v)
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "OPTIONS->User_Temperature_Ratio[%d] = %*.*g\n",
#else
#if INT_LONG
	     "OPTIONS->User_Temperature_Ratio[%ld] = %*.*g\n",
#else
	     "OPTIONS->User_Temperature_Ratio[%d] = %*.*g\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, OPTIONS->User_Temperature_Ratio[index_v]);
#endif /* RATIO_TEMPERATURE_SCALES */

#if USER_INITIAL_COST_TEMP
  fprintf (ptr_asa_out,
	   "OPTIONS->User_Cost_Temperature[0] = %*.*g\n",
	   G_FIELD, G_PRECISION, *initial_cost_temperature);
#endif /* USER_INITIAL_COST_TEMP */

  fflush (ptr_asa_out);
#endif /* ASA_PRINT */

#if ASA_PARALLEL
#if ASA_PRINT
  fprintf (ptr_asa_out,
#if INT_LONG
	   "Initial ASA_PARALLEL OPTIONS->\n\t Gener_Block = %ld\n\
 \t Gener_Block_Max = %ld\n \t Gener_Mov_Avr= %d\n\n",
#else
	   "ASA_PARALLEL OPTIONS->\n\t Gener_Block = %d\n\
 \t Gener_Block_Max = %d\n \t Gener_Mov_Avr= %d\n\n",
#endif
    OPTIONS->Gener_Block, OPTIONS->Gener_Block_Max, OPTIONS->Gener_Mov_Avr);
#endif
#endif /* ASA_PARALLEL */

#if ASA_SAMPLE
  fprintf (ptr_asa_out, "OPTIONS->Limit_Weights = %*.*g\n\n",
	   G_FIELD, G_PRECISION, OPTIONS->Limit_Weights);
#endif

#if ASA_SAVE
  if ((ptr_save = fopen ("asa_save", "r")) == NULL)
    {
      fclose (ptr_save);
      asa_read = FALSE;
    }
  else
    {
      fclose (ptr_save);
      asa_read = TRUE;

      /* give some value to avoid any problems with other OPTIONS */
#if USER_ACCEPTANCE_TEST
      OPTIONS->Cost_Temp_Curr =
	OPTIONS->Cost_Temp_Init =
#endif
	current_generated_state->cost
	= *initial_cost_temperature = *current_cost_temperature = 3.1416;
    }
#endif

  /* compute temperature scales */
  tmp_var_db1 = -F_LOG ((OPTIONS->Temperature_Ratio_Scale));
  tmp_var_db2 = F_LOG (OPTIONS->Temperature_Anneal_Scale);
  temperature_scale = tmp_var_db1 * F_EXP
    (-tmp_var_db2 / (double) *number_parameters);

  /* set here in case not used */
  tmp_var_db = ZERO;

#if QUENCH_PARAMETERS
#if RATIO_TEMPERATURE_SCALES
  VFOR (index_v)
    temperature_scale_parameters[index_v] =
    tmp_var_db1 * F_EXP
#if QUENCH_PARAMETERS_SCALE
    (-(tmp_var_db2 * OPTIONS->User_Quench_Param_Scale[index_v])
#else
    (-(tmp_var_db2)
#endif
     / (double) *number_parameters)
    * OPTIONS->User_Temperature_Ratio[index_v];
#else
  VFOR (index_v)
    temperature_scale_parameters[index_v] =
    tmp_var_db1 * F_EXP
#if QUENCH_PARAMETERS_SCALE
    (-(tmp_var_db2 * OPTIONS->User_Quench_Param_Scale[index_v])
#else
    (-(tmp_var_db2)
#endif
     / (double) *number_parameters);
#endif /* RATIO_TEMPERATURE_SCALES */
#else /* QUENCH_PARAMETERS */
#if RATIO_TEMPERATURE_SCALES
  VFOR (index_v)
    temperature_scale_parameters[index_v] =
    tmp_var_db1 * F_EXP (-(tmp_var_db2) / (double) *number_parameters)
    * OPTIONS->User_Temperature_Ratio[index_v];
#else
  VFOR (index_v)
    temperature_scale_parameters[index_v] =
    tmp_var_db1 * F_EXP (-(tmp_var_db2) / (double) *number_parameters);
#endif /* RATIO_TEMPERATURE_SCALES */
#endif /* QUENCH_PARAMETERS */

#if USER_ACCEPTANCE_TEST
  OPTIONS->Cost_Temp_Scale =
#endif
    *temperature_scale_cost =
#if QUENCH_COST
#if QUENCH_COST_SCALE
    tmp_var_db1 * F_EXP (-(tmp_var_db2 * OPTIONS->User_Quench_Cost_Scale[0])
#else
    tmp_var_db1 * F_EXP (-(tmp_var_db2)
#endif
       / (double) *number_parameters) * OPTIONS->Cost_Parameter_Scale_Ratio;
#else /* QUENCH_COST */
    tmp_var_db1 * F_EXP (-(tmp_var_db2)
       / (double) *number_parameters) * OPTIONS->Cost_Parameter_Scale_Ratio;
#endif /* QUENCH_COST */

  /* set the initial index of parameter generations to 1 */
  VFOR (index_v)
    index_parameter_generations[index_v] = 1;

  /* test user-defined options before calling cost function */
  tmp_var_int = test_asa_options (seed,
				  parameter_initial_final,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  ptr_asa_out,
				  OPTIONS);
  if (tmp_var_int > 0)
    {
#if ASA_PRINT
      fprintf (ptr_asa_out, "total number invalid OPTIONS = %d\n", tmp_var_int);
      fflush (ptr_asa_out);
#endif
      *exit_status = INVALID_USER_INPUT;
      goto EXIT_ASA;
    }

#if USER_INITIAL_COST_TEMP
#else
  /* calculate the average cost over samplings of the cost function */
  if (OPTIONS->Number_Cost_Samples < -1)
    {
      tmp_var_db1 = ZERO;
      tmp_var_db2 = ZERO;
      tmp_var_int = -OPTIONS->Number_Cost_Samples;
    }
  else
    {
      tmp_var_db1 = ZERO;
      tmp_var_int = OPTIONS->Number_Cost_Samples;
    }

  for (index_cost_constraint = 0;
       index_cost_constraint < tmp_var_int;
       ++index_cost_constraint)
    {
      *number_invalid_generated_states = 0;
      repeated_invalid_states = 0;
      OPTIONS->Sequential_Parameters = *start_sequence - 1;
      do
	{
	  ++(*number_invalid_generated_states);
	  generate_new_state (user_random_generator,
			      seed,
			      parameter_minimum,
			      parameter_maximum,
			      current_user_parameter_temp,
#if USER_GENERATING_FUNCTION
			      initial_user_parameter_temp,
			      temperature_scale_parameters,
#endif
			      number_parameters,
			      parameter_type,
			      current_generated_state,
			      last_saved_state,
			      OPTIONS);
	  *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	  OPTIONS->User_Acceptance_Flag = TRUE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	  tmp_var_db =
	    user_cost_function (current_generated_state->parameter,
				parameter_minimum,
				parameter_maximum,
				tangents,
				curvature,
				number_parameters,
				parameter_type,
				valid_state_generated_flag,
				exit_status,
				OPTIONS);
	  ++repeated_invalid_states;
	  if (repeated_invalid_states >
	      OPTIONS->Limit_Invalid_Generated_States)
	    {
	      *exit_status = TOO_MANY_INVALID_STATES;
	      goto EXIT_ASA;
	    }
	}
      while (*valid_state_generated_flag == FALSE);
      --(*number_invalid_generated_states);

      if (OPTIONS->Number_Cost_Samples < -1)
	{
	  tmp_var_db1 += tmp_var_db;
	  tmp_var_db2 += (tmp_var_db * tmp_var_db);
	}
      else
	{
	  tmp_var_db1 += fabs (tmp_var_db);
	}
    }
  if (OPTIONS->Number_Cost_Samples < -1)

    {
      tmp_var_db1 /= (double) tmp_var_int;
      tmp_var_db2 /= (double) tmp_var_int;
      tmp_var_db = sqrt (fabs ((tmp_var_db2 - tmp_var_db1 * tmp_var_db1)
			       * ((double) tmp_var_int
				  / ((double) tmp_var_int - ONE))))
	+ (double) EPS_DOUBLE;
    }
  else
    {
      tmp_var_db = tmp_var_db1 / tmp_var_int;
    }

#if USER_ACCEPTANCE_TEST
  OPTIONS->Cost_Temp_Curr =
    OPTIONS->Cost_Temp_Init =
#endif
    *initial_cost_temperature = *current_cost_temperature =
    tmp_var_db;
#endif /* USER_INITIAL_COST_TEMP */

  /* set all parameters to the initial parameter values */
  VFOR (index_v)
    best_generated_state->parameter[index_v] =
    last_saved_state->parameter[index_v] =
    current_generated_state->parameter[index_v] =
    parameter_initial_final[index_v];

  /* if using user's initial parameters */
  if (OPTIONS->User_Initial_Parameters == TRUE)
    {
      *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
      OPTIONS->User_Acceptance_Flag = TRUE;
      OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
#if ASA_SAVE
      if (asa_read == FALSE)
#endif
	current_generated_state->cost =
	  user_cost_function (current_generated_state->parameter,
			      parameter_minimum,
			      parameter_maximum,
			      tangents,
			      curvature,
			      number_parameters,
			      parameter_type,
			      valid_state_generated_flag,
			      exit_status,
			      OPTIONS);
#if ASA_PRINT
      if (*valid_state_generated_flag == FALSE)
	fprintf (ptr_asa_out,
		 "user's initial parameters generated \
FALSE *valid_state_generated_flag\n");
#endif
    }
  else
    {
      /* let asa generate valid initial parameters */
      repeated_invalid_states = 0;
      OPTIONS->Sequential_Parameters = *start_sequence - 1;
      do
	{
	  ++(*number_invalid_generated_states);
	  generate_new_state (user_random_generator,
			      seed,
			      parameter_minimum,
			      parameter_maximum,
			      current_user_parameter_temp,
#if USER_GENERATING_FUNCTION
			      initial_user_parameter_temp,
			      temperature_scale_parameters,
#endif
			      number_parameters,
			      parameter_type,
			      current_generated_state,
			      last_saved_state,
			      OPTIONS);
	  *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	  OPTIONS->User_Acceptance_Flag = TRUE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	  current_generated_state->cost =
	    user_cost_function (current_generated_state->parameter,
				parameter_minimum,
				parameter_maximum,
				tangents,
				curvature,
				number_parameters,
				parameter_type,
				valid_state_generated_flag,
				exit_status,
				OPTIONS);
	  ++repeated_invalid_states;
	  if (repeated_invalid_states >
	      OPTIONS->Limit_Invalid_Generated_States)
	    {
	      *exit_status = TOO_MANY_INVALID_STATES;
	      goto EXIT_ASA;
	    }
	}
      while (*valid_state_generated_flag == FALSE);
      --(*number_invalid_generated_states);
    }				/* OPTIONS->User_Initial_Parameters */

  /* set all states to the last one generated */
  VFOR (index_v)
  {
    /* ignore parameters that have too small a range */
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    best_generated_state->parameter[index_v] =
      last_saved_state->parameter[index_v] =
      current_generated_state->parameter[index_v];
  }

  /* set all costs to the last one generated */
#if USER_ACCEPTANCE_TEST
  OPTIONS->Last_Cost =
#endif
    best_generated_state->cost = last_saved_state->cost =
    current_generated_state->cost;

  *accepted_to_generated_ratio = ONE;

  /* do not calculate curvatures initially */
  *curvature_flag = FALSE;

#if ASA_PRINT
  fprintf (ptr_asa_out,
	   "temperature_scale = %*.*g\n",
	   G_FIELD, G_PRECISION, temperature_scale);
#if RATIO_TEMPERATURE_SCALES
#if ASA_PRINT_INTERMED
  VFOR (index_v)
  {
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "temperature_scale_parameters[%d] = %*.*g\n",
#else
#if INT_LONG
	     "temperature_scale_parameters[%ld] = %*.*g\n",
#else
	     "temperature_scale_parameters[%d] = %*.*g\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, temperature_scale_parameters[index_v]);
  }
#endif
#else
  fprintf (ptr_asa_out,
	   "temperature_scale_parameters[0] = %*.*g\n",
	   G_FIELD, G_PRECISION, temperature_scale_parameters[0]);
#endif /* RATIO_TEMPERATURE_SCALES */
  fprintf (ptr_asa_out,
	   "*temperature_scale_cost = %*.*g\n",
	   G_FIELD, G_PRECISION, *temperature_scale_cost);
  fprintf (ptr_asa_out, "\n\n");

#if ASA_PRINT_INTERMED
  print_state (parameter_minimum,
	       parameter_maximum,
	       tangents,
	       curvature,
	       current_cost_temperature,
	       current_user_parameter_temp,
	       accepted_to_generated_ratio,
	       number_parameters,
	       curvature_flag,
	       number_accepted,
	       index_cost_acceptances,
	       number_generated,
	       number_invalid_generated_states,
	       last_saved_state,
	       best_generated_state,
	       ptr_asa_out,
	       OPTIONS);
#endif
  fprintf (ptr_asa_out, "\n");

  fflush (ptr_asa_out);
#endif

#if ASA_SAMPLE
#if ASA_PRINT
  fprintf (ptr_asa_out,
	   ":SAMPLE:   n_accept   cost        cost_temp    bias_accept    \
 aver_weight\n");
  fprintf (ptr_asa_out,
	   ":SAMPLE:   index      param[]     temp[]       bias_gener[]   \
 range[]\n");
#endif
#endif

  /* reset the current cost and the number of generations performed */
  *number_invalid_generated_states = 0;
  *best_number_generated_saved =
    *number_generated = *recent_number_generated = 0;
  OPTIONS->N_Generated = *number_generated;
  VFOR (index_v)
  {
    /* ignore parameters that have too small a range */
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    index_parameter_generations[index_v] = 1;
  }
#if USER_ACCEPTANCE_TEST
  OPTIONS->User_Acceptance_Flag = FALSE;
  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif

#if ASA_QUEUE
  if (OPTIONS->Queue_Size > 0)
    {
      if ((save_queue_flag =
	   (int *) mycxalloc (OPTIONS->Queue_Size, sizeof (int))
	  ) == NULL)
	  exit (9);
      if ((save_queue_cost =
	   (double *) mycxalloc (OPTIONS->Queue_Size, sizeof (double))
	  ) == NULL)
	  exit (9);
      if ((save_queue_param =
	   (double *) mycxalloc ((*number_parameters) * OPTIONS->Queue_Size,
			      sizeof (double))
	  ) == NULL)
	  exit (9);
    }
#if ASA_PRINT
#if INT_ALLOC
  fprintf (ptr_asa_out, "OPTIONS->Queue_Size = %d\n",
	   OPTIONS->Queue_Size);
#else
#if INT_LONG
  fprintf (ptr_asa_out, "OPTIONS->Queue_Size = %ld\n",
	   OPTIONS->Queue_Size);
#else
  fprintf (ptr_asa_out, "OPTIONS->Queue_Size = %d\n",
	   OPTIONS->Queue_Size);
#endif
#endif
  if (OPTIONS->Queue_Size > 0)
    {
      VFOR (index_v)
      {
	fprintf (ptr_asa_out,
#if INT_ALLOC
		 "Queue_Resolution[%d] = %*.*g\n",
#else
#if INT_LONG
		 "Queue_Resolution[%ld] = %*.*g\n",
#else
		 "Queue_Resolution[%d] = %*.*g\n",
#endif
#endif
		 index_v,
		 G_FIELD, G_PRECISION, OPTIONS->Queue_Resolution[index_v]);
      }

#endif /* ASA_PRINT */
      /* fill arrays to check allocated memory */
      for (queue = 0; queue < OPTIONS->Queue_Size; ++queue)
	{
	  VFOR (index_v)
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      {
		continue;
	      }
	    queue_v = index_v + queue * (LONG_INT) (*number_parameters);
	    save_queue_param[queue_v] =
	      current_generated_state->parameter[index_v];
	  }
	  save_queue_cost[queue] = current_generated_state->cost;
	  save_queue_flag[queue] = *valid_state_generated_flag;
	}
    }
  save_queue = save_queue_indx = 0;
#endif /* ASA_QUEUE */

#if ASA_RESOLUTION
#if ASA_PRINT
  VFOR (index_v)
  {
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "Coarse_Resolution[%d] = %*.*g\n",
#else
#if INT_LONG
	     "Coarse_Resolution[%ld] = %*.*g\n",
#else
	     "Coarse_Resolution[%d] = %*.*g\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, OPTIONS->Coarse_Resolution[index_v]);
  }
#endif /* ASA_PRINT */
#endif /* ASA_RESOLUTION */

  OPTIONS->Sequential_Parameters = *start_sequence - 1;

  /* MAIN ANNEALING LOOP */
  while (
	  ((*number_accepted <= OPTIONS->Limit_Acceptances)
	   || (OPTIONS->Limit_Acceptances == 0))
	  &&
	  ((*number_generated <= OPTIONS->Limit_Generated)
	   || (OPTIONS->Limit_Generated == 0))
    )
    {

      tmp_var_db1 = -F_LOG ((OPTIONS->Temperature_Ratio_Scale));

      /* compute temperature scales */
      tmp_var_db2 = F_LOG (OPTIONS->Temperature_Anneal_Scale);
      temperature_scale = tmp_var_db1 *
	F_EXP (-tmp_var_db2 / (double) *number_parameters);

#if QUENCH_PARAMETERS
#if RATIO_TEMPERATURE_SCALES
      VFOR (index_v)
	temperature_scale_parameters[index_v] = tmp_var_db1 * F_EXP
#if QUENCH_PARAMETERS_SCALE
	(-(tmp_var_db2 * OPTIONS->User_Quench_Param_Scale[index_v])
#else
	(-(tmp_var_db2)
#endif
	 / (double) *number_parameters)
	* OPTIONS->User_Temperature_Ratio[index_v];
#else
      VFOR (index_v)
	temperature_scale_parameters[index_v] = tmp_var_db1 * F_EXP
#if QUENCH_PARAMETERS_SCALE
	(-(tmp_var_db2 * OPTIONS->User_Quench_Param_Scale[index_v])
#else
	(-(tmp_var_db2)
#endif
	 / (double) *number_parameters);
#endif /* RATIO_TEMPERATURE_SCALES */
#else /* QUENCH_PARAMETERS */
#if RATIO_TEMPERATURE_SCALES
      VFOR (index_v)
	temperature_scale_parameters[index_v] =
	tmp_var_db1 * F_EXP (-(tmp_var_db2) / (double) *number_parameters)
	* OPTIONS->User_Temperature_Ratio[index_v];
#else
      VFOR (index_v)
	temperature_scale_parameters[index_v] =
	tmp_var_db1 * F_EXP (-(tmp_var_db2) / (double) *number_parameters);
#endif /* RATIO_TEMPERATURE_SCALES */
#endif /* QUENCH_PARAMETERS */

#if USER_ACCEPTANCE_TEST
      OPTIONS->Cost_Temp_Scale =
#endif
	*temperature_scale_cost =
#if QUENCH_COST
#if QUENCH_COST_SCALE
	tmp_var_db1 * F_EXP (-(tmp_var_db2 * OPTIONS->User_Quench_Cost_Scale[0])
#else
	tmp_var_db1 * F_EXP (-(tmp_var_db2)
#endif
       / (double) *number_parameters) * OPTIONS->Cost_Parameter_Scale_Ratio;
#else /* QUENCH_COST */
	tmp_var_db1 * F_EXP (-(tmp_var_db2)
       / (double) *number_parameters) * OPTIONS->Cost_Parameter_Scale_Ratio;
#endif /* QUENCH_COST */

      /* CALCULATE NEW TEMPERATURES */

      /* calculate new parameter temperatures */
      VFOR (index_v)
      {
	/* skip parameters with too small a range */
	if (PARAMETER_RANGE_TOO_SMALL (index_v))
	  continue;

	log_new_temperature_ratio =
	  -temperature_scale_parameters[index_v] *
	  F_POW ((double) index_parameter_generations[index_v],
#if QUENCH_PARAMETERS
		 OPTIONS->User_Quench_Param_Scale[index_v]
#else /* QUENCH_PARAMETERS */
		 ONE
#endif /* QUENCH_PARAMETERS */
		 / (double) *number_parameters);
	/* check (and correct) for too large an exponent */
	log_new_temperature_ratio =
	  EXPONENT_CHECK (log_new_temperature_ratio);
	current_user_parameter_temp[index_v] =
	  initial_user_parameter_temp[index_v]
	  * F_EXP (log_new_temperature_ratio);

#if NO_PARAM_TEMP_TEST
	if (current_user_parameter_temp[index_v]
	    < (double) EPS_DOUBLE)
	  current_user_parameter_temp[index_v] =
	    (double) EPS_DOUBLE;
#else
	/* check for too small a parameter temperature */
	if (current_user_parameter_temp[index_v]
	    < (double) EPS_DOUBLE)
	  {
	    *exit_status = P_TEMP_TOO_SMALL;
	    *index_exit_v = index_v;
	    goto EXIT_ASA;
	  }
#endif
      }

      /* calculate new cost temperature */
      log_new_temperature_ratio =
	-*temperature_scale_cost
	* F_POW ((double) *index_cost_acceptances,
#if QUENCH_COST
		 OPTIONS->User_Quench_Cost_Scale[0]
#else
		 ONE
#endif
		 / (double) *number_parameters);
      log_new_temperature_ratio =
	EXPONENT_CHECK (log_new_temperature_ratio);
#if USER_ACCEPTANCE_TEST
      OPTIONS->Cost_Temp_Curr =
	OPTIONS->Cost_Temp_Init =
#endif
	*current_cost_temperature = *initial_cost_temperature
	* F_EXP (log_new_temperature_ratio);

#if NO_COST_TEMP_TEST
      if (*current_cost_temperature < (double) EPS_DOUBLE)
#if USER_ACCEPTANCE_TEST
	OPTIONS->Cost_Temp_Curr =
#endif
	  *current_cost_temperature = (double) EPS_DOUBLE;
#else
      /* check for too small a cost temperature */
      if (*current_cost_temperature < (double) EPS_DOUBLE)
	{
	  *exit_status = C_TEMP_TOO_SMALL;
	  goto EXIT_ASA;
	}
#endif

#if ASA_SAVE
      if (asa_read == TRUE)
	{
	  ptr_save = fopen ("asa_save", "r");

	  fread (number_parameters, sizeof (ALLOC_INT),
		 1, ptr_save);
	  fread (parameter_minimum, sizeof (double),
		 *number_parameters, ptr_save);
	  fread (parameter_maximum, sizeof (double),
		 *number_parameters, ptr_save);
	  fread (tangents, sizeof (double),
		 *number_parameters, ptr_save);
	  fread (current_user_parameter_temp, sizeof (double),
		 *number_parameters, ptr_save);
	  fread (initial_user_parameter_temp, sizeof (double),
		 *number_parameters, ptr_save);
	  fread (temperature_scale_parameters, sizeof (double),
		 *number_parameters, ptr_save);

	  fread (parameter_type, sizeof (int),
		 *number_parameters, ptr_save);
	  fread (&index_cost_repeat, sizeof (int), 1, ptr_save);

	  fread (current_cost_temperature, sizeof (double),
		 1, ptr_save);
	  fread (initial_cost_temperature, sizeof (double),
		 1, ptr_save);
	  fread (temperature_scale_cost, sizeof (double),
		 1, ptr_save);
	  fread (accepted_to_generated_ratio, sizeof (double),
		 1, ptr_save);

	  fread (curvature_flag, sizeof (int), 1, ptr_save);

	  fread (seed, sizeof (LONG_INT), 1, ptr_save);
	  fread (number_generated, sizeof (LONG_INT), 1, ptr_save);
	  fread (number_accepted, sizeof (LONG_INT), 1, ptr_save);
	  fread (number_acceptances_saved, sizeof (LONG_INT),
		 1, ptr_save);
	  fread (recent_number_acceptances, sizeof (LONG_INT),
		 1, ptr_save);
	  fread (recent_number_generated, sizeof (LONG_INT),
		 1, ptr_save);
	  fread (number_invalid_generated_states, sizeof (LONG_INT),
		 1, ptr_save);
	  fread (index_cost_acceptances, sizeof (LONG_INT),
		 1, ptr_save);
	  fread (best_number_generated_saved, sizeof (LONG_INT),
		 1, ptr_save);
	  fread (best_number_accepted_saved, sizeof (LONG_INT),
		 1, ptr_save);

	  fread (index_parameter_generations, sizeof (LONG_INT),
		 *number_parameters, ptr_save);

	  fread (current_generated_state->parameter,
		 sizeof (double), *number_parameters, ptr_save);
	  fread (last_saved_state->parameter,
		 sizeof (double), *number_parameters, ptr_save);
	  fread (best_generated_state->parameter,
		 sizeof (double), *number_parameters, ptr_save);
	  fread (&(current_generated_state->cost),
		 sizeof (double), 1, ptr_save);
	  fread (&(last_saved_state->cost),
		 sizeof (double), 1, ptr_save);
	  fread (&(best_generated_state->cost),
		 sizeof (double), 1, ptr_save);

	  fread (&(OPTIONS->Limit_Acceptances), sizeof (LONG_INT),
		 1, ptr_save);
	  fread (&(OPTIONS->Limit_Generated), sizeof (LONG_INT),
		 1, ptr_save);
	  fread (&(OPTIONS->Limit_Invalid_Generated_States), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Accepted_To_Generated_Ratio), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->Cost_Precision), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->Maximum_Cost_Repeat), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Number_Cost_Samples), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Temperature_Ratio_Scale), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->Cost_Parameter_Scale_Ratio), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->Temperature_Anneal_Scale), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->Include_Integer_Parameters), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->User_Initial_Parameters), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Sequential_Parameters), sizeof (ALLOC_INT),
		 1, ptr_save);
	  fread (&(OPTIONS->Initial_Parameter_Temperature), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->Acceptance_Frequency_Modulus), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Generated_Frequency_Modulus), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Reanneal_Cost), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Reanneal_Parameters), sizeof (int),
		 1, ptr_save);
	  fread (&(OPTIONS->Delta_X), sizeof (double),
		 1, ptr_save);
	  fread (&(OPTIONS->User_Tangents), sizeof (int),
		 1, ptr_save);

#if USER_INITIAL_COST_TEMP
	  fread (OPTIONS->User_Cost_Temperature, sizeof (double),
		 1, ptr_save);
#endif
#if RATIO_TEMPERATURE_SCALES
	  fread (OPTIONS->User_Temperature_Ratio, sizeof (double),
		 *number_parameters, ptr_save);
#endif
#if USER_INITIAL_PARAMETERS_TEMPS
	  fread (OPTIONS->User_Parameter_Temperature, sizeof (double),
		 *number_parameters, ptr_save);
#endif
#if DELTA_PARAMETERS
	  fread (OPTIONS->User_Delta_Parameter, sizeof (double),
		 *number_parameters, ptr_save);
#endif
#if QUENCH_PARAMETERS
	  fread (OPTIONS->User_Quench_Param_Scale, sizeof (double),
		 *number_parameters, ptr_save);
#endif
#if QUENCH_COST
	  fread (OPTIONS->User_Quench_Cost_Scale, sizeof (double),
		 1, ptr_save);
#endif
	  fread (&(OPTIONS->N_Accepted), sizeof (LONG_INT), 1, ptr_save);
	  fread (&(OPTIONS->N_Generated), sizeof (LONG_INT), 1, ptr_save);
	  fread (&(OPTIONS->Immediate_Exit), sizeof (int), 1, ptr_save);
#if OPTIONAL_DATA
	  fread (&(OPTIONS->Asa_Data_Dim), sizeof (ALLOC_INT),
		 1, ptr_save);
	  fread (OPTIONS->Asa_Data, sizeof (double),
		 OPTIONS->Asa_Data_Dim, ptr_save);
#endif
#if OPTIONAL_DATA_INT
	  fread (&(OPTIONS->Asa_Data_Dim_Int), sizeof (ALLOC_INT), 1, ptr_save);
	  fread (OPTIONS->Asa_Data_Int, sizeof (LONG_INT),
		 OPTIONS->Asa_Data_Dim_Int, ptr_save);
#endif
#if USER_ASA_OUT
	  fread (OPTIONS->Asa_Out_File, sizeof (char), 1, ptr_save);
#endif
#if USER_COST_SCHEDULE
	  fread (&(OPTIONS->Cost_Schedule), sizeof (char), 1, ptr_save);
#endif
#if USER_ACCEPT_ASYMP_EXP
	  fread (&(OPTIONS->Asymp_Exp_Param), sizeof (double), 1, ptr_save);
#endif
#if USER_ACCEPTANCE_TEST
	  fread (&(OPTIONS->Acceptance_Test), sizeof (char), 1, ptr_save);
	  fread (&(OPTIONS->User_Acceptance_Flag), sizeof (int), 1, ptr_save);
	  fread (&(OPTIONS->Cost_Acceptance_Flag), sizeof (int), 1, ptr_save);
	  fread (&(OPTIONS->Last_Cost), sizeof (double), 1, ptr_save);
	  fread (&(OPTIONS->Cost_Temp_Curr), sizeof (double), 1, ptr_save);
	  fread (&(OPTIONS->Cost_Temp_Init), sizeof (double), 1, ptr_save);
	  fread (&(OPTIONS->Cost_Temp_Scale), sizeof (double), 1, ptr_save);
#endif
#if USER_GENERATING_FUNCTION
	  fread (&(OPTIONS->Generating_Distrib), sizeof (char), 1, ptr_save);
#endif
#if USER_REANNEAL_COST
	  fread (OPTIONS->Reanneal_Cost_Function, sizeof (char), 1, ptr_save);
#endif
#if USER_REANNEAL_PARAMETERS
	  fread (&(OPTIONS->Reanneal_Params_Function), sizeof (char),
		 1, ptr_save);
#endif
#if ASA_SAMPLE
	  fread (&(OPTIONS->Bias_Acceptance), sizeof (double), 1, ptr_save);
	  fread (OPTIONS->Bias_Generated, sizeof (double),
		 *number_parameters, ptr_save);
	  fread (&(OPTIONS->Average_Weights), sizeof (double), 1, ptr_save);
	  fread (&(OPTIONS->Limit_Weights), sizeof (double), 1, ptr_save);
#endif
#if ASA_QUEUE
	  fread (&save_queue, sizeof (LONG_INT), 1, ptr_save);
	  fread (&save_queue_indx, sizeof (LONG_INT), 1, ptr_save);
	  fread (&(OPTIONS->Queue_Size), sizeof (ALLOC_INT),
		 1, ptr_save);
	  if (OPTIONS->Queue_Size > 0)
	    {
	      fread (save_queue_flag, sizeof (int), save_queue, ptr_save);
	      fread (save_queue_cost, sizeof (double), save_queue, ptr_save);
	      fread (save_queue_param, sizeof (double),
		    (*number_parameters) * (OPTIONS->Queue_Size), ptr_save);
	      fread (OPTIONS->Queue_Resolution, sizeof (double),
		     *number_parameters, ptr_save);
	    }
#endif
#if ASA_RESOLUTION
	  fread (OPTIONS->Coarse_Resolution, sizeof (double),
		 *number_parameters, ptr_save);
#endif
#if ASA_PARALLEL
	  fread (&parallel_generated, sizeof (LONG_INT), 1, ptr_save);
	  fread (&parallel_block_max, sizeof (LONG_INT), 1, ptr_save);
	  for (index_parallel = 0; index_parallel < parallel_block_max;
	       ++index_parallel)
	    {
	      fread (gener_block_state[index_parallel].parameter,
		     sizeof (double), *number_parameters, ptr_save);
	      fread (&(gener_block_state[index_parallel].cost),
		     sizeof (double), 1, ptr_save);
#if USER_ACCEPTANCE_TEST
	      fread (&(gener_block_state[index_parallel].par_user_accept_flag),
		     sizeof (int), 1, ptr_save);
	      fread (&(gener_block_state[index_parallel].par_cost_accept_flag),
		     sizeof (int), 1, ptr_save);
#endif
	    }
	  fread (&(OPTIONS->Gener_Mov_Avr), sizeof (int), 1, ptr_save);
	  fread (&(OPTIONS->Gener_Block), sizeof (LONG_INT), 1, ptr_save);
	  fread (&(OPTIONS->Gener_Block_Max), sizeof (LONG_INT), 1, ptr_save);
#endif

	  fclose (ptr_save);

	  asa_read = FALSE;
#if ASA_PRINT
	  print_state (parameter_minimum,
		       parameter_maximum,
		       tangents,
		       curvature,
		       current_cost_temperature,
		       current_user_parameter_temp,
		       accepted_to_generated_ratio,
		       number_parameters,
		       curvature_flag,
		       number_accepted,
		       index_cost_acceptances,
		       number_generated,
		       number_invalid_generated_states,
		       last_saved_state,
		       best_generated_state,
		       ptr_asa_out,
		       OPTIONS);
#endif /* ASA_PRINT */

	  goto SAVED_ASA;
	}
#endif /* ASA_SAVE */

      /* GENERATE NEW PARAMETERS */

      /* generate a new valid set of parameters */
#if ASA_PARALLEL
      /* *** ENTER CODE TO SPAWN OFF PARALLEL GENERATED STATES *** */

      /* check if need more memory allocated to gener_block_state */
      if (OPTIONS->Gener_Block_Max > parallel_block_max)
	{
	  for (index_parallel = 0; index_parallel < parallel_block_max;
	       ++index_parallel)
	    {
	      free (gener_block_state[index_parallel].parameter);
	    }
	  free (gener_block_state);

	  if ((gener_block_state =
	       (STATE *) mycxalloc (OPTIONS->Gener_Block_Max,
				 sizeof (STATE))) == NULL)
	    exit (9);

	  parallel_block_max = OPTIONS->Gener_Block_Max;

	  for (index_parallel = 0; index_parallel < parallel_block_max;
	       ++index_parallel)
	    {
	      if ((gener_block_state[index_parallel].parameter =
		   (double *) mycxalloc (*number_parameters, sizeof (double))
		  ) == NULL)
		  exit (9);
	    }
	}

#if ASA_TEMPLATE_PARALLEL
      for (index_parallel = 0; index_parallel < OPTIONS->Gener_Block;
	   ++index_parallel)
	{
#endif /* ASA_TEMPLATE_PARALLEL */
#endif /* ASA_PARALLEL */

	  repeated_invalid_states = 0;
	  do
	    {
	      ++(*number_invalid_generated_states);
	      generate_new_state (user_random_generator,
				  seed,
				  parameter_minimum,
				  parameter_maximum,
				  current_user_parameter_temp,
#if USER_GENERATING_FUNCTION
				  initial_user_parameter_temp,
				  temperature_scale_parameters,
#endif
				  number_parameters,
				  parameter_type,
				  current_generated_state,
				  last_saved_state,
				  OPTIONS);

	      *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	      OPTIONS->User_Acceptance_Flag = FALSE;
	      OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
#if ASA_QUEUE
	      /* Binary trees do not seem necessary since we are assuming
	         that the cost function calculation is the bottleneck.
	         However, see the section @@Hashed Lists for ASA_QUEUE
	         in the MISC.DIR/asa_contrib file. */
	      if (OPTIONS->Queue_Size == 0)	/* in case recursive use */
		{
		  queue_new = 1;
		}
	      else
		{
		  queue_new = 1;
		  for (queue = 0; queue < save_queue; ++queue)
		    {
		      save_queue_test = 0;
		      VFOR (index_v)
		      {
			if (PARAMETER_RANGE_TOO_SMALL (index_v))
			  {
			    ++save_queue_test;
			  }
			else
			  {
			    queue_v = index_v + queue
			      * (LONG_INT) (*number_parameters);
			    if (fabs (
				 current_generated_state->parameter[index_v]
				       - save_queue_param[queue_v])
				<= (OPTIONS->Queue_Resolution[index_v]
				    + EPS_DOUBLE))
			      {
				++save_queue_test;
			      }
			  }
		      }
		      if (save_queue_test == *number_parameters)
			{
			  tmp_var_db = save_queue_cost[queue];
			  *valid_state_generated_flag =
			    save_queue_flag[queue];
			  queue_new = 0;
			  --(*number_generated);
#if ASA_TEMPLATE_QUEUE
#if ASA_PRINT_MORE
#if INT_LONG
			  fprintf (ptr_asa_out, "ASA_QUEUE: %ld \t %*.*g\n",
#else
			  fprintf (ptr_asa_out, "ASA_QUEUE: %d \t %*.*g\n",
#endif
				   OPTIONS->N_Generated,
				   G_FIELD, G_PRECISION, tmp_var_db);
#endif
#endif
			  break;
			}
		    }
		}
	      if (queue_new == 1)
		{
		  tmp_var_db =
		    user_cost_function (
					 current_generated_state->parameter,
					 parameter_minimum,
					 parameter_maximum,
					 tangents,
					 curvature,
					 number_parameters,
					 parameter_type,
					 valid_state_generated_flag,
					 exit_status,
					 OPTIONS);
		  if (OPTIONS->Queue_Size > 0)	/* in case recursive use */
		    {
		      VFOR (index_v)
		      {
			if (PARAMETER_RANGE_TOO_SMALL (index_v))
			  {
			    continue;
			  }
			queue_v = index_v + save_queue_indx
			  * (LONG_INT) (*number_parameters);
			save_queue_param[queue_v] =
			  current_generated_state->parameter[index_v];
		      }
		      save_queue_cost[save_queue_indx] = tmp_var_db;
		      save_queue_flag[save_queue_indx]
			= *valid_state_generated_flag;

		      ++save_queue;
		      if (save_queue == (LONG_INT) OPTIONS->Queue_Size)
			--save_queue;

		      ++save_queue_indx;
		      if (save_queue_indx == (LONG_INT) OPTIONS->Queue_Size)
			save_queue_indx = 0;
		    }
		}
#else /* ASA_QUEUE */
	      tmp_var_db =
		user_cost_function (
				     current_generated_state->parameter,
				     parameter_minimum,
				     parameter_maximum,
				     tangents,
				     curvature,
				     number_parameters,
				     parameter_type,
				     valid_state_generated_flag,
				     exit_status,
				     OPTIONS);
#endif /* ASA_QUEUE */
	      current_generated_state->cost = tmp_var_db;
	      ++repeated_invalid_states;
	      if (repeated_invalid_states >
		  OPTIONS->Limit_Invalid_Generated_States)
		{
		  *exit_status = TOO_MANY_INVALID_STATES;
		  goto EXIT_ASA;
		}
	    }
	  while (*valid_state_generated_flag == FALSE);
	  --(*number_invalid_generated_states);
#if ASA_PARALLEL
	  gener_block_state[index_parallel].cost
	    = current_generated_state->cost;
#if USER_ACCEPTANCE_TEST
	  gener_block_state[index_parallel].par_user_accept_flag =
	    OPTIONS->User_Acceptance_Flag;
	  gener_block_state[index_parallel].par_cost_accept_flag =
	    OPTIONS->Cost_Acceptance_Flag;
#endif
	  VFOR (index_v)
	  {
	    /* ignore parameters with too small a range */
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      continue;
	    gener_block_state[index_parallel].parameter[index_v] =
	      current_generated_state->parameter[index_v];
	  }
#if ASA_TEMPLATE_PARALLEL
	}
#endif /* ASA_TEMPLATE_PARALLEL */
      /* *** EXIT CODE SPAWNING OFF PARALLEL GENERATED STATES *** */
#endif /* ASA_PARALLEL */

      /* ACCEPT/REJECT NEW PARAMETERS */

#if ASA_PARALLEL
      for (index_parallel = 0; index_parallel < OPTIONS->Gener_Block;
	   ++index_parallel)
	{
	  current_generated_state->cost
	    = gener_block_state[index_parallel].cost;
#if USER_ACCEPTANCE_TEST
	  OPTIONS->User_Acceptance_Flag =
	    gener_block_state[index_parallel].par_user_accept_flag;
	  OPTIONS->Cost_Acceptance_Flag =
	    gener_block_state[index_parallel].par_cost_accept_flag;
#endif
	  VFOR (index_v)
	  {
	    /* ignore parameters with too small a range */
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      continue;
	    current_generated_state->parameter[index_v] =
	      gener_block_state[index_parallel].parameter[index_v];
	  }
#endif /* ASA_PARALLEL */
	  /* decide to accept/reject the new state */
	  accept_new_state (user_random_generator,
			    seed,
			    parameter_minimum,
			    parameter_maximum,
			    current_cost_temperature,
#if ASA_SAMPLE
			    current_user_parameter_temp,
#endif
			    number_parameters,
			    recent_number_acceptances,
			    number_accepted,
			    index_cost_acceptances,
			    number_acceptances_saved,
			    recent_number_generated,
			    number_generated,
			    index_parameter_generations,
			    current_generated_state,
			    last_saved_state,
#if ASA_SAMPLE
			    ptr_asa_out,
#endif
			    OPTIONS);

	  /* calculate the ratio of acceptances to generated states */
	  *accepted_to_generated_ratio =
	    (double) (*recent_number_acceptances + 1) /
	    (double) (*recent_number_generated + 1);

	  /* CHECK FOR NEW MINIMUM */

	  if (current_generated_state->cost < best_generated_state->cost)
	    {
	      /* NEW MINIMUM FOUND */

	      /* reset the recent acceptances and generated counts */
#if ASA_PARALLEL
	      parallel_generated = *recent_number_generated;
#endif
	      *recent_number_acceptances = *recent_number_generated = 0;
	      *best_number_generated_saved = *number_generated;
	      *best_number_accepted_saved = *number_accepted;
	      index_cost_repeat = 0;

	      /* copy the current state into the best_generated state */
	      best_generated_state->cost = current_generated_state->cost;
	      VFOR (index_v)
	      {
		/* ignore parameters that have too small a range */
		if (PARAMETER_RANGE_TOO_SMALL (index_v))
		  continue;
		best_generated_state->parameter[index_v] =
		  current_generated_state->parameter[index_v];
	      }

	      /* printout the new minimum state and value */
#if ASA_PRINT
	      fprintf (ptr_asa_out,
#if INT_LONG
		       "best...->cost=%-*.*g  \
*number_accepted=%ld  *number_generated=%ld\n",
		       G_FIELD, G_PRECISION, best_generated_state->cost,
#else
		       "best...->cost=%-*.*g  \
*number_accepted=%d  *number_generated=%d\n",
		       G_FIELD, G_PRECISION, best_generated_state->cost,
#endif /* INT_LONG */
		       *number_accepted, *number_generated);
#if ASA_PARALLEL
	      /* print OPTIONS->Gener_Block just used */
	      fprintf (ptr_asa_out,
#if INT_LONG
		       "OPTIONS->Gener_Block = %ld\n",
#else
		       "OPTIONS->Gener_Block = %d\n",
#endif /* INT_LONG */
		       OPTIONS->Gener_Block);
#endif /* ASA_PARALLEL */
#if ASA_PRINT_MORE
#if INT_ALLOC
	      fprintf (ptr_asa_out, "Present Random Seed = %d\n\n", *seed);
#else
#if INT_LONG
	      fprintf (ptr_asa_out, "Present Random Seed = %ld\n\n", *seed);
#else
	      fprintf (ptr_asa_out, "Present Random Seed = %d\n\n", *seed);
#endif
#endif
	      print_state (parameter_minimum,
			   parameter_maximum,
			   tangents,
			   curvature,
			   current_cost_temperature,
			   current_user_parameter_temp,
			   accepted_to_generated_ratio,
			   number_parameters,
			   curvature_flag,
			   number_accepted,
			   index_cost_acceptances,
			   number_generated,
			   number_invalid_generated_states,
			   last_saved_state,
			   best_generated_state,
			   ptr_asa_out,
			   OPTIONS);
#endif /* ASA_PRINT_MORE */
	      fflush (ptr_asa_out);
#endif /* ASA_PRINT */

#if ASA_PARALLEL
	      /* leave index_parallel loop after new minimum */
	      break;
#endif /* ASA_PARALLEL */
	    }
#if ASA_PARALLEL
	}
#endif /* ASA_PARALLEL */

#if ASA_PARALLEL
      if (OPTIONS->Gener_Mov_Avr > 0)
	{
	  OPTIONS->Gener_Block = (LONG_INT)
	    ((((double) OPTIONS->Gener_Mov_Avr - ONE)
	    * (double) (OPTIONS->Gener_Block) + (double) parallel_generated)
	     / (double) (OPTIONS->Gener_Mov_Avr));
	  OPTIONS->Gener_Block =
	    MIN (OPTIONS->Gener_Block, parallel_block_max);
	}
#endif /* ASA_PARALLEL */

#if ASA_SAVE
      /* These writes are put here with these tests, instead of just
         after a new best state is found, to prevent any confusion with
         any parallel code that might be added by users. */
      if (
	   *recent_number_acceptances == 0
	   && *recent_number_generated == 0
	   && *best_number_generated_saved == *number_generated
	   && *best_number_accepted_saved == *number_accepted
	   && index_cost_repeat == 0
	)
	{
	  ptr_save = fopen ("asa_save", "w");

	  fwrite (number_parameters, sizeof (ALLOC_INT),
		  1, ptr_save);
	  fwrite (parameter_minimum, sizeof (double),
		  *number_parameters, ptr_save);
	  fwrite (parameter_maximum, sizeof (double),
		  *number_parameters, ptr_save);
	  fwrite (tangents, sizeof (double),
		  *number_parameters, ptr_save);
	  fwrite (current_user_parameter_temp, sizeof (double),
		  *number_parameters, ptr_save);
	  fwrite (initial_user_parameter_temp, sizeof (double),
		  *number_parameters, ptr_save);
	  fwrite (temperature_scale_parameters, sizeof (double),
		  *number_parameters, ptr_save);

	  fwrite (parameter_type, sizeof (int),
		  *number_parameters, ptr_save);
	  fwrite (&index_cost_repeat, sizeof (int), 1, ptr_save);

	  fwrite (current_cost_temperature, sizeof (double),
		  1, ptr_save);
	  fwrite (initial_cost_temperature, sizeof (double),
		  1, ptr_save);
	  fwrite (temperature_scale_cost, sizeof (double),
		  1, ptr_save);
	  fwrite (accepted_to_generated_ratio, sizeof (double),
		  1, ptr_save);

	  fwrite (curvature_flag, sizeof (int), 1, ptr_save);

	  fwrite (seed, sizeof (LONG_INT), 1, ptr_save);
	  fwrite (number_generated, sizeof (LONG_INT), 1, ptr_save);
	  fwrite (number_accepted, sizeof (LONG_INT), 1, ptr_save);
	  fwrite (number_acceptances_saved, sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (recent_number_acceptances, sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (recent_number_generated, sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (number_invalid_generated_states, sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (index_cost_acceptances, sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (best_number_generated_saved, sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (best_number_accepted_saved, sizeof (LONG_INT),
		  1, ptr_save);

	  fwrite (index_parameter_generations, sizeof (LONG_INT),
		  *number_parameters, ptr_save);

	  fwrite (current_generated_state->parameter,
		  sizeof (double), *number_parameters, ptr_save);
	  fwrite (last_saved_state->parameter,
		  sizeof (double), *number_parameters, ptr_save);
	  fwrite (best_generated_state->parameter,
		  sizeof (double), *number_parameters, ptr_save);
	  fwrite (&(current_generated_state->cost),
		  sizeof (double), 1, ptr_save);
	  fwrite (&(last_saved_state->cost),
		  sizeof (double), 1, ptr_save);
	  fwrite (&(best_generated_state->cost),
		  sizeof (double), 1, ptr_save);

	  fwrite (&(OPTIONS->Limit_Acceptances), sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Limit_Generated), sizeof (LONG_INT),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Limit_Invalid_Generated_States), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Accepted_To_Generated_Ratio), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Cost_Precision), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Maximum_Cost_Repeat), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Number_Cost_Samples), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Temperature_Ratio_Scale), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Cost_Parameter_Scale_Ratio), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Temperature_Anneal_Scale), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Include_Integer_Parameters), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->User_Initial_Parameters), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Sequential_Parameters), sizeof (ALLOC_INT),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Initial_Parameter_Temperature), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Acceptance_Frequency_Modulus), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Generated_Frequency_Modulus), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Reanneal_Cost), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Reanneal_Parameters), sizeof (int),
		  1, ptr_save);
	  fwrite (&(OPTIONS->Delta_X), sizeof (double),
		  1, ptr_save);
	  fwrite (&(OPTIONS->User_Tangents), sizeof (int),
		  1, ptr_save);

#if USER_INITIAL_COST_TEMP
	  fwrite (OPTIONS->User_Cost_Temperature, sizeof (double),
		  1, ptr_save);
#endif
#if RATIO_TEMPERATURE_SCALES
	  fwrite (OPTIONS->User_Temperature_Ratio, sizeof (double),
		  *number_parameters, ptr_save);
#endif
#if USER_INITIAL_PARAMETERS_TEMPS
	  fwrite (OPTIONS->User_Parameter_Temperature, sizeof (double),
		  *number_parameters, ptr_save);
#endif
#if DELTA_PARAMETERS
	  fwrite (OPTIONS->User_Delta_Parameter, sizeof (double),
		  *number_parameters, ptr_save);
#endif
#if QUENCH_PARAMETERS
	  fwrite (OPTIONS->User_Quench_Param_Scale, sizeof (double),
		  *number_parameters, ptr_save);
#endif
#if QUENCH_COST
	  fwrite (OPTIONS->User_Quench_Cost_Scale, sizeof (double),
		  1, ptr_save);
#endif
	  fwrite (&(OPTIONS->N_Accepted), sizeof (LONG_INT), 1, ptr_save);
	  fwrite (&(OPTIONS->N_Generated), sizeof (LONG_INT), 1, ptr_save);
	  fwrite (&(OPTIONS->Immediate_Exit), sizeof (int), 1, ptr_save);
#if OPTIONAL_DATA
	  fwrite (&(OPTIONS->Asa_Data_Dim), sizeof (ALLOC_INT), 1, ptr_save);
	  fwrite (OPTIONS->Asa_Data, sizeof (double),
		  OPTIONS->Asa_Data_Dim, ptr_save);
#endif
#if OPTIONAL_DATA_INT
	  fwrite (&(OPTIONS->Asa_Data_Dim_Int), sizeof (ALLOC_INT),
		  1, ptr_save);
	  fwrite (OPTIONS->Asa_Data_Int, sizeof (LONG_INT),
		  OPTIONS->Asa_Data_Dim_Int, ptr_save);
#endif
#if USER_ASA_OUT
	  fwrite (OPTIONS->Asa_Out_File, sizeof (char), 1, ptr_save);
#endif
#if USER_COST_SCHEDULE
	  fwrite (&(OPTIONS->Cost_Schedule), sizeof (char), 1, ptr_save);
#endif
#if USER_ACCEPT_ASYMP_EXP
	  fwrite (&(OPTIONS->Asymp_Exp_Param), sizeof (double), 1, ptr_save);
#endif
#if USER_ACCEPTANCE_TEST
	  fwrite (&(OPTIONS->Acceptance_Test), sizeof (char), 1, ptr_save);
	  fwrite (&(OPTIONS->User_Acceptance_Flag), sizeof (int), 1, ptr_save);
	  fwrite (&(OPTIONS->Cost_Acceptance_Flag), sizeof (int), 1, ptr_save);
	  fwrite (&(OPTIONS->Last_Cost), sizeof (double), 1, ptr_save);
	  fwrite (&(OPTIONS->Cost_Temp_Curr), sizeof (double), 1, ptr_save);
	  fwrite (&(OPTIONS->Cost_Temp_Init), sizeof (double), 1, ptr_save);
	  fwrite (&(OPTIONS->Cost_Temp_Scale), sizeof (double), 1, ptr_save);
#endif
#if USER_GENERATING_FUNCTION
	  fwrite (&(OPTIONS->Generating_Distrib), sizeof (char), 1, ptr_save);
#endif
#if USER_REANNEAL_COST
	  fwrite (OPTIONS->Reanneal_Cost_Function, sizeof (char), 1, ptr_save);
#endif
#if USER_REANNEAL_PARAMETERS
	  fwrite (&(OPTIONS->Reanneal_Params_Function), sizeof (char),
		  1, ptr_save);
#endif
#if ASA_SAMPLE
	  fwrite (&(OPTIONS->Bias_Acceptance), sizeof (double), 1, ptr_save);
	  fwrite (OPTIONS->Bias_Generated, sizeof (double),
		  *number_parameters, ptr_save);
	  fwrite (&(OPTIONS->Average_Weights), sizeof (double), 1, ptr_save);
	  fwrite (&(OPTIONS->Limit_Weights), sizeof (double), 1, ptr_save);
#endif
#if ASA_QUEUE
	  fwrite (save_queue, sizeof (LONG_INT), 1, ptr_save);
	  fwrite (save_queue_indx, sizeof (LONG_INT), 1, ptr_save);
	  fwrite (&(OPTIONS->Queue_Size), sizeof (ALLOC_INT),
		  1, ptr_save);
	  if (OPTIONS->Queue_Size > 0)
	    {
	      fwrite (save_queue_flag, sizeof (int), save_queue, ptr_save);
	      fwrite (save_queue_cost, sizeof (double), save_queue, ptr_save);
	      fwrite (save_queue_param, sizeof (double),
		    (*number_parameters) * (OPTIONS->Queue_Size), ptr_save);
	      fwrite (OPTIONS->Queue_Resolution, sizeof (double),
		      *number_parameters, ptr_save);
	    }
#endif
#if ASA_RESOLUTION
	  fwrite (OPTIONS->Coarse_Resolution, sizeof (double),
		  *number_parameters, ptr_save);
#endif
#if ASA_PARALLEL
	  fwrite (&parallel_generated, sizeof (LONG_INT), 1, ptr_save);
	  fwrite (&parallel_block_max, sizeof (LONG_INT), 1, ptr_save);
	  for (index_parallel = 0; index_parallel < parallel_block_max;
	       ++index_parallel)
	    {
	      fwrite (gener_block_state[index_parallel].parameter,
		      sizeof (double), *number_parameters, ptr_save);
	      fwrite (&(gener_block_state[index_parallel].cost),
		      sizeof (double), 1, ptr_save);
#if USER_ACCEPTANCE_TEST
	      fwrite (&(gener_block_state[index_parallel].par_user_accept_flag),
		      sizeof (int), 1, ptr_save);
	      fwrite (&(gener_block_state[index_parallel].par_cost_accept_flag),
		      sizeof (int), 1, ptr_save);
#endif
	    }
	  fwrite (&(OPTIONS->Gener_Mov_Avr), sizeof (int), 1, ptr_save);
	  fwrite (&(OPTIONS->Gener_Block), sizeof (LONG_INT), 1, ptr_save);
	  fwrite (&(OPTIONS->Gener_Block_Max), sizeof (LONG_INT), 1, ptr_save);
#endif

	  fclose (ptr_save);

	SAVED_ASA:

#if SYSTEM_CALL
	  /* extra protection in case run aborts during write */
	  system ("/bin/cp asa_save asa_save.old");
#endif
#if ASA_PRINT
#if INT_ALLOC
	  fprintf (ptr_asa_out, "Present Random Seed = %d\n\n", *seed);
#else
#if INT_LONG
	  fprintf (ptr_asa_out, "Present Random Seed = %ld\n\n", *seed);
#else
	  fprintf (ptr_asa_out, "Present Random Seed = %d\n\n", *seed);
#endif
#endif
#endif /* ASA_PRINT */
	}
#endif /* ASA_SAVE */

      if (OPTIONS->Immediate_Exit == TRUE)
	{
	  *exit_status = IMMEDIATE_EXIT;
	  goto EXIT_ASA;
	}

      /* PERIODIC TESTING/REANNEALING/PRINTING SECTION */

      if (OPTIONS->Acceptance_Frequency_Modulus == 0)
	tmp_var_int1 = FALSE;
      else if ((int) (*number_accepted %
		    ((LONG_INT) OPTIONS->Acceptance_Frequency_Modulus)) == 0
	       && *number_acceptances_saved == *number_accepted)
	tmp_var_int1 = TRUE;
      else
	tmp_var_int1 = FALSE;

      if (OPTIONS->Generated_Frequency_Modulus == 0)
	tmp_var_int2 = FALSE;
      else if ((int) (*number_generated %
		    ((LONG_INT) OPTIONS->Generated_Frequency_Modulus)) == 0)
	tmp_var_int2 = TRUE;
      else
	tmp_var_int2 = FALSE;

      if (
	   tmp_var_int1 == TRUE || tmp_var_int2 == TRUE
	   || (*accepted_to_generated_ratio
	       < OPTIONS->Accepted_To_Generated_Ratio)
	)
	{
	  if (*accepted_to_generated_ratio
	      < (OPTIONS->Accepted_To_Generated_Ratio))
	    *recent_number_acceptances = *recent_number_generated = 0;

	  /* if best.cost repeats OPTIONS->Maximum_Cost_Repeat then exit */
	  if (OPTIONS->Maximum_Cost_Repeat != 0)
	    {
	      if (fabs (last_saved_state->cost - best_generated_state->cost)
		  < OPTIONS->Cost_Precision)
		{
		  ++index_cost_repeat;
		  if (index_cost_repeat == (OPTIONS->Maximum_Cost_Repeat))
		    {
		      *exit_status = COST_REPEATING;
		      goto EXIT_ASA;
		    }
		}
	      else
		{
		  index_cost_repeat = 0;
		}
	    }

	  if (OPTIONS->Reanneal_Parameters == TRUE)
	    {
	      /* calculate tangents, not curvatures, to reanneal */
	      *curvature_flag = FALSE;
	      cost_derivatives (user_cost_function,
				parameter_minimum,
				parameter_maximum,
				tangents,
				curvature,
				maximum_tangent,
				number_parameters,
				parameter_type,
				exit_status,
				curvature_flag,
				valid_state_generated_flag,
				number_invalid_generated_states,
				current_generated_state,
				best_generated_state,
				ptr_asa_out,
				OPTIONS);
	    }

#if USER_REANNEAL_COST
#else
	  if (OPTIONS->Reanneal_Cost == 0 || OPTIONS->Reanneal_Cost == 1)
	    {
	      ;
	    }
	  else
	    {
	      if (OPTIONS->Reanneal_Cost < -1)
		{
		  tmp_var_int = -OPTIONS->Reanneal_Cost;
		}
	      else
		{
		  tmp_var_int = OPTIONS->Reanneal_Cost;
		}
	      tmp_var_db1 = ZERO;
	      tmp_var_db2 = ZERO;

	      for (index_cost_constraint = 0;
		   index_cost_constraint < tmp_var_int;
		   ++index_cost_constraint)
		{
		  *number_invalid_generated_states = 0;
		  repeated_invalid_states = 0;
		  OPTIONS->Sequential_Parameters = *start_sequence - 1;
		  do
		    {
		      ++(*number_invalid_generated_states);
		      generate_new_state (user_random_generator,
					  seed,
					  parameter_minimum,
					  parameter_maximum,
					  current_user_parameter_temp,
#if USER_GENERATING_FUNCTION
					  initial_user_parameter_temp,
					  temperature_scale_parameters,
#endif
					  number_parameters,
					  parameter_type,
					  current_generated_state,
					  last_saved_state,
					  OPTIONS);
		      *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
		      OPTIONS->User_Acceptance_Flag = TRUE;
		      OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif

#if ASA_QUEUE
		      if (OPTIONS->Queue_Size == 0)
			{
			  queue_new = 1;
			}
		      else
			{
			  queue_new = 1;
			  for (queue = 0; queue < save_queue; ++queue)
			    {
			      save_queue_test = 0;
			      VFOR (index_v)
			      {
				if (PARAMETER_RANGE_TOO_SMALL (index_v))
				  {
				    ++save_queue_test;
				  }
				else
				  {
				    queue_v = index_v + queue
				      * (LONG_INT) (*number_parameters);
				    if (fabs (
					       current_generated_state->parameter[index_v]
					       - save_queue_param[queue_v])
					< (OPTIONS->Queue_Resolution[index_v]
					   + EPS_DOUBLE))
				      {
					++save_queue_test;
				      }
				  }
			      }
			      if (save_queue_test == *number_parameters)
				{
				  tmp_var_db = save_queue_cost[queue];
				  *valid_state_generated_flag =
				    save_queue_flag[queue];
				  queue_new = 0;
#if ASA_TEMPLATE_QUEUE
#if ASA_PRINT_MORE
#if INT_LONG
				  fprintf (ptr_asa_out, "ASA_QUEUE: %ld \t %*.*g\n",
#else
				  fprintf (ptr_asa_out, "ASA_QUEUE: %d \t %*.*g\n",
#endif
					   OPTIONS->N_Generated,
					   G_FIELD, G_PRECISION, tmp_var_db);
#endif
#endif
				  break;
				}
			    }
			}
		      if (queue_new == 1)
			{
			  tmp_var_db =
			    user_cost_function (
					 current_generated_state->parameter,
						 parameter_minimum,
						 parameter_maximum,
						 tangents,
						 curvature,
						 number_parameters,
						 parameter_type,
						 valid_state_generated_flag,
						 exit_status,
						 OPTIONS);
			  if (OPTIONS->Queue_Size > 0)
			    {
			      VFOR (index_v)
			      {
				if (PARAMETER_RANGE_TOO_SMALL (index_v))
				  {
				    continue;
				  }
				queue_v = index_v + save_queue
				  * (LONG_INT) (*number_parameters);
				save_queue_param[queue_v] =
				  current_generated_state->parameter[index_v];
			      }
			      save_queue_cost[save_queue] = tmp_var_db;
			      save_queue_flag[save_queue]
				= *valid_state_generated_flag;

			      ++save_queue;
			      if (save_queue == (LONG_INT) OPTIONS->Queue_Size)
				--save_queue;

			      ++save_queue_indx;
			      if (save_queue_indx == (LONG_INT) OPTIONS->Queue_Size)
				save_queue_indx = 0;
			    }
			}
#else /* ASA_QUEUE */
		      tmp_var_db =
			user_cost_function (
					 current_generated_state->parameter,
					     parameter_minimum,
					     parameter_maximum,
					     tangents,
					     curvature,
					     number_parameters,
					     parameter_type,
					     valid_state_generated_flag,
					     exit_status,
					     OPTIONS);
#endif /* ASA_QUEUE */
		      ++repeated_invalid_states;
		      if (repeated_invalid_states >
			  OPTIONS->Limit_Invalid_Generated_States)
			{
			  *exit_status = TOO_MANY_INVALID_STATES;
			  goto EXIT_ASA;
			}
		    }
		  while (*valid_state_generated_flag == FALSE);
		  --(*number_invalid_generated_states);

		  tmp_var_db1 += tmp_var_db;
		  tmp_var_db2 += (tmp_var_db * tmp_var_db);
		}
	      tmp_var_db1 /= (double) tmp_var_int;
	      tmp_var_db2 /= (double) tmp_var_int;
	      tmp_var_db = sqrt (fabs ((tmp_var_db2 - tmp_var_db1 * tmp_var_db1)
				       * ((double) tmp_var_int
					  / ((double) tmp_var_int - ONE))));
	      if (OPTIONS->Reanneal_Cost < -1)
		{
		  *current_cost_temperature = *initial_cost_temperature =
		    tmp_var_db + (double) EPS_DOUBLE;
		}
	      else
		{
		  *initial_cost_temperature = tmp_var_db + (double) EPS_DOUBLE;
		}
	    }
#endif /* USER_REANNEAL_COST */

	  reanneal (parameter_minimum,
		    parameter_maximum,
		    tangents,
		    maximum_tangent,
		    current_cost_temperature,
		    initial_cost_temperature,
		    temperature_scale_cost,
		    current_user_parameter_temp,
		    initial_user_parameter_temp,
		    temperature_scale_parameters,
		    number_parameters,
		    parameter_type,
		    index_cost_acceptances,
		    index_parameter_generations,
		    last_saved_state,
		    best_generated_state,
		    OPTIONS);
#if ASA_PRINT_INTERMED
#if ASA_PRINT
	  print_state (parameter_minimum,
		       parameter_maximum,
		       tangents,
		       curvature,
		       current_cost_temperature,
		       current_user_parameter_temp,
		       accepted_to_generated_ratio,
		       number_parameters,
		       curvature_flag,
		       number_accepted,
		       index_cost_acceptances,
		       number_generated,
		       number_invalid_generated_states,
		       last_saved_state,
		       best_generated_state,
		       ptr_asa_out,
		       OPTIONS);

	  fprintf (ptr_asa_out, "\n");
	  fflush (ptr_asa_out);
#endif
#endif
	}
    }

  /* FINISHED ANNEALING and MINIMIZATION */

  *exit_status = NORMAL_EXIT;
EXIT_ASA:
  asa_exit (user_cost_function,
	    &final_cost,
	    parameter_initial_final,
	    parameter_minimum,
	    parameter_maximum,
	    tangents,
	    curvature,
	    maximum_tangent,
	    current_cost_temperature,
	    initial_user_parameter_temp,
	    current_user_parameter_temp,
	    accepted_to_generated_ratio,
	    number_parameters,
	    parameter_type,
	    valid_state_generated_flag,
	    exit_status,
	    index_exit_v,
	    start_sequence,
	    number_accepted,
	    best_number_accepted_saved,
	    index_cost_acceptances,
	    number_generated,
	    number_invalid_generated_states,
	    index_parameter_generations,
	    best_number_generated_saved,
	    current_generated_state,
	    last_saved_state,
	    best_generated_state,
	    ptr_asa_out,
	    OPTIONS);
  free (curvature_flag);
  free (maximum_tangent);
  free (accepted_to_generated_ratio);
  free (temperature_scale_cost);
  free (current_cost_temperature);
  free (initial_cost_temperature);
  free (number_generated);
  free (best_number_generated_saved);
  free (recent_number_generated);
  free (number_accepted);
  free (recent_number_acceptances);
  free (index_cost_acceptances);
  free (number_acceptances_saved);
  free (best_number_accepted_saved);
  free (number_invalid_generated_states);
  free (current_generated_state->parameter);
  free (last_saved_state->parameter);
  free (best_generated_state->parameter);
  free (current_generated_state);
  free (last_saved_state);
  free (best_generated_state);
#if ASA_QUEUE
  free (save_queue_flag);
  free (save_queue_cost);
  free (save_queue_param);
#endif
#if ASA_PARALLEL
  for (index_parallel = 0; index_parallel < parallel_block_max;
       ++index_parallel)
    {
      free (gener_block_state[index_parallel].parameter);
    }
  free (gener_block_state);
#endif
  free (initial_user_parameter_temp);
  free (index_exit_v);
  free (start_sequence);
  free (index_parameter_generations);
  free (current_user_parameter_temp);
  free (temperature_scale_parameters);
  if (recursive_asa_open == 0)
    asa_open = FALSE;
  return (final_cost);
}

/***********************************************************************
* asa_exit
*	This procedures copies the best parameters and cost into
*       final_cost and parameter_initial_final
***********************************************************************/
#if HAVE_ANSI
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)
#else
void
asa_exit (user_cost_function,
	  final_cost,
	  parameter_initial_final,
	  parameter_minimum,
	  parameter_maximum,
	  tangents,
	  curvature,
	  maximum_tangent,
	  current_cost_temperature,
	  initial_user_parameter_temp,
	  current_user_parameter_temp,
	  accepted_to_generated_ratio,
	  number_parameters,
	  parameter_type,
	  valid_state_generated_flag,
	  exit_status,
	  index_exit_v,
	  start_sequence,
	  number_accepted,
	  best_number_accepted_saved,
	  index_cost_acceptances,
	  number_generated,
	  number_invalid_generated_states,
	  index_parameter_generations,
	  best_number_generated_saved,
	  current_generated_state,
	  last_saved_state,
	  best_generated_state,
	  ptr_asa_out,
	  OPTIONS)
     double (*user_cost_function) ();
     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;
#endif
{
  ALLOC_INT index_v;		/* iteration index */
  int *curvature_flag;

  if ((curvature_flag =
       (int *) mycxalloc (1, sizeof (int))) == NULL)
      exit (9);

  if (*exit_status != TOO_MANY_INVALID_STATES
      && *exit_status != IMMEDIATE_EXIT
      && *exit_status != INVALID_USER_INPUT)
    {
      /* calculate curvatures and tangents at best point */
      *curvature_flag = TRUE;
      cost_derivatives (user_cost_function,
			parameter_minimum,
			parameter_maximum,
			tangents,
			curvature,
			maximum_tangent,
			number_parameters,
			parameter_type,
			exit_status,
			curvature_flag,
			valid_state_generated_flag,
			number_invalid_generated_states,
			current_generated_state,
			best_generated_state,
			ptr_asa_out,
			OPTIONS);
    }
  /* return final function minimum and associated parameters */
  *final_cost = best_generated_state->cost;
  VFOR (index_v)
  {
    parameter_initial_final[index_v] =
      best_generated_state->parameter[index_v];
  }

  OPTIONS->N_Accepted = *best_number_accepted_saved;
  OPTIONS->N_Generated = *best_number_generated_saved;

#if ASA_PRINT
  if (*exit_status != INVALID_USER_INPUT)
    print_state (parameter_minimum,
		 parameter_maximum,
		 tangents,
		 curvature,
		 current_cost_temperature,
		 current_user_parameter_temp,
		 accepted_to_generated_ratio,
		 number_parameters,
		 curvature_flag,
		 number_accepted,
		 index_cost_acceptances,
		 number_generated,
		 number_invalid_generated_states,
		 last_saved_state,
		 best_generated_state,
		 ptr_asa_out,
		 OPTIONS);

  switch (*exit_status)
    {
    case NORMAL_EXIT:
      fprintf (ptr_asa_out,
	       "\n\n NORMAL_EXIT exit_status = %d\n",
	       *exit_status);
      break;
    case P_TEMP_TOO_SMALL:
      fprintf (ptr_asa_out,
	       "\n\n P_TEMP_TOO_SMALL exit_status = %d\n",
	       *exit_status);
      fprintf (ptr_asa_out,
#if INT_ALLOC
	       "current_user_parameter_temp[%d] too small = %*.*g\n",
#else
#if INT_LONG
	       "current_user_parameter_temp[%ld] too small = %*.*g\n",
#else
	       "current_user_parameter_temp[%d] too small = %*.*g\n",
#endif
#endif
	       *index_exit_v,
	  G_FIELD, G_PRECISION, current_user_parameter_temp[*index_exit_v]);
      break;
    case C_TEMP_TOO_SMALL:
      fprintf (ptr_asa_out,
	       "\n\n C_TEMP_TOO_SMALL exit_status = %d\n",
	       *exit_status);
      fprintf (ptr_asa_out,
	       "*current_cost_temperature too small = %*.*g\n",
	       G_FIELD, G_PRECISION, *current_cost_temperature);
      break;
    case COST_REPEATING:
      fprintf (ptr_asa_out,
	       "\n\n COST_REPEATING exit_status = %d\n",
	       *exit_status);
      break;
    case TOO_MANY_INVALID_STATES:
      fprintf (ptr_asa_out,
	       "\n\n  TOO_MANY_INVALID_STATES exit_status = %d\n",
	       *exit_status);
      break;
    case IMMEDIATE_EXIT:
      fprintf (ptr_asa_out,
	       "\n\n  IMMEDIATE_EXIT exit_status = %d\n",
	       *exit_status);
      break;
    case INVALID_USER_INPUT:
      fprintf (ptr_asa_out,
	       "\n\n  INVALID_USER_INPUT exit_status = %d\n",
	       *exit_status);
      break;
    default:
      fprintf (ptr_asa_out, "\n\n ERR: no exit code available = %d\n",
	       *exit_status);
    }

  if (*exit_status != INVALID_USER_INPUT)
    {
      fprintf (ptr_asa_out,
	       "final_cost = best_generated_state->cost = %-*.*g\n",
	       G_FIELD, G_PRECISION, *final_cost);
#if INT_LONG
      fprintf (ptr_asa_out,
	       "*number_accepted at best_generated_state->cost = %ld\n",
	       *best_number_accepted_saved);
      fprintf (ptr_asa_out,
	       "*number_generated at best_generated_state->cost = %ld\n",
	       *best_number_generated_saved);
#else
      fprintf (ptr_asa_out,
	       "*number_accepted at best_generated_state->cost = %d\n",
	       *best_number_accepted_saved);
      fprintf (ptr_asa_out,
	       "*number_generated at best_generated_state->cost = %d\n",
	       *best_number_generated_saved);
#endif
    }
#endif

#if ASA_TEMPLATE_SELFOPT
  if (OPTIONS->Asa_Data[0] > (double) MIN_DOUBLE)
    OPTIONS->Asa_Data[1] = (double) (*best_number_generated_saved);
#endif

  /* reset OPTIONS->Sequential_Parameters */
  OPTIONS->Sequential_Parameters = *start_sequence;

  /* return unused space */
  free (curvature_flag);

#if ASA_PRINT
#if TIME_CALC
  /* print ending time */
  print_time ("asa_end", ptr_asa_out);
#endif
  fprintf (ptr_asa_out, "\n\n\n");
  fflush (ptr_asa_out);
  fclose (ptr_asa_out);
#endif
}

/***********************************************************************
* generate_new_state
*       Generates a valid new state from the old state
***********************************************************************/
#if HAVE_ANSI
void
generate_new_state (double (*user_random_generator) (LONG_INT *),
		    LONG_INT * seed,
		    double *parameter_minimum,
		    double *parameter_maximum,
		    double *current_user_parameter_temp,
#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)
#else
void
generate_new_state (user_random_generator,
		    seed,
		    parameter_minimum,
		    parameter_maximum,
		    current_user_parameter_temp,
#if USER_GENERATING_FUNCTION
		    initial_user_parameter_temp,
		    temperature_scale_parameters,
#endif
		    number_parameters,
		    parameter_type,
		    current_generated_state,
		    last_saved_state,
		    OPTIONS)
     double (*user_random_generator) ();
     LONG_INT *seed;
     double *parameter_minimum;
     double *parameter_maximum;
     double *current_user_parameter_temp;
#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;
#endif
{
  ALLOC_INT index_v;
  double x;
  double parameter_v, min_parameter_v, max_parameter_v, temperature_v,
    parameter_range_v;
#if USER_GENERATING_FUNCTION
  double init_param_temp_v;
  double temp_scale_params_v;
#endif
#if ASA_RESOLUTION
  double xres, xint, xminus, xplus, dx, dxminus, dxplus;
#endif

  /* generate a new value for each parameter */
  VFOR (index_v)
  {
    if (OPTIONS->Sequential_Parameters >= -1)
      {
	++OPTIONS->Sequential_Parameters;
	if (OPTIONS->Sequential_Parameters == *number_parameters)
	  OPTIONS->Sequential_Parameters = 0;
	index_v = OPTIONS->Sequential_Parameters;
      }
    min_parameter_v = parameter_minimum[index_v];
    max_parameter_v = parameter_maximum[index_v];
    parameter_range_v = max_parameter_v - min_parameter_v;

    /* ignore parameters that have too small a range */
    if (fabs (parameter_range_v) < (double) EPS_DOUBLE)
      continue;

    temperature_v = current_user_parameter_temp[index_v];
#if USER_GENERATING_FUNCTION
    init_param_temp_v = initial_user_parameter_temp[index_v];
    temp_scale_params_v = temperature_scale_parameters[index_v];
#endif
    parameter_v = last_saved_state->parameter[index_v];

    /* Handle discrete integer parameters. */
    if (INTEGER_PARAMETER (index_v))
      {
	min_parameter_v -= HALF;
	max_parameter_v += HALF;
	parameter_range_v = max_parameter_v - min_parameter_v;
      }
    /* generate a new state x within the parameter bounds */
    for (;;)
      {
#if USER_GENERATING_FUNCTION
	x = OPTIONS->Generating_Distrib (seed,
					 *number_parameters,
					 index_v,
					 temperature_v,
					 init_param_temp_v,
					 temp_scale_params_v,
					 parameter_v,
					 parameter_range_v,
					 OPTIONS);
#else
	x = parameter_v
	  + generate_asa_state (user_random_generator, seed, &temperature_v)
	  * parameter_range_v;
#endif /* USER_GENERATING_FUNCTION */
#if ASA_RESOLUTION
	xres = OPTIONS->Coarse_Resolution[index_v];
	if (xres > EPS_DOUBLE)
	  {
	    xint = xres * (double) ((LONG_INT) (x / xres));
	    xplus = xint + xres;
	    xminus = xint - xres;
	    dx = fabs (xint - x);
	    dxminus = fabs (xminus - x);
	    dxplus = fabs (xplus - x);

	    if (dx < dxminus && dx < dxplus)
	      x = xint;
	    else if (dxminus < dxplus)
	      x = xminus;
	    else
	      x = xplus;
	  }
#endif /* ASA_RESOLUTION */

	/* exit the loop if within its valid parameter range */
	if (x <= max_parameter_v - (double) EPS_DOUBLE
	    && x >= min_parameter_v + (double) EPS_DOUBLE)
	  break;
      }

    /* Handle discrete integer parameters.
       You might have to check rounding on your machine. */
    if (INTEGER_PARAMETER (index_v))
      {
	if (x < min_parameter_v + HALF)
	  x = min_parameter_v + HALF + (double) EPS_DOUBLE;
	if (x > max_parameter_v - HALF)
	  x = max_parameter_v - HALF + (double) EPS_DOUBLE;

	if (x + HALF > ZERO)
	  {
	    x = (double) ((LONG_INT) (x + HALF));
	  }
	else
	  {
	    x = (double) ((LONG_INT) (x - HALF));
	  }
	if (x > parameter_maximum[index_v])
	  x = parameter_maximum[index_v];
	if (x < parameter_minimum[index_v])
	  x = parameter_minimum[index_v];
      }
    /* save the newly generated value */
    current_generated_state->parameter[index_v] = x;

    if (OPTIONS->Sequential_Parameters >= 0)
      break;
  }

}

/***********************************************************************
* generate_asa_state
*       This function generates a single value according to the
*       ASA generating function and the passed temperature
***********************************************************************/
#if HAVE_ANSI
double
generate_asa_state (double (*user_random_generator) (LONG_INT *),
		    LONG_INT * seed,
		    double *temp)
#else
double
generate_asa_state (user_random_generator,
		    seed,
		    temp)
     double (*user_random_generator) ();
     LONG_INT *seed;
     double *temp;
#endif
{
  double x, y, z;

  x = (*user_random_generator) (seed);
  y = x < HALF ? -ONE : ONE;
  z = y * *temp * (F_POW ((ONE + ONE / *temp), fabs (TWO * x - ONE)) - ONE);

  return (z);

}

/***********************************************************************
* accept_new_state
*	This procedure accepts or rejects a newly generated state,
*	depending on whether the difference between new and old
*	cost functions passes a statistical test. If accepted,
*	the current state is updated.
***********************************************************************/
#if HAVE_ANSI
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)
#else
void
accept_new_state (user_random_generator,
		  seed,
		  parameter_minimum,
		  parameter_maximum,
		  current_cost_temperature,
#if ASA_SAMPLE
		  current_user_parameter_temp,
#endif
		  number_parameters,
		  recent_number_acceptances,
		  number_accepted,
		  index_cost_acceptances,
		  number_acceptances_saved,
		  recent_number_generated,
		  number_generated,
		  index_parameter_generations,
		  current_generated_state,
		  last_saved_state,
#if ASA_SAMPLE
		  ptr_asa_out,
#endif
		  OPTIONS)
     double (*user_random_generator) ();
     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;

#endif
{
#if USER_ACCEPTANCE_TEST
#else
  double delta_cost;
#endif
#if USER_ACCEPT_ASYMP_EXP
  double q;
#endif
  double prob_test, unif_test;
  double curr_cost_temp;
  ALLOC_INT index_v;
#if ASA_SAMPLE
  LONG_INT active_params;
  double weight_param_ind, weight_aver, range;
#endif

  /* update accepted and generated count */
  ++*number_acceptances_saved;
  ++*recent_number_generated;
  ++*number_generated;
  OPTIONS->N_Generated = *number_generated;

  /* increment the parameter index generation for each parameter */
  if (OPTIONS->Sequential_Parameters >= 0)
    {
      /* ignore parameters with too small a range */
      if (!PARAMETER_RANGE_TOO_SMALL (OPTIONS->Sequential_Parameters))
	++index_parameter_generations[OPTIONS->Sequential_Parameters];
    }
  else
    {
      VFOR (index_v)
      {
	if (!PARAMETER_RANGE_TOO_SMALL (index_v))
	  ++index_parameter_generations[index_v];
      }
    }

  /* effective cost function for testing acceptance criteria,
     calculate the cost difference and divide by the temperature */
  curr_cost_temp = *current_cost_temperature;
#if USER_ACCEPTANCE_TEST
  if (OPTIONS->Cost_Acceptance_Flag == TRUE)
    {
      if (OPTIONS->User_Acceptance_Flag == TRUE)
	{
	  unif_test = ZERO;
	  OPTIONS->User_Acceptance_Flag = FALSE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
	}
      else
	{
	  unif_test = ONE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
	}
    }
  else
    {
      OPTIONS->Acceptance_Test (current_generated_state->cost,
				*number_parameters,
				OPTIONS);
      if (OPTIONS->User_Acceptance_Flag == TRUE)
	{
	  unif_test = ZERO;
	  OPTIONS->User_Acceptance_Flag = FALSE;
	}
      else
	{
	  unif_test = ONE;
	}
    }
  prob_test = OPTIONS->Prob_Bias;
#else /* USER_ACCEPTANCE_TEST */
#if USER_COST_SCHEDULE
  curr_cost_temp =
    (OPTIONS->Cost_Schedule (*current_cost_temperature, OPTIONS)
     + (double) EPS_DOUBLE);
#endif
  delta_cost = (current_generated_state->cost - last_saved_state->cost)
    / (curr_cost_temp + (double) EPS_DOUBLE);

#if USER_ACCEPT_ASYMP_EXP
  q = OPTIONS->Asymp_Exp_Param;
  if (fabs (ONE - q) < (double) EPS_DOUBLE)
    prob_test = MIN (ONE, (F_EXP (EXPONENT_CHECK (-delta_cost))));
  else if ((ONE - (ONE - q) * delta_cost) < (double) EPS_DOUBLE)
    prob_test = MIN (ONE, (F_EXP (EXPONENT_CHECK (-delta_cost))));
  else
    prob_test = MIN (ONE, F_POW ((ONE - (ONE - q) * delta_cost),
				 (ONE / (ONE - q))));
#else /* USER_ACCEPT_ASYMP_EXP */
  prob_test = MIN (ONE, (F_EXP (EXPONENT_CHECK (-delta_cost))));
#endif /* USER_ACCEPT_ASYMP_EXP */

  unif_test = (*user_random_generator) (seed);
#endif /* USER_ACCEPTANCE_TEST */

#if ASA_SAMPLE
  active_params = 0;
  weight_aver = ZERO;
  VFOR (index_v)
  {
    /* ignore parameters with too small a range */
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    ++active_params;
    range = parameter_maximum[index_v] - parameter_minimum[index_v];
    weight_param_ind = TWO
      * (fabs ((last_saved_state->parameter[index_v]
		- current_generated_state->parameter[index_v]) / range)
	 + current_user_parameter_temp[index_v])
      * F_LOG (ONE + ONE / current_user_parameter_temp[index_v]);
    weight_aver += weight_param_ind;
    OPTIONS->Bias_Generated[index_v] = ONE / weight_param_ind;
  }
  weight_aver /= (double) active_params;
  OPTIONS->Average_Weights = weight_aver;
  if (prob_test >= unif_test)
    {
      OPTIONS->Bias_Acceptance = prob_test;
    }
  else
    {
      OPTIONS->Bias_Acceptance = ONE - prob_test;
    }

#if ASA_PRINT
  if (OPTIONS->Limit_Weights < OPTIONS->Average_Weights)
    {
      fprintf (ptr_asa_out, ":SAMPLE#\n");
      if (prob_test >= unif_test)
	{
	  fprintf (ptr_asa_out,
#if INT_LONG
		   ":SAMPLE+ %10ld %*.*g %*.*g %*.*g %*.*g\n",
#else
		   ":SAMPLE+ %10d %*.*g %*.*g %*.*g\n",
#endif
		   OPTIONS->N_Accepted,
		   G_FIELD, G_PRECISION, current_generated_state->cost,
		   G_FIELD, G_PRECISION, *current_cost_temperature,
		   G_FIELD, G_PRECISION, OPTIONS->Bias_Acceptance,
		   G_FIELD, G_PRECISION, OPTIONS->Average_Weights);
	  VFOR (index_v)
	  {
	    /* ignore parameters with too small a range */
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      continue;
	    range = parameter_maximum[index_v] - parameter_minimum[index_v];
	    fprintf (ptr_asa_out,
#if INT_ALLOC
		     ":SAMPLE %11d %*.*g %*.*g %*.*g %*.*g\n",
#else
#if INT_LONG
		     ":SAMPLE %11ld %*.*g %*.*g %*.*g %*.*g\n",
#else
		     ":SAMPLE %11d %*.*g %*.*g %*.*g %*.*g\n",
#endif
#endif
		     index_v,
		     G_FIELD, G_PRECISION, current_generated_state->parameter[index_v],
		 G_FIELD, G_PRECISION, current_user_parameter_temp[index_v],
		     G_FIELD, G_PRECISION, OPTIONS->Bias_Generated[index_v],
		     G_FIELD, G_PRECISION, range);
	  }
	}
      else
	{
	  fprintf (ptr_asa_out,
#if INT_LONG
		   ":SAMPLE %11ld %*.*g %*.*g %*.*g %*.*g\n",
#else
		   ":SAMPLE %11d %*.*g %*.*g %*.*g\n",
#endif
		   OPTIONS->N_Accepted,
		   G_FIELD, G_PRECISION, last_saved_state->cost,
		   G_FIELD, G_PRECISION, *current_cost_temperature,
		   G_FIELD, G_PRECISION, OPTIONS->Bias_Acceptance,
		   G_FIELD, G_PRECISION, OPTIONS->Average_Weights);
	  VFOR (index_v)
	  {
	    /* ignore parameters with too small a range */
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      continue;
	    range = parameter_maximum[index_v] - parameter_minimum[index_v];
	    fprintf (ptr_asa_out,
#if INT_ALLOC
		     ":SAMPLE %11d %*.*g %*.*g %*.*g %*.*g\n",
#else
#if INT_LONG
		     ":SAMPLE %11ld %*.*g %*.*g %*.*g %*.*g\n",
#else
		     ":SAMPLE %11d %*.*g %*.*g %*.*g %*.*g\n",
#endif
#endif
		     index_v,
		 G_FIELD, G_PRECISION, last_saved_state->parameter[index_v],
		 G_FIELD, G_PRECISION, current_user_parameter_temp[index_v],
		     G_FIELD, G_PRECISION, OPTIONS->Bias_Generated[index_v],
		     G_FIELD, G_PRECISION, range);
	  }
	}
    }
#endif
#endif /* ASA_SAMPLE */

  /* accept/reject the new state */
  if (prob_test >= unif_test)
    {
      /* copy current state to the last saved state */

#if USER_ACCEPTANCE_TEST
      OPTIONS->Last_Cost =
#endif
	last_saved_state->cost = current_generated_state->cost;
      VFOR (index_v)
      {
	/* ignore parameters with too small a range */
	if (PARAMETER_RANGE_TOO_SMALL (index_v))
	  continue;
	last_saved_state->parameter[index_v] =
	  current_generated_state->parameter[index_v];
      }

      /* update acceptance counts */
      ++*recent_number_acceptances;
      ++*number_accepted;
      ++*index_cost_acceptances;
      *number_acceptances_saved = *number_accepted;
      OPTIONS->N_Accepted = *number_accepted;
    }
}

/***********************************************************************
* reanneal
*	Readjust temperatures of generating and acceptance functions
***********************************************************************/
#if HAVE_ANSI
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)
#else
void
reanneal (parameter_minimum,
	  parameter_maximum,
	  tangents,
	  maximum_tangent,
	  current_cost_temperature,
	  initial_cost_temperature,
	  temperature_scale_cost,
	  current_user_parameter_temp,
	  initial_user_parameter_temp,
	  temperature_scale_parameters,
	  number_parameters,
	  parameter_type,
	  index_cost_acceptances,
	  index_parameter_generations,
	  last_saved_state,
	  best_generated_state,
	  OPTIONS)
     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;
#endif
{
  ALLOC_INT index_v;
  int cost_test;
  double tmp_var_db3;
  double new_temperature;
  double log_new_temperature_ratio;
  double log_init_cur_temp_ratio;
  double temperature_rescale_power;
  double cost_best, cost_last;
  double tmp_dbl, tmp_dbl1;

  if (OPTIONS->Reanneal_Parameters == TRUE)
    {
      VFOR (index_v)
      {
	if (NO_REANNEAL (index_v))
	  continue;

	/* use the temp double to prevent overflow */
	tmp_dbl = (double) index_parameter_generations[index_v];

	/* skip parameters with too small range or integer parameters */
	if (OPTIONS->Include_Integer_Parameters == TRUE)
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      continue;
	  }
	else
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v) ||
		INTEGER_PARAMETER (index_v))
	      continue;
	  }

	/* ignore parameters with too small tangents */
	if (fabs (tangents[index_v]) < (double) EPS_DOUBLE)
	  continue;

	/* reset the index of parameter generations appropriately */
#if USER_REANNEAL_PARAMETERS
	new_temperature =
	  fabs (OPTIONS->Reanneal_Params_Function (
				       current_user_parameter_temp[index_v],
						    tangents[index_v],
						    *maximum_tangent,
						    OPTIONS));
#else
	new_temperature =
	  fabs (FUNCTION_REANNEAL_PARAMS (current_user_parameter_temp[index_v],
					  tangents[index_v],
					  *maximum_tangent));
#endif
	if (new_temperature < initial_user_parameter_temp[index_v])
	  {
	    log_init_cur_temp_ratio =
	      fabs (F_LOG (((double) EPS_DOUBLE
			    + initial_user_parameter_temp[index_v])
			   / ((double) EPS_DOUBLE + new_temperature)));
	    tmp_dbl = (double) EPS_DOUBLE
	      + F_POW (log_init_cur_temp_ratio
		       / temperature_scale_parameters[index_v],
		       (double) *number_parameters
#if QUENCH_PARAMETERS
		       / OPTIONS->User_Quench_Param_Scale[index_v]);
#else
	      );
#endif
	  }
	else
	  {
	    tmp_dbl = ONE;
	  }

	/* Reset index_parameter_generations if index reset too large,
	   and also reset the initial_user_parameter_temp, to achieve
	   the same new temperature. */
	while (tmp_dbl
	       > ((double) MAXIMUM_REANNEAL_INDEX))
	  {
	    log_new_temperature_ratio =
	      -temperature_scale_parameters[index_v] *
	      F_POW (tmp_dbl,
#if QUENCH_PARAMETERS
		     OPTIONS->User_Quench_Param_Scale[index_v]
#else
		     ONE
#endif
		     / (double) *number_parameters);
	    log_new_temperature_ratio =
	      EXPONENT_CHECK (log_new_temperature_ratio);
	    new_temperature =
	      initial_user_parameter_temp[index_v]
	      * F_EXP (log_new_temperature_ratio);
	    tmp_dbl /= (double) REANNEAL_SCALE;
	    temperature_rescale_power = ONE
	      / F_POW ((double) REANNEAL_SCALE,
#if QUENCH_PARAMETERS
		       OPTIONS->User_Quench_Param_Scale[index_v]
#else
		       ONE
#endif
		       / (double) *number_parameters);
	    initial_user_parameter_temp[index_v] = new_temperature
	      * F_POW (initial_user_parameter_temp[index_v] / new_temperature,
		       temperature_rescale_power);
	  }
	/* restore from temporary double */
	index_parameter_generations[index_v] = (LONG_INT) tmp_dbl;
      }
    }

  if (OPTIONS->Reanneal_Cost == 0)
    {
      ;
    }
  else if (OPTIONS->Reanneal_Cost < -1)
    {
      *index_cost_acceptances = 1;
    }
  else
    {
      /* reanneal : Reset the current cost temp and rescale the
         index of cost acceptances. */

      cost_best = best_generated_state->cost;
      cost_last = last_saved_state->cost;
#if USER_REANNEAL_COST
      cost_test = OPTIONS->Reanneal_Cost_Function (&cost_best,
						   &cost_last,
						   initial_cost_temperature,
						   current_cost_temperature,
						   OPTIONS);
      tmp_dbl1 = *current_cost_temperature;
#else
      cost_test = TRUE;
      if (OPTIONS->Reanneal_Cost == 1)
	{
	  /* (re)set the initial cost_temperature */
	  tmp_dbl = MAX (fabs (cost_last), fabs (cost_best));
	  tmp_dbl = MAX (tmp_dbl, fabs (cost_best - cost_last));
	  tmp_dbl = MAX ((double) EPS_DOUBLE, tmp_dbl);
	  *initial_cost_temperature = MIN (*initial_cost_temperature, tmp_dbl);
	}

      tmp_dbl = (double) *index_cost_acceptances;

      tmp_dbl1 = MAX (fabs (cost_last - cost_best), *current_cost_temperature);
      tmp_dbl1 = MAX ((double) EPS_DOUBLE, tmp_dbl1);
      tmp_dbl1 = MIN (tmp_dbl1, *initial_cost_temperature);
#endif /* USER_REANNEAL_COST */
      if (cost_test == TRUE && (*current_cost_temperature > tmp_dbl1))
	{
	  tmp_var_db3 =
	    fabs (F_LOG (((double) EPS_DOUBLE + *initial_cost_temperature) /
			 (tmp_dbl1)));
	  tmp_dbl = (double) EPS_DOUBLE + F_POW (tmp_var_db3
		      / *temperature_scale_cost, (double) *number_parameters
#if QUENCH_COST
				      / OPTIONS->User_Quench_Cost_Scale[0]);
#else
	    );
#endif
	}
      else
	{
	  log_init_cur_temp_ratio =
	    fabs (F_LOG (((double) EPS_DOUBLE + *initial_cost_temperature) /
			 ((double) EPS_DOUBLE + *current_cost_temperature)));
	  tmp_dbl = (double) EPS_DOUBLE
	    + F_POW (log_init_cur_temp_ratio
		     / *temperature_scale_cost, (double) *number_parameters
#if QUENCH_COST
		     / OPTIONS->User_Quench_Cost_Scale[0]
#else
#endif
	    );
	}

      /* reset index_cost_temperature if index reset too large */
      while (tmp_dbl > ((double) MAXIMUM_REANNEAL_INDEX))
	{
	  log_new_temperature_ratio = -*temperature_scale_cost *
	    F_POW (tmp_dbl,
#if QUENCH_COST
		   OPTIONS->User_Quench_Cost_Scale[0]
#else
		   ONE
#endif
		   / (double) *number_parameters);
	  log_new_temperature_ratio =
	    EXPONENT_CHECK (log_new_temperature_ratio);
	  new_temperature = *initial_cost_temperature
	    * F_EXP (log_new_temperature_ratio);
	  tmp_dbl /= (double) REANNEAL_SCALE;
	  temperature_rescale_power = ONE / F_POW ((double) REANNEAL_SCALE,
#if QUENCH_COST
					  OPTIONS->User_Quench_Cost_Scale[0]
#else
						   ONE
#endif
					     / (double) *number_parameters);
	  *initial_cost_temperature = new_temperature * F_POW
	    (*initial_cost_temperature / new_temperature,
	     temperature_rescale_power);
	}
      *index_cost_acceptances = (LONG_INT) tmp_dbl;
#if USER_ACCEPTANCE_TEST
      OPTIONS->Cost_Temp_Init = *initial_cost_temperature;
#endif
    }
}

/***********************************************************************
* cost_derivatives
*	This procedure calculates the derivatives of the cost function
*	with respect to its parameters.  The first derivatives are
*	used as a sensitivity measure for reannealing.  The second
*	derivatives are calculated only if *curvature_flag=TRUE;
*	these are a measure of the covariance of the fit when a
*	minimum is found.
***********************************************************************/
	  /* Calculate the numerical derivatives of the best
	     generated state found so far */

	  /* In this implementation of ASA, no checks are made for
	     *valid_state_generated_flag=FALSE for differential neighbors
	     to the current best state. */

	  /* Assuming no information is given about the metric of the parameter
	     space, use simple Cartesian space to calculate curvatures. */

#if HAVE_ANSI
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)
#else
void
cost_derivatives (user_cost_function,
		  parameter_minimum,
		  parameter_maximum,
		  tangents,
		  curvature,
		  maximum_tangent,
		  number_parameters,
		  parameter_type,
		  exit_status,
		  curvature_flag,
		  valid_state_generated_flag,
		  number_invalid_generated_states,
		  current_generated_state,
		  best_generated_state,
		  ptr_asa_out,
		  OPTIONS)
     double (*user_cost_function) ();
     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;
#endif
{
  ALLOC_INT index_v, index_vv, index_v_vv, index_vv_v;
  LONG_INT saved_num_invalid_gen_states;
#if ASA_PRINT
  LONG_INT tmp_saved;
#endif
  double parameter_v, parameter_vv, parameter_v_offset, parameter_vv_offset;
  double recent_best_cost;
  double new_cost_state_1, new_cost_state_2, new_cost_state_3;
  double delta_parameter_v, delta_parameter_vv;

  if (OPTIONS->Curvature_0 == TRUE)
    *curvature_flag = FALSE;
  if (OPTIONS->Curvature_0 == -1)
    *curvature_flag = TRUE;

  /* save the best cost */
  recent_best_cost = best_generated_state->cost;

  /* copy the best state into the current state */
  VFOR (index_v)
  {
    /* ignore parameters with too small ranges */
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    current_generated_state->parameter[index_v] =
      best_generated_state->parameter[index_v];
  }

  saved_num_invalid_gen_states = (*number_invalid_generated_states);

  /* set parameters (& possibly constraints) to best state */
  *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
  OPTIONS->User_Acceptance_Flag = TRUE;
  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
  current_generated_state->cost =
    user_cost_function (current_generated_state->parameter,
			parameter_minimum,
			parameter_maximum,
			tangents,
			curvature,
			number_parameters,
			parameter_type,
			valid_state_generated_flag,
			exit_status,
			OPTIONS);
  if (*valid_state_generated_flag == FALSE)
    ++(*number_invalid_generated_states);

  if (OPTIONS->User_Tangents == TRUE)
    {
      *valid_state_generated_flag = FALSE;
#if USER_ACCEPTANCE_TEST
      OPTIONS->User_Acceptance_Flag = TRUE;
      OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
      current_generated_state->cost =
	user_cost_function (current_generated_state->parameter,
			    parameter_minimum,
			    parameter_maximum,
			    tangents,
			    curvature,
			    number_parameters,
			    parameter_type,
			    valid_state_generated_flag,
			    exit_status,
			    OPTIONS);
      if (*valid_state_generated_flag == FALSE)
	++(*number_invalid_generated_states);
    }
  else
    {
      /* calculate tangents */
      VFOR (index_v)
      {
	if (NO_REANNEAL (index_v))
	  {
	    tangents[index_v] = ZERO;
	    continue;
	  }
	/* skip parameters with too small range or integer parameters */
	if (OPTIONS->Include_Integer_Parameters == TRUE)
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      {
		tangents[index_v] = ZERO;
		continue;
	      }
	  }
	else
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v) ||
		INTEGER_PARAMETER (index_v))
	      {
		tangents[index_v] = ZERO;
		continue;
	      }
	  }

	/* save the v_th parameter and delta_parameter */
	parameter_v = best_generated_state->parameter[index_v];
#if DELTA_PARAMETERS
	delta_parameter_v = OPTIONS->User_Delta_Parameter[index_v];
#else
	delta_parameter_v = OPTIONS->Delta_X;
#endif

	parameter_v_offset = (ONE + delta_parameter_v) * parameter_v;
	if (parameter_v_offset > parameter_maximum[index_v] ||
	    parameter_v_offset < parameter_minimum[index_v])
	  {
	    delta_parameter_v = -delta_parameter_v;
	    parameter_v_offset = (ONE + delta_parameter_v) * parameter_v;
	  }

	/* generate the first sample point */
	current_generated_state->parameter[index_v] = parameter_v_offset;
	*valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	OPTIONS->User_Acceptance_Flag = TRUE;
	OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	current_generated_state->cost =
	  user_cost_function (current_generated_state->parameter,
			      parameter_minimum,
			      parameter_maximum,
			      tangents,
			      curvature,
			      number_parameters,
			      parameter_type,
			      valid_state_generated_flag,
			      exit_status,
			      OPTIONS);
	if (*valid_state_generated_flag == FALSE)
	  ++(*number_invalid_generated_states);
	new_cost_state_1 = current_generated_state->cost;

	/* restore the parameter state */
	current_generated_state->parameter[index_v] = parameter_v;

	/* calculate the numerical derivative */
	tangents[index_v] = (new_cost_state_1 - recent_best_cost)
	  / (delta_parameter_v * parameter_v + (double) EPS_DOUBLE);

      }
    }

  /* find the maximum |tangent| from all tangents */
  *maximum_tangent = 0;
  VFOR (index_v)
  {
    if (NO_REANNEAL (index_v))
      continue;

    /* ignore too small ranges and integer parameters types */
    if (OPTIONS->Include_Integer_Parameters == TRUE)
      {
	if (PARAMETER_RANGE_TOO_SMALL (index_v))
	  continue;
      }
    else
      {
	if (PARAMETER_RANGE_TOO_SMALL (index_v) ||
	    INTEGER_PARAMETER (index_v))
	  continue;
      }

    /* find the maximum |tangent| (from all tangents) */
    if (fabs (tangents[index_v]) > *maximum_tangent)
      {
	*maximum_tangent = fabs (tangents[index_v]);
      }
  }

  if (*curvature_flag == TRUE || *curvature_flag == -1)
    {
      /* calculate diagonal curvatures */
      VFOR (index_v)
      {
	if (NO_REANNEAL (index_v))
	  {
	    index_v_vv = ROW_COL_INDEX (index_v, index_v);
	    curvature[index_v_vv] = ZERO;
	    continue;
	  }
	/* skip parameters with too small range or integer parameters */
	if (OPTIONS->Include_Integer_Parameters == TRUE)
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v))
	      {
		index_v_vv = ROW_COL_INDEX (index_v, index_v);
		curvature[index_v_vv] = ZERO;
		continue;
	      }
	  }
	else
	  {
	    if (PARAMETER_RANGE_TOO_SMALL (index_v) ||
		INTEGER_PARAMETER (index_v))
	      {
		index_v_vv = ROW_COL_INDEX (index_v, index_v);
		curvature[index_v_vv] = ZERO;
		continue;
	      }
	  }

	/* save the v_th parameter and delta_parameter */
	parameter_v = best_generated_state->parameter[index_v];
#if DELTA_PARAMETERS
	delta_parameter_v = OPTIONS->User_Delta_Parameter[index_v];
#else
	delta_parameter_v = OPTIONS->Delta_X;
#endif

	if (parameter_v + delta_parameter_v * fabs (parameter_v)
	    > parameter_maximum[index_v])
	  {
	    /* generate the first sample point */
	    current_generated_state->parameter[index_v] =
	      parameter_v - TWO * delta_parameter_v * fabs (parameter_v);
	    *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	    OPTIONS->User_Acceptance_Flag = TRUE;
	    OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	    current_generated_state->cost =
	      user_cost_function (current_generated_state->parameter,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  OPTIONS);
	    if (*valid_state_generated_flag == FALSE)
	      ++(*number_invalid_generated_states);
	    new_cost_state_1 = current_generated_state->cost;

	    /* generate the second sample point */
	    current_generated_state->parameter[index_v] =
	      parameter_v - delta_parameter_v * fabs (parameter_v);

	    *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	    OPTIONS->User_Acceptance_Flag = TRUE;
	    OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	    current_generated_state->cost =
	      user_cost_function (current_generated_state->parameter,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  OPTIONS);
	    if (*valid_state_generated_flag == FALSE)
	      ++(*number_invalid_generated_states);
	    new_cost_state_2 = current_generated_state->cost;

	    /* restore the parameter state */
	    current_generated_state->parameter[index_v] =
	      parameter_v;

	    /* index_v_vv: row index_v, column index_v */
	    index_v_vv = ROW_COL_INDEX (index_v, index_v);

	    /* calculate and store the curvature */
	    curvature[index_v_vv] =
	      (recent_best_cost - TWO * new_cost_state_2
	       + new_cost_state_1) / (delta_parameter_v * delta_parameter_v
			 * parameter_v * parameter_v + (double) EPS_DOUBLE);
	  }
	else if (parameter_v - delta_parameter_v * fabs (parameter_v)
		 < parameter_minimum[index_v])
	  {
	    /* generate the first sample point */
	    current_generated_state->parameter[index_v] =
	      parameter_v + TWO * delta_parameter_v * fabs (parameter_v);
	    *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	    OPTIONS->User_Acceptance_Flag = TRUE;
	    OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	    current_generated_state->cost =
	      user_cost_function (current_generated_state->parameter,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  OPTIONS);
	    if (*valid_state_generated_flag == FALSE)
	      ++(*number_invalid_generated_states);
	    new_cost_state_1 = current_generated_state->cost;

	    /* generate the second sample point */
	    current_generated_state->parameter[index_v] =
	      parameter_v + delta_parameter_v * fabs (parameter_v);

	    *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	    OPTIONS->User_Acceptance_Flag = TRUE;
	    OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	    current_generated_state->cost =
	      user_cost_function (current_generated_state->parameter,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  OPTIONS);
	    if (*valid_state_generated_flag == FALSE)
	      ++(*number_invalid_generated_states);
	    new_cost_state_2 = current_generated_state->cost;

	    /* restore the parameter state */
	    current_generated_state->parameter[index_v] =
	      parameter_v;

	    /* index_v_vv: row index_v, column index_v */
	    index_v_vv = ROW_COL_INDEX (index_v, index_v);

	    /* calculate and store the curvature */
	    curvature[index_v_vv] =
	      (recent_best_cost - TWO * new_cost_state_2
	       + new_cost_state_1) / (delta_parameter_v * delta_parameter_v
			 * parameter_v * parameter_v + (double) EPS_DOUBLE);
	  }
	else
	  {
	    /* generate the first sample point */
	    parameter_v_offset = (ONE + delta_parameter_v) * parameter_v;
	    current_generated_state->parameter[index_v] = parameter_v_offset;
	    *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	    OPTIONS->User_Acceptance_Flag = TRUE;
	    OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	    current_generated_state->cost =
	      user_cost_function (current_generated_state->parameter,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  OPTIONS);
	    if (*valid_state_generated_flag == FALSE)
	      ++(*number_invalid_generated_states);
	    new_cost_state_1 = current_generated_state->cost;

	    /* generate the second sample point */
	    current_generated_state->parameter[index_v] =
	      (ONE - delta_parameter_v) * parameter_v;

	    *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	    OPTIONS->User_Acceptance_Flag = TRUE;
	    OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	    current_generated_state->cost =
	      user_cost_function (current_generated_state->parameter,
				  parameter_minimum,
				  parameter_maximum,
				  tangents,
				  curvature,
				  number_parameters,
				  parameter_type,
				  valid_state_generated_flag,
				  exit_status,
				  OPTIONS);
	    if (*valid_state_generated_flag == FALSE)
	      ++(*number_invalid_generated_states);
	    new_cost_state_2 = current_generated_state->cost;

	    /* restore the parameter state */
	    current_generated_state->parameter[index_v] =
	      parameter_v;

	    /* index_v_vv: row index_v, column index_v */
	    index_v_vv = ROW_COL_INDEX (index_v, index_v);

	    /* calculate and store the curvature */
	    curvature[index_v_vv] =
	      (new_cost_state_2 - TWO * recent_best_cost
	       + new_cost_state_1) / (delta_parameter_v * delta_parameter_v
			 * parameter_v * parameter_v + (double) EPS_DOUBLE);
	  }
      }

      /* calculate off-diagonal curvatures */
      VFOR (index_v)
      {
	/* save the v_th parameter and delta_x */
	parameter_v = current_generated_state->parameter[index_v];
#if DELTA_PARAMETERS
	delta_parameter_v = OPTIONS->User_Delta_Parameter[index_v];
#else
	delta_parameter_v = OPTIONS->Delta_X;
#endif

	VFOR (index_vv)
	{
	  /* index_v_vv: row index_v, column index_vv */
	  index_v_vv = ROW_COL_INDEX (index_v, index_vv);
	  index_vv_v = ROW_COL_INDEX (index_vv, index_v);

	  if (NO_REANNEAL (index_vv) || NO_REANNEAL (index_v))
	    {
	      curvature[index_vv_v] = curvature[index_v_vv] = ZERO;
	      continue;
	    }

	  /* calculate only the upper diagonal */
	  if (index_v <= index_vv)
	    continue;

	  /* skip parms with too small range or integer parameters */
	  if (OPTIONS->Include_Integer_Parameters == TRUE)
	    {
	      if (PARAMETER_RANGE_TOO_SMALL (index_v) ||
		  PARAMETER_RANGE_TOO_SMALL (index_vv))
		{
		  curvature[index_vv_v] = curvature[index_v_vv] = ZERO;
		  continue;
		}
	    }
	  else
	    {
	      if (INTEGER_PARAMETER (index_v) ||
		  INTEGER_PARAMETER (index_vv) ||
		  PARAMETER_RANGE_TOO_SMALL (index_v) ||
		  PARAMETER_RANGE_TOO_SMALL (index_vv))
		{
		  curvature[index_vv_v] = curvature[index_v_vv] = ZERO;
		  continue;
		}
	    }
	  /* save the vv_th parameter and delta_parameter */
	  parameter_vv =
	    current_generated_state->parameter[index_vv];
#if DELTA_PARAMETERS
	  delta_parameter_vv = OPTIONS->User_Delta_Parameter[index_vv];
#else
	  delta_parameter_vv = OPTIONS->Delta_X;
#endif

	  /* generate first sample point */
	  parameter_v_offset = current_generated_state->parameter[index_v] =
	    (ONE + delta_parameter_v) * parameter_v;
	  parameter_vv_offset = current_generated_state->parameter[index_vv] =
	    (ONE + delta_parameter_vv) * parameter_vv;
	  if (parameter_v_offset > parameter_maximum[index_v] ||
	      parameter_v_offset < parameter_minimum[index_v])
	    {
	      delta_parameter_v = -delta_parameter_v;
	      current_generated_state->parameter[index_v] =
		(ONE + delta_parameter_v) * parameter_v;
	    }
	  if (parameter_vv_offset > parameter_maximum[index_vv] ||
	      parameter_vv_offset < parameter_minimum[index_vv])
	    {
	      delta_parameter_vv = -delta_parameter_vv;
	      current_generated_state->parameter[index_vv] =
		(ONE + delta_parameter_vv) * parameter_vv;
	    }

	  *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	  OPTIONS->User_Acceptance_Flag = TRUE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	  current_generated_state->cost =
	    user_cost_function (current_generated_state->parameter,
				parameter_minimum,
				parameter_maximum,
				tangents,
				curvature,
				number_parameters,
				parameter_type,
				valid_state_generated_flag,
				exit_status,
				OPTIONS);
	  if (*valid_state_generated_flag == FALSE)
	    ++(*number_invalid_generated_states);
	  new_cost_state_1 = current_generated_state->cost;

	  /* restore the v_th parameter */
	  current_generated_state->parameter[index_v] =
	    parameter_v;

	  /* generate second sample point */
	  *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	  OPTIONS->User_Acceptance_Flag = TRUE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	  current_generated_state->cost =
	    user_cost_function (current_generated_state->parameter,
				parameter_minimum,
				parameter_maximum,
				tangents,
				curvature,
				number_parameters,
				parameter_type,
				valid_state_generated_flag,
				exit_status,
				OPTIONS);
	  if (*valid_state_generated_flag == FALSE)
	    ++(*number_invalid_generated_states);
	  new_cost_state_2 = current_generated_state->cost;

	  /* restore the vv_th parameter */
	  current_generated_state->parameter[index_vv] =
	    parameter_vv;

	  /* generate third sample point */
	  current_generated_state->parameter[index_v] =
	    (ONE + delta_parameter_v) * parameter_v;
	  *valid_state_generated_flag = TRUE;
#if USER_ACCEPTANCE_TEST
	  OPTIONS->User_Acceptance_Flag = TRUE;
	  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
	  current_generated_state->cost =
	    user_cost_function (current_generated_state->parameter,
				parameter_minimum,
				parameter_maximum,
				tangents,
				curvature,
				number_parameters,
				parameter_type,
				valid_state_generated_flag,
				exit_status,
				OPTIONS);
	  if (*valid_state_generated_flag == FALSE)
	    ++(*number_invalid_generated_states);
	  new_cost_state_3 = current_generated_state->cost;

	  /* restore the v_th parameter */
	  current_generated_state->parameter[index_v] =
	    parameter_v;

	  /* calculate and store the curvature */
	  curvature[index_vv_v] = curvature[index_v_vv] =
	    (new_cost_state_1 - new_cost_state_2
	     - new_cost_state_3 + recent_best_cost)
	    / (delta_parameter_v * delta_parameter_vv
	       * parameter_v * parameter_vv
	       + (double) EPS_DOUBLE);
	}
      }
    }
  /* restore the best cost function value */
  current_generated_state->cost = recent_best_cost;
#if ASA_PRINT
  tmp_saved = *number_invalid_generated_states - saved_num_invalid_gen_states;
  if (tmp_saved > 0)
#if INT_LONG
    fprintf (ptr_asa_out,
	  "Generated %ld invalid states when calculating the derivatives\n",
	     tmp_saved);
#else
    fprintf (ptr_asa_out,
	   "Generated %d invalid states when calculating the derivatives\n",
	     tmp_saved);
#endif
#endif /* ASA_PRINT */
  *number_invalid_generated_states = saved_num_invalid_gen_states;
#if USER_ACCEPTANCE_TEST
  OPTIONS->User_Acceptance_Flag = TRUE;
  OPTIONS->Cost_Acceptance_Flag = FALSE;
#endif
}

/***********************************************************************
* test_asa_options
*       Tests user's selected options
***********************************************************************/
#if HAVE_ANSI
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)
#else
int
test_asa_options (seed,
		  parameter_initial_final,
		  parameter_minimum,
		  parameter_maximum,
		  tangents,
		  curvature,
		  number_parameters,
		  parameter_type,
		  valid_state_generated_flag,
		  exit_status,
		  ptr_asa_out,
		  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;
#endif /* HAVE_ANSI */
{
  int invalid, index_v;

  invalid = 0;

  if (seed == NULL)
    {
      print_string (ptr_asa_out, "*** seed == NULL ***");
      ++invalid;
    }
  if (parameter_initial_final == NULL)
    {
      print_string (ptr_asa_out, "*** parameter_initial_final == NULL ***");
      ++invalid;
    }
  if (parameter_minimum == NULL)
    {
      print_string (ptr_asa_out, "*** parameter_minimum == NULL ***");
      ++invalid;
    }
  if (parameter_maximum == NULL)
    {
      print_string (ptr_asa_out, "*** parameter_maximum == NULL ***");
      ++invalid;
    }
  if (tangents == NULL)
    {
      print_string (ptr_asa_out, "*** tangents == NULL ***");
      ++invalid;
    }
  if (OPTIONS->Curvature_0 == FALSE || OPTIONS->Curvature_0 == -1)
    {
      if (curvature == NULL)
	{
	  print_string (ptr_asa_out, "*** curvature == NULL ***");
	  ++invalid;
	}
    }
  if (number_parameters == NULL)
    {
      print_string (ptr_asa_out, "*** number_parameters == NULL ***");
      ++invalid;
    }
  if (parameter_type == NULL)
    {
      print_string (ptr_asa_out, "*** parameter_type == NULL ***");
      ++invalid;
    }
  if (valid_state_generated_flag == NULL)
    {
      print_string (ptr_asa_out, "*** valid_state_generated_flag == NULL ***");
      ++invalid;
    }
  if (exit_status == NULL)
    {
      print_string (ptr_asa_out, "*** exit_status == NULL ***");
      ++invalid;
    }
  if (OPTIONS == NULL)
    {
      print_string (ptr_asa_out, "*** OPTIONS == NULL ***");
      ++invalid;
    }

  VFOR (index_v)
    if (parameter_minimum[index_v] > parameter_maximum[index_v])
    {
      print_string_index (ptr_asa_out, "*** parameter_minimum[] > parameter_maximum[] ***", index_v);
      ++invalid;
    }
  VFOR (index_v)
    if (parameter_initial_final[index_v] < parameter_minimum[index_v])
    {
      print_string_index (ptr_asa_out, "*** parameter_initial[] < parameter_minimum[] ***", index_v);
      ++invalid;
    }
  VFOR (index_v)
    if (parameter_initial_final[index_v] > parameter_maximum[index_v])
    {
      print_string_index (ptr_asa_out, "*** parameter_initial[] > parameter_maximum[] ***", index_v);
      ++invalid;
    }
  if (*number_parameters < 1)
    {
      print_string (ptr_asa_out, "*** *number_parameters < 1 ***");
      ++invalid;
    }
  VFOR (index_v)
    if (parameter_type[index_v] != -2 && parameter_type[index_v] != 2 && parameter_type[index_v] != -1 && parameter_type[index_v] != 1)
    {
      print_string_index (ptr_asa_out, "*** parameter_type[] != -2 && parameter_type[] != 2 && parameter_type[] != -1 && parameter_type[] != 1 ***", index_v);
      ++invalid;
    }

  if (OPTIONS_FILE != FALSE && OPTIONS_FILE != TRUE)
    {
      print_string (ptr_asa_out, "*** OPTIONS_FILE != FALSE && OPTIONS_FILE != TRUE ***");
      ++invalid;
    }
  if (OPTIONS_FILE_DATA != FALSE && OPTIONS_FILE_DATA != TRUE)
    {
      print_string (ptr_asa_out, "*** OPTIONS_FILE_DATA != FALSE && OPTIONS_FILE_DATA != TRUE ***");
      ++invalid;
    }
  if (RECUR_OPTIONS_FILE != FALSE && RECUR_OPTIONS_FILE != TRUE)
    {
      print_string (ptr_asa_out, "*** RECUR_OPTIONS_FILE != FALSE && RECUR_OPTIONS_FILE != TRUE ***");
      ++invalid;
    }
  if (RECUR_OPTIONS_FILE_DATA != FALSE && RECUR_OPTIONS_FILE_DATA != TRUE)
    {
      print_string (ptr_asa_out, "*** RECUR_OPTIONS_FILE_DATA != FALSE && RECUR_OPTIONS_FILE_DATA != TRUE ***");
      ++invalid;
    }
  if (COST_FILE != FALSE && COST_FILE != TRUE)
    {
      print_string (ptr_asa_out, "*** COST_FILE != FALSE && COST_FILE != TRUE ***");
      ++invalid;
    }
  if (ASA_LIB != FALSE && ASA_LIB != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_LIB != FALSE && ASA_LIB != TRUE ***");
      ++invalid;
    }
  if (MY_TEMPLATE != FALSE && MY_TEMPLATE != TRUE)
    {
      print_string (ptr_asa_out, "*** MY_TEMPLATE != FALSE && MY_TEMPLATE != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_LIB != FALSE && ASA_TEMPLATE_LIB != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_LIB != FALSE && ASA_TEMPLATE_LIB != TRUE ***");
      ++invalid;
    }
  if (HAVE_ANSI != FALSE && HAVE_ANSI != TRUE)
    {
      print_string (ptr_asa_out, "*** HAVE_ANSI != FALSE && HAVE_ANSI != TRUE ***");
      ++invalid;
    }
  if (IO_PROTOTYPES != FALSE && IO_PROTOTYPES != TRUE)
    {
      print_string (ptr_asa_out, "*** IO_PROTOTYPES != FALSE && IO_PROTOTYPES != TRUE ***");
      ++invalid;
    }
  if (TIME_CALC != FALSE && TIME_CALC != TRUE)
    {
      print_string (ptr_asa_out, "*** TIME_CALC != FALSE && TIME_CALC != TRUE ***");
      ++invalid;
    }
  if (TIME_STD != FALSE && TIME_STD != TRUE)
    {
      print_string (ptr_asa_out, "*** TIME_STD != FALSE && TIME_STD != TRUE ***");
      ++invalid;
    }
  if (INT_LONG != FALSE && INT_LONG != TRUE)
    {
      print_string (ptr_asa_out, "*** INT_LONG != FALSE && INT_LONG != TRUE ***");
      ++invalid;
    }
  if (INT_ALLOC != FALSE && INT_ALLOC != TRUE)
    {
      print_string (ptr_asa_out, "*** INT_ALLOC != FALSE && INT_ALLOC != TRUE ***");
      ++invalid;
    }
  if (SMALL_FLOAT < ZERO)
    {
      print_string (ptr_asa_out, "*** SMALL_FLOAT < ZERO ***");
      ++invalid;
    }
  if (MIN_DOUBLE < ZERO)
    {
      print_string (ptr_asa_out, "*** MIN_DOUBLE < ZERO ***");
      ++invalid;
    }
  if (MAX_DOUBLE < ZERO)
    {
      print_string (ptr_asa_out, "*** MAX_DOUBLE < ZERO ***");
      ++invalid;
    }
  if (EPS_DOUBLE < ZERO)
    {
      print_string (ptr_asa_out, "*** EPS_DOUBLE < ZERO ***");
      ++invalid;
    }
  if (CHECK_EXPONENT != FALSE && CHECK_EXPONENT != TRUE)
    {
      print_string (ptr_asa_out, "*** CHECK_EXPONENT != FALSE && CHECK_EXPONENT != TRUE ***");
      ++invalid;
    }
  if (NO_PARAM_TEMP_TEST != FALSE && NO_PARAM_TEMP_TEST != TRUE)
    {
      print_string (ptr_asa_out, "*** NO_PARAM_TEMP_TEST != FALSE && NO_PARAM_TEMP_TEST != TRUE ***");
      ++invalid;
    }
  if (NO_COST_TEMP_TEST != FALSE && NO_COST_TEMP_TEST != TRUE)
    {
      print_string (ptr_asa_out, "*** NO_COST_TEMP_TEST != FALSE && NO_COST_TEMP_TEST != TRUE ***");
      ++invalid;
    }
  if (SELF_OPTIMIZE != FALSE && SELF_OPTIMIZE != TRUE)
    {
      print_string (ptr_asa_out, "*** SELF_OPTIMIZE != FALSE && SELF_OPTIMIZE != TRUE ***");
      ++invalid;
    }
  if (ASA_TEST != FALSE && ASA_TEST != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEST != FALSE && ASA_TEST != TRUE ***");
      ++invalid;
    }
  if (ASA_TEST_POINT != FALSE && ASA_TEST_POINT != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEST_POINT != FALSE && ASA_TEST_POINT != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE != FALSE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE != FALSE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_ASA_OUT_PID != FALSE && ASA_TEMPLATE_ASA_OUT_PID != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_ASA_OUT_PID != FALSE && ASA_TEMPLATE_ASA_OUT_PID != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_MULTIPLE != FALSE && ASA_TEMPLATE_MULTIPLE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_MULTIPLE != FALSE && ASA_TEMPLATE_MULTIPLE != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_SELFOPT != FALSE && ASA_TEMPLATE_SELFOPT != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_SELFOPT != FALSE && ASA_TEMPLATE_SELFOPT != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_SAMPLE != FALSE && ASA_TEMPLATE_SAMPLE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_SAMPLE != FALSE && ASA_TEMPLATE_SAMPLE != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_QUEUE != FALSE && ASA_TEMPLATE_QUEUE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_QUEUE != FALSE && ASA_TEMPLATE_QUEUE != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_PARALLEL != FALSE && ASA_TEMPLATE_PARALLEL != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_PARALLEL != FALSE && ASA_TEMPLATE_PARALLEL != TRUE ***");
      ++invalid;
    }
  if (ASA_TEMPLATE_SAVE != FALSE && ASA_TEMPLATE_SAVE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_TEMPLATE_SAVE != FALSE && ASA_TEMPLATE_SAVE != TRUE ***");
      ++invalid;
    }
  if (USER_INITIAL_COST_TEMP != FALSE && USER_INITIAL_COST_TEMP != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_INITIAL_COST_TEMP != FALSE && USER_INITIAL_COST_TEMP != TRUE ***");
      ++invalid;
    }
  if (RATIO_TEMPERATURE_SCALES != FALSE && RATIO_TEMPERATURE_SCALES != TRUE)
    {
      print_string (ptr_asa_out, "*** RATIO_TEMPERATURE_SCALES != FALSE && RATIO_TEMPERATURE_SCALES != TRUE ***");
      ++invalid;
    }
  if (USER_INITIAL_PARAMETERS_TEMPS != FALSE && USER_INITIAL_PARAMETERS_TEMPS != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_INITIAL_PARAMETERS_TEMPS != FALSE && USER_INITIAL_PARAMETERS_TEMPS != TRUE ***");
      ++invalid;
    }
  if (DELTA_PARAMETERS != FALSE && DELTA_PARAMETERS != TRUE)
    {
      print_string (ptr_asa_out, "*** DELTA_PARAMETERS != FALSE && DELTA_PARAMETERS != TRUE ***");
      ++invalid;
    }
  if (QUENCH_PARAMETERS != FALSE && QUENCH_PARAMETERS != TRUE)
    {
      print_string (ptr_asa_out, "*** QUENCH_PARAMETERS != FALSE && QUENCH_PARAMETERS != TRUE ***");
      ++invalid;
    }
  if (QUENCH_COST != FALSE && QUENCH_COST != TRUE)
    {
      print_string (ptr_asa_out, "*** QUENCH_COST != FALSE && QUENCH_COST != TRUE ***");
      ++invalid;
    }
  if (QUENCH_PARAMETERS_SCALE != FALSE && QUENCH_PARAMETERS_SCALE != TRUE)
    {
      print_string (ptr_asa_out, "*** QUENCH_PARAMETERS_SCALE != FALSE && QUENCH_PARAMETERS_SCALE != TRUE ***");
      ++invalid;
    }
  if (QUENCH_COST_SCALE != FALSE && QUENCH_COST_SCALE != TRUE)
    {
      print_string (ptr_asa_out, "*** QUENCH_COST_SCALE != FALSE && QUENCH_COST_SCALE != TRUE ***");
      ++invalid;
    }
  if (OPTIONAL_DATA != FALSE && OPTIONAL_DATA != TRUE)
    {
      print_string (ptr_asa_out, "*** OPTIONAL_DATA != FALSE && OPTIONAL_DATA != TRUE ***");
      ++invalid;
    }
  if (OPTIONAL_DATA_INT != FALSE && OPTIONAL_DATA_INT != TRUE)
    {
      print_string (ptr_asa_out, "*** OPTIONAL_DATA_INT != FALSE && OPTIONAL_DATA_INT != TRUE ***");
      ++invalid;
    }
  if (USER_COST_SCHEDULE != FALSE && USER_COST_SCHEDULE != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_COST_SCHEDULE != FALSE && USER_COST_SCHEDULE != TRUE ***");
      ++invalid;
    }
  if (USER_ACCEPT_ASYMP_EXP != FALSE && USER_ACCEPT_ASYMP_EXP != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_ACCEPT_ASYMP_EXP != FALSE && USER_ACCEPT_ASYMP_EXP != TRUE ***");
      ++invalid;
    }
  if (USER_ACCEPTANCE_TEST != FALSE && USER_ACCEPTANCE_TEST != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_ACCEPTANCE_TEST != FALSE && USER_ACCEPTANCE_TEST != TRUE ***");
      ++invalid;
    }
  if (USER_GENERATING_FUNCTION != FALSE && USER_GENERATING_FUNCTION != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_GENERATING_FUNCTION != FALSE && USER_GENERATING_FUNCTION != TRUE ***");
      ++invalid;
    }
  if (USER_REANNEAL_COST != FALSE && USER_REANNEAL_COST != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_REANNEAL_COST != FALSE && USER_REANNEAL_COST != TRUE ***");
      ++invalid;
    }
  if (USER_REANNEAL_PARAMETERS != FALSE && USER_REANNEAL_PARAMETERS != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_REANNEAL_PARAMETERS != FALSE && USER_REANNEAL_PARAMETERS != TRUE ***");
      ++invalid;
    }
  if (MAXIMUM_REANNEAL_INDEX < 1)
    {
      print_string (ptr_asa_out, "*** MAXIMUM_REANNEAL_INDEX < 1 ***");
      ++invalid;
    }
  if (REANNEAL_SCALE < ZERO)
    {
      print_string (ptr_asa_out, "*** REANNEAL_SCALE < ZERO ***");
      ++invalid;
    }
  if (ASA_SAMPLE != FALSE && ASA_SAMPLE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_SAMPLE != FALSE && ASA_SAMPLE != TRUE ***");
      ++invalid;
    }
  if (ASA_QUEUE != FALSE && ASA_QUEUE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_QUEUE != FALSE && ASA_QUEUE != TRUE ***");
      ++invalid;
    }
  if (ASA_RESOLUTION != FALSE && ASA_RESOLUTION != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_RESOLUTION != FALSE && ASA_RESOLUTION != TRUE ***");
      ++invalid;
    }
  if (ASA_PARALLEL != FALSE && ASA_PARALLEL != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_PARALLEL != FALSE && ASA_PARALLEL != TRUE ***");
      ++invalid;
    }
  if (ASA_SAVE != FALSE && ASA_SAVE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_SAVE != FALSE && ASA_SAVE != TRUE ***");
      ++invalid;
    }
  if (SYSTEM_CALL != FALSE && SYSTEM_CALL != TRUE)
    {
      print_string (ptr_asa_out, "*** SYSTEM_CALL != FALSE && SYSTEM_CALL != TRUE ***");
      ++invalid;
    }
  if (FDLIBM_POW != FALSE && FDLIBM_POW != TRUE)
    {
      print_string (ptr_asa_out, "*** FDLIBM_POW != FALSE && FDLIBM_POW != TRUE ***");
      ++invalid;
    }
  if (FDLIBM_LOG != FALSE && FDLIBM_LOG != TRUE)
    {
      print_string (ptr_asa_out, "*** FDLIBM_LOG != FALSE && FDLIBM_LOG != TRUE ***");
      ++invalid;
    }
  if (FDLIBM_EXP != FALSE && FDLIBM_EXP != TRUE)
    {
      print_string (ptr_asa_out, "*** FDLIBM_EXP != FALSE && FDLIBM_EXP != TRUE ***");
      ++invalid;
    }
  if (ASA_PRINT != FALSE && ASA_PRINT != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_PRINT != FALSE && ASA_PRINT != TRUE ***");
      ++invalid;
    }
  if (USER_ASA_OUT != FALSE && USER_ASA_OUT != TRUE)
    {
      print_string (ptr_asa_out, "*** USER_ASA_OUT != FALSE && USER_ASA_OUT != TRUE ***");
      ++invalid;
    }
  if (ASA_PRINT_INTERMED != FALSE && ASA_PRINT_INTERMED != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_PRINT_INTERMED != FALSE && ASA_PRINT_INTERMED != TRUE ***");
      ++invalid;
    }
  if (ASA_PRINT_MORE != FALSE && ASA_PRINT_MORE != TRUE)
    {
      print_string (ptr_asa_out, "*** ASA_PRINT_MORE != FALSE && ASA_PRINT_MORE != TRUE ***");
      ++invalid;
    }
  if (G_FIELD < 0)
    {
      print_string (ptr_asa_out, "*** G_FIELD < 0 ***");
      ++invalid;
    }
  if (G_PRECISION < 0)
    {
      print_string (ptr_asa_out, "*** G_PRECISION < 0 ***");
      ++invalid;
    }

  if (OPTIONS->Limit_Acceptances < 0)
    {
      print_string (ptr_asa_out, "*** Limit_Acceptances < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Limit_Generated < 0)
    {
      print_string (ptr_asa_out, "*** Limit_Generated < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Limit_Invalid_Generated_States < 0)
    {
      print_string (ptr_asa_out, "*** Limit_Invalid_Generated_States < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Accepted_To_Generated_Ratio <= ZERO)
    {
      print_string (ptr_asa_out, "*** Accepted_To_Generated_Ratio <= ZERO ***");
      ++invalid;
    }
  if (OPTIONS->Cost_Precision <= ZERO)
    {
      print_string (ptr_asa_out, "*** Cost_Precision <= ZERO ***");
      ++invalid;
    }
  if (OPTIONS->Maximum_Cost_Repeat < 0)
    {
      print_string (ptr_asa_out, "*** Maximum_Cost_Repeat < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Number_Cost_Samples == 0 || OPTIONS->Number_Cost_Samples == -1)
    {
      print_string (ptr_asa_out, "*** Number_Cost_Samples == 0 || Number_Cost_Samples == -1 ***");
      ++invalid;
    }
  if (OPTIONS->Temperature_Ratio_Scale <= ZERO)
    {
      print_string (ptr_asa_out, "*** Temperature_Ratio_Scale <= ZERO ***");
      ++invalid;
    }
  if (OPTIONS->Cost_Parameter_Scale_Ratio <= ZERO)
    {
      print_string (ptr_asa_out, "*** Cost_Parameter_Scale_Ratio <= ZERO ***");
      ++invalid;
    }
  if (OPTIONS->Temperature_Anneal_Scale <= ZERO)
    {
      print_string (ptr_asa_out, "*** Temperature_Anneal_Scale <= ZERO ***");
      ++invalid;
    }
#if USER_INITIAL_COST_TEMP
  if (OPTIONS->User_Cost_Temperature[0] <= ZERO)
    {
      print_string (ptr_asa_out, "*** User_Cost_Temperature[0] <= ZERO ***");
      ++invalid;
    }
#endif
  if (OPTIONS->Include_Integer_Parameters != FALSE && OPTIONS->Include_Integer_Parameters != TRUE)
    {
      print_string (ptr_asa_out, "");
      ++invalid;
    }
  if (OPTIONS->User_Initial_Parameters != FALSE && OPTIONS->User_Initial_Parameters != TRUE)
    {
      print_string (ptr_asa_out, "*** User_Initial_Parameters != FALSE && User_Initial_Parameters != TRUE ***");
      ++invalid;
    }
  if (OPTIONS->Sequential_Parameters >= *number_parameters)
    {
      print_string (ptr_asa_out, "*** Sequential_Parameters >= *number_parameters ***");
      ++invalid;
    }
  if (OPTIONS->Initial_Parameter_Temperature <= ZERO)
    {
      print_string (ptr_asa_out, "*** Initial_Parameter_Temperature <= ZERO ***");
      ++invalid;
    }
#if RATIO_TEMPERATURE_SCALES
  VFOR (index_v)
    if (OPTIONS->User_Temperature_Ratio[index_v] <= ZERO)
    {
      print_string_index (ptr_asa_out, "*** User_Temperature_Ratio[] <= ZERO ***", index_v);
      ++invalid;
    }
#endif
#if USER_INITIAL_PARAMETERS_TEMPS
  VFOR (index_v)
    if (OPTIONS->User_Parameter_Temperature[index_v] <= ZERO)
    {
      print_string_index (ptr_asa_out, "*** User_Parameter_Temperature[] <= ZERO ***", index_v);
      ++invalid;
    }
#endif
  if (OPTIONS->Acceptance_Frequency_Modulus < 0)
    {
      print_string (ptr_asa_out, "*** Acceptance_Frequency_Modulus < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Generated_Frequency_Modulus < 0)
    {
      print_string (ptr_asa_out, "*** Generated_Frequency_Modulus < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Reanneal_Cost == -1)
    {
      print_string (ptr_asa_out, "*** Reanneal_Cost == -1 ***");
      ++invalid;
    }
  if (OPTIONS->Reanneal_Parameters != FALSE && OPTIONS->Reanneal_Parameters != TRUE)
    {
      print_string (ptr_asa_out, "*** Reanneal_Parameters != FALSE && Reanneal_Parameters != TRUE ***");
      ++invalid;
    }
  if (OPTIONS->Delta_X <= ZERO)
    {
      print_string (ptr_asa_out, "*** Delta_X <= ZERO ***");
      ++invalid;
    }
#if DELTA_PARAMETERS
  VFOR (index_v)
    if (OPTIONS->User_Delta_Parameter[index_v] <= ZERO)
    {
      print_string_index (ptr_asa_out, "*** User_Delta_Parameter[] <= ZERO ***", index_v);
      ++invalid;
    }
#endif
  if (OPTIONS->User_Tangents != FALSE && OPTIONS->User_Tangents != TRUE)
    {
      print_string (ptr_asa_out, "*** User_Tangents != FALSE && User_Tangents != TRUE ***");
      ++invalid;
    }
  if (OPTIONS->Curvature_0 - 1 && OPTIONS->Curvature_0 != FALSE && OPTIONS->Curvature_0 != TRUE)
    {
      print_string (ptr_asa_out, "*** Curvature_0 -1 && Curvature_0 != FALSE && Curvature_0 != TRUE ***");
      ++invalid;
    }
#if QUENCH_PARAMETERS
  VFOR (index_v)
    if (OPTIONS->User_Quench_Param_Scale[index_v] <= ZERO)
    {
      print_string_index (ptr_asa_out, "*** User_Quench_Param_Scale[] <= ZERO ***", index_v);
      ++invalid;
    }
#endif
#if QUENCH_COST
  if (OPTIONS->User_Quench_Cost_Scale[0] <= ZERO)
    {
      print_string (ptr_asa_out, "*** User_Quench_Cost_Scale[0] <= ZERO ***");
      ++invalid;
    }
#endif
#if OPTIONAL_DATA
  if (OPTIONS->Asa_Data_Dim < 1)
    {
      print_string (ptr_asa_out, "*** Asa_Data_Dim < 1 ***");
      ++invalid;
    }
  if (OPTIONS->Asa_Data == NULL)
    {
      print_string (ptr_asa_out, "*** Asa_Data == NULL ***");
      ++invalid;
    }
#endif
#if OPTIONAL_DATA_INT
  if (OPTIONS->Asa_Data_Dim_Int < 1)
    {
      print_string (ptr_asa_out, "*** Asa_Data_Dim_Int < 1 ***");
      ++invalid;
    }
  if (OPTIONS->Asa_Data_Int == NULL)
    {
      print_string (ptr_asa_out, "*** Asa_Data_Int == NULL ***");
      ++invalid;
    }
#endif
#if USER_ASA_OUT
  if (OPTIONS->Asa_Out_File == NULL)
    {
      print_string (ptr_asa_out, "*** Asa_Out_File == NULL ***");
      ++invalid;
    }
#endif
#if USER_COST_SCHEDULE
  if (OPTIONS->Cost_Schedule == NULL)
    {
      print_string (ptr_asa_out, "*** Cost_Schedule == NULL ***");
      ++invalid;
    }
#endif
#if USER_ACCEPTANCE_TEST
  if (OPTIONS->Acceptance_Test == NULL)
    {
      print_string (ptr_asa_out, "*** Acceptance_Test == NULL ***");
      ++invalid;
    }
  if (OPTIONS->User_Acceptance_Flag != FALSE && OPTIONS->User_Acceptance_Flag != TRUE)
    {
      print_string (ptr_asa_out, "*** User_Acceptance_Flag != FALSE && User_Acceptance_Flag != TRUE ***");
      ++invalid;
    }
  if (OPTIONS->Cost_Acceptance_Flag != FALSE && OPTIONS->Cost_Acceptance_Flag != TRUE)
    {
      print_string (ptr_asa_out, "*** Cost_Acceptance_Flag != FALSE && Cost_Acceptance_Flag != TRUE ***");
      ++invalid;
    }
#endif
#if USER_GENERATING_FUNCTION
  if (OPTIONS->Generating_Distrib == NULL)
    {
      print_string (ptr_asa_out, "*** Generating_Distrib == NULL ***");
      ++invalid;
    }
#endif
#if USER_REANNEAL_COST
  if (OPTIONS->Reanneal_Cost_Function == NULL)
    {
      print_string (ptr_asa_out, "*** Reanneal_Cost_Function == NULL ***");
      ++invalid;
    }
#endif
#if USER_REANNEAL_PARAMETERS
  if (OPTIONS->Reanneal_Params_Function == NULL)
    {
      print_string (ptr_asa_out, "*** Reanneal_Params_Function == NULL ***");
      ++invalid;
    }
#endif
#if ASA_SAMPLE
  if (OPTIONS->Bias_Generated == NULL)
    {
      print_string (ptr_asa_out, "*** Bias_Generated == NULL ***");
      ++invalid;
    }
  if (OPTIONS->Limit_Weights < ZERO)
    {
      print_string (ptr_asa_out, "*** Limit_Weights < ZERO ***");
      ++invalid;
    }
#endif
#if ASA_QUEUE
  if (OPTIONS->Queue_Size < 0)
    {
      print_string (ptr_asa_out, "*** Queue_Size < 0 ***");
      ++invalid;
    }
  if (OPTIONS->Queue_Size > 0)
    {
      if (OPTIONS->Queue_Resolution == NULL)
	{
	  print_string (ptr_asa_out, "*** Queue_Resolution == NULL ***");
	  ++invalid;
	}
    }
#endif
#if ASA_RESOLUTION
  if (OPTIONS->Coarse_Resolution == NULL)
    {
      print_string (ptr_asa_out, "*** Coarse_Resolution == NULL ***");
      ++invalid;
    }
#endif
#if ASA_PARALLEL
  if (OPTIONS->Gener_Block < 1)
    {
      print_string (ptr_asa_out, "*** Gener_Block < 1 ***");
      ++invalid;
    }
  if (OPTIONS->Gener_Block_Max < 1)
    {
      print_string (ptr_asa_out, "*** Gener_Block_Max < 1 ***");
      ++invalid;
    }
  if (OPTIONS->Gener_Mov_Avr < 1)
    {
      print_string (ptr_asa_out, "*** Gener_Mov_Avr < 1 ***");
      ++invalid;
    }
#endif

  return (invalid);
}

/***********************************************************************
* print_string
*	This prints the designated string
***********************************************************************/
#if HAVE_ANSI
void
print_string (FILE * ptr_asa_out, char *string)
#else
void
print_string (ptr_asa_out, string)
     FILE *ptr_asa_out;
     char *string;
#endif /* HAVE_ANSI */
{
#if ASA_PRINT
  fprintf (ptr_asa_out, "%s\n", string);
#else
  ;
#endif
}

/***********************************************************************
* print_string_index
*	This prints the designated string and index
***********************************************************************/
#if HAVE_ANSI
void
print_string_index (FILE * ptr_asa_out, char *string, ALLOC_INT index)
#else
void
print_string_index (ptr_asa_out, string, index)
     FILE *ptr_asa_out;
     char *string;
     ALLOC_INT index;
#endif /* HAVE_ANSI */
{
#if ASA_PRINT
#if INT_ALLOC
  fprintf (ptr_asa_out, "%s index = %d\n", string, index);
#else
#if INT_LONG
  fprintf (ptr_asa_out, "%s index = %ld\n", string, index);
#else
  fprintf (ptr_asa_out, "%s index = %d\n", string, index);
#endif
#endif
#else
  ;
#endif
}

#if ASA_PRINT
/***********************************************************************
* print_state
*	Prints a description of the current state of the system
***********************************************************************/
#if HAVE_ANSI
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)
#else
void
print_state (parameter_minimum,
	     parameter_maximum,
	     tangents,
	     curvature,
	     current_cost_temperature,
	     current_user_parameter_temp,
	     accepted_to_generated_ratio,
	     number_parameters,
	     curvature_flag,
	     number_accepted,
	     index_cost_acceptances,
	     number_generated,
	     number_invalid_generated_states,
	     last_saved_state,
	     best_generated_state,
	     ptr_asa_out,
	     OPTIONS)
     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;
#endif /* HAVE_ANSI */
{
  ALLOC_INT index_v;
  ALLOC_INT index_vv, index_v_vv;

  fprintf (ptr_asa_out, "\n");
#if TIME_CALC
  print_time ("", ptr_asa_out);
#endif

  if (OPTIONS->Curvature_0 == TRUE)
    *curvature_flag = FALSE;
  if (OPTIONS->Curvature_0 == -1)
    *curvature_flag = TRUE;

#if INT_LONG
  fprintf (ptr_asa_out,
       "*index_cost_acceptances = %ld, *current_cost_temperature = %*.*g\n",
	   *index_cost_acceptances,
	   G_FIELD, G_PRECISION, *current_cost_temperature);
  fprintf (ptr_asa_out,
	   "*accepted_to_generated_ratio = %*.*g,\
 *number_invalid... = %ld\n",
	   G_FIELD, G_PRECISION, *accepted_to_generated_ratio,
	   (*number_invalid_generated_states));
  fprintf (ptr_asa_out,
	   "*number_generated = %ld, *number_accepted = %ld\n",
	   *number_generated, *number_accepted);
#else
  fprintf (ptr_asa_out,
	"*index_cost_acceptances = %d, *current_cost_temperature = %*.*g\n",
	   *index_cost_acceptances,
	   G_FIELD, G_PRECISION, *current_cost_temperature);
  fprintf (ptr_asa_out,
	   "*accepted_to_generated_ratio = %*.*g,\
 *number_invalid... = %d\n",
	   G_FIELD, G_PRECISION, *accepted_to_generated_ratio,
	   *number_invalid_generated_states);
  fprintf (ptr_asa_out,
	   "*number_generated = %d, *number_accepted = %d\n",
	   *number_generated, *number_accepted);
#endif

  fprintf (ptr_asa_out,
	   "best...->cost = %*.*g,\
 last...->cost = %*.*g\n",
	   G_FIELD, G_PRECISION, best_generated_state->cost,
	   G_FIELD, G_PRECISION, last_saved_state->cost);

  /* Note that tangents will not be calculated until reanneal
     is called, and therefore their listing in the printout only
     is relevant then */

  fprintf (ptr_asa_out, "index_v  best...->parameter current_parameter_temp\ttangent\n");
  VFOR (index_v)
  {
    /* ignore too small ranges */
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    fprintf (ptr_asa_out,
#if INT_ALLOC
	     "%d\t%*.*g\t\t%*.*g\t%*.*g\n",
#else
#if INT_LONG
	     "%ld\t%*.*g\t\t%*.*g\t%*.*g\n",
#else
	     "%d\t%*.*g\t\t%*.*g\t%*.*g\n",
#endif
#endif
	     index_v,
	     G_FIELD, G_PRECISION, best_generated_state->parameter[index_v],
	     G_FIELD, G_PRECISION, current_user_parameter_temp[index_v],
	     G_FIELD, G_PRECISION, tangents[index_v]);
  }

  if (*curvature_flag == TRUE)
    {
      /* print curvatures */
      VFOR (index_v)
      {
	/* ignore too small ranges */
	if (PARAMETER_RANGE_TOO_SMALL (index_v))
	  continue;
	fprintf (ptr_asa_out, "\n");
	VFOR (index_vv)
	{
	  /* only print upper diagonal of matrix */
	  if (index_v < index_vv)
	    continue;
	  /* ignore too small ranges (index_vv) */
	  if (PARAMETER_RANGE_TOO_SMALL (index_vv))
	    continue;

	  /* index_v_vv: row index_v, column index_vv */
	  index_v_vv = ROW_COL_INDEX (index_v, index_vv);

	  if (index_v == index_vv)
	    {
	      fprintf (ptr_asa_out,
#if INT_ALLOC
		       "curvature[%d][%d] = %*.*g\n",
#else
#if INT_LONG
		       "curvature[%ld][%ld] = %*.*g\n",
#else
		       "curvature[%d][%d] = %*.*g\n",
#endif
#endif
		       index_v, index_vv,
		       G_FIELD, G_PRECISION, curvature[index_v_vv]);
	    }
	  else
	    {
	      fprintf (ptr_asa_out,
#if INT_ALLOC
		       "curvature[%d][%d] = %*.*g \t = curvature[%d][%d]\n",
#else
#if INT_LONG
		   "curvature[%ld][%ld] = %*.*g \t = curvature[%ld][%ld]\n",
#else
		       "curvature[%d][%d] = %*.*g \t = curvature[%d][%d]\n",
#endif
#endif
		       index_v, index_vv,
		       G_FIELD, G_PRECISION, curvature[index_v_vv],
		       index_vv, index_v);
	    }
	}
      }
    }
  fprintf (ptr_asa_out, "\n");
  fflush (ptr_asa_out);

}

/***********************************************************************
* print_asa_options
*	Prints user's selected options
***********************************************************************/
#if HAVE_ANSI
void
print_asa_options (FILE * ptr_asa_out, USER_DEFINES * OPTIONS)
#else
void
print_asa_options (ptr_asa_out, OPTIONS)
     FILE *ptr_asa_out;
     USER_DEFINES *OPTIONS;
#endif /* HAVE_ANSI */
{
  fprintf (ptr_asa_out,
	   "\t\tADAPTIVE SIMULATED ANNEALING\n\n");

  fprintf (ptr_asa_out, "%s\n\n", ASA_ID);

  fprintf (ptr_asa_out, "OPTIONS_FILE = %d\n",
	   (int) OPTIONS_FILE);
  fprintf (ptr_asa_out, "OPTIONS_FILE_DATA = %d\n",
	   (int) OPTIONS_FILE_DATA);
  fprintf (ptr_asa_out, "RECUR_OPTIONS_FILE = %d\n",
	   (int) RECUR_OPTIONS_FILE);
  fprintf (ptr_asa_out, "RECUR_OPTIONS_FILE_DATA = %d\n",
	   (int) RECUR_OPTIONS_FILE_DATA);
  fprintf (ptr_asa_out, "COST_FILE = %d\n",
	   (int) COST_FILE);
  fprintf (ptr_asa_out, "ASA_LIB = %d\n",
	   (int) ASA_LIB);
  fprintf (ptr_asa_out, "HAVE_ANSI = %d\n",
	   (int) HAVE_ANSI);
  fprintf (ptr_asa_out, "IO_PROTOTYPES = %d\n",
	   (int) IO_PROTOTYPES);
  fprintf (ptr_asa_out, "TIME_CALC = %d\n",
	   (int) TIME_CALC);
  fprintf (ptr_asa_out, "TIME_STD = %d\n",
	   (int) TIME_STD);
  fprintf (ptr_asa_out, "INT_LONG = %d\n",
	   (int) INT_LONG);
  fprintf (ptr_asa_out, "INT_ALLOC = %d\n",
	   (int) INT_ALLOC);
  fprintf (ptr_asa_out, "SMALL_FLOAT = %*.*g\n",
	   G_FIELD, G_PRECISION, (double) SMALL_FLOAT);
  fprintf (ptr_asa_out, "MIN_DOUBLE = %*.*g\n",
	   G_FIELD, G_PRECISION, (double) MIN_DOUBLE);
  fprintf (ptr_asa_out, "MAX_DOUBLE = %*.*g\n",
	   G_FIELD, G_PRECISION, (double) MAX_DOUBLE);
  fprintf (ptr_asa_out, "EPS_DOUBLE = %*.*g\n",
	   G_FIELD, G_PRECISION, (double) EPS_DOUBLE);
  fprintf (ptr_asa_out, "CHECK_EXPONENT = %d\n",
	   (int) CHECK_EXPONENT);
  fprintf (ptr_asa_out, "NO_PARAM_TEMP_TEST = %d\n",
	   (int) NO_PARAM_TEMP_TEST);
  fprintf (ptr_asa_out, "NO_COST_TEMP_TEST = %d\n",
	   (int) NO_COST_TEMP_TEST);
  fprintf (ptr_asa_out, "SELF_OPTIMIZE = %d\n",
	   (int) SELF_OPTIMIZE);
  fprintf (ptr_asa_out, "ASA_TEST = %d\n",
	   (int) ASA_TEST);
  fprintf (ptr_asa_out, "ASA_TEST_POINT = %d\n",
	   (int) ASA_TEST_POINT);
  fprintf (ptr_asa_out, "ASA_TEMPLATE = %d\n",
	   (int) ASA_TEMPLATE);
  fprintf (ptr_asa_out, "MY_TEMPLATE = %d\n",
	   (int) MY_TEMPLATE);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_LIB = %d\n",
	   (int) ASA_TEMPLATE_LIB);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_ASA_OUT_PID = %d\n",
	   (int) ASA_TEMPLATE_ASA_OUT_PID);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_MULTIPLE = %d\n",
	   (int) ASA_TEMPLATE_MULTIPLE);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_SELFOPT = %d\n",
	   (int) ASA_TEMPLATE_SELFOPT);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_SAMPLE = %d\n",
	   (int) ASA_TEMPLATE_SAMPLE);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_QUEUE = %d\n",
	   (int) ASA_TEMPLATE_QUEUE);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_PARALLEL = %d\n",
	   (int) ASA_TEMPLATE_PARALLEL);
  fprintf (ptr_asa_out, "ASA_TEMPLATE_SAVE = %d\n",
	   (int) ASA_TEMPLATE_SAVE);
  fprintf (ptr_asa_out, "USER_INITIAL_COST_TEMP = %d\n",
	   (int) USER_INITIAL_COST_TEMP);
  fprintf (ptr_asa_out, "RATIO_TEMPERATURE_SCALES = %d\n",
	   (int) RATIO_TEMPERATURE_SCALES);
  fprintf (ptr_asa_out, "USER_INITIAL_PARAMETERS_TEMPS = %d\n",
	   (int) USER_INITIAL_PARAMETERS_TEMPS);
  fprintf (ptr_asa_out, "DELTA_PARAMETERS = %d\n",
	   (int) DELTA_PARAMETERS);
  fprintf (ptr_asa_out, "QUENCH_PARAMETERS = %d\n",
	   (int) QUENCH_PARAMETERS);
  fprintf (ptr_asa_out, "QUENCH_COST = %d\n",
	   (int) QUENCH_COST);
  fprintf (ptr_asa_out, "QUENCH_PARAMETERS_SCALE = %d\n",
	   (int) QUENCH_PARAMETERS_SCALE);
  fprintf (ptr_asa_out, "QUENCH_COST_SCALE = %d\n",
	   (int) QUENCH_COST_SCALE);
  fprintf (ptr_asa_out, "OPTIONAL_DATA = %d\n",
	   (int) OPTIONAL_DATA);
  fprintf (ptr_asa_out, "OPTIONAL_DATA_INT = %d\n",
	   (int) OPTIONAL_DATA_INT);
  fprintf (ptr_asa_out, "USER_COST_SCHEDULE = %d\n",
	   (int) USER_COST_SCHEDULE);
  fprintf (ptr_asa_out, "USER_ACCEPT_ASYMP_EXP = %d\n",
	   (int) USER_ACCEPT_ASYMP_EXP);
  fprintf (ptr_asa_out, "USER_ACCEPTANCE_TEST = %d\n",
	   (int) USER_ACCEPTANCE_TEST);
  fprintf (ptr_asa_out, "USER_GENERATING_FUNCTION = %d\n",
	   (int) USER_GENERATING_FUNCTION);
  fprintf (ptr_asa_out, "USER_REANNEAL_COST = %d\n",
	   (int) USER_REANNEAL_COST);
  fprintf (ptr_asa_out, "USER_REANNEAL_PARAMETERS = %d\n",
	   (int) USER_REANNEAL_PARAMETERS);
#if INT_LONG
  fprintf (ptr_asa_out, "MAXIMUM_REANNEAL_INDEX = %ld\n",
	   (LONG_INT) MAXIMUM_REANNEAL_INDEX);
#else
  fprintf (ptr_asa_out, "MAXIMUM_REANNEAL_INDEX = %d\n",
	   (LONG_INT) MAXIMUM_REANNEAL_INDEX);
#endif
  fprintf (ptr_asa_out, "REANNEAL_SCALE = %*.*g\n",
	   G_FIELD, G_PRECISION, (double) REANNEAL_SCALE);
  fprintf (ptr_asa_out, "ASA_SAMPLE = %d\n",
	   (int) ASA_SAMPLE);
  fprintf (ptr_asa_out, "ASA_QUEUE = %d\n",
	   (int) ASA_QUEUE);
  fprintf (ptr_asa_out, "ASA_RESOLUTION = %d\n",
	   (int) ASA_RESOLUTION);
  fprintf (ptr_asa_out, "ASA_PARALLEL = %d\n",
	   (int) ASA_PARALLEL);
  fprintf (ptr_asa_out, "ASA_SAVE = %d\n",
	   (int) ASA_SAVE);
  fprintf (ptr_asa_out, "SYSTEM_CALL = %d\n",
	   (int) SYSTEM_CALL);
  fprintf (ptr_asa_out, "FDLIBM_POW = %d\n",
	   (int) FDLIBM_POW);
  fprintf (ptr_asa_out, "FDLIBM_LOG = %d\n",
	   (int) FDLIBM_LOG);
  fprintf (ptr_asa_out, "FDLIBM_EXP = %d\n\n",
	   (int) FDLIBM_EXP);

  fprintf (ptr_asa_out, "ASA_PRINT = %d\n",
	   (int) ASA_PRINT);
#if USER_ASA_OUT
  fprintf (ptr_asa_out, "ASA_OUT = %s\n",
	   OPTIONS->Asa_Out_File);
#else
  fprintf (ptr_asa_out, "ASA_OUT = %s\n",
	   ASA_OUT);
#endif
  fprintf (ptr_asa_out, "USER_ASA_OUT = %d\n",
	   (int) USER_ASA_OUT);
  fprintf (ptr_asa_out, "ASA_PRINT_INTERMED = %d\n",
	   (int) ASA_PRINT_INTERMED);
  fprintf (ptr_asa_out, "ASA_PRINT_MORE = %d\n",
	   (int) ASA_PRINT_MORE);
  fprintf (ptr_asa_out, "G_FIELD = %d\n",
	   (int) G_FIELD);
  fprintf (ptr_asa_out, "G_PRECISION = %d\n\n",
	   (int) G_PRECISION);

#if INT_LONG
  fprintf (ptr_asa_out, "OPTIONS->Limit_Acceptances = %ld\n",
	   (LONG_INT) OPTIONS->Limit_Acceptances);
  fprintf (ptr_asa_out, "OPTIONS->Limit_Generated = %ld\n",
	   (LONG_INT) OPTIONS->Limit_Generated);
#else
  fprintf (ptr_asa_out, "OPTIONS->Limit_Acceptances = %d\n",
	   (LONG_INT) OPTIONS->Limit_Acceptances);
  fprintf (ptr_asa_out, "OPTIONS->Limit_Generated = %d\n",
	   (LONG_INT) OPTIONS->Limit_Generated);
#endif
  fprintf (ptr_asa_out, "OPTIONS->Limit_Invalid_Generated_States = %d\n",
	   OPTIONS->Limit_Invalid_Generated_States);
  fprintf (ptr_asa_out, "OPTIONS->Accepted_To_Generated_Ratio = %*.*g\n\n",
	   G_FIELD, G_PRECISION, OPTIONS->Accepted_To_Generated_Ratio);

  fprintf (ptr_asa_out, "OPTIONS->Cost_Precision = %*.*g\n",
	   G_FIELD, G_PRECISION, OPTIONS->Cost_Precision);
  fprintf (ptr_asa_out, "OPTIONS->Maximum_Cost_Repeat = %d\n",
	   OPTIONS->Maximum_Cost_Repeat);
  fprintf (ptr_asa_out, "OPTIONS->Number_Cost_Samples = %d\n",
	   OPTIONS->Number_Cost_Samples);
  fprintf (ptr_asa_out, "OPTIONS->Temperature_Ratio_Scale = %*.*g\n",
	   G_FIELD, G_PRECISION, OPTIONS->Temperature_Ratio_Scale);
  fprintf (ptr_asa_out, "OPTIONS->Cost_Parameter_Scale_Ratio = %*.*g\n",
	   G_FIELD, G_PRECISION, OPTIONS->Cost_Parameter_Scale_Ratio);
  fprintf (ptr_asa_out, "OPTIONS->Temperature_Anneal_Scale = %*.*g\n",
	   G_FIELD, G_PRECISION, OPTIONS->Temperature_Anneal_Scale);

  fprintf (ptr_asa_out, "OPTIONS->Include_Integer_Parameters = %d\n",
	   OPTIONS->Include_Integer_Parameters);
  fprintf (ptr_asa_out, "OPTIONS->User_Initial_Parameters = %d\n",
	   OPTIONS->User_Initial_Parameters);
#if INT_ALLOC
  fprintf (ptr_asa_out, "OPTIONS->Sequential_Parameters = %d\n",
	   (int) OPTIONS->Sequential_Parameters);
#else
#if INT_LONG
  fprintf (ptr_asa_out, "OPTIONS->Sequential_Parameters = %ld\n",
	   (LONG_INT) OPTIONS->Sequential_Parameters);
#else
  fprintf (ptr_asa_out, "OPTIONS->Sequential_Parameters = %d\n",
	   (LONG_INT) OPTIONS->Sequential_Parameters);
#endif
#endif
  fprintf (ptr_asa_out, "OPTIONS->Initial_Parameter_Temperature = %*.*g\n",
	   G_FIELD, G_PRECISION, OPTIONS->Initial_Parameter_Temperature);

  fprintf (ptr_asa_out, "OPTIONS->Acceptance_Frequency_Modulus = %d\n",
	   OPTIONS->Acceptance_Frequency_Modulus);
  fprintf (ptr_asa_out, "OPTIONS->Generated_Frequency_Modulus = %d\n",
	   OPTIONS->Generated_Frequency_Modulus);
  fprintf (ptr_asa_out, "OPTIONS->Reanneal_Cost = %d\n",
	   OPTIONS->Reanneal_Cost);
  fprintf (ptr_asa_out, "OPTIONS->Reanneal_Parameters = %d\n\n",
	   OPTIONS->Reanneal_Parameters);

  fprintf (ptr_asa_out, "OPTIONS->Delta_X = %*.*g\n",
	   G_FIELD, G_PRECISION, OPTIONS->Delta_X);
  fprintf (ptr_asa_out, "OPTIONS->User_Tangents = %d\n",
	   OPTIONS->User_Tangents);
  fprintf (ptr_asa_out, "OPTIONS->Curvature_0 = %d\n\n",
	   OPTIONS->Curvature_0);

  fprintf (ptr_asa_out, "\n");
}

#if TIME_CALC
/***********************************************************************
* print_time
*	This calculates the time and runtime and prints it.
***********************************************************************/
#if HAVE_ANSI
void
print_time (char *message, FILE * ptr_asa_out)
#else
void
print_time (message, ptr_asa_out)
     char *message;
     FILE *ptr_asa_out;
#endif /* HAVE_ANSI */
{
  int who = RUSAGE_SELF;	/* Check our own time */
  struct rusage usage;

  /* get the resource usage information */
#if TIME_STD
  syscall (SYS_GETRUSAGE, who, &usage);
#else
  getrusage (who, &usage);
#endif

  /* print the usage time in reasonable form */
  aux_print_time (&usage.ru_utime, message, ptr_asa_out);
}

/***********************************************************************
* aux_print_time
*      auxiliary print the time routine
***********************************************************************/
#if HAVE_ANSI
void
aux_print_time (struct timeval *time, char *message,
		FILE * ptr_asa_out)
#else
void
aux_print_time (time, message, ptr_asa_out)
     struct timeval *time;
     char *message;
     FILE *ptr_asa_out;
#endif /* HAVE_ANSI */
{
  static double sx;
  double us, s, m, h;
  double ds, dm, dh;

  /* calculate the new microseconds, seconds, minutes, hours
     and the differences since the last call */
  us = (double) ((int) ((double) EPS_DOUBLE + time->tv_usec)) / 1.E6;
  s = (double) ((int) ((double) EPS_DOUBLE + time->tv_sec)) + us;
  ds = s - sx;
  sx = s;

  h = (int) ((double) EPS_DOUBLE + s / 3600.);
  m = (int) ((double) EPS_DOUBLE + s / 60.) - 60. * h;
  s -= (3600. * h + 60. * m);
  dh = (int) ((double) EPS_DOUBLE + ds / 3600.);
  dm = (int) ((double) EPS_DOUBLE + ds / 60.) - 60. * dh;
  ds -= (3600. * dh + 60. * dm);

  /* print the statistics */
  fprintf (ptr_asa_out,
	   "%s:time: %gh %gm %gs; incr: %gh %gm %gs\n",
	   message, h, m, s, dh, dm, ds);
}

#endif /* TIME_CALC */
#endif /* ASA_PRINT */
