/*
 * $Id: gs_set.cpp 2422 2014-09-29 19:27:29Z johnoel $
 *
 * Author: David Fournier
 * Copyright (c) 2008-2012 Regents of the University of California
 */
/**
 * \file
 * Functions for setting memory allocation and array limits
 */
#include "fvar.hpp"
#ifdef __TURBOC__
  #pragma hdrstop
#endif
#include <limits.h>

/**
 * Produce error if gradient structure hasn't been set
 * \param variable_name string with variable name
 */
void gradient_structure::check_set_error(const char* variable_name)
{
  if (instances > 0)
  {
    cerr << "Error -- variable '" << variable_name <<"' must be set before\n"
            "declaration of gradient_structure object.\n";
    ad_exit(1);
  }
}

/**
 * Set the return arrays size controlling the amount of complexity that
 * one line of arithmetic can have
 * \param i size of return arrays
 */
void gradient_structure::set_RETURN_ARRAYS_SIZE(int i)
{
  RETURN_ARRAYS_SIZE=i;
}

/**
 * Set the maximum allowable depth of nesting of functions that return autodif
 * variable types
 * \param i number of return arrays
 */
void gradient_structure::set_NUM_RETURN_ARRAYS(int i)
{
  check_set_error("NUM_RETURN_ARRAYS");
  NUM_RETURN_ARRAYS = i;
}

/**
 * Set the the maximum amount of memory (in bytes) available for
 * the autodif variable type container class objects
 * \param i value in bytes
 */
void gradient_structure::set_ARRAY_MEMBLOCK_SIZE(unsigned long i)
{
  cerr << " This is not the way to set the ARRAY_MEMBLOCK_SIZE -- sorry\n"
    " You set it by declaring the number of bytes you want in the\n";
  cerr << " declaration  gradient_structure gs(num_bytes)\n"
  " in your program .. the default value is 100000L\n";
  ad_exit(1);
  check_set_error("ARRAY_MEMBLOCK_SIZE");
}

/**
 * Set the size in bytes of the buffer used to contain the information
 * generated by the "precompiled" derivative code
 * \param i value in bytes
 */
#ifdef __BORLANDC__
void gradient_structure::set_CMPDIF_BUFFER_SIZE(long int i)
#else
void gradient_structure::set_CMPDIF_BUFFER_SIZE(const size_t i)
#endif
{
#ifdef __BORLANDC__
  if ( (unsigned long int) (LONG_MAX) < (unsigned long int)i)
  {
    long int max_size=LONG_MAX;

    cerr << "\n\n It appears that the size you are setting for "
      "the\n CMPDIF_BUFFER is > " <<  LONG_MAX <<
      "This appears\n to be an error. The maximum size argument ";
    cerr << "for the function\n"
      "--- gradient_structure::set_CMPDIF_BUFFER_SIZE(long long int i) ---\n"
      "should probably be  " << max_size << endl;
  }
#else
  if (i > ULONG_MAX)
  {
    cerr << "\n\n It appears that the size you are setting for "
      "the\n CMPDIF_BUFFER is > " <<  ULONG_MAX <<
      "This appears\n to be an error. The maximum size argument ";
    cerr << "for the function\n"
      "--- gradient_structure::set_CMPDIF_BUFFER_SIZE(long long int i) ---\n"
      "should probably be  " << ULONG_MAX << endl;
  }
#endif
  check_set_error("CMPDIF_BUFFER_SIZE");
  CMPDIF_BUFFER_SIZE = i;
}

/**
 * Set the number of entries contained in the buffer that, in turn, contains the
 * information necessary for calculating derivatives. For historical reasons,
 * the actual amount of memory (in bytes) reserved for the buffer is equal to
 * the value of GRADSTACK_BUFFER_SIZE multiplied by the size (in bytes) of an
 * autodif structure, grad_stack_entry.
 * See also set_GRADSTACK_BUFFER_BYTES which performs the same function
 * but with input in units of bytes
 * \param i memory allocation in units of "gs_size" (which is about 36 bytes)
 */
#ifdef __BORLANDC__
void gradient_structure::set_GRADSTACK_BUFFER_SIZE(long int i)
#else
void gradient_structure::set_GRADSTACK_BUFFER_SIZE(const size_t i)
#endif
{
#ifdef __BORLANDC__
  long int gs_size=(long int) (sizeof(grad_stack_entry));

  if ( (unsigned long int) (LONG_MAX) < gs_size *i)
  {
    unsigned int max_size=LONG_MAX/gs_size;

    cerr << "\n\n It appears that the size you are setting for "
      "the\n GRADSTACK_BUFFER is > " << LONG_MAX <<
      "This appears\n to be an error. The maximum size argument ";
    cerr << "for the function\n"
      "--- gradient_structure::set_GRADSTACK_BUFFER_SIZE(long long int i) ---\n"
      "should probably be  " << max_size << endl;
    cerr << "Note: the Borland compiler limit is a long integer\n"
      "      other compilers allow long long integers" << endl;
    cerr << "LONG_MAX = " << (unsigned long int) (LONG_MAX) << endl;
    cerr << " i = " << i << endl;
    cerr << " gs_size = " << gs_size << endl;
    cerr << " i*gs_size = " << i*gs_size << endl;
  }
#else
  if (i > ULONG_MAX)
  {
    cerr << "\n\n It appears that the size you are setting for "
      "the\n GRADSTACK_BUFFER is > " << ULONG_MAX <<
      "This appears\n to be an error. The maximum size argument ";

    size_t max_size = size_t(ULONG_MAX) / sizeof(grad_stack_entry);
    cerr << "for the function\n"
      "--- gradient_structure::set_GRADSTACK_BUFFER_SIZE(long long int i) ---\n"
      "should probably be  " << max_size << endl;
    cerr << "ULONG_MAX = " << ULONG_MAX << endl;
    cerr << " i = " << i << endl;
    cerr << " max_size = " << max_size << endl;
    cerr << " total = " << max_size * i << endl;
  }
#endif
  check_set_error("GRADSTACK_BUFFER_SIZE");
  GRADSTACK_BUFFER_SIZE = i;
}

/**
 * Set (in bytes) the number of entries contained in the buffer used for
 * calculating derivatives. This is an alternative to
 * set_GRADSTACK_BUFFER_SIZE which is in units of "gs_size" rather than bytes.
 * \author Ian Taylor
 * \param i memory allocation in bytes
 */
#ifdef __BORLANDC__
void gradient_structure::set_GRADSTACK_BUFFER_BYTES(long int i)
#else
void gradient_structure::set_GRADSTACK_BUFFER_BYTES(const size_t i)
#endif
{
#ifdef __BORLANDC__
  long int gs_size=(long int) (sizeof(grad_stack_entry));

  if ( (unsigned long int) (LONG_MAX) < i)
  {
    unsigned int max_size=LONG_MAX;

    cerr << "\n\n It appears that the size you are setting for "
      "the\n GRADSTACK_BUFFER is > " << LONG_MAX <<
      "This appears\n to be an error. The maximum size argument ";
    cerr << "for the function\n"
      "--- gradient_structure::set_GRADSTACK_BUFFER_BYTES(long int i) ---\n"
      "should probably be  " << max_size << endl;
    cerr << "LONG_MAX = " << (unsigned long int) (LONG_MAX) << endl;
    cerr << " i = " << i << endl;
    cerr << "Note: the Borland compiler limit is a long integer\n"
      "      other compilers allow long long integers" << endl;
  }
#else
  if (i > ULONG_MAX)
  {
    size_t max_size = ULONG_MAX;

    cerr << "\n\n It appears that the size you are setting for "
      "the\n GRADSTACK_BUFFER is > " << ULONG_MAX <<
      "This appears\n to be an error. The maximum size argument ";
    cerr << "for the function\n"
     "--- gradient_structure::set_GRADSTACK_BUFFER_BYTES(long long int i) ---\n"
      "should probably be  " << max_size << endl;
    cerr << "ULONG_MAX = " << ULONG_MAX << endl;
    cerr << " i = " << i << endl;
  }
  size_t gs_size = sizeof(grad_stack_entry);
#endif
  check_set_error("GRADSTACK_BUFFER_SIZE");
  GRADSTACK_BUFFER_SIZE = i/gs_size;
}

/**
 * Set the the maximum number of independent variables that can be used
 * \param i the value to set
 */
void gradient_structure::set_MAX_NVAR_OFFSET(unsigned int i)
{
  check_set_error("MAX_NVAR_OFFSET");
  MAX_NVAR_OFFSET = i;
}

/**
 * Set the maximum number of dvariable objects that can be in scope at one time
 * \param i the value to set
 */
void gradient_structure::set_MAX_DLINKS(int i)
{
  check_set_error("MAX_DLINKS");
  MAX_DLINKS = i > 0 ? (unsigned int)i : 0;
}
