NEURON interface to GAUL (Neymotin and Lytton)

Accession:102464
This interface allows the use of genetic algorithms for optimization and search in high-dimensional spaces from within the NEURON environment. It includes converted .c,.h files from GAUL wrapped in proper MOD file syntax as well as MOD code interfacing to the library. It also comes with hoc utilitiy functions to make it easier to use the GA.
Tool Information (Click on a link to find other Tools with that property)
Tool Type: Control Simulations;
Simulation Environment: NEURON;
\
neuron_gaul_2
gaul
readme.txt
compatibility.mod
ga_bitstring.mod
ga_chromo.mod
ga_climbing.mod
ga_compare.mod
ga_core.mod
ga_crossover.mod
ga_de.mod
ga_deterministiccrowding.mod
ga_gradient.mod
ga_hoc.mod
ga_intrinsics.mod
ga_io.mod
ga_mutate.mod
ga_optim.mod
ga_qsort.mod
ga_randomsearch.mod
ga_rank.mod
ga_replace.mod
ga_sa.mod
ga_seed.mod
ga_select.mod
ga_similarity.mod
ga_simplex.mod
ga_stats.mod
ga_systematicsearch.mod
ga_tabu.mod
ga_utility.mod
linkedlist.mod
log_util.mod
memory_chunks.mod
memory_util.mod
nn_util.mod
random_util.mod
avltree.mod
table_util.mod
timer_util.mod
vecst.mod
mosinit.hoc
ga_utils.hoc
init.hoc
declist.hoc
setup.hoc
decvec.hoc
ga_test.hoc
gaul.h
xtmp
                            
: $Id: ga_hoc.mod,v 1.17 2007/12/05 15:45:23 samn Exp $

NEURON {
  SUFFIX GA
  GLOBAL verbose
}

PARAMETER {
  verbose = 0
}

VERBATIM

#define MY_MAX_V_SZ 1024
double my_data[MY_MAX_V_SZ];//up to 1024 values

#define MY_MAX_ALLELES 32

double allele_max[MY_MAX_ALLELES]={0.0};
double allele_min[MY_MAX_ALLELES]={0.0};

double alleles[MY_MAX_ALLELES]={0.0};

#include "gaul.h"

int giNumAlleles = 1;
int giPopSize = 2;
int giMaxGen = 1;
int giNumIslands = 1;
int giElitism = GA_ELITISM_PARENTS_SURVIVE;
int giAlleleScale = 0;
int giReseedDups = 0;

//if != 0, alleles HAVE a max upper bound
//note: this is the default
//note: not compatible with mode where alleles are scaled btwn 0 and 1
int giBoundAlleleMax = 1;

double gdCrossover = 0.8;
double gdMutate = 0.95;
double gdMigrate = 0.1;

double gdFitness = 0.0;

double gdBest=0.0,gdAvg=0.0,gdStddev=0.0;

int giSeed = 23091975;

Symbol* pHocFitFunc=0;

#define MAX_NUM_ISLANDS 100

population* gpPop[MAX_NUM_ISLANDS]={0};

#define MY_STR_MAX 2048

char gStatFilePath[MY_STR_MAX]={0};

//default fitness func
#define DEF_FIT_FUNC "GetFitness"

char gFitFuncName[MY_STR_MAX]={0};

char gHocSeedFuncName[MY_STR_MAX]={0};
Symbol* pHocSeedFunc=0;

static double v2data(void* vv) {
  int i, n, num;
  double *x;
  n = vector_instance_px(vv, &x);
  if (n>MY_MAX_V_SZ)
  {
    n = MY_MAX_V_SZ - 1;
    printf("Vector size should be <= %d , only storing first %d values\n",n,n);
  }
  for (i=0; i<n; i++) {my_data[i] = x[i];}
  return (double)n;
}

static double data2v(void* vv,int iSz){
  int i, n, num;
  double *x;
  n = vector_instance_px(vv, &x);
  if (n>MY_MAX_V_SZ)
  {
    n = MY_MAX_V_SZ - 1;
    printf("Vector size should be <= %d , only setting first %d values\n",n,n);
  }
  for (i=0; i<n; i++) {x[i]=my_data[i];}
  return (double)n;
}

static double double2vec(void* vv,double* p,int iMax){

  double* pVec;

  int n = vector_instance_px(vv,&pVec);

  if(n > iMax){
    printf("get_pointer_vals ERRA: vec size %d > max %d\n",n,iMax);
    return 0.0;
  }

  memcpy(pVec,p,sizeof(double)*n);

  return (double) n;
}

static double vec2double(void* vv,double* p,int iMax){
  double* pVec;

  int n = vector_instance_px(vv,&pVec);
  
  if(n > iMax){
    printf("vec2double ERRA: vec size %d > max %d\n",n,iMax);
    return 0.0;
  }

  memcpy(p,pVec,sizeof(double)*n);

  return (double) n;
}

static double get_allele_mins(void* vv) {
  return double2vec(vv,allele_min,MY_MAX_ALLELES);
}

static double get_allele_maxs(void* vv) {
  return double2vec(vv,allele_max,MY_MAX_ALLELES);
}

static double get_alleles(void* vv){
  return double2vec(vv,alleles,MY_MAX_ALLELES);
}

static double set_allele_mins(void* vv) {
  return vec2double(vv,allele_min,MY_MAX_ALLELES);
}

static double set_allele_maxs(void* vv) {
  return vec2double(vv,allele_max,MY_MAX_ALLELES);
}

static double set_alleles(void* vv) {
  return vec2double(vv,alleles,MY_MAX_ALLELES);
}

int PopConverged(population* pop,int iChromeLen){
  if(!pop || iChromeLen < 1) return 0;
  int idx = 0;
  for(idx=0;idx<iChromeLen;idx++){
    if(((double *)pop->entity_iarray[0]->chromosome[0])[idx] !=
       ((double *)pop->entity_iarray[pop->size-1]->chromosome[0])[idx])
    {
      return 0;
    } 
  }
  return 1;
}

//get value scaled to be between 0 and 1
double Scale01(double dInVal,double dMin,double dMax){
  return (dInVal - dMin) / (dMax - dMin);
}

double DeScale01(double dInVal,double dMin,double dMax){
  return (dMax - dMin) * dInVal + dMin;
}

int WriteEntity(char* fname,entity* adam,int iter){
  FILE* fp = fopen(fname,"a");
  if(!fp) return 0;
  fprintf(fp,"gen_iter%d: best alleles",iter);
  int i;
  for(i=0;i<giNumAlleles;i++){
    fprintf(fp,"[%d]=%g ", giAlleleScale ? \
                      DeScale01(((double*)adam->chromosome[0])[i],allele_min[i],allele_max[i]) : \
                      ((double*)adam->chromosome[0])[i]);
  }
  fprintf(fp,"fit=%g\n",adam->fitness);
  fclose(fp);
  return 1;
}

int HocUpdateGenStats(double best,double avg,double stddev,entity* adam){

  //let hoc update generation stats to vectors as well

  Symbol* sym = hoc_lookup("UpdateGenStats"); 

  if(sym){
    int i;
    for(i=0;i<giNumAlleles;i++){
      alleles[i] = giAlleleScale ? \
                    DeScale01(((double*)adam->chromosome[0])[i],allele_min[i],allele_max[i]) : \
                    ((double*)adam->chromosome[0])[i];
    }
     
    //these vals need to be read by hoc func UpdateGenStats
    gdBest   = best;
    gdAvg    = avg;
    gdStddev = stddev;

    hoc_call_func(sym,0);
  }
  else{
    printf("Couldn't lookup hoc function UpdateGenStats\n");
    return 0;
  }
  return 1;
}

//evaluates a member of population
boolean eval_callback(population* pop,entity* adam){

  if(verbose) printf("eval entity w alleles: ");

  int i;

  for(i=0;i<giNumAlleles;i++){

   alleles[i] = pop->allele_scale ? \
                  DeScale01(((double*)adam->chromosome[0])[i],allele_min[i],allele_max[i]) : \
                  ((double*)adam->chromosome[0])[i];
 
   if(alleles[i] < allele_min[i]){
      ((double*)adam->chromosome[0])[i] = alleles[i] = allele_min[i];
    } else if(giBoundAlleleMax && alleles[i] > allele_max[i]){
      ((double*)adam->chromosome[0])[i] = alleles[i] = allele_max[i];
    }

    if(verbose) printf("[%d]=%g, ",i,alleles[i]);
  }

  if(verbose) printf("\n");

  hoc_call_func(pHocFitFunc,0);

  adam->fitness = gdFitness; //set by hoc
  
  return TRUE;
}


//initializes new members of population
boolean seed_callback(population* pop,entity* adam){
  int i;
  if(verbose) printf("init entity w alleles: ");

  if(pHocSeedFunc){

    hoc_call_func(pHocSeedFunc,0); //hoc seed func must call v2data

    for(i=0;i<giNumAlleles;i++){

      double val = my_data[i];
      if(val < allele_min[i]){
        val = allele_min[i];
      } else if(giBoundAlleleMax && val > allele_max[i]){ 
        val = allele_max[i];
      }

      if(pop->allele_scale){
        val = Scale01(val,allele_min[i],allele_max[i]);
      }

      ((double *)adam->chromosome[0])[i] = val;

      if(verbose) printf(" [%d]=%g",i,val);
    }
  } else {

    for(i=0;i<giNumAlleles;i++){

      double val = pop->allele_scale ? \
                     random_double_range(0.0,1.0) : \
                     random_double_range(allele_min[i],allele_max[i]);

      ((double *)adam->chromosome[0])[i] = val;

      if(verbose) printf(" [%d]=%g ",i,val);
    }
  }
  if(verbose) printf("\n");
  return TRUE;
}

void reseed_duplicates(population* pop){
  int i = 0 , j = 0;

  for(i=0;i<pop->size && i<pop->stable_size;i++){
    for(j=0;j<pop->size && j<pop->stable_size;j++){
      if(i==j){
        continue;
      }
      if(ga_compare_genome(pop,pop->entity_iarray[i],pop->entity_iarray[j])){
        plog(verbose,"** Re-seeding duplicate %d ***\n",i);
        seed_callback(pop,pop->entity_iarray[i]);
        eval_callback(pop,pop->entity_iarray[i]); //need to re-evaluate it
        break;
      }
    }
  }
}

//called @ end of each generation (per island)
boolean generation_callback(int generation, population* pop){
  double avg,stddev,best;
  ga_fitness_mean_stddev(pop, &avg, &stddev);
  best = pop->entity_iarray[0]->fitness;

  printf("gen%d:\n\tbest_params:",generation);

  int i;
  for(i=0;i<giNumAlleles;i++){
      printf("[%d]=%g, ",i, \
      pop->allele_scale ? \
        DeScale01(((double*)pop->entity_iarray[0]->chromosome[0])[i],allele_min[i],allele_max[i]) : \
        ((double*)pop->entity_iarray[0]->chromosome[0])[i]);
  }

  printf("\n\t(best fit=%g, mean=%g, stddev=%g)\n",best,avg,stddev);

  if(strlen(gStatFilePath)){
    WriteEntity(gStatFilePath,pop->entity_iarray[0],generation);
    if(verbose) printf("saved generation %d's fitness params to file...\n",generation);
  }

  HocUpdateGenStats(best,avg,stddev,pop->entity_iarray[0]);

  if(giReseedDups){
    reseed_duplicates(pop);
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////

//turns on memory debugging
void MemDebug(){
  memory_set_verbose(3);
  memory_set_strict(3);
  memory_set_bounds(3);
}

void CheckMem(){
  printf("MEMORY_DEBUG=%d\n",MEMORY_DEBUG);
  printf("MEMORY_ALLOC_DEBUG=%d\n",MEMORY_ALLOC_DEBUG);
  printf("MEMORY_ALLOC_SAFE=%d\n",MEMORY_ALLOC_SAFE);
  memory_display_status();
  memory_display_table();
  memory_check_all_bounds();
}

int InitGaul(){
  log_init(LOG_NORMAL, NULL, NULL, FALSE);
  random_seed(giSeed);
  return 1;
}

int ValidParams(){
  int valid = 1;

  if(giNumAlleles < 1 || giNumAlleles > MY_MAX_ALLELES){
    printf("Evolution ERRA: invalid # of alleles %d\n",giNumAlleles);
    valid = 0;
  }

  if(giPopSize < 2){
    printf("Evolution ERRB: invalid population size %d\n",giPopSize);
    valid = 0;
  }

  if(giMaxGen < 1){
    printf("Evolution ERRC: invalid max generation %d\n",giMaxGen);
    valid = 0;
  }

  if(giNumIslands < 1 || giNumIslands > MAX_NUM_ISLANDS){
    printf("Evolution ERRD: invalid num islands %d\n",giNumIslands);
    valid = 0;
  }

  if(gdCrossover < 0.0 || gdCrossover > 1.0){
    printf("Evolution ERRE: invalid crossover rate %f\n",gdCrossover);
    valid = 0;
  }

  if(gdMutate < 0.0 || gdMutate > 1.0){
    printf("Evolution ERRF: invalid mutation rate %f\n",gdMutate);
    valid = 0;
  }

  if(gdMigrate < 0.0 || gdMigrate > 1.0){
    printf("Evolution ERRG: invalid migration rate %f\n",gdMigrate);
    valid = 0;
  }

  if(!strlen(gFitFuncName)){
    strcpy(gFitFuncName,DEF_FIT_FUNC);
    if(verbose) printf("No fitness func specified, using default %s\n",gFitFuncName);
  }

  pHocFitFunc = hoc_lookup(gFitFuncName);
  if(!pHocFitFunc){
    printf("Couldn't find hoc fitness func %s\n",gFitFuncName);
    valid = 0;
  }

  return valid;
}

void PrintSettings(){
  printf("NumIslands=%d\n",giNumIslands);
  printf("PopSize=%d\n",giPopSize);
  printf("NumAlleles=%d\n",giNumAlleles);
  printf("Elitism=%d\n",giElitism);
  printf("Crossover=%.2f\n",gdCrossover);
  printf("Mutate=%.2f\n",gdMutate);
  printf("Migrate=%.2f\n",gdMigrate);
  printf("MaxGen=%d\n",giMaxGen);
  if(gFitFuncName && strlen(gFitFuncName)){
    printf("FitFunc=%s\n",gFitFuncName);
  }
  if(gHocSeedFuncName && strlen(gHocSeedFuncName) && pHocSeedFunc){
    printf("HocSeedFunc=%s %p\n",gHocSeedFuncName,pHocSeedFunc);
  } else {
    printf("Using default seed_callback\n");
  }
  if(giAlleleScale){
    printf("Scaling alleles between 0 and 1 for GA use\n");
  } else {
    printf("NOT scaling alleles\n");
  }
  if(giReseedDups){
    printf("Reseed duplicates each generation\n");
  } else {
    printf("NOT reseeding duplicates each generation\n");
  }
  if(!giBoundAlleleMax){
    printf("No upper bound on allele values!\n");
  } else {
    printf("Using an upper bound on allele values\n");
  }
  printf("Random # Generator Seed = %d\n",giSeed);
}


ENDVERBATIM

: perform evolution
FUNCTION Evolution(){
  VERBATIM

  if(!InitGaul()){
    return 0.0;
  }

  printf("Evolution...\n");
 
  if(!ValidParams()){
    return 0.0;
  }

  if(verbose) PrintSettings();

  int i;

  for(i=0;i<giNumIslands;i++){
    gpPop[i] = ga_genesis_double(
             giPopSize,
             1,
             giNumAlleles,
             generation_callback,
             NULL,
             NULL,
             NULL,
             eval_callback,
             seed_callback,
             NULL,
             ga_select_one_bestof2,
             ga_select_two_bestof2,
             ga_mutate_double_allpoint,
             giNumAlleles==1?ga_crossover_double_singlepoints:ga_crossover_double_doublepoints,
             NULL,
             NULL,
             allele_min,
             allele_max,
             giBoundAlleleMax );

    if(!gpPop[i]){
      printf("Evolution ERRH: Couldn't create isle %d\n",i);
      return 0.0;
    }
    if(verbose) printf("Created isle %d\n",i);

    ga_population_set_parameters(
       gpPop[i],
       GA_SCHEME_DARWIN,
       giElitism,
       gdCrossover,
       gdMutate,
       gdMigrate );

    gpPop[i]->allele_scale = giAlleleScale; //whether to scale alleles btwn 0 & 1

    if(verbose) printf("Set params for isle %d\n",i);
  }

  Symbol* sym = hoc_lookup("InitGenStats");
  if(sym){
    if(verbose) printf("Calling InitGenStats\n");
    hoc_call_func(sym,0);
  } else {
    if(verbose) printf("Couldn't lookup hoc function InitGenStats\n");
  }

  if(giNumIslands > 1){
    //steps in evolution:
    // generation callback
    // duplicate removal (if giReeseedDups == 1.0)
    // crossover
    // mutation
    // evaluation
    // survival of fittest
    ga_evolution_archipelago(giNumIslands,gpPop,giMaxGen);
  } else {
    ga_evolution(gpPop[0],giMaxGen);
  }

  printf("Finished evolution...\n");

  for(i=0;i<giNumIslands;i++){
    ga_extinction(gpPop[i]);
  }

  return 1.0;

  ENDVERBATIM
}

: get maximum possible number of params for a population member
FUNCTION GetMaxNumAlleles() {
  VERBATIM
  return MY_MAX_ALLELES;
  ENDVERBATIM
}

FUNCTION GetNumAlleles() {
  VERBATIM
  return giNumAlleles;
  ENDVERBATIM
}

: set number of alleles/params a population member has
FUNCTION SetNumAlleles(nAlleles) {
  VERBATIM
  int iNumAlleles = (int) _lnAlleles;
  if(iNumAlleles > 0 && iNumAlleles < MY_MAX_ALLELES){
    giNumAlleles = iNumAlleles;
    return 1.0;
  } else {
    printf("SetNumAlleles ERRA: Invalid # of alleles specified %d\n",iNumAlleles);
    return (double) 0;
  }
  ENDVERBATIM
}

FUNCTION GetPopSize() {
  VERBATIM
  return giPopSize;
  ENDVERBATIM
}

: set population size on each island
FUNCTION SetPopSize(nPopSize) {
  VERBATIM
  int iPopSize = (int) _lnPopSize;
  if(iPopSize > 0){
    giPopSize = iPopSize;
    return 1.0;
  } else {
    printf("SetPopSize ERRA: Invalid population size specified %d\n",iPopSize);
    return 0.0;
  }
  ENDVERBATIM
}

FUNCTION GetMaxGen() {
  VERBATIM
  return (double) giMaxGen;
  ENDVERBATIM
}

: set maximum generation for evolution
FUNCTION SetMaxGen(nMaxGen) {
  VERBATIM
  int iMaxGen = (int) _lnMaxGen;
  if(iMaxGen > 0){
    giMaxGen = iMaxGen;
    return 1.0;
  } else {
    printf("SetMaxGen ERRA: Invalid max generation specified %d\n",iMaxGen);
    return 0.0;
  }
  ENDVERBATIM
}

FUNCTION GetNumIslands() {
  VERBATIM
  return (double) giNumIslands;
  ENDVERBATIM
}

: set number of islands for use in next evolution
FUNCTION SetNumIslands(nNumIslands) {
  VERBATIM
  int iNumIslands = (int) _lnNumIslands;
  if(iNumIslands > 0 && iNumIslands <= MAX_NUM_ISLANDS){
    giNumIslands = iNumIslands;
    return 1.0;
  } else {
    printf("SetNumIslands ERRA: Invalid num islands specified %d\n",iNumIslands);
    return 0.0;
  }
  ENDVERBATIM
}

: get maximum number of islands, defined above, can be modified pre-compilation
FUNCTION GetMaxNumIslands() {
  VERBATIM
  return (double) MAX_NUM_ISLANDS;
  ENDVERBATIM
}

FUNCTION GetCrossover() {
  VERBATIM
  return gdCrossover;
  ENDVERBATIM
}

: set crossover rate
FUNCTION SetCrossover(nCrossover) {
  VERBATIM
  double dCrossover = _lnCrossover;
  if(dCrossover >= 0.0 && dCrossover <= 1.0){
    gdCrossover = dCrossover;
    return 1.0;
  } else {
    printf("SetCrossover ERRA: Invalid crossover rate specified %g\n",dCrossover);
    return 0.0;
  }
  ENDVERBATIM
}

FUNCTION GetMutate() {
  VERBATIM
  return gdMutate;
  ENDVERBATIM
}

: set mutation rate
FUNCTION SetMutate(nMutate) {
  VERBATIM
  double dMutate = _lnMutate;
  if(dMutate >= 0.0 && dMutate <= 1.0){
    gdMutate = dMutate;
    return 1.0;
  } else {
    printf("SetMutate ERRA: Invalid mutation rate specified %g\n",dMutate);
    return 0.0;
  }
  ENDVERBATIM
}

FUNCTION GetMigrate() {
  VERBATIM
  return gdMigrate;
  ENDVERBATIM
}

: set migration rate ( between different islands )
FUNCTION SetMigrate(nMigrate) {
  VERBATIM
  double dMigrate = _lnMigrate;
  if(dMigrate >= 0.0 && dMigrate <= 1.0){
    gdMigrate = dMigrate;
    return 1.0;
  } else {
    printf("SetMutate ERRA: Invalid migration rate specified %g\n",dMigrate);
    return 0.0;
  }
  ENDVERBATIM
}

FUNCTION GetElitism() {
  VERBATIM
  return giElitism;
  ENDVERBATIM
}

: set elitism option - see GAUL docs for description
FUNCTION SetElitism(nElitism) {
  VERBATIM
  int iElitism = _lnElitism;
  if(iElitism > GA_ELITISM_UNKNOWN && iElitism <= GA_ELITISM_RESCORE_PARENTS){
    giElitism = iElitism;
    return 1.0;
  } else {
    printf("SetElitism ERRA: Invalid elitism specified %d\n",iElitism);
    return 0.0;
  }
  ENDVERBATIM
}

:set fitness - should be called in hoc
:FitnessFunc , before returning
PROCEDURE SetFitness(nFitness){
  VERBATIM
  gdFitness = _lnFitness;
  ENDVERBATIM
}

:set pop's best fitness
PROCEDURE SetBest(nBest){
  VERBATIM
  gdBest = _lnBest;
  ENDVERBATIM
}

:get pop's best fitness in UpdateGenStats
FUNCTION GetBest(){
  VERBATIM
  return gdBest;
  ENDVERBATIM
}

:set pop's avg fitness
PROCEDURE SetAvg(nAvg){
  VERBATIM
  gdAvg = _lnAvg;
  ENDVERBATIM
}

:get's pop's avg fitness in UpdateGenStats
FUNCTION GetAvg(){
  VERBATIM
  return gdAvg;
  ENDVERBATIM
}

:set stddev in UpdateGenStats
PROCEDURE SetStddev(nStddev){
  VERBATIM
  gdStddev = _lnStddev;
  ENDVERBATIM
}

:get pops stddev - called in UpdateGenStats
FUNCTION GetStddev(){
  VERBATIM
  return gdStddev;
  ENDVERBATIM
}

:set a hoc function to use as seed/init new individuals
FUNCTION SetHocSeedFunc(){
  VERBATIM

  char* in = gargstr(1);
  int iLen = strlen(in);

  if(iLen > MY_STR_MAX){
    printf("SetHocSeedFunc ERRA: name too long %d %d\n",iLen,MY_STR_MAX);
    return 0.0;
  }

  pHocSeedFunc = hoc_lookup(in);
  if(pHocSeedFunc){
    //this only means a symbol exists in hoc code with the
    //given name, it doesn't mean the symbol is a proc/func/obfunc
    //if its not, ga_utils.hoc's Evolution() will fail later
    printf("Using %s hoc seed func for new individuals\n",in);
    strcpy(gHocSeedFuncName,in);
    return 1.0;
  } else {
    printf("Couldn't look up %s hoc seed func, using default seed_callback\n",in);
    pHocSeedFunc=(Symbol*)0;
    gHocSeedFuncName[0]=0;
    return 0.0;
  }

  ENDVERBATIM
}

:print the name of hoc seed func,if any
PROCEDURE PrintHocSeedFunc(){
  VERBATIM
  if(gHocSeedFuncName && strlen(gHocSeedFuncName)){
    printf("%s ",gHocSeedFuncName);
  }
  if(pHocSeedFunc){
    printf("%p",pHocSeedFunc);
  }
  printf("\n");
  ENDVERBATIM
}

:set file path for stats to be
:written to during run
FUNCTION SetStatFile(){
  VERBATIM

  char* in = gargstr(1);
  int iLen = strlen(in);

  if(iLen > MY_STR_MAX){
    printf("SetStatFile path too long %d %d\n",iLen,MY_STR_MAX);
    return 0.0;
  } 

  strcpy(gStatFilePath,in);
  return 1.0;

  ENDVERBATIM

}

:set file path for GA info
:file written during run
FUNCTION GetStatFilePath(){
  VERBATIM
  int iLen;
  if((iLen=strlen(gStatFilePath))){
    printf("%s",gStatFilePath);
  }
  printf("\n");
  return (double) iLen;
  ENDVERBATIM
}

:set whether to scale alleles between 0 and 1
:for use by GA, for eval, Descaled first
FUNCTION SetAlleleScale(scaleA){
  VERBATIM
  if(!giBoundAlleleMax && ((int) _lscaleA)){
    printf("SetAlleleScale ERRA: must turn on upper bound for alleles with SetBoundAlleleMax(1)\
            before using allele scaling!\n");
    return 0.0;
  }

  if(_lscaleA == 0.0 || _lscaleA == 1.0){
    giAlleleScale = _lscaleA;
    return 1.0;
  } else {
    printf("SetAlleleScale ERRA: arg1 must be 0 or 1\n");
    return 0.0;
  }
  ENDVERBATIM
}

FUNCTION GetAlleleScale(){
  VERBATIM
  return (double) giAlleleScale;
  ENDVERBATIM
}

: reseed duplicates each generation
FUNCTION SetReseedDups(reseedA){
  VERBATIM
  if(_lreseedA == 0.0 || _lreseedA == 1.0){
    giReseedDups = _lreseedA;
    return 1.0;
  } else {
    printf("SetReseedDups ERRA: arg1 must be 0 or 1\n");
    return 0;
  }
  ENDVERBATIM
}

FUNCTION GetReseedDups(){
  VERBATIM
  return giReseedDups;
  ENDVERBATIM
}

FUNCTION GetRandSeed(){
  VERBATIM
  return giSeed;
  ENDVERBATIM
}

:set random seed for ga
FUNCTION SetRandSeed(seed){
  VERBATIM
  giSeed = _lseed;
  random_seed(giSeed);
  return _lseed;
  ENDVERBATIM
}

:set whether to allow free movement of allele to positive infiniti
:if pass in 0, will allow movement to infiniti & otherwise won't
FUNCTION SetBoundAlleleMax(nm){
  VERBATIM
  //if there is no max allele value
  if(giAlleleScale && ! ((int) _lnm)){
    printf("SetBoundAlleleMax ERRA: can't allow infinite allele value when allele scaling is on!\n");
    printf("First call SetAlleleScale(0)\n");
    return 0.0;
  }
  giBoundAlleleMax = (int) _lnm;
  return 1.0;
  ENDVERBATIM
}

FUNCTION GetBoundAlleleMax(){
  VERBATIM
  return (double) giBoundAlleleMax;
  ENDVERBATIM
}

:check for memory usage info
PROCEDURE GACheckMem(){
  VERBATIM
  CheckMem();
  ENDVERBATIM
}

:turn memory debugging on
PROCEDURE GAMemDebug(){
  VERBATIM
  MemDebug();
  ENDVERBATIM
}

PROCEDURE GAPrintSettings(){
  VERBATIM
  PrintSettings();
  ENDVERBATIM
}

PROCEDURE install_methods() {
  VERBATIM 
  static int inst = 0;
  if(!inst){
    install_vector_method("v2data", v2data);
    install_vector_method("data2v", data2v);
    install_vector_method("set_allele_mins",set_allele_mins);
    install_vector_method("set_allele_maxs",set_allele_maxs);
    install_vector_method("get_allele_mins",get_allele_mins);
    install_vector_method("get_allele_maxs",get_allele_maxs);
    install_vector_method("get_alleles",get_alleles);
    install_vector_method("set_alleles",set_alleles);
    inst=1;
  }
  ENDVERBATIM
}