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

#define ASA_ID \
"/* $Id: asa.c,v 25.27 2005/04/03 17:44:54 ingber Exp ingber $ */"

#include "asa.h"

/***********************************************************************
* asa
*       This procedure implements the full ASA function optimization.
***********************************************************************/

#if !ASA_SAVE && !ASA_FILE_PIPE
#define fprintf if (ptr_asa_out)\
		fprintf
#define fflush if (ptr_asa_out)\
		fflush
#endif  /*!ASA_SAVE && !ASA_FILE_PIPE*/


#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_SAVE
  FILE *ptr_save, *ptr_comm;
  int asa_read;
  char asa_save_comm[100];
#if ASA_SAVE_OPT
  char read_option[80];
  char read_if[4], read_FALSE[6], read_comm1[3], read_ASA_SAVE[9],
    read_comm2[3];
  int read_int;
#if INT_LONG
  LONG_INT read_long;
#endif
  double read_double;
  FILE *ptr_save_opt;
#endif
#endif /* ASA_SAVE */

#if ASA_PIPE_FILE
  FILE *ptr_asa_pipe;
#endif

  int immediate_flag;           /* save Immediate_Exit */
  int asa_exit_value;

  double xnumber_parameters[1];

  /* 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 */
  ALLOC_INT queue_size_tmp;
#endif

#if MULTI_MIN
  int multi_index;
  int multi_test, multi_test_cmp, multi_test_dim;
  int *multi_sort;
  double *multi_cost;
  double **multi_params;
#endif /* MULTI_MIN */

#if ASA_PARALLEL
  LONG_INT *parallel_sort;
  LONG_INT index_parallel, sort_index;  /* count of parallel generated states */
  LONG_INT parallel_generated;  /* saved *recent_number_generated */
  LONG_INT parallel_block_max;  /* saved OPTIONS->Gener_Block_Max */
  STATE *gener_block_state;
#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 *) calloc (1, sizeof (int))) == NULL) {
    strcpy (exit_msg, "asa(): curvature_flag");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((maximum_tangent = (double *) calloc (1, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): maximum_tangent");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((accepted_to_generated_ratio =
       (double *) calloc (1, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): accepted_to_generated_ratio");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((temperature_scale_cost =
       (double *) calloc (1, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): temperature_scale_cost");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((current_cost_temperature =
       (double *) calloc (1, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): current_cost_temperature");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((initial_cost_temperature =
       (double *) calloc (1, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): initial_cost_temperature");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((index_exit_v = (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): index_exit_v");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((start_sequence = (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): start_sequence");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((number_generated =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): number_generated");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((best_number_generated_saved =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): best_number_generated_saved");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((recent_number_generated =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): recent_number_generated");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((number_accepted =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): number_accepted");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((recent_number_acceptances =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): recent_number_acceptances");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((index_cost_acceptances =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): index_cost_acceptances");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((number_acceptances_saved =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): number_acceptances_saved");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((best_number_accepted_saved =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): best_number_accepted_saved");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((number_invalid_generated_states =
       (ALLOC_INT *) calloc (1, sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): number_invalid_generated_states");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }

  if ((current_generated_state =
       (STATE *) calloc (1, sizeof (STATE))) == NULL) {
    strcpy (exit_msg, "asa(): current_generated_state");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((last_saved_state = (STATE *) calloc (1, sizeof (STATE))) == NULL) {
    strcpy (exit_msg, "asa(): last_saved_state");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((best_generated_state = (STATE *) calloc (1, sizeof (STATE))) == NULL) {
    strcpy (exit_msg, "asa(): best_generated_state");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
#if ASA_PARALLEL
  if ((gener_block_state =
       (STATE *) calloc (OPTIONS->Gener_Block_Max, sizeof (STATE))) == NULL) {
    strcpy (exit_msg, "asa(): gener_block_state");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  gener_block_state_qsort = gener_block_state;
  if ((parallel_sort =
       (LONG_INT *) calloc (OPTIONS->Gener_Block_Max,
                            sizeof (LONG_INT))) == NULL) {
    strcpy (exit_msg, "asa(): parallel_sort");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
#endif

  /* set default */
  ptr_asa_out = (FILE *) NULL;

  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")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
      }
      else if (strcmp (OPTIONS->Asa_Out_File, "NULL")){
#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")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_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")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
      } else if(strcmp (OPTIONS->Asa_Out_File, "NULL")) {
        ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
      }
#else
      if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_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")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
      } else {
        ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
      }
#else
      if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
      } else {
        ptr_asa_out = fopen (ASA_OUT, "a");
      }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
      if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
      } else {
        ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
      }
#else
      if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_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")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
      } else {
        ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
      }
#else
      if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
        ptr_asa_out = stdout;
#endif /* INCL_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_PIPE_FILE
  ptr_asa_pipe = fopen ("asa_pipe", "a");
  fprintf (ptr_asa_pipe, "%s", "%generate");
  fprintf (ptr_asa_pipe, "\t%s", "accept");
  fprintf (ptr_asa_pipe, "\t%s", "best_cost");
  VFOR (index_v)
#if INT_ALLOC
    fprintf (ptr_asa_pipe, "\t%s-%d", "param", index_v);
#else
#if INT_LONG
    fprintf (ptr_asa_pipe, "\t%s-%ld", "param", index_v);
#else
    fprintf (ptr_asa_pipe, "\t%s-%d", "param", index_v);
#endif
#endif
  fprintf (ptr_asa_pipe, "\t%s", "cost_temp");
  VFOR (index_v)
#if INT_ALLOC
    fprintf (ptr_asa_pipe, "\t%s-%d", "param_temp", index_v);
#else
#if INT_LONG
    fprintf (ptr_asa_pipe, "\t%s-%ld", "param_temp", index_v);
#else
    fprintf (ptr_asa_pipe, "\t%s-%d", "param_temp", index_v);
#endif
#endif
  fprintf (ptr_asa_pipe, "\t%s", "last_cost");
  fprintf (ptr_asa_pipe, "\n");
  fflush (ptr_asa_pipe);
#endif /* ASA_PIPE_FILE */

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

#if TIME_CALC
  /* print starting time */
  if (ptr_asa_out)
	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 *) calloc (*number_parameters, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): current_generated_state->parameter");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((last_saved_state->parameter =
       (double *) calloc (*number_parameters, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): last_saved_state->parameter");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((best_generated_state->parameter =
       (double *) calloc (*number_parameters, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): best_generated_state->parameter");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
#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 *) calloc (*number_parameters, sizeof (double))) == NULL) {
      strcpy (exit_msg, "asa(): gener_block_state[index_parallel].parameter");
      Exit_ASA (exit_msg);
      *exit_status = CALLOC_FAILED;
      return (-1);
    }
  }
#endif

  OPTIONS->Best_Cost = &(best_generated_state->cost);
  OPTIONS->Best_Parameters = best_generated_state->parameter;
  OPTIONS->Last_Cost = &(last_saved_state->cost);
  OPTIONS->Last_Parameters = last_saved_state->parameter;

  if ((initial_user_parameter_temp =
       (double *) calloc (*number_parameters, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): initial_user_parameter_temp");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((index_parameter_generations =
       (ALLOC_INT *) calloc (*number_parameters,
                             sizeof (ALLOC_INT))) == NULL) {
    strcpy (exit_msg, "asa(): index_parameter_generations");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }

  /* set all temperatures */
  if ((current_user_parameter_temp =
       (double *) calloc (*number_parameters, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): current_user_parameter_temp");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
#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 *) calloc (*number_parameters, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): temperature_scale_parameters");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
#if ASA_QUEUE
  if (OPTIONS->Queue_Size > 0) {
    queue_size_tmp = OPTIONS->Queue_Size;
  } else {
    queue_size_tmp = 1;
  }
  if ((save_queue_flag =
       (int *) calloc (queue_size_tmp, sizeof (int))) == NULL) {
    strcpy (exit_msg, "asa(): save_queue_flag");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((save_queue_cost =
       (double *) calloc (queue_size_tmp, sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): save_queue_cost");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((save_queue_param =
       (double *) calloc ((*number_parameters) * queue_size_tmp,
                          sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): save_queue_param");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
#endif /* ASA_QUEUE */

#if MULTI_MIN
  if ((multi_cost =
       (double *) calloc (OPTIONS->Multi_Number + 1,
                          sizeof (double))) == NULL) {
    strcpy (exit_msg, "asa(): *multi_cost");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  multi_cost_qsort = multi_cost;
  if ((multi_sort =
       (int *) calloc (OPTIONS->Multi_Number + 1, sizeof (int))) == NULL) {
    strcpy (exit_msg, "asa(): *multi_sort");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  if ((multi_params =
       (double **) calloc (OPTIONS->Multi_Number + 1,
                           sizeof (double *))) == NULL) {
    strcpy (exit_msg, "asa(): *multi_params");
    Exit_ASA (exit_msg);
    *exit_status = CALLOC_FAILED;
    return (-1);
  }
  for (multi_index = 0; multi_index <= OPTIONS->Multi_Number; ++multi_index) {
    if ((multi_params[multi_index] =
         (double *) calloc (*number_parameters, sizeof (double))) == NULL) {
      strcpy (exit_msg, "asa(): multi_params[multi_index]");
      Exit_ASA (exit_msg);
      *exit_status = CALLOC_FAILED;
      return (-1);
    }
  }
#endif /* MULTI_MIN */

#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]);
  fprintf (ptr_asa_out, "\n");
#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 MULTI_MIN
#if ASA_PRINT
  fprintf (ptr_asa_out, "\n");
  fprintf (ptr_asa_out, "Multi_Number = %d\n", OPTIONS->Multi_Number);
  fprintf (ptr_asa_out, "Multi_Specify = %d\n", OPTIONS->Multi_Specify);
#if ASA_RESOLUTION
#else
  VFOR (index_v) {
    fprintf (ptr_asa_out,
#if INT_ALLOC
             "Multi_Grid[%d] = %*.*g\n",
#else
#if INT_LONG
             "Multi_Grid[%ld] = %*.*g\n",
#else
             "Multi_Grid[%d] = %*.*g\n",
#endif
#endif
             index_v, G_FIELD, G_PRECISION, OPTIONS->Multi_Grid[index_v]);
  }
#endif /* ASA_RESOLUTION */
  fprintf (ptr_asa_out, "\n");
  fflush (ptr_asa_out);
#endif /* ASA_PRINT */
#endif /* MULTI_MIN */

#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
#if ASA_PRINT
  fprintf (ptr_asa_out, "OPTIONS->Limit_Weights = %*.*g\n\n",
           G_FIELD, G_PRECISION, OPTIONS->Limit_Weights);
#endif
#endif
  if (OPTIONS->Asa_Recursive_Level > asa_recursive_max)
    asa_recursive_max = OPTIONS->Asa_Recursive_Level;
#if ASA_SAVE
  if (OPTIONS->Asa_Recursive_Level > 0)
    sprintf (asa_save_comm, "asa_save_%d", OPTIONS->Asa_Recursive_Level);
  else
    sprintf (asa_save_comm, "asa_save");
  if ((ptr_save = fopen (asa_save_comm, "r")) == NULL) {
    asa_read = FALSE;
  } else {
#if ASA_PRINT
    fprintf (ptr_asa_out, "\n\n\trestart after ASA_SAVE\n\n");
#endif
    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

  tmp_var_int = cost_function_test (current_generated_state->cost,
                                    current_generated_state->parameter,
                                    parameter_minimum,
                                    parameter_maximum, number_parameters,
                                    xnumber_parameters);

  /* 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 / *xnumber_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
     / *xnumber_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
     / *xnumber_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) / *xnumber_parameters)
    * OPTIONS->User_Temperature_Ratio[index_v];
#else
  VFOR (index_v)
    temperature_scale_parameters[index_v] =
    tmp_var_db1 * F_EXP (-(tmp_var_db2) / *xnumber_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
                         / *xnumber_parameters) *
    OPTIONS->Cost_Parameter_Scale_Ratio;
#else /* QUENCH_COST */
    tmp_var_db1 * F_EXP (-(tmp_var_db2)
                         / *xnumber_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 = asa_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
#if ASA_SAVE
  if (asa_read == TRUE)
    OPTIONS->Number_Cost_Samples = 1;
#endif
  /* 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;
  }

  OPTIONS->Locate_Cost = 0;     /* initial cost temp */

  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);
      if (cost_function_test
          (tmp_var_db, current_generated_state->parameter,
           parameter_minimum, parameter_maximum, number_parameters,
           xnumber_parameters) == 0) {
        *exit_status = INVALID_COST_FUNCTION;
        goto EXIT_ASA;
      }

      ++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];

  OPTIONS->Locate_Cost = 1;     /* initial cost value */

  /* 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 (cost_function_test
        (current_generated_state->cost, current_generated_state->parameter,
         parameter_minimum, parameter_maximum, number_parameters,
         xnumber_parameters) == 0) {
      *exit_status = INVALID_COST_FUNCTION;
      goto EXIT_ASA;
    }
#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);
      if (cost_function_test
          (current_generated_state->cost,
           current_generated_state->parameter, parameter_minimum,
           parameter_maximum, number_parameters, xnumber_parameters) == 0) {
        *exit_status = INVALID_COST_FUNCTION;
        goto EXIT_ASA;
      }
      ++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) {
#if DROPPED_PARAMETERS
    /* ignore parameters that have too small a range */
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
#endif
    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 */
  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
  if (ptr_asa_out)
	  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 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
  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 < queue_size_tmp; ++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 */

#if MULTI_MIN
  multi_sort[OPTIONS->Multi_Number] = OPTIONS->Multi_Number;
  multi_cost[OPTIONS->Multi_Number] = current_generated_state->cost;
  VFOR (index_v) {
    multi_params[OPTIONS->Multi_Number][index_v] =
      current_generated_state->parameter[index_v];
  }
  for (multi_index = 0; multi_index < OPTIONS->Multi_Number; ++multi_index) {
    multi_sort[multi_index] = multi_index;
    multi_cost[multi_index] = OPTIONS->Multi_Cost[multi_index] =
      current_generated_state->cost;
    VFOR (index_v) {
      multi_params[multi_index][index_v] =
        OPTIONS->Multi_Params[multi_index][index_v] =
        current_generated_state->parameter[index_v];
    }
  }
#endif /* MULTI_MIN */

  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 / *xnumber_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
       / *xnumber_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
       / *xnumber_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) / *xnumber_parameters)
      * OPTIONS->User_Temperature_Ratio[index_v];
#else
    VFOR (index_v)
      temperature_scale_parameters[index_v] =
      tmp_var_db1 * F_EXP (-(tmp_var_db2) / *xnumber_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
                           / *xnumber_parameters) *
      OPTIONS->Cost_Parameter_Scale_Ratio;
#else /* QUENCH_COST */
      tmp_var_db1 * F_EXP (-(tmp_var_db2)
                           / *xnumber_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 */
               / *xnumber_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
                                        / *xnumber_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 && OPTIONS->Asa_Recursive_Level == asa_recursive_max) {
      if (OPTIONS->Asa_Recursive_Level > 0)
        sprintf (asa_save_comm, "asa_save_%d", OPTIONS->Asa_Recursive_Level);
      else
        sprintf (asa_save_comm, "asa_save");
      ptr_save = fopen (asa_save_comm, "r");

      fread (number_parameters, sizeof (ALLOC_INT), 1, ptr_save);
      fread (xnumber_parameters, sizeof (double), 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 (&asa_open, sizeof (int), 1, ptr_save);
      fread (&number_asa_open, sizeof (int), 1, ptr_save);
      fread (&recursive_asa_open, 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->Locate_Cost), sizeof (int), 1, ptr_save);
      fread (&(OPTIONS->Immediate_Exit), sizeof (int), 1, ptr_save);
#if OPTIONAL_DATA_DBL
      fread (&(OPTIONS->Asa_Data_Dim_Dbl), sizeof (ALLOC_INT), 1, ptr_save);
      fread (OPTIONS->Asa_Data_Dbl, sizeof (double),
             OPTIONS->Asa_Data_Dim_Dbl, ptr_save);
#endif
      fread (&(OPTIONS->Random_Array_Dim), sizeof (ALLOC_INT), 1, ptr_save);
      fread (OPTIONS->Random_Array, sizeof (double),
             OPTIONS->Random_Array_Dim, ptr_save);
      fread (&(OPTIONS->Asa_Recursive_Level), sizeof (int), 1, ptr_save);
#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 OPTIONAL_DATA_PTR
      fread (&(OPTIONS->Asa_Data_Dim_Ptr), sizeof (ALLOC_INT), 1, ptr_save);
      if (OPTIONS->Asa_Recursive_Level == 0)
        fread (OPTIONS->Asa_Data_Ptr, sizeof (OPTIONAL_PTR_TYPE),
               OPTIONS->Asa_Data_Dim_Ptr, ptr_save);
#if ASA_TEMPLATE_SELFOPT
      if (OPTIONS->Asa_Recursive_Level == 1)
        fread (OPTIONS->Asa_Data_Ptr, sizeof (RECUR_OPTIONAL_PTR_TYPE),
               OPTIONS->Asa_Data_Dim_Ptr, ptr_save);
#endif
#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->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);
      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);
#if ASA_RESOLUTION
#else
      fread (OPTIONS->Queue_Resolution, sizeof (double),
             *number_parameters, ptr_save);
#endif
#endif
#if ASA_RESOLUTION
      fread (OPTIONS->Coarse_Resolution, sizeof (double),
             *number_parameters, ptr_save);
#endif
#if FITLOC
      fread (&(OPTIONS->Fit_Local), sizeof (int), 1, ptr_save);
      fread (&(OPTIONS->Iter_Max), sizeof (int), 1, ptr_save);
      fread (&(OPTIONS->Penalty), sizeof (double), 1, ptr_save);
#endif
#if MULTI_MIN
      fread (OPTIONS->Multi_Number, sizeof (int), 1, ptr_save);
      fread (OPTIONS->Multi_Grid,
             sizeof (double), *number_parameters, ptr_save);
      fread (&(OPTIONS->Multi_Specify), sizeof (int), 1, ptr_save);
      for (multi_index = 0; multi_index < OPTIONS->Multi_Number;
           ++multi_index) {
        fread (&(OPTIONS->Multi_Cost[multi_index]), sizeof (double), 1,
               ptr_save);
        fread (&(OPTIONS->Multi_Params[multi_index]), 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
  if (ptr_asa_out)
      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 */

#include "asa_opt"
#if ASA_SAVE_OPT
      if ((ptr_save_opt = fopen ("asa_save_opt", "r")) == NULL) {
#if INCL_STDOUT
        printf ("\n\n*** WARNING fopen asa_save_opt failed *** \n\n");
#endif /* INCL_STDOUT */
#if ASA_PRINT
        fprintf (ptr_asa_out,
                 "\n\n*** WARNING fopen asa_save_opt failed *** \n\n");
        fflush (ptr_asa_out);
#endif
      } else {
        fscanf (ptr_save_opt, "%s%s%s%s%s",
                read_if, read_FALSE, read_comm1, read_ASA_SAVE, read_comm2);
        if (strcmp (read_if, "#if") || strcmp (read_FALSE, "FALSE")
            || strcmp (read_comm1, "/*")
            || strcmp (read_ASA_SAVE, "ASA_SAVE")
            || strcmp (read_comm2, "*/")) {
#if INCL_STDOUT
          printf ("\n\n*** EXIT not asa_save_opt for this version *** \n\n");
#endif /* INCL_STDOUT */
#if ASA_PRINT
          fprintf (ptr_asa_out,
                   "\n\n*** not asa_save_opt for this version *** \n\n");
          fflush (ptr_asa_out);
#endif
          *exit_status = INVALID_USER_INPUT;
          goto EXIT_ASA;
        }
#if INT_LONG
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%ld", &read_long);
        OPTIONS->Limit_Acceptances = read_long;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%ld", &read_long);
        OPTIONS->Limit_Generated = read_long;
#else
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Limit_Acceptances = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Limit_Generated = read_int;
#endif
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Limit_Invalid_Generated_States = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Accepted_To_Generated_Ratio = read_double;

        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Cost_Precision = read_double;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Maximum_Cost_Repeat = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Number_Cost_Samples = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Temperature_Ratio_Scale = read_double;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Cost_Parameter_Scale_Ratio = read_double;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Temperature_Anneal_Scale = read_double;

        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Include_Integer_Parameters = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->User_Initial_Parameters = read_int;
#if INT_ALLOC
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Sequential_Parameters = read_int;
#else
#if INT_LONG
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%ld", &read_long);
        OPTIONS->Sequential_Parameters = read_long;
#else
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Sequential_Parameters = read_int;
#endif
#endif
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Initial_Parameter_Temperature = read_double;

        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Acceptance_Frequency_Modulus = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Generated_Frequency_Modulus = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Reanneal_Cost = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Reanneal_Parameters = read_int;

        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%lf", &read_double);
        OPTIONS->Delta_X = read_double;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->User_Tangents = read_int;
        fscanf (ptr_save_opt, "%s", read_option);
        fscanf (ptr_save_opt, "%d", &read_int);
        OPTIONS->Curvature_0 = read_int;

        fclose (ptr_save_opt);
      }
#endif /* ASA_SAVE_OPT */

      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 *) calloc (OPTIONS->Gener_Block_Max,
                             sizeof (STATE))) == NULL) {
        strcpy (exit_msg, "asa(): gener_block_state");
        Exit_ASA (exit_msg);
        *exit_status = CALLOC_FAILED;
        return (-1);
      }

      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 *) calloc (*number_parameters,
                                sizeof (double))) == NULL) {
          strcpy (exit_msg,
                  "asa(): gener_block_state[index_parallel].parameter");
          Exit_ASA (exit_msg);
          *exit_status = CALLOC_FAILED;
          return (-1);
        }
      }
    }
#if ASA_TEMPLATE_PARALLEL
    for (index_parallel = 0; index_parallel < OPTIONS->Gener_Block;
         ++index_parallel) {
#endif /* ASA_TEMPLATE_PARALLEL */
#endif /* ASA_PARALLEL */

      if (OPTIONS->Locate_Cost < 0) {
        OPTIONS->Locate_Cost = 12;      /* generate new state from new best */
      } else {
        OPTIONS->Locate_Cost = 2;       /* generate new state */
      }

      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 MISC.DIR/asa_contrib file for
           source code for doubly-linked and hashed lists. */
        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;
              --(*number_generated);
#if ASA_PRINT_MORE
#if INT_LONG
              fprintf (ptr_asa_out, "ASA_QUEUE: %ld \t %*.*g\n",
                       OPTIONS->N_Generated,
                       G_FIELD, G_PRECISION, tmp_var_db);
#else
              fprintf (ptr_asa_out, "ASA_QUEUE: %d \t %*.*g\n",
                       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 (cost_function_test (tmp_var_db,
                                  current_generated_state->parameter,
                                  parameter_minimum,
                                  parameter_maximum,
                                  number_parameters,
                                  xnumber_parameters) == 0) {
            *exit_status = INVALID_COST_FUNCTION;
            goto EXIT_ASA;
          }
          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);
        if (cost_function_test (tmp_var_db,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION;
          goto EXIT_ASA;
        }
#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 (sort_index = 0; sort_index < OPTIONS->Gener_Block; ++sort_index)
      parallel_sort[sort_index] = sort_index;
    qsort (parallel_sort, OPTIONS->Gener_Block, sizeof (LONG_INT),
           sort_parallel);

    for (sort_index = 0; sort_index < OPTIONS->Gener_Block; ++sort_index) {
      index_parallel = parallel_sort[sort_index];
      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);

#if ASA_PARALLEL
#else
#if ASA_PIPE_FILE
#if INT_ALLOC
      fprintf (ptr_asa_pipe, "%d", *number_generated);
#else
#if INT_LONG
      fprintf (ptr_asa_pipe, "%ld", *number_generated);
#else
      fprintf (ptr_asa_pipe, "%d", *number_generated);
#endif
#endif
#if INT_ALLOC
      fprintf (ptr_asa_pipe, "\t%d", *number_accepted);
#else
#if INT_LONG
      fprintf (ptr_asa_pipe, "\t%ld", *number_accepted);
#else
      fprintf (ptr_asa_pipe, "\t%d", *number_accepted);
#endif
#endif
      fprintf (ptr_asa_pipe, "\t%g", best_generated_state->cost);
      VFOR (index_v)
        fprintf (ptr_asa_pipe, "\t%g",
                 best_generated_state->parameter[index_v]);
      fprintf (ptr_asa_pipe, "\t%g", *current_cost_temperature);
      VFOR (index_v)
        fprintf (ptr_asa_pipe, "\t%g", current_user_parameter_temp[index_v]);
      fprintf (ptr_asa_pipe, "\t%g", last_saved_state->cost);
      fprintf (ptr_asa_pipe, "\n");
      fflush (ptr_asa_pipe);
#endif /* ASA_PIPE_FILE */
#if INCL_STDOUT
#if ASA_PIPE
#if INT_ALLOC
      printf ("%d", *number_generated);
#else
#if INT_LONG
      printf ("%ld", *number_generated);
#else
      printf ("%d", *number_generated);
#endif
#endif
#if INT_ALLOC
      printf ("\t%d", *number_accepted);
#else
#if INT_LONG
      printf ("\t%ld", *number_accepted);
#else
      printf ("\t%d", *number_accepted);
#endif
#endif
      printf ("\t%g", best_generated_state->cost);
      VFOR (index_v)
        printf ("\t%g", best_generated_state->parameter[index_v]);
      printf ("\t%g", *current_cost_temperature);
      VFOR (index_v)
        printf ("\t%g", current_user_parameter_temp[index_v]);
      printf ("\n");
#endif /* ASA_PIPE */
#endif /* INCL_STDOUT */
#endif /* ASA_PARALLEL */

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

#if MULTI_MIN
      if (((OPTIONS->Multi_Specify == 0)
           && (current_generated_state->cost <= best_generated_state->cost))
          || ((OPTIONS->Multi_Specify == 1)
              && (current_generated_state->cost <
                  best_generated_state->cost))) {
#if ASA_RESOLUTION
        VFOR (index_v) {
          if (OPTIONS->Multi_Grid[index_v] <
              OPTIONS->Coarse_Resolution[index_v])
            OPTIONS->Multi_Grid[index_v] =
              OPTIONS->Coarse_Resolution[index_v];
        }
#endif /* ASA_RESOLUTION */
        VFOR (index_v) {
          if (OPTIONS->Multi_Grid[index_v] < EPS_DOUBLE)
            OPTIONS->Multi_Grid[index_v] = EPS_DOUBLE;
        }

        multi_test = 0;
        for (multi_index = 0; multi_index < OPTIONS->Multi_Number;
             ++multi_index) {
          multi_test_cmp = 0;
          multi_test_dim = 0;
          VFOR (index_v) {
            if (PARAMETER_RANGE_TOO_SMALL (index_v))
              continue;
            ++multi_test_dim;
            if (fabs (current_generated_state->parameter[index_v]
                      - OPTIONS->Multi_Params[multi_index][index_v])
                < OPTIONS->Multi_Grid[index_v] - EPS_DOUBLE)
              ++multi_test_cmp;
          }
          if (multi_test_cmp == multi_test_dim)
            multi_test = 1;
          if (OPTIONS->Multi_Specify == 1)
            break;
        }

        if (multi_test == 0) {
          multi_cost[OPTIONS->Multi_Number] = current_generated_state->cost;
          VFOR (index_v) {
            multi_params[OPTIONS->Multi_Number][index_v] =
              current_generated_state->parameter[index_v];
          }
          for (multi_index = 0; multi_index < OPTIONS->Multi_Number;
               ++multi_index) {
            multi_cost[multi_index] = OPTIONS->Multi_Cost[multi_index];
            VFOR (index_v) {
              multi_params[multi_index][index_v] =
                OPTIONS->Multi_Params[multi_index][index_v];
            }
          }

          qsort (multi_sort, OPTIONS->Multi_Number + 1, sizeof (int),
                 multi_compare);
          for (multi_index = 0; multi_index < OPTIONS->Multi_Number;
               ++multi_index) {
            OPTIONS->Multi_Cost[multi_index] =
              multi_cost[multi_sort[multi_index]];
            VFOR (index_v) {
              OPTIONS->Multi_Params[multi_index][index_v] =
                multi_params[multi_sort[multi_index]][index_v];
            }
          }
        }
      }
#endif /* MULTI_MIN */

      /* CHECK FOR NEW MINIMUM */

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

        OPTIONS->Locate_Cost = -1;

        /* 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) {
#if DROPPED_PARAMETERS
          /* ignore parameters that have too small a range */
          if (PARAMETER_RANGE_TOO_SMALL (index_v))
            continue;
#endif
          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
  if (ptr_asa_out)
        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
        && OPTIONS->Asa_Recursive_Level == asa_recursive_max
        && index_cost_repeat == 0) {
      if (OPTIONS->Asa_Recursive_Level > 0)
        sprintf (asa_save_comm, "asa_save_%d", OPTIONS->Asa_Recursive_Level);
      else
        sprintf (asa_save_comm, "asa_save");
      ptr_save = fopen (asa_save_comm, "w");

      fwrite (number_parameters, sizeof (ALLOC_INT), 1, ptr_save);
      fwrite (xnumber_parameters, sizeof (double), 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 (&asa_open, sizeof (int), 1, ptr_save);
      fwrite (&number_asa_open, sizeof (int), 1, ptr_save);
      fwrite (&recursive_asa_open, 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->Locate_Cost), sizeof (int), 1, ptr_save);
      fwrite (&(OPTIONS->Immediate_Exit), sizeof (int), 1, ptr_save);
#if OPTIONAL_DATA_DBL
      fwrite (&(OPTIONS->Asa_Data_Dim_Dbl), sizeof (ALLOC_INT), 1, ptr_save);
      fwrite (OPTIONS->Asa_Data_Dbl, sizeof (double),
              OPTIONS->Asa_Data_Dim_Dbl, ptr_save);
#endif
      fwrite (&(OPTIONS->Random_Array_Dim), sizeof (ALLOC_INT), 1, ptr_save);
      fwrite (OPTIONS->Random_Array, sizeof (double),
              OPTIONS->Random_Array_Dim, ptr_save);
      fwrite (&(OPTIONS->Asa_Recursive_Level), sizeof (int), 1, ptr_save);
#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 OPTIONAL_DATA_PTR
      fwrite (&(OPTIONS->Asa_Data_Dim_Ptr), sizeof (ALLOC_INT), 1, ptr_save);
      if (OPTIONS->Asa_Recursive_Level == 0)
        fwrite (OPTIONS->Asa_Data_Ptr, sizeof (OPTIONAL_PTR_TYPE),
                OPTIONS->Asa_Data_Dim_Ptr, ptr_save);
#if ASA_TEMPLATE_SELFOPT
      if (OPTIONS->Asa_Recursive_Level == 1)
        fwrite (OPTIONS->Asa_Data_Ptr, sizeof (RECUR_OPTIONAL_PTR_TYPE),
                OPTIONS->Asa_Data_Dim_Ptr, ptr_save);
#endif
#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->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);
      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);
#if ASA_RESOLUTION
#else
      fwrite (OPTIONS->Queue_Resolution, sizeof (double),
              *number_parameters, ptr_save);
#endif
#endif
#if ASA_RESOLUTION
      fwrite (OPTIONS->Coarse_Resolution, sizeof (double),
              *number_parameters, ptr_save);
#endif
#if FITLOC
      fwrite (&(OPTIONS->Fit_Local), sizeof (int), 1, ptr_save);
      fwrite (&(OPTIONS->Iter_Max), sizeof (int), 1, ptr_save);
      fwrite (&(OPTIONS->Penalty), sizeof (double), 1, ptr_save);
#endif
#if MULTI_MIN
      fwrite (OPTIONS->Multi_Number, sizeof (int), 1, ptr_save);
      fwrite (OPTIONS->Multi_Grid,
              sizeof (double), *number_parameters, ptr_save);
      fwrite (&(OPTIONS->Multi_Specify), sizeof (int), 1, ptr_save);
      for (multi_index = 0; multi_index < OPTIONS->Multi_Number;
           ++multi_index) {
        fwrite (&(OPTIONS->Multi_Cost[multi_index]), sizeof (double), 1,
                ptr_save);
        fwrite (&(OPTIONS->Multi_Params[multi_index]), 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
#if ASA_SAVE_BACKUP
#if INT_LONG
      if (OPTIONS->Asa_Recursive_Level > 0)
        sprintf (asa_save_comm, "/bin/cp asa_save_%d asa_save_%d.%ld",
                 OPTIONS->Asa_Recursive_Level,
                 OPTIONS->Asa_Recursive_Level, OPTIONS->N_Accepted);
      else
        sprintf (asa_save_comm, "/bin/cp asa_save asa_save.%ld",
                 OPTIONS->N_Accepted);
#else
      if (OPTIONS->Asa_Recursive_Level > 0)
        sprintf (asa_save_comm, "/bin/cp asa_save_%d asa_save_%d.%d",
                 OPTIONS->Asa_Recursive_Level,
                 OPTIONS->Asa_Recursive_Level, OPTIONS->N_Accepted);
      else
        sprintf (asa_save_comm, "/bin/cp asa_save asa_save.%d",
                 OPTIONS->N_Accepted);
#endif
      ptr_comm = popen (asa_save_comm, "r");
      pclose (ptr_comm);
#else /* ASA_SAVE_BACKUP */
      /* extra protection in case run aborts during write */
      if (OPTIONS->Asa_Recursive_Level > 0)
        sprintf (asa_save_comm, "/bin/cp asa_save_%d asa_save_%d.old",
                 OPTIONS->Asa_Recursive_Level, OPTIONS->Asa_Recursive_Level);
      else
        sprintf (asa_save_comm, "/bin/cp asa_save asa_save.old");
      ptr_comm = popen (asa_save_comm, "r");
      pclose (ptr_comm);
#endif /* ASA_SAVE_BACKUP */
#endif /* SYSTEM_CALL */
    }
#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) {
        OPTIONS->Locate_Cost = 3;       /* reanneal parameters */

        /* 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 (*exit_status == INVALID_COST_FUNCTION_DERIV) {
          goto EXIT_ASA;
        }
      }
#if USER_REANNEAL_COST
#else
      if (OPTIONS->Reanneal_Cost == 0 || OPTIONS->Reanneal_Cost == 1) {
        ;
      } else {
        immediate_flag = OPTIONS->Immediate_Exit;

        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) {
          OPTIONS->Locate_Cost = 4;     /* reanneal cost */

          *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_PRINT_MORE
#if INT_LONG
                  fprintf (ptr_asa_out,
                           "ASA_QUEUE: %ld \t %*.*g\n",
                           OPTIONS->N_Generated, G_FIELD,
                           G_PRECISION, tmp_var_db);
#else
                  fprintf (ptr_asa_out,
                           "ASA_QUEUE: %d \t %*.*g\n",
                           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 (cost_function_test
                  (tmp_var_db, current_generated_state->parameter,
                   parameter_minimum, parameter_maximum,
                   number_parameters, xnumber_parameters) == 0) {
                *exit_status = INVALID_COST_FUNCTION;
                goto EXIT_ASA;
              }
              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);
            if (cost_function_test
                (tmp_var_db, current_generated_state->parameter,
                 parameter_minimum, parameter_maximum,
                 number_parameters, xnumber_parameters) == 0) {
              *exit_status = INVALID_COST_FUNCTION;
              goto EXIT_ASA;
            }
#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;
        }
        OPTIONS->Immediate_Exit = immediate_flag;
      }
#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
  if (ptr_asa_out)
      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_value = 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);
  if (asa_exit_value == 9) {
    *exit_status = CALLOC_FAILED;
    return (-1);
  }

  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 MULTI_MIN
  for (multi_index = 0; multi_index <= OPTIONS->Multi_Number; ++multi_index)
    free (multi_params[multi_index]);
  free (multi_params);
  free (multi_sort);
  free (multi_cost);
#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);
  free (parallel_sort);
#endif
#if ASA_PIPE_FILE
  fclose (ptr_asa_pipe);
#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
int
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
int

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 curvatureFlag;
  int exit_exit_status, tmp_locate;
#if MULTI_MIN
  int multi_index;
#endif

  tmp_locate = OPTIONS->Locate_Cost;

  /* 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 MULTI_MIN
  for (multi_index = 0; multi_index < OPTIONS->Multi_Number; ++multi_index) {
    best_generated_state->cost = OPTIONS->Multi_Cost[multi_index];
    VFOR (index_v) {
      best_generated_state->parameter[index_v] =
        OPTIONS->Multi_Params[multi_index][index_v];
    }
#if ASA_PRINT
    fprintf (ptr_asa_out, "\n\t\t multi_index = %d\n", multi_index);
#endif /* ASA_PRINT */
#endif /* MULTI_MIN */
    if (*exit_status != TOO_MANY_INVALID_STATES
        && *exit_status != IMMEDIATE_EXIT
        && *exit_status != INVALID_USER_INPUT
        && *exit_status != INVALID_COST_FUNCTION
        && *exit_status != INVALID_COST_FUNCTION_DERIV) {
      if (OPTIONS->Curvature_0 != TRUE)
        OPTIONS->Locate_Cost = 5;       /* calc curvatures while exiting asa */

      /* calculate curvatures and tangents at best point */
      curvatureFlag = TRUE;
      cost_derivatives (user_cost_function,
                        parameter_minimum,
                        parameter_maximum,
                        tangents,
                        curvature,
                        maximum_tangent,
                        number_parameters,
                        parameter_type,
                        &exit_exit_status,
                        &curvatureFlag,
                        valid_state_generated_flag,
                        number_invalid_generated_states,
                        current_generated_state,
                        best_generated_state, ptr_asa_out, OPTIONS);
    }
#if ASA_PRINT
    if (exit_exit_status == INVALID_COST_FUNCTION_DERIV)
      fprintf (ptr_asa_out, "\n\n  in asa_exit: INVALID_COST_FUNCTION_DERIV");

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

#if MULTI_MIN
  }
  best_generated_state->cost = OPTIONS->Multi_Cost[0];
  VFOR (index_v) {
    best_generated_state->parameter[index_v] =
      OPTIONS->Multi_Params[0][index_v];
  }
#endif /* MULTI_MIN */

#if ASA_PRINT
  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;
  case INVALID_COST_FUNCTION:
    fprintf (ptr_asa_out,
             "\n\n  INVALID_COST_FUNCTION exit_status = %d\n", *exit_status);
    break;
  case INVALID_COST_FUNCTION_DERIV:
    fprintf (ptr_asa_out,
             "\n\n  INVALID_COST_FUNCTION_DERIV exit_status = %d\n",
             *exit_status);
    break;
  default:
    fprintf (ptr_asa_out, "\n\n ERR: no exit code available = %d\n",
             *exit_status);
  }

  switch (OPTIONS->Locate_Cost) {
  case 0:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, initial cost temperature\n",
             OPTIONS->Locate_Cost);
    break;
  case 1:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, initial cost value\n", OPTIONS->Locate_Cost);
    break;
  case 2:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, new generated state\n",
             OPTIONS->Locate_Cost);
    break;
  case 12:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, new generated state just after a new best state\n",
             OPTIONS->Locate_Cost);
    break;
  case 3:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, cost derivatives, reannealing parameters\n",
             OPTIONS->Locate_Cost);
    break;
  case 4:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, reannealing cost temperature\n",
             OPTIONS->Locate_Cost);
    break;
  case 5:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, calculating curvatures while exiting asa ()\n",
             OPTIONS->Locate_Cost);
    break;
  case -1:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, exited main asa () loop by user-defined OPTIONS\n",
             OPTIONS->Locate_Cost);
    break;
  default:
    fprintf (ptr_asa_out,
             " Locate_Cost = %d, no index available for Locate_Cost\n",
             OPTIONS->Locate_Cost);
  }

  if (*exit_status != INVALID_USER_INPUT
      && *exit_status != INVALID_COST_FUNCTION
      && *exit_status != INVALID_COST_FUNCTION_DERIV) {
    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_Dbl[0] > (double) MIN_DOUBLE)
    OPTIONS->Asa_Data_Dbl[1] = (double) (*best_number_generated_saved);
#endif

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

#if ASA_PRINT
#if TIME_CALC
  /* print ending time */
  if (ptr_asa_out)
	  print_time ("asa_end", ptr_asa_out);
#endif
  fprintf (ptr_asa_out, "\n\n\n");
  fflush (ptr_asa_out);
#if INCL_STDOUT
  if (ptr_asa_out && (ptr_asa_out != stdout ))
  	fclose (ptr_asa_out);
#endif
#endif

  return (0);
}

/***********************************************************************
* 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 parameters. */
#if ASA_RESOLUTION
    xres = OPTIONS->Coarse_Resolution[index_v];
    if (xres > EPS_DOUBLE) {
      min_parameter_v -= (xres / TWO);
      max_parameter_v += (xres / TWO);
      parameter_range_v = max_parameter_v - min_parameter_v;
    }
#endif /* ASA_RESOLUTION */
    if (INTEGER_PARAMETER (index_v)) {
#if ASA_RESOLUTION
      if (xres > EPS_DOUBLE) {
        ;
      } else {
#endif /* ASA_RESOLUTION */
        min_parameter_v -= HALF;
        max_parameter_v += HALF;
        parameter_range_v = max_parameter_v - min_parameter_v;
      }
#if ASA_RESOLUTION
    }
#endif

    /* 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,
                                       last_saved_state->parameter, OPTIONS);
#else
      x = parameter_v
        + generate_asa_state (user_random_generator, seed, &temperature_v)
        * parameter_range_v;
#endif /* USER_GENERATING_FUNCTION */
#if ASA_RESOLUTION
      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 parameters.
       You might have to check rounding on your machine. */
    if (INTEGER_PARAMETER (index_v)) {
#if ASA_RESOLUTION
      if (xres > EPS_DOUBLE) {
        ;
      } else {
#endif /* ASA_RESOLUTION */
        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];
      }
#if ASA_RESOLUTION
    }
    if (xres > EPS_DOUBLE) {
      if (x < min_parameter_v + xres / TWO)
        x = min_parameter_v + xres / TWO + (double) EPS_DOUBLE;
      if (x > max_parameter_v - xres / TWO)
        x = max_parameter_v - xres / TWO + (double) EPS_DOUBLE;

      if (x > parameter_maximum[index_v])
        x = parameter_maximum[index_v];
      if (x < parameter_minimum[index_v])
        x = parameter_minimum[index_v];
    }
#endif /* ASA_RESOLUTION */

    /* 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;
#if USER_ACCEPT_ASYMP_EXP
  double q;
#endif
#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,
                              parameter_minimum,
                              parameter_maximum, *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 */

#if USER_ACCEPT_THRESHOLD       /* USER_ACCEPT_THRESHOLD */
  prob_test = delta_cost <= 1.0 ? 1.0 : 0.0;
#else /* Metropolis */
  prob_test = MIN (ONE, (F_EXP (EXPONENT_CHECK (-delta_cost))));
#endif /* USER_ACCEPT_THRESHOLD */

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

    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;

  double xnumber_parameters[1];

  cost_test = cost_function_test (last_saved_state->cost,
                                  last_saved_state->parameter,
                                  parameter_minimum,
                                  parameter_maximum, number_parameters,
                                  xnumber_parameters);

  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],
                   *xnumber_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
                                                          /
                                                          *xnumber_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
                                                 / *xnumber_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,
                                             *xnumber_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, *xnumber_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
                                                                    /
                                                                    *xnumber_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
                                               / *xnumber_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;
  int immediate_flag;
  double xnumber_parameters[1];

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

  /* save Immediate_Exit flag */
  immediate_flag = OPTIONS->Immediate_Exit;

  /* 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 (cost_function_test (current_generated_state->cost,
                          current_generated_state->parameter,
                          parameter_minimum,
                          parameter_maximum, number_parameters,
                          xnumber_parameters) == 0) {
    *exit_status = INVALID_COST_FUNCTION_DERIV;
    return;
  }
  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 (cost_function_test (current_generated_state->cost,
                            current_generated_state->parameter,
                            parameter_minimum,
                            parameter_maximum, number_parameters,
                            xnumber_parameters) == 0) {
      *exit_status = INVALID_COST_FUNCTION_DERIV;
      return;
    }
    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 (cost_function_test
          (current_generated_state->cost,
           current_generated_state->parameter, parameter_minimum,
           parameter_maximum, number_parameters, xnumber_parameters) == 0) {
        *exit_status = INVALID_COST_FUNCTION_DERIV;
        return;
      }
      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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 (cost_function_test (current_generated_state->cost,
                                current_generated_state->parameter,
                                parameter_minimum,
                                parameter_maximum, number_parameters,
                                xnumber_parameters) == 0) {
          *exit_status = INVALID_COST_FUNCTION_DERIV;
          return;
        }
        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 Immediate_Exit flag */
  OPTIONS->Immediate_Exit = immediate_flag;

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

/***********************************************************************
* asa_test_asa_options
*       Tests user's selected options
***********************************************************************/
#if HAVE_ANSI
int

asa_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

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

  VFOR (index_v) if (parameter_minimum[index_v] > parameter_maximum[index_v]) {
    strcpy (exit_msg, "*** parameter_minimum[] > parameter_maximum[] ***");
    print_string_index (ptr_asa_out, exit_msg, index_v);
    ++invalid;
  }
  VFOR (index_v)
    if (parameter_initial_final[index_v] < parameter_minimum[index_v]) {
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    strcpy (exit_msg, "*** parameter_initial[] < parameter_minimum[] ***");
    print_string_index (ptr_asa_out, exit_msg, index_v);
    ++invalid;
  }
  VFOR (index_v)
    if (parameter_initial_final[index_v] > parameter_maximum[index_v]) {
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
    strcpy (exit_msg, "*** parameter_initial[] > parameter_maximum[] ***");
    print_string_index (ptr_asa_out, exit_msg, index_v);
    ++invalid;
  }
  if (*number_parameters < 1) {
    strcpy (exit_msg, "*** *number_parameters < 1 ***");
    print_string (ptr_asa_out, exit_msg);
    ++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) {
    strcpy (exit_msg,
            "*** parameter_type[] != -2 && parameter_type[] != 2 && parameter_type[] != -1 && parameter_type[] != 1 ***");
    print_string_index (ptr_asa_out, exit_msg, index_v);
    ++invalid;
  }

  if (OPTIONS_FILE != FALSE && OPTIONS_FILE != TRUE) {
    strcpy (exit_msg,
            "*** OPTIONS_FILE != FALSE && OPTIONS_FILE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (OPTIONS_FILE_DATA != FALSE && OPTIONS_FILE_DATA != TRUE) {
    strcpy (exit_msg,
            "*** OPTIONS_FILE_DATA != FALSE && OPTIONS_FILE_DATA != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (RECUR_OPTIONS_FILE != FALSE && RECUR_OPTIONS_FILE != TRUE) {
    strcpy (exit_msg,
            "*** RECUR_OPTIONS_FILE != FALSE && RECUR_OPTIONS_FILE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (RECUR_OPTIONS_FILE_DATA != FALSE && RECUR_OPTIONS_FILE_DATA != TRUE) {
    strcpy (exit_msg,
            "*** RECUR_OPTIONS_FILE_DATA != FALSE && RECUR_OPTIONS_FILE_DATA != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (COST_FILE != FALSE && COST_FILE != TRUE) {
    strcpy (exit_msg, "*** COST_FILE != FALSE && COST_FILE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_LIB != FALSE && ASA_LIB != TRUE) {
    strcpy (exit_msg, "*** ASA_LIB != FALSE && ASA_LIB != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (MY_TEMPLATE != FALSE && MY_TEMPLATE != TRUE) {
    strcpy (exit_msg, "*** MY_TEMPLATE != FALSE && MY_TEMPLATE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_LIB != FALSE && ASA_TEMPLATE_LIB != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_LIB != FALSE && ASA_TEMPLATE_LIB != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (HAVE_ANSI != FALSE && HAVE_ANSI != TRUE) {
    strcpy (exit_msg, "*** HAVE_ANSI != FALSE && HAVE_ANSI != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (IO_PROTOTYPES != FALSE && IO_PROTOTYPES != TRUE) {
    strcpy (exit_msg,
            "*** IO_PROTOTYPES != FALSE && IO_PROTOTYPES != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (TIME_CALC != FALSE && TIME_CALC != TRUE) {
    strcpy (exit_msg, "*** TIME_CALC != FALSE && TIME_CALC != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (TIME_STD != FALSE && TIME_STD != TRUE) {
    strcpy (exit_msg, "*** TIME_STD != FALSE && TIME_STD != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (TIME_GETRUSAGE != FALSE && TIME_GETRUSAGE != TRUE) {
    strcpy (exit_msg,
            "*** TIME_GETRUSAGE != FALSE && TIME_GETRUSAGE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (INT_LONG != FALSE && INT_LONG != TRUE) {
    strcpy (exit_msg, "*** INT_LONG != FALSE && INT_LONG != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (INT_ALLOC != FALSE && INT_ALLOC != TRUE) {
    strcpy (exit_msg, "*** INT_ALLOC != FALSE && INT_ALLOC != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (SMALL_FLOAT < ZERO) {
    strcpy (exit_msg, "*** SMALL_FLOAT < ZERO ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (MIN_DOUBLE < ZERO) {
    strcpy (exit_msg, "*** MIN_DOUBLE < ZERO ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (MAX_DOUBLE < ZERO) {
    strcpy (exit_msg, "*** MAX_DOUBLE < ZERO ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (EPS_DOUBLE < ZERO) {
    strcpy (exit_msg, "*** EPS_DOUBLE < ZERO ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (CHECK_EXPONENT != FALSE && CHECK_EXPONENT != TRUE) {
    strcpy (exit_msg,
            "*** CHECK_EXPONENT != FALSE && CHECK_EXPONENT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (NO_PARAM_TEMP_TEST != FALSE && NO_PARAM_TEMP_TEST != TRUE) {
    strcpy (exit_msg,
            "*** NO_PARAM_TEMP_TEST != FALSE && NO_PARAM_TEMP_TEST != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (NO_COST_TEMP_TEST != FALSE && NO_COST_TEMP_TEST != TRUE) {
    strcpy (exit_msg,
            "*** NO_COST_TEMP_TEST != FALSE && NO_COST_TEMP_TEST != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (SELF_OPTIMIZE != FALSE && SELF_OPTIMIZE != TRUE) {
    strcpy (exit_msg,
            "*** SELF_OPTIMIZE != FALSE && SELF_OPTIMIZE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEST != FALSE && ASA_TEST != TRUE) {
    strcpy (exit_msg, "*** ASA_TEST != FALSE && ASA_TEST != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEST_POINT != FALSE && ASA_TEST_POINT != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEST_POINT != FALSE && ASA_TEST_POINT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE != FALSE) {
    strcpy (exit_msg, "*** ASA_TEMPLATE != FALSE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_ASA_OUT_PID != FALSE && ASA_TEMPLATE_ASA_OUT_PID != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_ASA_OUT_PID != FALSE && ASA_TEMPLATE_ASA_OUT_PID != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_MULTIPLE != FALSE && ASA_TEMPLATE_MULTIPLE != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_MULTIPLE != FALSE && ASA_TEMPLATE_MULTIPLE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_SELFOPT != FALSE && ASA_TEMPLATE_SELFOPT != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_SELFOPT != FALSE && ASA_TEMPLATE_SELFOPT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_SAMPLE != FALSE && ASA_TEMPLATE_SAMPLE != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_SAMPLE != FALSE && ASA_TEMPLATE_SAMPLE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_QUEUE != FALSE && ASA_TEMPLATE_QUEUE != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_QUEUE != FALSE && ASA_TEMPLATE_QUEUE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_PARALLEL != FALSE && ASA_TEMPLATE_PARALLEL != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_PARALLEL != FALSE && ASA_TEMPLATE_PARALLEL != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_TEMPLATE_SAVE != FALSE && ASA_TEMPLATE_SAVE != TRUE) {
    strcpy (exit_msg,
            "*** ASA_TEMPLATE_SAVE != FALSE && ASA_TEMPLATE_SAVE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_INITIAL_COST_TEMP != FALSE && USER_INITIAL_COST_TEMP != TRUE) {
    strcpy (exit_msg,
            "*** USER_INITIAL_COST_TEMP != FALSE && USER_INITIAL_COST_TEMP != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (RATIO_TEMPERATURE_SCALES != FALSE && RATIO_TEMPERATURE_SCALES != TRUE) {
    strcpy (exit_msg,
            "*** RATIO_TEMPERATURE_SCALES != FALSE && RATIO_TEMPERATURE_SCALES != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_INITIAL_PARAMETERS_TEMPS != FALSE
      && USER_INITIAL_PARAMETERS_TEMPS != TRUE) {
    strcpy (exit_msg,
            "*** USER_INITIAL_PARAMETERS_TEMPS != FALSE && USER_INITIAL_PARAMETERS_TEMPS != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (DELTA_PARAMETERS != FALSE && DELTA_PARAMETERS != TRUE) {
    strcpy (exit_msg,
            "*** DELTA_PARAMETERS != FALSE && DELTA_PARAMETERS != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (QUENCH_PARAMETERS != FALSE && QUENCH_PARAMETERS != TRUE) {
    strcpy (exit_msg,
            "*** QUENCH_PARAMETERS != FALSE && QUENCH_PARAMETERS != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (QUENCH_COST != FALSE && QUENCH_COST != TRUE) {
    strcpy (exit_msg, "*** QUENCH_COST != FALSE && QUENCH_COST != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (QUENCH_PARAMETERS_SCALE != FALSE && QUENCH_PARAMETERS_SCALE != TRUE) {
    strcpy (exit_msg,
            "*** QUENCH_PARAMETERS_SCALE != FALSE && QUENCH_PARAMETERS_SCALE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (QUENCH_COST_SCALE != FALSE && QUENCH_COST_SCALE != TRUE) {
    strcpy (exit_msg,
            "*** QUENCH_COST_SCALE != FALSE && QUENCH_COST_SCALE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (OPTIONAL_DATA_DBL != FALSE && OPTIONAL_DATA_DBL != TRUE) {
    strcpy (exit_msg,
            "*** OPTIONAL_DATA_DBL != FALSE && OPTIONAL_DATA_DBL != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (OPTIONAL_DATA_INT != FALSE && OPTIONAL_DATA_INT != TRUE) {
    strcpy (exit_msg,
            "*** OPTIONAL_DATA_INT != FALSE && OPTIONAL_DATA_INT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (OPTIONAL_DATA_PTR != FALSE && OPTIONAL_DATA_PTR != TRUE) {
    strcpy (exit_msg,
            "*** OPTIONAL_DATA_PTR != FALSE && OPTIONAL_DATA_PTR != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_COST_SCHEDULE != FALSE && USER_COST_SCHEDULE != TRUE) {
    strcpy (exit_msg,
            "*** USER_COST_SCHEDULE != FALSE && USER_COST_SCHEDULE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_ACCEPT_ASYMP_EXP != FALSE && USER_ACCEPT_ASYMP_EXP != TRUE) {
    strcpy (exit_msg,
            "*** USER_ACCEPT_ASYMP_EXP != FALSE && USER_ACCEPT_ASYMP_EXP != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_ACCEPT_THRESHOLD != FALSE && USER_ACCEPT_THRESHOLD != TRUE) {
    strcpy (exit_msg,
            "*** USER_ACCEPT_THRESHOLD != FALSE && USER_ACCEPT_THRESHOLD != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_ACCEPTANCE_TEST != FALSE && USER_ACCEPTANCE_TEST != TRUE) {
    strcpy (exit_msg,
            "*** USER_ACCEPTANCE_TEST != FALSE && USER_ACCEPTANCE_TEST != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_GENERATING_FUNCTION != FALSE && USER_GENERATING_FUNCTION != TRUE) {
    strcpy (exit_msg,
            "*** USER_GENERATING_FUNCTION != FALSE && USER_GENERATING_FUNCTION != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_REANNEAL_COST != FALSE && USER_REANNEAL_COST != TRUE) {
    strcpy (exit_msg,
            "*** USER_REANNEAL_COST != FALSE && USER_REANNEAL_COST != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_REANNEAL_PARAMETERS != FALSE && USER_REANNEAL_PARAMETERS != TRUE) {
    strcpy (exit_msg,
            "*** USER_REANNEAL_PARAMETERS != FALSE && USER_REANNEAL_PARAMETERS != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (MAXIMUM_REANNEAL_INDEX < 1) {
    strcpy (exit_msg, "*** MAXIMUM_REANNEAL_INDEX < 1 ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (REANNEAL_SCALE < ZERO) {
    strcpy (exit_msg, "*** REANNEAL_SCALE < ZERO ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_SAMPLE != FALSE && ASA_SAMPLE != TRUE) {
    strcpy (exit_msg, "*** ASA_SAMPLE != FALSE && ASA_SAMPLE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_QUEUE != FALSE && ASA_QUEUE != TRUE) {
    strcpy (exit_msg, "*** ASA_QUEUE != FALSE && ASA_QUEUE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_RESOLUTION != FALSE && ASA_RESOLUTION != TRUE) {
    strcpy (exit_msg,
            "*** ASA_RESOLUTION != FALSE && ASA_RESOLUTION != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (FITLOC != FALSE && FITLOC != TRUE) {
    strcpy (exit_msg, "*** FITLOC != FALSE && FITLOC != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (FITLOC_ROUND != FALSE && FITLOC_ROUND != TRUE) {
    strcpy (exit_msg,
            "*** FITLOC_ROUND != FALSE && FITLOC_ROUND != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (FITLOC_PRINT != FALSE && FITLOC_PRINT != TRUE) {
    strcpy (exit_msg,
            "*** FITLOC_PRINT != FALSE && FITLOC_PRINT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (MULTI_MIN != FALSE && MULTI_MIN != TRUE) {
    strcpy (exit_msg, "*** MULTI_MIN != FALSE && MULTI_MIN != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
#if MULTI_MIN
  if (OPTIONS->Multi_Number <= 0) {
    strcpy (exit_msg, "*** OPTIONS->Multi_Number <= 0 ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  VFOR (index_v) {
    if (((OPTIONS->Multi_Grid[index_v]) != (OPTIONS->Multi_Grid[index_v]))
        || OPTIONS->Multi_Grid[index_v] < 0) {
      strcpy (exit_msg,
              "*** (OPTIONS->Multi_Grid[]) != (OPTIONS->Multi_Grid[]) || OPTIONS->Multi_Grid[] < 0 ***");
      print_string_index (ptr_asa_out, exit_msg, index_v);
      ++invalid;
    }
  }
  if (OPTIONS->Multi_Specify != 0 && OPTIONS->Multi_Specify != 1) {
    strcpy (exit_msg,
            "*** OPTIONS->Multi_Specify != 0 && OPTIONS->Multi_Specify != 1 ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
#endif
  if (ASA_PARALLEL != FALSE && ASA_PARALLEL != TRUE) {
    strcpy (exit_msg,
            "*** ASA_PARALLEL != FALSE && ASA_PARALLEL != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_SAVE != FALSE && ASA_SAVE != TRUE) {
    strcpy (exit_msg, "*** ASA_SAVE != FALSE && ASA_SAVE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_SAVE_OPT != FALSE && ASA_SAVE_OPT != TRUE) {
    strcpy (exit_msg,
            "*** ASA_SAVE_OPT != FALSE && ASA_SAVE_OPT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_SAVE_BACKUP != FALSE && ASA_SAVE_BACKUP != TRUE) {
    strcpy (exit_msg,
            "*** ASA_SAVE_BACKUP != FALSE && ASA_SAVE_BACKUP != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_PIPE != FALSE && ASA_PIPE != TRUE) {
    strcpy (exit_msg, "*** ASA_PIPE != FALSE && ASA_PIPE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_PIPE_FILE != FALSE && ASA_PIPE_FILE != TRUE) {
    strcpy (exit_msg,
            "*** ASA_PIPE_FILE != FALSE && ASA_PIPE_FILE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (SYSTEM_CALL != FALSE && SYSTEM_CALL != TRUE) {
    strcpy (exit_msg, "*** SYSTEM_CALL != FALSE && SYSTEM_CALL != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (FDLIBM_POW != FALSE && FDLIBM_POW != TRUE) {
    strcpy (exit_msg, "*** FDLIBM_POW != FALSE && FDLIBM_POW != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (FDLIBM_LOG != FALSE && FDLIBM_LOG != TRUE) {
    strcpy (exit_msg, "*** FDLIBM_LOG != FALSE && FDLIBM_LOG != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (FDLIBM_EXP != FALSE && FDLIBM_EXP != TRUE) {
    strcpy (exit_msg, "*** FDLIBM_EXP != FALSE && FDLIBM_EXP != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_PRINT != FALSE && ASA_PRINT != TRUE) {
    strcpy (exit_msg, "*** ASA_PRINT != FALSE && ASA_PRINT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (USER_ASA_OUT != FALSE && USER_ASA_OUT != TRUE) {
    strcpy (exit_msg,
            "*** USER_ASA_OUT != FALSE && USER_ASA_OUT != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_PRINT_INTERMED != FALSE && ASA_PRINT_INTERMED != TRUE) {
    strcpy (exit_msg,
            "*** ASA_PRINT_INTERMED != FALSE && ASA_PRINT_INTERMED != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (ASA_PRINT_MORE != FALSE && ASA_PRINT_MORE != TRUE) {
    strcpy (exit_msg,
            "*** ASA_PRINT_MORE != FALSE && ASA_PRINT_MORE != TRUE ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (G_FIELD < 0) {
    strcpy (exit_msg, "*** G_FIELD < 0 ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }
  if (G_PRECISION < 0) {
    strcpy (exit_msg, "*** G_PRECISION < 0 ***");
    print_string (ptr_asa_out, exit_msg);
    ++invalid;
  }

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

  return (invalid);
}



/***********************************************************************
* cost_function_test
*       Tests user's returned cost function values and parameters
***********************************************************************/
#if HAVE_ANSI
int

cost_function_test (double cost,
                    double *parameter,
                    double *parameter_minimum,
                    double *parameter_maximum,
                    ALLOC_INT * number_parameters, double *xnumber_parameters)
#else
int

cost_function_test (cost,
                    parameter,
                    parameter_minimum, parameter_maximum,
                    number_parameters, xnumber_parameters)
     double cost;
     double *parameter;
     double *parameter_minimum;
     double *parameter_maximum;
     ALLOC_INT *number_parameters;
     double *xnumber_parameters;
#endif /* HAVE_ANSI */
{
  ALLOC_INT index_v;
  int test_flag;

  test_flag = 1;

  if (((cost) != (cost)) || (cost < -MAX_DOUBLE || cost > MAX_DOUBLE))
    test_flag = 0;

  *xnumber_parameters = (double) *number_parameters;
  VFOR (index_v) {
    if (PARAMETER_RANGE_TOO_SMALL (index_v)) {
      *xnumber_parameters -= 1.0;
      continue;
    }
    if (parameter[index_v] < parameter_minimum[index_v] ||
        parameter[index_v] > parameter_maximum[index_v]) {
      test_flag = 0;
    }
  }

  return (test_flag);
}



/***********************************************************************
* 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 INCL_STDOUT
  printf ("\n\n%s\n\n", string);
#endif /* INCL_STDOUT */
#if ASA_PRINT
  fprintf (ptr_asa_out, "\n\n%s\n\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 INCL_STDOUT
#if INT_ALLOC
  printf ("\n\n%s index = %d\n\n", string, index);
#else /* INT_ALLOC */
#if INT_LONG
  printf ("\n\n%s index = %ld\n\n", string, index);
#else /* INT_LONG */
  printf ("\n\n%s index = %ld\n\n", string, index);
#endif /* INT_LONG */
#endif /* INT_ALLOC */
#endif /* INCL_STDOUT */

#if ASA_PRINT
#if INT_ALLOC
  fprintf (ptr_asa_out, "\n\n%s index = %d\n\n", string, index);
#else /* INT_ALLOC */
#if INT_LONG
  fprintf (ptr_asa_out, "\n\n%s index = %ld\n\n", string, index);
#else /* INT_LONG */
  fprintf (ptr_asa_out, "\n\n%s index = %d\n\n", string, index);
#endif /* INT_LONG */
#endif /* INT_ALLOC */
#else /* ASA_PRINT */
  ;
#endif /* ASA_PRINT */
}

#if  !ASA_SAVE && !ASA_FILE_PIPE
#undef fprintf
#undef fflush
#endif  /*!ASA_SAVE && !ASA_FILE_PIPE*/

#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 DROPPED_PARAMETERS
    if (PARAMETER_RANGE_TOO_SMALL (index_v))
      continue;
#endif
    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, "TIME_GETRUSAGE = %d\n", (int) TIME_GETRUSAGE);
  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_DBL = %d\n", (int) OPTIONAL_DATA_DBL);
  fprintf (ptr_asa_out, "OPTIONAL_DATA_INT = %d\n", (int) OPTIONAL_DATA_INT);
  fprintf (ptr_asa_out, "OPTIONAL_DATA_PTR = %d\n", (int) OPTIONAL_DATA_PTR);
  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_ACCEPT_THRESHOLD = %d\n",
           (int) USER_ACCEPT_THRESHOLD);
  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, "FITLOC = %d\n", (int) FITLOC);
  fprintf (ptr_asa_out, "FITLOC_ROUND = %d\n", (int) FITLOC_ROUND);
  fprintf (ptr_asa_out, "FITLOC_PRINT = %d\n", (int) FITLOC_PRINT);
  fprintf (ptr_asa_out, "MULTI_MIN = %d\n", (int) MULTI_MIN);
  fprintf (ptr_asa_out, "ASA_PARALLEL = %d\n", (int) ASA_PARALLEL);
  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);
  fprintf (ptr_asa_out, "USER_OUT = %s\n", USER_OUT);
#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, "INCL_STDOUT = %d\n", (int) INCL_STDOUT);
  fprintf (ptr_asa_out, "G_FIELD = %d\n", (int) G_FIELD);
  fprintf (ptr_asa_out, "G_PRECISION = %d\n", (int) G_PRECISION);
  fprintf (ptr_asa_out, "ASA_SAVE = %d\n", (int) ASA_SAVE);
  fprintf (ptr_asa_out, "ASA_SAVE_OPT = %d\n", (int) ASA_SAVE_OPT);
  fprintf (ptr_asa_out, "ASA_SAVE_BACKUP = %d\n", (int) ASA_SAVE_BACKUP);
  fprintf (ptr_asa_out, "ASA_PIPE = %d\n", (int) ASA_PIPE);
  fprintf (ptr_asa_out, "ASA_PIPE_FILE = %d\n", (int) ASA_PIPE_FILE);
  fprintf (ptr_asa_out, "SYSTEM_CALL = %d\n\n", (int) SYSTEM_CALL);

#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", OPTIONS->Curvature_0);
  fprintf (ptr_asa_out, "OPTIONS->Asa_Recursive_Level = %d\n\n",
           OPTIONS->Asa_Recursive_Level);

  fprintf (ptr_asa_out, "\n");
}
#endif /* ASA_PRINT */

#if TIME_CALC
#if TIME_GETRUSAGE
/***********************************************************************
* 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);
}
#else /* TIME_GETRUSAGE */
  /* Note that on many machines the time resolution of this algorithm
   * may be less than the other alternatives, e.g., rounding off the
   * number of ticks to the nearest tens of thousands.  Also, because
   * time here is typically indexed by a long integer, there typically
   * is a cycle of time in periods of fractions of an hour.  For
   * example, under Solaris 2.5.1:  The value returned by clock() is
   * defined in microseconds, since the first call to clock(), for
   *  compatibility with  systems that have * CPU clocks with much higher
   * resolution.  Because of this, the value returned will wrap around
   * after accumulating only 2147 seconds of CPU time (about 36 minutes).
   *
   * Set TIME_GETRUSAGE to FALSE and TIME_STD to TRUE under
   * Cygwin with -mno-cygwin
   *
   * See asa.h for two places where some additional modifications should
   * be made under SunOS 4.1.x. */

#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 */
{
  aux_print_time (clock (), message, ptr_asa_out);

}                               /*print_time */

/***********************************************************************
* aux_print_time
*      auxiliary print the time routine
***********************************************************************/
#if HAVE_ANSI
void
aux_print_time (clock_t time, char *message, FILE * ptr_asa_out)
#else
void
aux_print_time (time, message, ptr_asa_out)
     clock_t time;
     char *message;
     FILE *ptr_asa_out;
#endif /* HAVE_ANSI */
{
  static clock_t previousTime = -1;
  clock_t diffTime;
  double clocksPerSecF = CLOCKS_PER_SEC;
  double timeF, diffF;
  double s, m, h;
  double ds, dm, dh;

  if (previousTime != -1) {
    diffTime = time - previousTime;
    timeF = time;
    diffF = diffTime;
    previousTime = time;

    s = timeF / clocksPerSecF;
    ds = diffF / clocksPerSecF;

    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);

    fprintf (ptr_asa_out,
             "%s:time: %gh %gm %gs; incr: %gh %gm %gs\n",
             message, h, m, s, dh, dm, ds);
  } else {
    /* The first call will be invalid - don't output anything. */
    fprintf (ptr_asa_out, "TIMING PARAMETERS: ticks/sec: %lu\n",
             CLOCKS_PER_SEC);
    previousTime = time;
    /* Output initial message. */
    print_time (message, ptr_asa_out);
  }
}                               /* aux_print_time */

#endif /* TIME_GETRUSAGE */

#endif /* TIME_CALC */

#if MULTI_MIN
#if HAVE_ANSI
static int
multi_compare (const void *ii, const void *jj)
#else /* HAVE_ANSI */
static int
multi_compare (ii, jj)
     char *ii;
     char *jj;
#endif /* HAVE_ANSI */
{
  int i;
  int j;

  i = *(int *) ii;
  j = *(int *) jj;

  if (multi_cost_qsort[i] > multi_cost_qsort[j] + (double) EPS_DOUBLE)
    return (1);
  else if (multi_cost_qsort[i] < multi_cost_qsort[j] - (double) EPS_DOUBLE)
    return (-1);
  else
    return (0);
}
#endif /* MULTI_MIN */

#if ASA_PARALLEL
#if HAVE_ANSI
static int
sort_parallel (const void *ii, const void *jj)
#else /* HAVE_ANSI */
static int
sort_parallel (ii, jj)
     void *ii;
     void *jj;
#endif /* HAVE_ANSI */
{
  LONG_INT i;
  LONG_INT j;

  i = *(LONG_INT *) ii;
  j = *(LONG_INT *) jj;

  if (gener_block_state_qsort[i].cost > gener_block_state_qsort[j].cost)
    return (1);
  else if (gener_block_state_qsort[i].cost < gener_block_state_qsort[j].cost)
    return (-1);
  else
    return (0);
}
#endif /* ASA_PARALLEL */
#if HAVE_ANSI
void
Exit_ASA (char *statement)
#else /* HAVE_ANSI */
void
Exit_ASA (statement)
     char *statement;
#endif /* HAVE_ANSI */
{
#if INCL_STDOUT
  printf ("\n\n*** EXIT calloc failed in ASA *** %s\n\n", statement);
#else
  ;
#endif /* INCL_STDOUT */
}
