/* ga_iface.h */

#ifndef GA_IFACE__H
#define GA_IFACE__H

#include "component.h"
#include "EvMikeAlgor.hh"
#include "EvBitGenome.hh"
#include "EvPerformance.hh"

class EvStdMetric;
class StdBitString;
class dc_func;
class dc_int;
class dc_element;
class dc_arg;

const char nIndividuals_label[] = "nindividuals";
const char generation_label[] = "generation";
const char steady_state_label[] = "steady_state";
const char exit_cond_label[] = "exit_condition";
const char outfile_label[] = "outfile";

/* Each phase of the ga operation will evaluate its exit condition a maximum
   number of times before exiting with a warning message and moving to the next
   phase */
extern double steady_state_max_iters; /* = 100 */
extern double evaluation_max_iters; /* = 100 */

class ga : public dc_component, public EvPerformance {
private:
  void child_init( dc_label *child ); /* virtual from dc_node */
  bool open; /* true if ga has run successfully and can be closed */

protected:
  /* searched for in child_list during init.
     not owned */
  dc_element *steady_state; /* steady state condition -- bool */
  dc_element *exit_cond;    /* exit condition         -- bool */
  dc_element *nIndividuals; /* size of population     -- int */

  dc_func *fitness; /* owned */

  EvMikeAlgor<EvBitGenome> *Algor; /* owned */
  EvIndividual<EvBitGenome> best;

  dc_int *generation;    /* number of gernerations simulated so far */
  double pCrossover;     /* corssover prob.   [0:1] */
  double pMut;           /* mutation prob.    [0:1-pCrossover ] */
  double mutVar;         /* mutation variance [0:oo] */

  /*  double tau; */
  double int_acc;

  double time_step;
  double fBestPerformance;

  int nGens;

  /**************************************************************************/

  /* PHASE 1 of execute -- find steady_state and exit elements
     set up population and run spreadsheet to steady 
     state */
  virtual bool init( void ) = 0;
  /* PHASE 2 of execute -- run ga until exit_condition satisfied */
  virtual bool run( void ) = 0;
  /* PHASE 3 of execute -- run spreadsheet to steady state */
  virtual bool finish( void ) = 0;
  /* PHASE 4 of execute -- dumps state to output file */
  virtual bool output( void ) = 0;

  /* if error during output, resets state before dropping out of execute */
  virtual void cleanup( void ) = 0;

  /* Performance Stuff */
  /* Evaluate the performance */
  virtual double Evaluate( const StdBitString &bstring ) = 0;

  /* returns performance of simulation */
  virtual double Simulate( void ) = 0;
  
  virtual double Step( double stepSize ) = 0;

  virtual void Reset( void ) = 0;
public:
  ga( void );
  ~ga( void );

  /* functions to init state -- type checked at init.  Real_t */
  void set_fitness_fn( dc_func *f );
  
  /* checked at init */
  bool set_pCrossover( double );
  bool set_pMut( double );
  bool set_mutVar( double );

  bool set_time_step( double );
  /*  void set_tau( double ) */
  /* integration accuracy */  
  bool set_int_accuracy( double );
  bool set_nGens( int );
  
  /* execute runs ga and exits with false if a genome is found without errors.
     true otherwise. */
  bool execute( void );

  /* runs another simulation round. returns true on error */
  bool simulate( void );

  /* after a ga has been run successfully it must be closed.  if a run is 
     unsucessful it is already closed */
  void close( void ) { if( open ) { open = false; cleanup(); } }

  bool opened( void ) const { return open; }

  const dc_type sub_type( void ) const { return GA_t; }
  string type_string( void ) const { return string( "ga" ); }

  EvIndividual<EvBitGenome> &get_best( void ) { return best; }
};


/* iteration functions used to change ga status */
void set_child_a( dc_label * ); /* active */
void set_child_f( dc_label * ); /* frozen */
void set_child_df( dc_label * ); /* dormant & frozen */

#endif

/* 

common ga <label>( eval ) {
  set_time_step( d=.1 );
  set_tau( d=.1 >= 0 );
  set_int_accuracy( d=.001 ); // integration accuracy.used to bound timestep
  
  set_sstate_cond( fn );      // used to iterate spreadsheet until steady state 
                              // reached for each chromosome 
  // iterate while( !entry_cond )
  set_exit_cond( fn );        // iterate ga while( !exit_cond ) 
  // need access to #generations, #individuals,
  // #illegal constraints 
  
  set_pop_size( i );
  set_pmut( d=.5 );
  set_pcrossover( d=.3 );
  set_mut_var( d=1 );
  
  load_file( str );
  set_outfile( str );
  output { <effects> }
  
  add_input( input_block )
}

optimizer
ga <label>( eval ) {
};

input_block
  real -> min, max, nbits
  integer -> min, max
  index -> array


nnet
ga <label>( eval_fn ) {
set_nInputs( i );
set_nOut( i );
set_nHidden( i );
set_weight_range( i, label, range ); default [-18..18], 8 bits
set_act_fn( i, fnodeType = [ sin, sigmoid, linear, ... ] );
};

[bias(cgN), input_scale(cgInput), weights()]

eval_fn
  ga.time
  ga.time_step 

output {
  n = out[1];
  m = out[1]^2 / 4;
  j = out[3] + 1;
}

let file be read in as component so can be templated
ga : readfile();

   
 */


/*
optimizer ga( rover.mass ) {
  modify wheel {
    wheel.w = wheel.diam * .2;
  }
  add_input( wheel.diam, ( 0.2m, 0.9m, 16 bit ) );
  add_input( .. )
  set_sstate_condition( rover.mass - old rover.mass < .5 kg );
  set_exit_condition( best_perf ... )
  input {
    imass = rover.mass;
  }

  output {
    a = b + c;
  }

  real imass = <nil>;
}

exit variables
best_perf
ngenerations
nindividuals

allow resolutions in range

at exit
  set chromosome to best
  execute until steady state cond
  execute output


phases                 ga_status              finish cond
regular ssheet         dormant&frozen         command line
ga_init                active/frozen?         sstate_cond
ga_run                 active/frozen?         exit_cond
ga_cleanup             frozen                 sstate_cond
post_ga                dormant&frozen
*/
