/*  lil-gp Genetic Programming System, version 1.0, 11 July 1995
 *  Copyright (C) 1995  Michigan State University
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of version 2 of the GNU General Public License as
 *  published by the Free Software Foundation.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *  
 *  Douglas Zongker       (zongker@isl.cps.msu.edu)
 *  Dr. Bill Punch        (punch@isl.cps.msu.edu)
 *
 *  Computer Science Department
 *  A-714 Wells Hall
 *  Michigan State University
 *  East Lansing, Michigan  48824
 *  USA
 *  
 */

#include <lilgp.h>


/*
 * note:  that almost all these functions that recurse through the tree
 * come in two parts:  the wrapper and the recursive part.  the "standard"
 * method of traversing a tree like this is to set up a pointer to the
 * first node in the tree, then subsequent recursive calls step the
 * pointer forward, traversing the tree in preorder.  the wrapper function
 * sets up this pointer, then passes the address of that pointer [that's
 * an (lnode **)] to the recursive part.
 *
 * the first function in this file [tree_size()] is commented in detail,
 * others (which are just variations on this theme) are rather glossed over.
 *
 * note:  when I refer to a tree's "size" I almost always mean "how many
 * lnodes the tree takes to store", NOT how many nodes are in the tree.
 * watch out for this.  (the major exception is, of course, "tree_size()"
 * which returns the node count.)
 */

/*
 * tree_nodes:  return the number of nodes in the tree.
 */

int tree_nodes ( lnode *tree )
{
     lnode *l = tree;
     return tree_nodes_recurse ( &l );
}

int tree_nodes_recurse ( lnode **l )
{
     /*
      *  *l always points at a function node here; save the function.
      */
     function *f = (**l).f;
     int i, j = 1;

     /* step the pointer over the function. */
     ++*l;

     /* if the function is a terminal, then the recursion bottoms out. */
     if ( f->arity == 0 )
     {
          /* skip the pointer over the ERC value if this node has one. */
          if ( f->ephem_gen )
               ++*l;

          /* return this subtree size. */
          return 1;
     }
     else
     {
          /* function is not a terminal, so add up its subtrees and return
           * the total.
           */

          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
                    j += tree_nodes_recurse ( l );
               break;
               
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    /* skip the pointer over the skipsize node. */
                    ++*l;
                    /* add this subtree's size to the total. */
                    j += tree_nodes_recurse ( l );
               }
               break;
          }
     }
     
     return j;
}

/*
 * tree_nodes_internal:  return number of internal (function) nodes in the
 *     tree.
 */

int tree_nodes_internal ( lnode *data )
{
     lnode *l = data;
     return tree_nodes_internal_recurse ( &l );
}

int tree_nodes_internal_recurse ( lnode **l )
{
     function *f = (**l).f;
     int i, j = 1;

     ++*l;
     
     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
               ++*l;
          return 0;
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
                    j += tree_nodes_internal_recurse ( l );
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    j += tree_nodes_internal_recurse ( l );
               }
               break;
          }
     }

     return j;
}

/*
 * tree_nodes_external:  return number of external (terminal) nodes in the
 *     tree.
 */

int tree_nodes_external ( lnode *data )
{
     lnode *l = data;
     return tree_nodes_external_recurse ( &l );
}

int tree_nodes_external_recurse ( lnode **l )
{
     function *f = (**l).f;
     int i, j = 0;

     ++*l;
     
     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
               ++*l;
          return 1;
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
                    j += tree_nodes_external_recurse ( l ) ;
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    j += tree_nodes_external_recurse ( l ) ;
               }
               break;
          }
     }
     return j;
}

/*
 * print_tree_array:  print the tree, as an array, on stdout.  primarily
 *     for debugging.
 */

void print_tree_array ( lnode *data )
{
     lnode *l = data;
     int i = 0;
     print_tree_array_recurse ( &l, &i );
}

void print_tree_array_recurse ( lnode **l, int *index )
{
     function *f = (**l).f;
     int i;

     fprintf ( stderr, "%3d: function: \"%s\"\n", *index, f->string );
     
     ++*l;
     ++*index;

     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
          {
               fprintf ( stderr, "%3d:    value: %s\n", *index, (f->ephem_str)((**l).d->d) );
               ++*l;
               ++*index;
          }
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    print_tree_array_recurse ( l, index );
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    fprintf ( stderr, "%3d:    {skip %d}\n", *index, (**l).s );
                    ++*l;
                    ++*index;
                    print_tree_array_recurse ( l, index );
               }
               break;
          }
     }
}

/*
 * print_tree:  print the tree, as a LISP S-expression, to the given FILE *.
 */

void print_tree ( lnode *data, FILE *fil )
{
     lnode *c = data;
     print_tree_recurse ( &c, fil );
     fprintf ( fil, "\n" );
}

void print_tree_recurse ( lnode **l, FILE *fil )
{
     function *f;
     int i;

     f = (**l).f;

     fprintf ( fil, " " );
     if ( f->arity != 0 )
          fprintf ( fil, "(" );
     
     ++*l;
     if ( f->ephem_gen )
     {
          fprintf ( fil, "%s", (f->ephem_str)((**l).d->d) );
#ifdef DEBUG
          fprintf ( fil, " <%d>", (**l).d->refcount );
#endif
          ++*l;
     }
     else
          fprintf ( fil, "%s", f->string );
     
     switch ( f->type )
     {
        case FUNC_DATA:
        case EVAL_DATA:
          for ( i = 0; i < f->arity; ++i )
          {
               print_tree_recurse ( l, fil );
          }
          break;
        case FUNC_EXPR:
        case EVAL_EXPR:
          for ( i = 0; i < f->arity; ++i )
          {
#ifdef DEBUG               
               fprintf ( fil, " {skip %d}", (**l).s );
#endif               
               ++*l;
               print_tree_recurse ( l, fil );
          }
          break;
     }

     if ( f->arity != 0 )
          fprintf ( fil, ")" );
}

/*
 * generate_random_full_tree:  generates, in the given generation space,
 *     a random full tree of the specified depth.
 */

int generate_random_full_tree ( int space, int depth, function_set *fset, int return_type )
{
     int i, j;
     int save, used_save, is_expr;
     int c_nval, *f_used, f_num_used, f_this;
     int notvalid = 0;

     /* Reached maximum depth so choose terminal */
     if ( depth == 0 )
     {
          /* Check if a terminal exists for this type */
          if ( fset->terminal_count_by_type[return_type] == 0 )
               return 1;
          
          /* Randomly select the terminal and add it to the tree */
          i = random_int(&globrand, fset->terminal_count_by_type[return_type])+
	      (fset->function_count_by_type[return_type]);
          gensp_next(space)->f = (fset->cset_by_type[return_type])+i;

          /* if this terminal is an ERC, then generate one and store it. */
          if ( (fset->cset_by_type[return_type])[i].ephem_gen )
               gensp_next(space)->d = new_ephemeral_const 
		   ( (fset->cset_by_type[return_type])+i );

          /* Tree is OK */
          return 0;
     }
     
     /* Check if a function of this type exists */
     if ( fset->function_count_by_type[return_type] == 0 )
          return 1;
     
     /* Possible function so init function used array */
     f_used = (int *) MALLOC ((fset->function_count_by_type[return_type]) * sizeof(int));
     for ( i = 0; i < fset->function_count_by_type[return_type]; ++i )
          f_used[i] = 0;
     f_num_used = 0;

     /* Get a ptr to the next free lnode */
     f_this = gensp_next_int(space);
     /* Save our position in the genspace */
     used_save = gensp[space].used;

     /* Try to generate a tree to attach to parent node */
     do 
     {
          /* Reset to possibly valid */
          notvalid = 0;

          /* Check if any more functions exist */
          if ( f_num_used >= fset->function_count_by_type[return_type] )
          {
               /* Unuse the function we recieved */
               --gensp[space].used;
               FREE (f_used);
               return 1;
          }

          /* Generate unique function (not at depth 0) */
          do {
               i = random_int(&globrand, fset->function_count_by_type[return_type]);
          } while ( f_used[i] );
          /* Mark function used */
          f_used[i] = 1;
          ++f_num_used;
          /* Setup function in genspace */
          gensp[space].data[f_this].f = (fset->cset_by_type[return_type])+i;

          /* Check if this is a EXPR type function */
          is_expr = gensp[space].data[f_this].f->type;
          is_expr = (is_expr == FUNC_EXPR || is_expr == EVAL_EXPR);
     
          /* now generate the node's children. */
          for ( j = 0; j < gensp[space].data[f_this].f->arity; ++j )
          {
               /* if this is a EXPR function then get a location for the skip node */
               if ( is_expr )
                    save = gensp_next_int ( space );
                    
               /* generate a full tree of depth [depth-1]. */
               c_nval = generate_random_full_tree ( space, depth - 1, fset,
                    gensp[space].data[f_this].f->argument_type[j]);
                    
               /* save the size of the subtree in the skip node, if we need to. */
               if ( is_expr )
                    gensp[space].data[save].s = gensp[space].used - save - 1;
               
               /* if one child is not creatable then quit */ 
               if ( c_nval )
               {
                    /* Roll back in genspace to before children created */
                    gensp[space].used = used_save;
                    notvalid = 1;
                    break;
               }
          }
     } while ( notvalid );
     FREE(f_used);
     
     /* Tree is OK */
     return 0;
}

/*
 * generate_random_grow_tree:  grow a random tree, of (maximum) depth [depth].
 *     works just like genereate_random_full_tree, except that a node with
 *     depth > 0 can be a terminal.
 */
       
int generate_random_grow_tree ( int space, int depth, function_set *fset, int return_type )
{
     int i, j;
     int save, used_save, is_expr;
     int c_nval, *f_used, f_num_used, f_this;
     int notvalid = 0;
     int num_node = fset->function_count_by_type[return_type]+fset->terminal_count_by_type[return_type];
     int num_func = fset->function_count_by_type[return_type];
     int sel_term = 0;

     /* Calculate whether a function or terminal is selected */
     if ( random_double ( &globrand ) >= (double) num_func / (double) num_node )
          sel_term = 1;
     
     /* Reached maximum depth so choose terminal */
     if ( depth == 0 || sel_term )
     {
          /* Check if a terminal exists for this type */
          if ( fset->terminal_count_by_type[return_type] == 0 )
               return 1;

          i = random_int(&globrand, fset->terminal_count_by_type[return_type])+
	      (fset->function_count_by_type[return_type]);
          gensp_next(space)->f = (fset->cset_by_type[return_type])+i;

          if ( (fset->cset_by_type[return_type])[i].ephem_gen )
               gensp_next(space)->d = new_ephemeral_const ( (fset->cset_by_type[return_type])+i );

          /* Tree OK */
          return 0;
     }
     
     /* Check if a function of this type exists */
     if ( fset->function_count_by_type[return_type] == 0 )
               return 1;
          
     /* Possible function so init function used array */
     f_used = (int *) MALLOC ((fset->function_count_by_type[return_type]) * sizeof(int));
     for ( i = 0; i < fset->function_count_by_type[return_type]; ++i )
          f_used[i] = 0;
     f_num_used = 0;

     /* Get a ptr to the next free lnode */
     f_this = gensp_next_int(space);
     /* Save our position in the genspace */
     used_save = gensp[space].used;

     /* Try to generate a tree to attach to parent node */
     do 
     {
          /* Reset to possibly valid */
          notvalid = 0;
          
          /* Check if any more functions exist */
          if ( f_num_used >= fset->function_count_by_type[return_type] )
          {
               /* Unuse the function we recieved */
               --gensp[space].used;
               FREE(f_used);
               return 1;
          }

          /* Generate unique function (not at depth 0) */
          do {
               i = random_int(&globrand, fset->function_count_by_type[return_type]);
          } while ( f_used[i] );
          /* Mark function used */
          f_used[i] = 1;
          ++f_num_used;
          /* Setup function in genspace */
          gensp[space].data[f_this].f = (fset->cset_by_type[return_type])+i;

          /* Check if this is a EXPR type function */
          is_expr = gensp[space].data[f_this].f->type;
          is_expr = (is_expr == FUNC_EXPR || is_expr == EVAL_EXPR);
     
          /* now generate the node's children. */
          for ( j = 0; j < gensp[space].data[f_this].f->arity; ++j )
          {
               /* if this is a EXPR function then get a location for the skip node */
               if ( is_expr )
                    save = gensp_next_int ( space );
                    
               /* generate a full tree of depth [depth-1]. */
               c_nval = generate_random_grow_tree ( space, depth - 1, fset,
                    gensp[space].data[f_this].f->argument_type[j]);

               /* save the size of the subtree in the skip node, if we need to. */
               if ( is_expr )
                    gensp[space].data[save].s = gensp[space].used - save - 1;
               
               /* if one child is not creatable then quit */ 
               if ( c_nval )
               {
                    /* Roll back in genspace to before children created */
                    gensp[space].used = used_save;
                    notvalid = 1;
                    break;
               }
          }
     } while ( notvalid );
     FREE(f_used);

     /* Tree OK */
     return 0;
}

/*
 * tree_depth:  return the depth of the tree.  a tree with one node has
 *     depth 0.
 */

int tree_depth ( lnode *data )
{
     lnode *l = data;
     return tree_depth_recurse ( &l );
}

int tree_depth_recurse ( lnode **l )
{

     function *f = (**l).f;
     int i, j, k = 0;

     ++*l;
     if ( f->arity == 0 )
     {
          /* a terminal node; advance the pointer and return 0. */
          
          if ( f->ephem_gen )
               ++*l;
          return 0;
     }

     /* a nonterminal; find the deepest child and return its depth plus one. */
     
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    j = tree_depth_recurse ( l );
                    if ( j > k )
                         k = j;
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    j = tree_depth_recurse ( l );
                    if ( j > k )
                         k = j;
               }
               break;
          }
     
     return k+1;
}

int tree_depth_to_subtree ( lnode *data, lnode *sub )
{
     lnode *l = data;
     return tree_depth_to_subtree_recurse ( &l, sub, 0 );
}

int tree_depth_to_subtree_recurse ( lnode **l, lnode *sub, int depth )
{
     function *f = (**l).f;
     int i, j;

     if ( *l == sub )
          return depth;

     ++*l;
     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
               ++*l;
          return -1;
     }

          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    j = tree_depth_to_subtree_recurse ( l, sub, depth+1 );
                    if ( j != -1 )
                         return j;
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    j = tree_depth_to_subtree_recurse ( l, sub, depth+1 );
                    if ( j != -1 )
                         return j;
               }
               break;
          }

     return -1;
}
     

/*
 * get_subtree:  returns the start'th subtree of the tree, where start
 *     ranges from 0..(nodecount-1).  the zeroth subtree is the tree itself.
 *     the subtrees are returned in preorder.
 */

lnode *get_subtree ( lnode *data, int start )
{
     lnode *l = data;
     /* initialize a counter with start.  the counter is passed by address,
      * and so is shared across all recursive calls.  it is decremented once
      * for every node in the tree -- the current node when it reaches zero
      * is returned.
      */
     int c = start;
     
     return get_subtree_recurse ( &l, &c );
}

lnode *get_subtree_recurse ( lnode **l, int *c )
{
     function *f = (**l).f;
     lnode *r;
     int i;

     /* if the counter is zero, return the current subtree. */
     if ( *c == 0 )
          return *l;

     ++*l;
     --*c;

     if ( f->arity == 0 )
     {
          /* skip over the terminal nodes. */
          if ( f->ephem_gen )
               ++*l;
     }
     else
     {
          /* recurse into this node's children.  if one of them returns
           * non-NULL, it means that the subtree has been found and the
           * return value is immediately propagated up the call chain.
           * if all of them return NULL, then the desired subtree is
           * not in this subtree and we return NULL. */
          
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    r = get_subtree_recurse ( l, c );
                    if ( r != NULL )
                         return r;
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    r = get_subtree_recurse ( l, c );
                    if ( r != NULL )
                         return r;
               }
               break;
          }
     }

     return NULL;
}

/*
 * get_subtree_internal:  just like get_subtree, but only selects nonterminal
 *     points.  start should range from 0..(internalnodecount-1).
 */

lnode *get_subtree_internal ( lnode *data, int start )
{
     lnode *l = data;
     int c = start;
     return get_subtree_internal_recurse ( &l, &c );
}

lnode *get_subtree_internal_recurse ( lnode **l, int *c )
{
     function *f = (**l).f;
     int i;
     lnode *r;

     /* if the current subtree is a terminal node, skip it immediately. */
     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
               ++*l;
          ++*l;
     }
     else
     {
          if ( *c == 0 )
               return *l;

          ++*l;
          --*c;

          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    r = get_subtree_internal_recurse ( l, c );
                    if ( r != NULL )
                         return r;
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    r = get_subtree_internal_recurse ( l, c );
                    if ( r != NULL )
                         return r;
               }
               break;
          }
     }

     return NULL;
}

/*
 * get_subtree_external:  just like get_subtree, but only selects terminal
 *     nodes (that is, 1-node subtrees).  start ranges from
 *     0..(externalnodecount-1).
 */

lnode *get_subtree_external ( lnode *data, int start )
{
     lnode *l = data;
     int c = start;
     return get_subtree_external_recurse ( &l, &c );
}

lnode *get_subtree_external_recurse ( lnode **l, int *c )
{
     function *f = (**l).f;
     int i;
     lnode *r;

     if ( f->arity == 0 )
     {
          if ( *c == 0 )
               return *l;

          ++*l;
          --*c;

          if ( f->ephem_gen )
               ++*l;
     }
     else
     {
          ++*l;

          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    r = get_subtree_external_recurse ( l, c );
                    if ( r != NULL )
                         return r;
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    r = get_subtree_external_recurse ( l, c );
                    if ( r != NULL )
                         return r;
               }
               break;
          }
     }

     return NULL;
}

/*
 * copy_tree:  allocates space for and makes a copy of a tree.
 */

void copy_tree ( tree *to, tree *from )
{
     to->data = (lnode *)MALLOC ( from->size * sizeof ( lnode ) );
     to->size = from->size;
     to->nodes = from->nodes;
     memcpy ( to->data, from->data, from->size * sizeof ( lnode ) );
}

/*
 * free_tree:  frees the memory allocated by a tree, and resets variables.
 */

void free_tree ( tree *t )
{
     FREE ( t->data );
     t->data = NULL;
     t->size = -1;
     t->nodes = -1;
}

/*
 * tree_size:  returns the number of lnodes used to store the tree.
 *     this is equal to
 *        (node count)+(ERC count)+(conditionally evaluated subtree count).
 */

int tree_size ( lnode *data )
{
     lnode *l = data;
     return tree_size_recurse ( &l );
}

int tree_size_recurse ( lnode **l )
{
     function *f = (**l).f;
     int i, j = 1;

     ++*l;

     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
          {
               ++*l;
               ++j;
          }
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
                    j += tree_size_recurse ( l );
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    ++j;
                    j += tree_size_recurse ( l );
               }
               break;
          }
     }

     return j;

}

/*
 * copy_tree_replace_many:  copies a tree, replacing some of its subtrees
 *     with other subtrees.  arguments:
 *
 *         space      - the generation space to put the new tree in
 *         parent     - the tree to copy from
 *         replace    - a list of subtrees to replace
 *         with       - a list of subtrees to replace them with
 *         count      - the size of the replace and width arrays
 *         repcount   - returns the number of subtrees replaced
 *
 *     this function starts to recursively copy the "parent" tree to "dest".
 *     when the recursive copy hits any subtree in the "replace" array,
 *     the corresponding subtree in the "with" array is copied in its
 *     place.  repcount returns the number of subtrees that were hit and
 *     replaced.  this can be less than count, as some subtrees may never
 *     be found (if, for instance, one of the subtrees in the "replace"
 *     array is the subtree of another).
 */

void copy_tree_replace_many ( int space, lnode *parent, lnode **replace,
                            lnode **with, int count, int *repcount )
{
     lnode *lp = parent;

     gensp_reset ( space );
     *repcount = 0;
     copy_tree_replace_many_recurse ( space, &lp, replace,
                                     with, count, repcount );
}

void copy_tree_replace_many_recurse ( int space, lnode **lp, lnode **lr,
                                    lnode **lw, int count, int *repcount )
{
     function *f = (**lp).f;
     int i;
     int save;
     lnode *new;

     /* only do the comparison if the lr is non-NULL. */
     if ( lr )
     {
          /* check the current subtree against everything in the lr array. */
          for ( i = 0; i < count; ++i )
               if ( *lp == lr[i] )
               {
                    /* we have a match! */

                    /* increment the replacement count. */
                    ++*repcount;
                    
                    /* copy the new tree into the destination.  note that the
                     * lr and lw arguments are passed as NULL to prevent
                     * further replacement within the replacement tree.
                     */
                    new = lw[i];
                    copy_tree_replace_many_recurse ( space, &new, NULL,
                                                    NULL, count, repcount );
                    
                    /* now skip the lp pointer over the lr subtree. */
                    skip_over_subtree ( lp );

                    return;
               }
     }

     /* copy the node from the parent to the destination. */

     gensp_next(space)->f = (**lp).f;
     ++*lp;

     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
          {
               /* copy the ERC pointer. */

               gensp_next(space)->d = (**lp).d;
               ++*lp;
          }
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
               {
                    copy_tree_replace_many_recurse ( space, lp, lr, lw,
                                                    count, repcount );
               }
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    /* note that we just can't copy the skip value, since
                     * replacement within the subtree may change it.  we
                     * have to save where it is needed and fill it in 
                     * afterwards, just like generate_random_full_tree(). */
                    
                    save = gensp_next_int ( space );
                    ++*lp;
                    copy_tree_replace_many_recurse ( space, lp, lr, lw,
                                                    count, repcount );
                    gensp[space].data[save].s = gensp[space].used-save-1;
               }
               break;
          }
     }
     return;
}

/*
 * skip_over_subtree:  takes a traversal pointer and skips it over the
 *     subtree it points to.
 */

void skip_over_subtree ( lnode **l )
{
     function *f = (**l).f;
     int i;

     ++*l;
     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
               ++*l;
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
                    skip_over_subtree ( l );
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    skip_over_subtree ( l );
               }
               break;
          }
     }
     return;
}

/*
 * reference_ephem_constants:  traverses a tree, adding "count" to the
 *     refcount of each ERC that is used within the tree.
 */

void reference_ephem_constants ( lnode *data, int count )
{
     lnode *l = data;
     reference_ephem_constants_recurse ( &l, count );
}

void reference_ephem_constants_recurse ( lnode **l, int count )
{
     function *f = (**l).f;
     int i;

     ++*l;

     if ( f->arity == 0 )
     {
          if ( f->ephem_gen )
          {
               if ( (**l).d )
               {
                    (**l).d->refcount += count;
                    ++*l;
               }
               else
                    error ( E_FATAL_ERROR, "aarg: this can't happen." );
          }
     }
     else
     {
          switch ( f->type )
          {
             case FUNC_DATA:
             case EVAL_DATA:
               for ( i = 0; i < f->arity; ++i )
                    reference_ephem_constants_recurse ( l, count );
               break;
             case FUNC_EXPR:
             case EVAL_EXPR:
               for ( i = 0; i < f->arity; ++i )
               {
                    ++*l;
                    reference_ephem_constants_recurse ( l, count );
               }
               break;
          }
     }

}


