/*  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
 *
 *  This parallel version based on PVM is an extension of version 1.1
 *  of Lil-gp.
 *
 *  Johan Parent        (johan@info.vub.ac.be)
 *
 *  Faculty of Applied Sciences (Engineering Faculty)
 *  Building K, Computer Science Department
 *  Vrije Universiteit Brussel
 *  Pleinlaan 2, 1050 Etterbeek
 *  Belgium
 *
 */

#include <lilgp.h>

#ifdef _PARALLEL_H
Exchange_list export_list;
Exchange_list import_list;
Exchange_list normal_list;

int empty_import_nodes;
char init = 0;
#endif

/* initialize_topology()
 *
 * reads the parameter database and builds the exchange table.
 */

void initialize_topology ( multipop *mpop )
{
     char pnamebuf[100], pnamebuf2[100];
     char *param, *param2, *param3;
     int i, j, k;
     int errors = 0;

     if ( mpop->size == 1 )
     {
	  /* singlepop problem -- no topology needed. */
          mpop->exch = NULL;
          mpop->exchanges = -1;
          return;
     }

     oprintf ( OUT_SYS, 30, "building subpopulation exchange topology:\n" );
     
     param = get_parameter ( "multiple.exchanges" );
     if ( param == NULL )
     {
	  /* multipop problem, but no exchanges specified. */
	  
          mpop->exch = NULL;
          mpop->exchanges = 0;
          return;
     }
     else
     {
          mpop->exchanges = atoi ( param );
          if ( mpop->exchanges < 0 )
               error ( E_FATAL_ERROR, "\"exchanges\" must be nonnegative." );
     }

     mpop->exch = (exchange *)MALLOC ( mpop->exchanges * sizeof ( exchange ) );
     
     for ( i = 0; i < mpop->exchanges; ++i )
     {
	  /** read the destination subpop. **/
	  
          sprintf ( pnamebuf, "exch[%d].to", i+1 );
          param = get_parameter ( pnamebuf );
          if ( param == NULL )
          {
               ++errors;
               error ( E_ERROR, "\"%s\" must be set.", pnamebuf );
          }
          else
          {
               mpop->exch[i].to = atoi ( param ) - 1;
               if ( mpop->exch[i].to < 0 || mpop->exch[i].to >= mpop->size )
               {
                    ++errors;
                    error ( E_ERROR, "\"%s\" is out of range.\n", pnamebuf );
               }
          }

	  /** read how the individuals to be replaced in the destination
	    subpop are selected. **/
	  
          sprintf ( pnamebuf, "exch[%d].toselect", i+1 );
          mpop->exch[i].tosc = get_parameter ( pnamebuf );
          if ( mpop->exch[i].tosc == NULL )
          {
               ++errors;
               error ( E_ERROR, "\"%s\" must be set.", pnamebuf );
          }
          else
          {
               if ( ! exists_select_method ( mpop->exch[i].tosc ) )
               {
                    ++errors;
                    error ( E_ERROR, "\"%s\": \"%s\" is not a selection method.",
                           pnamebuf, mpop->exch[i].tosc );
               }
          }

	  /** read how many individuals are to be exchanged in this
	    manner. **/
	  
          sprintf ( pnamebuf, "exch[%d].count", i+1 );
          param = get_parameter ( pnamebuf );
          if ( param == NULL )
          {
               ++errors;
               error ( E_ERROR, "\"%s\" must be set.", pnamebuf );
          }
          else
          {
               mpop->exch[i].count = atoi ( param );
               if ( mpop->exch[i].count < 0 )
               {
                    ++errors;
                    error ( E_ERROR, "\"%s\" must be nonnegative.", pnamebuf );
               }
          }

	  /** check to see if "from" is specified without a "tree[#]". **/
	  
          sprintf ( pnamebuf, "exch[%d].from", i+1 );
          param = get_parameter ( pnamebuf );
          if ( param )
          {
               /** if "from" is specified, then we're copying whole individuals
		 from one subpop to another. **/

	       /* these arrays are not needed. */
               mpop->exch[i].from = NULL;
               mpop->exch[i].as = NULL;
	       /* allocate an array of one string (to hold the selection
		  method). */
               mpop->exch[i].fromsc = (char **)MALLOC ( sizeof ( char * ) );

	       /* the subpop that individuals are taken from. */
               mpop->exch[i].copywhole = atoi ( param ) - 1;
               if ( mpop->exch[i].copywhole < 0 ||
                    mpop->exch[i].copywhole >= mpop->size )
               {
                    ++errors;
                    error ( E_ERROR, "\"%s\" is out of range.", pnamebuf );
               }

	       /* the selection method used to pick the individuals from the
		  source subpop. */
               sprintf ( pnamebuf, "exch[%d].fromselect", i+1 );
               mpop->exch[i].fromsc[0] = get_parameter ( pnamebuf );
               if ( mpop->exch[i].fromsc[0] == NULL )
               {
                    ++errors;
                    error ( E_ERROR, "\"%s\" must be set.", pnamebuf );
               }
               else
               {
                    if ( ! exists_select_method ( mpop->exch[i].fromsc[0] ) )
                    {
                         ++errors;
                         error ( E_ERROR, "\"%s\": \"%s\" is not a selection method.",
                                pnamebuf, mpop->exch[i].fromsc[0] );
                    }
               }
          }
          else
          {

               /** since "from" is not defined, we're taking trees from different
		 subpops and merging them to create a composite individual to place
		 in the destination subpop. **/
	       
               mpop->exch[i].copywhole = -1;
	       /* this array lists, for each tree, which subpop it comes from. */
               mpop->exch[i].from = (int *)MALLOC ( tree_count * sizeof ( int ) );
	       /* this array keeps track of when two trees are supposed to always
		  come from the same individual (not just the same subpop). */
               mpop->exch[i].as = (int *)MALLOC ( tree_count * sizeof ( int ) );
	       /* this array holds the selection method strings used for each
		  tree. */
               mpop->exch[i].fromsc = (char **)MALLOC ( tree_count * sizeof ( char * ) );

	       /* get the default selection method, if one is specified. */
               sprintf ( pnamebuf, "exch[%d].fromselect", i+1 );
               param3 = get_parameter ( pnamebuf );
               
               for ( j = 0; j < tree_count; ++j )
               {
		    /** for each tree, attempt to read the "from" and
		      "fromselect" parameters. **/
		    
                    sprintf ( pnamebuf, "exch[%d].from.tree[%d]", i+1, j );
                    param = get_parameter ( pnamebuf );
                    sprintf ( pnamebuf2, "exch[%d].fromselect.tree[%d]",
                             i+1, j );
                    param2 = get_parameter ( pnamebuf2 );

                    if ( param == NULL && param2 == NULL )
                    {
			 /* neither is set, we're supposed to leave this
			    tree untouched in the destination individual. */
			 
                         mpop->exch[i].from[j] = -1;
                         mpop->exch[i].as[j] = -1;
                         mpop->exch[i].fromsc[j] = NULL;
                    }
                    else if ( param2 == NULL )
                    {
                         /* only "from" is set, examine param3 for default
			    selection method. */

			 /* source subpop. */
                         mpop->exch[i].from[j] = atoi ( param ) - 1;
                         if ( mpop->exch[i].from[j] < 0 || mpop->exch[i].from[j] >= mpop->size )
                         {
                              ++errors;
                              error ( E_ERROR, "\"%s\" is out of range.", pnamebuf );
                         }

			 /* no default set, error. */
                         if ( param3 == NULL )
                         {
                              ++errors;
                              error ( E_ERROR, "\"%s\" must be set.", pnamebuf2 );
                         }
                         else
                         {
                              mpop->exch[i].as[j] = -1;
                              if ( ! exists_select_method ( param3 ) )
                              {
                                   ++errors;
                                   error ( E_ERROR, "\"%s\": \"%s\" is not a selection method.",
                                          pnamebuf, param3 );
                              }
                         }
                         mpop->exch[i].fromsc[j] = param3;
                    }
                    else if ( param == NULL )
                    {
                         /* only "fromselect" is set; it better be of the form
			    "as_#". */
                         
                         if ( strncmp ( param2, "as_", 3 ) == 0 )
                         {
                              mpop->exch[i].from[j] = -1;
                              mpop->exch[i].fromsc[j] = NULL;
			      /* "as" stores which tree this one comes from the
				 same subpop as. */
                              mpop->exch[i].as[j] = atoi ( param2 + 3 );
                              if ( mpop->exch[i].as[j] < 0 ||
                                  mpop->exch[i].as[j] >= tree_count )
                              {
                                   ++errors;
                                   error ( E_ERROR, "\"%s\" is out of range.", pnamebuf2 );
                              }
                         }
                         else
                         {
                              ++errors;
                              error ( E_ERROR, "\"%s\" must be \"as_#\".", pnamebuf2 );
                         }
                    }
                    else
                    {
                         /* they're both set. */

                         mpop->exch[i].as[j] = -1;
                         mpop->exch[i].from[j] = atoi ( param ) - 1;
                         if ( mpop->exch[i].from[j] < 0 || mpop->exch[i].from[j] >= mpop->size )
                         {
                              ++errors;
                              error ( E_ERROR, "\"%s\" is out of range.", pnamebuf );
                         }
                         mpop->exch[i].fromsc[j] = param2;
                         if ( ! exists_select_method ( param2 ) )
                         {
                              ++errors;
                              error ( E_ERROR, "\"%s\": \"%s\" is not a selection method.",
                                     pnamebuf2, param2 );
                         }
                    }
               }

	       /* now we need to resolve any chains of "as_" references: if
		  tree 2 comes from the same individual as tree 1, and tree 1
		  comes from the same individual as tree 0, we need to change that
		  to say that both 2 and 1 come from tree 0.

		  also detect circular references. */
	       
               for ( j = 0; j < tree_count; ++j )
               {
                    if ( mpop->exch[i].as[j] == -1 )
                         continue;
                    k = mpop->exch[i].as[j];
                    while ( k != -1 )
                    {
                         if ( k == j )
                         {
                              ++errors;
                              error ( E_ERROR, "Circular reference resolving \"exch[%d].fromselect.tree[%d]\".",
                                     i+1, j );
                              j = tree_count;
                              break;
                         }
                         mpop->exch[i].as[j] = k;
                         k = mpop->exch[i].as[k];
                    }
                    k = mpop->exch[i].as[j];
                    if ( mpop->exch[i].from[k] == -1 && mpop->exch[i].as[k] == -1 )
                         mpop->exch[i].as[j] = -1;
               }
          }

          
#ifdef DEBUG
	  /* print out information on this exchange. */
          printf ( "exchange %d:\n", i+1 );
          printf ( "to: %d; count: %d; select: %s\n", mpop->exch[i].to,
                  mpop->exch[i].count, mpop->exch[i].tosc );
          if ( mpop->exch[i].copywhole == -1 )
          {
               for ( j = 0; j < tree_count; ++j )
               {
                    param = mpop->exch[i].fromsc[j];
                    printf ( "   %3d:  from: %3d   as: %3d   select: %s\n",
                            j, mpop->exch[i].from[j], mpop->exch[i].as[j],
                            param==NULL?"NULL":param );
               }
          }
          else
          {
               param = mpop->exch[i].fromsc[0];
               printf ( "copywhole: %d   select: %s\n",
                       mpop->exch[i].copywhole, param==NULL?"NULL":param );
          }
#endif
     }

     /* if any errors occurred then stop now. */
     if ( errors )
          error ( E_FATAL_ERROR, "Errors occurred while building topology.  Aborting." );

     /* print out the summary of exchanges. */
     oprintf ( OUT_SYS, 30, "    %d exchange(s) total.\n", mpop->exchanges );
     for ( i = 0; i < mpop->exchanges; ++i )
     {
          oprintf ( OUT_SYS, 30, "    exchange %d:\n", i+1 );
          oprintf ( OUT_SYS, 30, "        replace %d individual(s) in subpop %d (selected by %s)\n",
                   mpop->exch[i].count, mpop->exch[i].to+1, mpop->exch[i].tosc );
          if ( mpop->exch[i].copywhole != -1 )
               oprintf ( OUT_SYS, 30, "        with individual(s) from subpop %d (selected by %s)\n",
                        mpop->exch[i].copywhole+1, mpop->exch[i].fromsc[0] );
          else
               for ( j = 0; j < tree_count; ++j )
               {
                    if ( mpop->exch[i].from[j] == -1 )
                    {
                         if ( mpop->exch[i].as[j] == -1 )
                              oprintf ( OUT_SYS, 30, "        tree %d: leaving original tree\n", j );
                         else
                              oprintf ( OUT_SYS, 30, "        tree %d: from same individual as tree %d\n", j, mpop->exch[i].as[j] );
                    }
                    else
                         oprintf ( OUT_SYS, 30, "        tree %d: from subpop %d (selected by %s)\n", j,
                                  mpop->exch[i].from[j]+1, mpop->exch[i].fromsc[j] );
               }
     }

}

/* free_topology()
 *
 * this frees the topology table.
 */

void free_topology ( multipop *mpop )
{
     int i;
     for ( i = 0; i < mpop->exchanges; ++i )
     {
          if ( mpop->exch[i].from )
               FREE ( mpop->exch[i].from );
          if ( mpop->exch[i].as )
               FREE ( mpop->exch[i].as );
          FREE ( mpop->exch[i].fromsc );
     }
     if ( mpop->exch )
          FREE ( mpop->exch );
}

/* exchange_subpopulations()
 *
 * this performs the actual exchanges, using the information stored
 * in the exchange table.
 */

void exchange_subpopulations ( multipop *mpop )
{
     int i, j, k;
     sel_context *tocon;
     sel_context **fromcon;
     select_context_func_ptr select_con;
     int tp, *fp;
     int ti, *fi;

#ifdef _PARALLEL_H
     /* Are we working in parallel  */
     if (get_operation_mode() == SLAVE)
	{
	if (get_sync_mode() == ASYNC)
		{
		exchange_async_filter(mpop);
		}
	else
		{
		exchange_sync_filter(mpop);
		}

	return;
	}
#endif

     /** arrays used for composite individuals. **/

     /* fromcon[j] holds the selection context used to pick individual
	to take tree j from. */
     fromcon = (sel_context **)MALLOC ( tree_count * sizeof ( sel_context * ) );
     /* fp[j] holds the population from which to take tree j from. */
     fp = (int *)MALLOC ( tree_count * sizeof ( int ) );
     /* fi[j] holds the individual from which to take tree j from. */
     fi = (int *)MALLOC ( tree_count * sizeof ( int ) );

     for ( i = 0; i < mpop->exchanges; ++i )
     {
	  /* where individuals are going. */
          tp = mpop->exch[i].to;

	  /* set up selection method to pick individuals to be replaced. */
          select_con = get_select_context ( mpop->exch[i].tosc );
          tocon = select_con ( SELECT_INIT, NULL, mpop->pop[tp],
                              mpop->exch[i].tosc );

	  /* are we copying whole individuals or creating composites? */
          if ( mpop->exch[i].copywhole > -1 )
          {
	       /*** copying whole individuals. ***/

	       /* the source subpop. */
               fp[0] = mpop->exch[i].copywhole;

	       /* selection method for choosing individuals from source
		  subpop. */
               select_con = get_select_context ( mpop->exch[i].fromsc[0] );
               fromcon[0] = select_con ( SELECT_INIT, NULL, mpop->pop[fp[0]],
                                        mpop->exch[i].fromsc[0] );

               for ( k = 0; k < mpop->exch[i].count; ++k )
               {
                    do
                    {
                         ti = tocon->select_method ( tocon );
                    }
                    while ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH );

		    /* pick an individual from the source subpop. */
                    fi[0] = fromcon[0]->select_method ( fromcon[0] );
                                        
                    /** remove the old iondividual from the population. **/
                    for ( j = 0; j < tree_count; ++j )
                    {
			 /* always dereference ERCs when removing trees
			    from the population. */
                         reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, -1 );
                         free_tree ( mpop->pop[tp]->ind[ti].tr+j );
                    }

		    /* copy the individual. */
                    duplicate_individual ( mpop->pop[tp]->ind+ti,
                                           mpop->pop[fp[0]]->ind+fi[0] );

		    /* reference the ERCs in the new individual. */
                    for ( j = 0; j < tree_count; ++j )
                         reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, 1 );

		    /* mark the individual as just coming from an exchange. */
                    mpop->pop[tp]->ind[ti].flags = FLAG_NEWEXCH;
               }

	       /* all done with this exchange, delete the selection context. */
               fromcon[0]->context_method ( SELECT_CLEAN, fromcon[0],
                                           NULL, NULL );
          }
          else
          {
               /*** creating composite individuals. ***/

	       /** create selection contexts for each tree. **/
               for ( j = 0; j < tree_count; ++j )
               {
		    /* does this tree need a context? */
                    if ( mpop->exch[i].fromsc[j] )
                    {
			 /* create it. */
                         select_con = get_select_context ( mpop->exch[i].fromsc[j] );
                         fromcon[j] = select_con ( SELECT_INIT, NULL,
                                                  mpop->pop[mpop->exch[i].from[j]],
                                                  mpop->exch[i].fromsc[j] );
                    }
                    else
			 /* don't need one. */
                         fromcon[j] = NULL;
               }

               for ( k = 0; k < mpop->exch[i].count; ++k )
               {
		    /** select an individual to be replaced that hasn't already
		      been during this exchange cycle. **/
                    do
                    {
                         ti = tocon->select_method ( tocon );
                    }
                    while ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH );
                    
		    /** now select the individuals that we will merge to
		      replace trees of the destination individual. **/
                    for ( j = 0; j < tree_count; ++j )
                    {
			 /* we don't need to do a selection for a particular
			    tree if (1) it uses the same individual as another
			    tree or (2) it doesn't get replaced in the destination
			    individual. */

                         fp[j] = mpop->exch[i].from[j];
                         if ( fp[j] != -1 )
                         {
                              fi[j] = fromcon[fp[j]]->select_method ( fromcon[fp[j]] );
                         }
                    }

		    /** now resolve "as_" references in the fp and fi arrays. */
                    for ( j = 0; j < tree_count; ++j )
                         if ( fp[j] == -1 )
                         {
                              if ( mpop->exch[i].as[j] == -1 )
				   /* tree j doesn't get replaced, so set both
				      values to -1. */
                                   fp[j] = fi[j] = -1;
                              else
                              {
				   /* tree j comes from the same individual as
				      some other tree. */
                                   fp[j] = fp[mpop->exch[i].as[j]];
                                   fi[j] = fi[mpop->exch[i].as[j]];
                              }
                         }

                    /** replace the appropriate parts of the old tree. **/
                    for ( j = 0; j < tree_count; ++j )
                    {
			 /* skip trees that don't get replaced. */
                         if ( fp[j] == -1 )
                              continue;

			 /* dereference ERCs in old tree. */
                         reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, -1 );
			 /* delete old tree. */
                         free_tree ( mpop->pop[tp]->ind[ti].tr+j );
			 /* copy new tree. */
                         copy_tree ( mpop->pop[tp]->ind[ti].tr+j, mpop->pop[fp[j]]->ind[fi[j]].tr+j );
			 /* reference ERCs in new tree. */
                         reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, 1 );
                    }
		    /* evaluate the fitness of the new composite individual. */
                    app_eval_fitness ( mpop->pop[tp]->ind+ti );
                    mpop->pop[tp]->ind[ti].flags = FLAG_NEWEXCH;
               }

	       /* destroy source selection contexts. */
               for ( j = 0; j < tree_count; ++j )
                    if ( fromcon[j] )
                         fromcon[j]->context_method ( SELECT_CLEAN,
                                                     fromcon[j], NULL, NULL );
          }

	  /* destroy destination selection context. */
          tocon->context_method ( SELECT_CLEAN, tocon, NULL, NULL );
     }

     FREE ( fromcon );
     FREE ( fp );
     FREE ( fi );

     /* erase all the NEWEXCH flags. */
     for ( i = 0; i < mpop->size; ++i )
          for ( j = 0; j < mpop->pop[i]->size; ++j )
               mpop->pop[i]->ind[j].flags &= ~FLAG_NEWEXCH;

}

/* rebuild_exchange_topology()
 *
 * rebuilds the exchange table.  called from user code after making changes
 * to the parameters governing exchanges.
 */

void rebuild_exchange_topology ( multipop *mpop )
{
     free_topology ( mpop );
     initialize_topology ( mpop );
}


#ifdef _PARALLEL_H

/* exchange_test()
 *
 * returns the exchange type: NO, SEND, RECEIVE, NORMAL
 */

int exchange_test( int tp, int fp )
{
     static const int exch_matrix[2][2] = { { NOP, SEND }, { RECEIVE, NORMAL } };
     int from;
     int to;
     int low;
     int high;


     low = get_low();
     high = get_high();

     to = OTHER;
     if ( (low <= tp) && (tp < high) )
	{
	/* The destination population resides on this node */
	to = MYSELF;
	}

     from = OTHER;
     if ( (low <= fp) && (fp < high) )
	{
	/* The source population resides on this node */
	from = MYSELF;
	}


return exch_matrix[to][from];
}


/* exchange_async_filter()
 *
 * does a traversal of all the exchanges and invoke the appropriate functions
 */

void exchange_async_filter ( multipop *mpop )
{
     int i, j, k;
     sel_context **fromcon;
     sel_context *tocon;

     int tp, *fp;
     int *fi;
     int ti;
#ifdef PDEBUG_SYNC_FILTER
     int exch_type;
#endif

     int low;
     int high;

     int counter;
     int cursor_import, cursor_normal;

     Exchange_item *tmp_exchange;

     /* First we build a list for the different types of exchange */
     if (init == 0)
	{
	export_list = build_exchange_list (mpop, SEND);
	import_list = build_exchange_list (mpop, RECEIVE);
	normal_list = build_exchange_list (mpop, NORMAL);

#ifdef PDEBUG_SYNC_FILTER
	print_exchange_list (export_list);
	print_exchange_list (import_list);
	print_exchange_list (normal_list);
#endif

	/* Initialisation done */
	init = 1;
	}

     low = get_low();
     high = get_high();

     /** arrays used for composite individuals. **/

     /* fromcon[j] holds the selection context used to pick individual
	to take tree j from. */
     fromcon = (sel_context **)MALLOC ( tree_count * sizeof ( sel_context * ) );
     /* fp[j] holds the population from which to take tree j from. */
     fp = (int *)MALLOC ( tree_count * sizeof ( int ) );
     /* fi[j] holds the individual from which to take tree j from. */
     fi = (int *)MALLOC ( tree_count * sizeof ( int ) );

     /* Initialize the selection contexts */
     set_exchange_list (mpop, &export_list, SELECT_INIT);
     set_exchange_list (mpop, &import_list, SELECT_INIT);
     set_exchange_list (mpop, &normal_list, SELECT_INIT);

     /* First we send all the individuals & tree we export */
     exchange_export (mpop, &export_list, fromcon, fp, fi);

     /* At this point all the exports should have been done (if any of course) */

     /* Second we wait until we receive the different individuals & tree ourselves */
     exchange_async_import (mpop, &import_list);

     /* Check whether the user termination criterion was not met by another node in which case we stop */
     if (get_term() == 1)
	{
	FREE ( fromcon );
	FREE ( fp );
	FREE ( fi );

	return;
        }

#ifdef PDEBUG_SYNC_FILTER
     print_exchange_list (import_list);
#endif

     /* And three, now we can execute the exchanges in ORDER */
     /* Huge code duplication :-(( */
     cursor_import = 0;
     cursor_normal = 0;

     counter = 0;

     /* The big loop where we do all the exchanges in the same order as in the sequential code. */
     while ( (cursor_import < import_list.size) || (cursor_normal < normal_list.size) )
	{
	/* What is the next exchange? */
	tmp_exchange = next_exchange(&import_list, &normal_list, &cursor_import, &cursor_normal);
	i = tmp_exchange->exch;

#ifdef PDEBUG_SYNC_FILTER
	/* Major debugging stuff here: printf */
	printf(" exchange_id : %d exchange: %d counter: %d tree: %d\n",
		tmp_exchange->id,
		tmp_exchange->exch,
		tmp_exchange->count,
		tmp_exchange->tree);
#endif

	/* where individuals are going. */
	tp = mpop->exch[i].to;

	tocon = tmp_exchange->tocon;

	/* are we copying whole individuals or creating composites? */
        if (tmp_exchange->copywhole > -1 )
		{
	       	/*** copying whole individuals. ***/

		/** pick an individual to be replaced that has not already
		    been replaced during this exchange cycle. **/
		do
		{
			ti = tocon->select_method ( tocon );
		}
		while ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH );

	       	/* the source subpop. */
               	fp[0] = tmp_exchange->copywhole;

		/* selection method for choosing individuals from source
		       subpop. */
		fromcon[0] = tmp_exchange->fromcon;

		k = tmp_exchange->count;

		if (tmp_exchange->type == RECEIVE)
			{
			if (tmp_exchange->valid == 0)
				continue;

			exchange_import_lowlevel(mpop, i, tp, ti, tmp_exchange->ind_ptr, &tmp_exchange->tmp_tree, tmp_exchange->tree);

			/* Invalidate explicitly (including the pointer, just to make it hurt immediatly) */
			tmp_exchange->valid = 0;
			tmp_exchange->ind_ptr = NULL;
			}
		else
			{
		    	/* pick an individual from the source subpop. */
                    	fi[0] = fromcon[0]->select_method ( fromcon[0] );

			exchange_normal(mpop, i, tp, ti, fp[0], fi[0], -1);
			}
		}
	else
		{
		/*** creating composite individuals. ***/
		/** create selection contexts for each tree. **/
		j = tmp_exchange->tree;
		k = tmp_exchange->count;

		/* does this tree need a context? */
		fromcon[j] = tmp_exchange->fromcon;

		/** now select the individuals that we will merge to
		    replace trees of the destination individual. **/

		/** select an individual to be replaced that hasn't already
		    been during this exchange cycle. **/
                do
                	{
                	ti = tocon->select_method ( tocon );
			}
		while ( ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH ) &&
			( mpop->pop[tp]->ind[ti].current_exch != tmp_exchange->exch )	);


		/* Not a 'new' individual */
		if (!( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH ))
			{
#ifdef PDEBUG_IMPORT_LOWLEVEL
			printf("Marking an individual in exchange_sync_filter()\n");
#endif
			/* This one is 'untouched' we take it! */
			mpop->pop[tp]->ind[ti].current_exch = tmp_exchange->exch;
			mpop->pop[tp]->ind[ti].new_trees = 0;
			}
		else
			{
			if (mpop->pop[tp]->ind[ti].current_exch != tmp_exchange->exch )
				{
				error (E_ERROR, "No individual found in exchange_import_lowlevel");
				}
			}

		/* we don't need to do a selection for a particular
		  tree if (1) it uses the same individual as another
		  tree or (2) it doesn't get replaced in the destination
		  individual. */

		fp[j] = mpop->exch[i].from[j];

		if ( fp[j] != -1 )
			{
			fi[j] = fromcon[fp[j]]->select_method ( fromcon[fp[j]] );
			}

		/** now resolve "as_" references in the fp and fi arrays. */
		if ( fp[j] == -1 )
			{
			if ( mpop->exch[i].as[j] == -1 )
				/* tree j doesn't get replaced, so set both
				   values to -1. */
				fp[j] = fi[j] = -1;
			else
				{
				/* tree j comes from the same individual as
				   some other tree. */
				fp[j] = fp[mpop->exch[i].as[j]];
				fi[j] = fi[mpop->exch[i].as[j]];
				}
			}

		/** replace the appropriate parts of the old tree. **/
		/* skip trees that don't get replaced. */
		if ( fp[j] == -1 )
			continue;

		if (tmp_exchange->type == RECEIVE)
			{
			if (tmp_exchange->valid == 0)
				continue;

			exchange_import_lowlevel(mpop, i, tp, ti, tmp_exchange->ind_ptr, &tmp_exchange->tmp_tree, tmp_exchange->tree);
			tmp_exchange->valid = 0;
			}
		else
			{
			exchange_normal(mpop, i, tp, ti, fp[j], fi[j], j);
			}
		}

	/* And one more exchange done */
	counter++;
	}  /* End of loop */


#ifdef PDEBUG_SYNC_FILTER
	print_exchange_list (import_list);

	/* Did we indeed do all the exchanges? */
	if (counter != (import_list.size + normal_list.size))
	      error (E_FATAL_ERROR, "Incorrect exchange in exchange_sync_filter() (V)");
#endif

     /* Clean of the selection contexts */
     set_exchange_list (mpop, &export_list, SELECT_CLEAN);
     set_exchange_list (mpop, &import_list, SELECT_CLEAN);
     set_exchange_list (mpop, &normal_list, SELECT_CLEAN);


/* erase all the NEWEXCH flags. */
for ( i = low; i < high; ++i )
    for ( j = 0; j < mpop->pop[i]->size; ++j )
	 {
         mpop->pop[i]->ind[j].flags &= ~FLAG_NEWEXCH;
	 mpop->pop[i]->ind[j].current_exch = -1;
	 mpop->pop[i]->ind[j].new_trees = 0;
	 }


FREE ( fromcon );
FREE ( fp );
FREE ( fi );

}


/* exchange_sync_filter()
 *
 * does a traversal of all the exchanges and invoke the appropriate functions
 */

void exchange_sync_filter ( multipop *mpop )
{
     int i, j, k;
     sel_context **fromcon;
     sel_context *tocon;

     int tp, *fp;
     int *fi;
     int ti;
#ifdef PDEBUG_SYNC_FILTER
     int exch_type;
#endif

     int low;
     int high;
     int nhost;

     int counter;
     int cursor_import, cursor_normal;
     int group_id;

     Exchange_item *tmp_exchange;

     /* First we build a list for the different types of exchange */
     if (init == 0)
	{
	export_list = build_exchange_list (mpop, SEND);
	import_list = build_exchange_list (mpop, RECEIVE);
	normal_list = build_exchange_list (mpop, NORMAL);

	empty_import_nodes = no_import_nodes (mpop);

	group_id = pvm_joingroup (PARALLEL_GROUP);

#ifdef PDEBUG_SYNC_FILTER
	print_exchange_list (export_list);
	print_exchange_list (import_list);
	print_exchange_list (normal_list);
#endif

	/* Initialisation done */
	init = 1;
	}

     nhost = get_nhost();

     low = get_low();
     high = get_high();

     /** arrays used for composite individuals. **/

     /* fromcon[j] holds the selection context used to pick individual
	to take tree j from. */
     fromcon = (sel_context **)MALLOC ( tree_count * sizeof ( sel_context * ) );
     /* fp[j] holds the population from which to take tree j from. */
     fp = (int *)MALLOC ( tree_count * sizeof ( int ) );
     /* fi[j] holds the individual from which to take tree j from. */
     fi = (int *)MALLOC ( tree_count * sizeof ( int ) );

     /* Initialize the selection contexts */
     set_exchange_list (mpop, &export_list, SELECT_INIT);
     set_exchange_list (mpop, &import_list, SELECT_INIT);
     set_exchange_list (mpop, &normal_list, SELECT_INIT);

     /* First we send all the individuals & tree we export */
     exchange_export (mpop, &export_list, fromcon, fp, fi);

     /* At this point all the exports should have been done (if any of course) */

     /* Second we wait until we receive the different individuals & tree ourselves */
     exchange_sync_import (mpop, &import_list);

     /* Check whether the user termination criterion was not met by another node in which case we stop */
     if (get_term() == 1)
	{
	FREE ( fromcon );
	FREE ( fp );
	FREE ( fi );

	return;
        }

#ifdef PDEBUG_SYNC_FILTER
     print_exchange_list (import_list);
#endif

     /* And three, now we can execute the exchanges in ORDER */
     /* Huge code duplication :-(( */
     cursor_import = 0;
     cursor_normal = 0;

     counter = 0;

     /* The big loop where we do all the exchanges in the same order as in the sequential code. */
     while ( (cursor_import < import_list.size) || (cursor_normal < normal_list.size) )
	{
	/* What is the next exchange? */
	tmp_exchange = next_exchange(&import_list, &normal_list, &cursor_import, &cursor_normal);
	i = tmp_exchange->exch;

#ifdef PDEBUG_SYNC_FILTER
	/* Major debugging stuff here: printf */
	printf(" exchange_id : %d exchange: %d counter: %d tree: %d\n",
		tmp_exchange->id,
		tmp_exchange->exch,
		tmp_exchange->count,
		tmp_exchange->tree);
#endif

	/* where individuals are going. */
	tp = mpop->exch[i].to;

	tocon = tmp_exchange->tocon;

	/* are we copying whole individuals or creating composites? */
        if (tmp_exchange->copywhole > -1 )
		{
	       	/*** copying whole individuals. ***/

		/** pick an individual to be replaced that has not already
		    been replaced during this exchange cycle. **/
		do
		{
			ti = tocon->select_method ( tocon );
		}
		while ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH );

	       	/* the source subpop. */
               	fp[0] = tmp_exchange->copywhole;

		/* selection method for choosing individuals from source
		       subpop. */
		fromcon[0] = tmp_exchange->fromcon;

		k = tmp_exchange->count;

		if (tmp_exchange->type == RECEIVE)
			{
			if (tmp_exchange->valid == 0)
				error (E_FATAL_ERROR, "Invalid individual in exchange_sync_filter()");

			exchange_import_lowlevel(mpop, i, tp, ti, tmp_exchange->ind_ptr, &tmp_exchange->tmp_tree, tmp_exchange->tree);

			/* Invalidate explicitly (including the pointer, just to make it hurt immediatly) */
			tmp_exchange->valid = 0;
			tmp_exchange->ind_ptr = NULL;
			}
		else
			{
		    	/* pick an individual from the source subpop. */
                    	fi[0] = fromcon[0]->select_method ( fromcon[0] );

			exchange_normal(mpop, i, tp, ti, fp[0], fi[0], -1);
			}
		}
	else
		{
		/*** creating composite individuals. ***/
		/** create selection contexts for each tree. **/
		j = tmp_exchange->tree;
		k = tmp_exchange->count;

		/* does this tree need a context? */
		fromcon[j] = tmp_exchange->fromcon;

		/** now select the individuals that we will merge to
		    replace trees of the destination individual. **/

		/** select an individual to be replaced that hasn't already
		    been during this exchange cycle. **/
                do
                	{
                	ti = tocon->select_method ( tocon );
			}
		while ( ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH ) &&
			( mpop->pop[tp]->ind[ti].current_exch != tmp_exchange->exch )	);


		/* Not a 'new' individual */
		if (!( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH ))
			{
#ifdef PDEBUG_IMPORT_LOWLEVEL
			printf("Marking an individual in exchange_sync_filter()\n");
#endif
			/* This one is 'untouched' we take it! */
			mpop->pop[tp]->ind[ti].current_exch = tmp_exchange->exch;
			mpop->pop[tp]->ind[ti].new_trees = 0;
			}
		else
			{
			if (mpop->pop[tp]->ind[ti].current_exch != tmp_exchange->exch )
				{
				error (E_ERROR, "No individual found in exchange_import_lowlevel");
				}
			}

		/* we don't need to do a selection for a particular
		  tree if (1) it uses the same individual as another
		  tree or (2) it doesn't get replaced in the destination
		  individual. */

		fp[j] = mpop->exch[i].from[j];

		if ( fp[j] != -1 )
			{
			fi[j] = fromcon[fp[j]]->select_method ( fromcon[fp[j]] );
			}

		/** now resolve "as_" references in the fp and fi arrays. */
		if ( fp[j] == -1 )
			{
			if ( mpop->exch[i].as[j] == -1 )
				/* tree j doesn't get replaced, so set both
				   values to -1. */
				fp[j] = fi[j] = -1;
			else
				{
				/* tree j comes from the same individual as
				   some other tree. */
				fp[j] = fp[mpop->exch[i].as[j]];
				fi[j] = fi[mpop->exch[i].as[j]];
				}
			}

		/** replace the appropriate parts of the old tree. **/
		/* skip trees that don't get replaced. */
		if ( fp[j] == -1 )
			continue;

		if (tmp_exchange->type == RECEIVE)
			{
			if (tmp_exchange->valid == 0)
				error (E_FATAL_ERROR, "Invalid tree in exchange_sync_filter()");

			exchange_import_lowlevel(mpop, i, tp, ti, tmp_exchange->ind_ptr, &tmp_exchange->tmp_tree, tmp_exchange->tree);
			tmp_exchange->valid = 0;
			}
		else
			{
			exchange_normal(mpop, i, tp, ti, fp[j], fi[j], j);
			}
		}

	/* And one more exchange done */
	counter++;
	}  /* End of loop */

	/* Do we need barrier synchronisation? */
	if (empty_import_nodes)
		{
#ifdef PDEBUG_SYNC_FILTER
		printf ("Barrier synchronisation needed for %d tasks in exchange_synch_filter()\n", nhost);
#endif
		pvm_barrier (PARALLEL_GROUP, nhost);
		}

#ifdef PDEBUG_SYNC_FILTER
	print_exchange_list (import_list);

	/* Did we indeed do all the exchanges? */
	if (counter != (import_list.size + normal_list.size))
	      error (E_FATAL_ERROR, "Incorrect exchange in exchange_sync_filter() (V)");
#endif

     /* Clean of the selection contexts */
     set_exchange_list (mpop, &export_list, SELECT_CLEAN);
     set_exchange_list (mpop, &import_list, SELECT_CLEAN);
     set_exchange_list (mpop, &normal_list, SELECT_CLEAN);


/* erase all the NEWEXCH flags. */
for ( i = low; i < high; ++i )
    for ( j = 0; j < mpop->pop[i]->size; ++j )
	 {
         mpop->pop[i]->ind[j].flags &= ~FLAG_NEWEXCH;
	 mpop->pop[i]->ind[j].current_exch = -1;
	 mpop->pop[i]->ind[j].new_trees = 0;
	 }


FREE ( fromcon );
FREE ( fp );
FREE ( fi );

}


/* exchange_export
 *
 * exports the tree/individuals as specified by the given exchange list
 */

void exchange_export (multipop *mpop, Exchange_list *export_list, sel_context **fromcon, int *fp, int *fi)
{
     int i, j, k;
//     sel_context **fromcon;
     int tp;
//     int *fp;
//     int *fi;
#ifdef PDEBUG_ASYNC_FILTER
     int exch_type;
#endif
     int stop;
     int index;
     int low;
     int high;

     Exchange_item *tmp_exchange;

     low = get_low();
     high = get_high();

     /* First we send all the individuals & tree we export */
     stop = export_list->size;
     for (index = 0; index < stop; index++)
	{
	/* Avoid indexing by using a tmp variable */
	tmp_exchange = &(export_list->exchanges[index]);
	i = tmp_exchange->exch;

	/* where individuals are going. */
	tp = mpop->exch[i].to;

	/* are we copying whole individuals or creating composites? */
	if (tmp_exchange->copywhole > -1 )
        	{
		/*** copying whole individuals. ***/
	       	/* the source subpop. */
               	fp[0] = tmp_exchange->copywhole;
               	k = tmp_exchange->count;

#ifdef PDEBUG_EXPORT
		exch_type = exchange_test(tp, fp[0]);
	       	if ( exch_type != SEND )
			error (E_FATAL_ERROR, "Incorrect exchange in exchange_sync_filter() (I)");
#endif

	       	/* selection method for choosing individuals from source
		   subpop. */
	       	fromcon[0] = tmp_exchange->fromcon;

		/* pick an individual from the source subpop. */
                fi[0] = fromcon[0]->select_method ( fromcon[0] );

	    	/* We know the: populations,, ind */
		exchange_export_lowlevel(mpop, tmp_exchange->id, i, tp, fp[0], fi[0], -1);
		}
	else
		{
		/*** creating composite individuals. ***/
		/** create selection contexts for each tree. **/
		j = tmp_exchange->tree;
		k = tmp_exchange->count;
		j = tmp_exchange->tree;

#ifdef PDEBUG_EXPORT
		exch_type = exchange_test(tp, mpop->exch[i].from[j]);
		if (exch_type != SEND )
			error (E_FATAL_ERROR, "Incorrect exchange in exchange_sync_filter() (II)");
#endif

		/** now select the individuals that we will merge to
		    replace trees of the destination individual. **/
		fromcon[k] = tmp_exchange->fromcon;

		/* we don't need to do a selection for a particular
		   tree if (1) it uses the same individual as another
		   tree or (2) it doesn't get replaced in the destination
		   individual. */

		fp[j] = mpop->exch[i].from[j];

#ifdef PDEBUG_EXPORT
		exch_type = exchange_test(tp, fp[j]);
		if (exch_type != SEND)
			error (E_FATAL_ERROR, "Incorrect exchange in exchange_sync_filter() (III)");
#endif

		if ( fp[j] != -1 )
			{
			fi[j] = fromcon[fp[j]]->select_method ( fromcon[fp[j]] );
                        }

		/** now resolve "as_" references in the fp and fi arrays. */
		if ( fp[j] == -1 )
			{
			if ( mpop->exch[i].as[j] == -1 )
				/* tree j doesn't get replaced, so set both
				   values to -1. */
				fp[j] = fi[j] = -1;
			else
				{
				/* tree j comes from the same individual as some other tree. */
				fp[j] = fp[mpop->exch[i].as[j]];
				fi[j] = fi[mpop->exch[i].as[j]];
				}
			}

		/** replace the appropriate parts of the old tree. **/
		/* skip trees that don't get replaced. */
		if ( fp[j] == -1 )
			continue;
#ifdef PDEBUG_EXPORT
		exch_type = exchange_test(tp, fp[0]);
		if ( exch_type != SEND )
			error (E_FATAL_ERROR, "Incorrect exchange in exchange_sync_filter() (IV)");
#endif

		exchange_export_lowlevel(mpop, tmp_exchange->id, i, tp, fp[j], fi[j], j);
		}
	}  /* End export loop */

return;
}


/* exchange_async_import()
 *
 * checks whether there are trees/individuals can be imported and merged/copied
 * this function has a event driven character since its processing is based on the
 * received messages.
 */

void exchange_async_import ( multipop *mpop, Exchange_list *list)
{
struct timeval time_out;

#ifdef PDEBUG_ASYNC_IMPORT
int i;
#endif

int k;

int ft;

int bufid;
int exch;
int exch_id;

int bytes;
int msgtg;
int tid;
int gen;

int stop;
int current_gen;
int index;
int received;

individual *ind_ptr;
tree tmp_tree;

#ifdef PDEBUG_ASYNC_IMPORT
printf ("Receiving asynchronous mode\n");
#endif

/* Received nothing yet */
received = 0;

/* Stop when the list is full */
stop = list->size;

/* the current generation */
current_gen = get_current_generation();

/* Initialise the time out for ASYNCHRONOUS operations */
time_out.tv_usec = 0;
time_out.tv_sec = 0;


while ( (received != stop) && (bufid = pvm_trecv(-1, -1, &time_out)) )
	{
	pvm_bufinfo ( bufid, &bytes, &msgtg, &tid );

	/* Intermediate reset */
	ft = -1;

#ifdef PDEBUG_ASYNC_IMPORT
printf ("MSG FROM tid[%x]\n", tid);
#endif

	switch (msgtg)
		{
		case TERM_REQUEST_TAG:
				{
				/* We are asked to stop working. We set the termination criterion
				   artificially and we leave this function. */
				/* Force the user termination criterium */
				set_term(1);

#ifdef PDEBUG_ASYNC_IMPORT
				printf ("ASYNC_IMPORT TERM\n");
#endif

				return;

				break;  /* Useless, yes I know that. */
				}

		case IND_TAG:
				{
				/* Extract exchange_number and all the trees */
				receive_individual ( &exch_id, &exch, &ind_ptr, &gen );
				received++;
#ifdef PDEBUG_ASYNC_IMPORT
				printf ("SYNC_IMPORT RECEIVE IND\n");
#endif

				break;
				}

		case TREE_TAG:
				{
				/* Extract exchange_number, destination pop. the tree and the tree number */
				receive_tree ( &exch_id, &exch, &ft, &tmp_tree, &gen );
				received++;
#ifdef PDEBUG_ASYNC_IMPORT
				printf ("ASYNC_IMPORT TREE\n");
#endif
				break;
				}

		default:
				{
				error (E_FATAL_ERROR, "Unkown tag in exchange_async_import() value = %d", msgtg);
				}
		}

#ifdef PDEBUG_ASYNC_IMPORT
	/* Major debugging stuff here: printf */
	printf(" exchange_id : %d exchange: %d from_tree: %d generation: %d received: %d\n",
		exch_id,
		exch,
		ft,
		gen,
		received);
#endif

	/* Look for some space in the list to put what we just received. */
	index = 0;

	while ( (index <stop) && (list->exchanges[index].id != exch_id) )
		index++;

	if (msgtg == IND_TAG)
		{
		if (index < stop)
			{
#ifdef PDEBUG_ASYNC_IMPORT
			printf("Adding at %d individual %#lx --> ", index, (long) ind_ptr);
#endif
			list->exchanges[index].ind_ptr = ind_ptr;
			list->exchanges[index].valid = 1;

#ifdef PDEBUG_ASYNC_IMPORT
			printf("Done  at %d individual %#lx\n", index, (long) list->exchanges[index].ind_ptr);
#endif
			}
		else
			{
			/* No space we free the individual */
			/* Starting with all the trees themselves */
			for (k=0; k<tree_count; k++)
				free_tree(ind_ptr->tr+k);

			/* Free the individual structure */
			FREE(ind_ptr);

			}
		}
	else
		{
		if (index < stop)
			{
#ifdef PDEBUG_ASYNC_IMPORT
			printf("Adding 1 tree\n");
#endif

			list->exchanges[index].tmp_tree = tmp_tree;
			list->exchanges[index].valid = 1;

#ifdef PDEBUG_ASYNC_IMPORT
			printf("Done   1 tree\n");
#endif
			}
		else
			{
			/* No space we throw the tree away */
			free_tree( &tmp_tree ) ;
			}
		}

	}


return;
}





/* exchange_sync_import()
 *
 * checks whether there are trees/individuals can be imported and merged/copied
 * this function has a event driven character since its processing is based on the
 * received messages.
 */

void exchange_sync_import ( multipop *mpop, Exchange_list *list )
{
struct timeval time_out;

#ifdef PDEBUG_SYNC_IMPORT
int i;
#endif

int ft;

int bufid;
int exch;
int exch_id;

int bytes;
int msgtg;
int tid;
int gen;

int stop;
int current_gen;
int index;
int received;

individual *ind_ptr;
tree tmp_tree;

#ifdef PDEBUG_SYNC_IMPORT
printf ("Receiving\n");
#endif

/* Received nothing yet */
received = 0;

/* Stop when the list is full */
stop = list->size;

/* the current generation */
current_gen = get_current_generation();

/* Initialise the time out for ASYNCHRONOUS operations */
time_out.tv_usec = 0;
time_out.tv_sec = TIME_OUT;


while ( (received != stop) && (bufid = pvm_trecv(-1, -1, &time_out)) )
	{
	pvm_bufinfo ( bufid, &bytes, &msgtg, &tid );

	/* Intermediate reset */
	ft = -1;

#ifdef PDEBUG_SYNC_IMPORT
printf ("MSG FROM tid[%x]\n", tid);
#endif

	switch (msgtg)
		{
		case TERM_REQUEST_TAG:
				{
				/* We are asked to stop working. We set the termination criterion
				   artificially and we leave this function. */
				/* Force the user termination criterium */
				set_term(1);

#ifdef PDEBUG_SYNC_IMPORT
				printf ("SYNC_IMPORT TERM\n");
#endif

				return;

				break;  /* Useless, yes I know that. */
				}

		case IND_TAG:
				{
				/* Extract exchange_number and all the trees */
				receive_individual ( &exch_id, &exch, &ind_ptr, &gen );
				received++;
#ifdef PDEBUG_SYNC_IMPORT
printf ("SYNC_IMPORT RECEIVE IND\n");
#endif

				break;
				}

		case TREE_TAG:
				{
				/* Extract exchange_number, destination pop. the tree and the tree number */
				receive_tree ( &exch_id, &exch, &ft, &tmp_tree, &gen );
				received++;
#ifdef PDEBUG_SYNC_IMPORT
printf ("SYNC_IMPORT TREE\n");
#endif
				break;
				}

		default:
				{
				error (E_FATAL_ERROR, "Unkown tag in exchange_sync_import() value = %d", msgtg);
				}
		}

#ifdef PDEBUG_SYNC_IMPORT
	/* Major debugging stuff here: printf */
	printf(" exchange_id : %d exchange: %d from_tree: %d generation: %d received: %d\n",
		exch_id,
		exch,
		ft,
		gen,
		received);
#endif

	if ( gen != current_gen )
		{
		/* Oh oh, the individual/tree we just got is from a previous generation!
		This should not happen. */
		error (E_FATAL_ERROR, "individual/tree from a different generation! %d (locally) vs %d exchange_sync_import()", current_gen, gen);
		}

	/* Look for some space in the list to put what we just received. */
	index = 0;

	while ( (index <stop) && (list->exchanges[index].id != exch_id) )
		index++;

	if (index == stop)
		error (E_ERROR, "Exchange_list is full in exchange_sync_import()");

	if (list->exchanges[index].valid == 1)
		error (E_ERROR, "Position in Exchange_list is occupied in exchange_sync_import()");

	if (msgtg == IND_TAG)
		{
#ifdef PDEBUG_SYNC_IMPORT
		printf("Adding at %d individual %#lx --> ", index, (long) ind_ptr);
#endif
		list->exchanges[index].ind_ptr = ind_ptr;
		list->exchanges[index].valid = 1;
#ifdef PDEBUG_SYNC_IMPORT
		printf("Done  at %d individual %#lx\n", index, (long) list->exchanges[index].ind_ptr);
#endif
		}
	else
		{
#ifdef PDEBUG_SYNC_IMPORT
		printf("Adding 1 tree\n");
#endif
		list->exchanges[index].tmp_tree = tmp_tree;
		list->exchanges[index].valid = 1;
#ifdef PDEBUG_SYNC_IMPORT
		printf("Done   1 tree\n");
#endif
		}

	}

/* Run-time check to detect timeouts!! */
if (received != stop)
	error (E_FATAL_ERROR, "Timeout, did not receive everything in exchange_sync_import() %d out of %d edit parallel.h if necessary.", received, stop);

#ifdef PDEBUG_SYNC_IMPORT
/* A little integrity check */
received = 0;
for (i = 0; i< stop; i++)
	{
	if (list->exchanges[i].valid)
		received++;
	}

if (received != stop)
	error (E_FATAL_ERROR, "Did not REALLY receive everything in exchange_sync_import() %d out of %d", received, stop);

#endif


return;
}


/* exchange_import_lowlevel()
 *
 * performs the import for all the imports (sync & async)
 */

void exchange_import_lowlevel ( multipop *mpop, int exch, int tp, int ti, individual *ind_ptr, tree *tmp_tree, int tree)
{
int i, j, k;
int ft;

int tid;

/* Reuse the variable "i" from the original code :-) */
i = exch;
ft = tree;

#ifdef PDEBUG_IMPORT_LOWLEVEL
printf ("Exchange nr. %d dest. pop %d from tree %d \n", i, mpop->exch[i].to, ft);
#endif


/* Check if the population to node mapping was correct */
tid = population_mapping (tp);
if (tid != pvm_mytid())
	error (E_FATAL_ERROR, "Incorrect mapping! Received msg meant for population number %d\n", tp);


/* are we copying whole individuals or creating composites? */
if ( mpop->exch[i].copywhole > -1 )
	{
	/*** copying whole individuals. ***/
	/** remove the old iondividual from the population. **/
        for ( j = 0; j < tree_count; ++j )
        	{
		/* always dereference ERCs when removing trees
		    from the population. */
                reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, -1 );
                free_tree ( mpop->pop[tp]->ind[ti].tr+j );
                }

	/* copy the individual. */
	duplicate_individual ( mpop->pop[tp]->ind+ti, ind_ptr );

	/* Freeing the individual */
	/* Starting with all the trees themselves */
	for (k=0; k<tree_count; k++)
		free_tree(ind_ptr->tr+k);

	/* Free the array */
	FREE(ind_ptr->tr);

	/* Free the individual structure */
	FREE(ind_ptr);

	/* reference the ERCs in the new individual. */
        for ( j = 0; j < tree_count; ++j )
		reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, 1 );

	/* mark the individual as just coming from an exchange. */
        mpop->pop[tp]->ind[ti].flags = FLAG_NEWEXCH;
        }
else
	{
        /*** creating composite individuals. ***/

	/* dereference ERCs in old tree. */
	reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[ft].data, -1 );
	/* delete old tree. */
	free_tree ( mpop->pop[tp]->ind[ti].tr+ft );

	/* copy new tree. */
	copy_tree ( mpop->pop[tp]->ind[ti].tr+ft, tmp_tree);

	/* Free the tree */
	free_tree (tmp_tree);

	/* reference ERCs in new tree. */
	reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[ft].data, 1 );

	/* We need to mark and identify a individual being assembled with new TREES */
	mpop->pop[tp]->ind[ti].flags = FLAG_NEWEXCH;
	mpop->pop[tp]->ind[ti].new_trees++;

	/* If this individual has completely been renewed we reevaluate it */
	if (mpop->pop[tp]->ind[ti].new_trees == tree_count)
		{
		/* This is a completely new individual we can evaluate it now */
		/* evaluate the fitness of the new composite individual. */
		app_eval_fitness ( mpop->pop[tp]->ind+ti );
		}
	}

return;
}


/* exchange_normal
 *
 * should do the same as the initial exchange function
 */

void exchange_normal ( multipop *mpop, int exch, int tp, int ti, int fp, int fi, int ft )
{
     const int i =  exch;
     int j;


	/* are we copying whole individuals or creating composites? */
	if ( mpop->exch[i].copywhole > -1 )
		{
		/*** copying whole individuals. ***/
		/** remove the old iondividual from the population. **/
		for ( j = 0; j < tree_count; ++j )
			{
			/* always dereference ERCs when removing trees
			   from the population. */
			reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, -1 );
			free_tree ( mpop->pop[tp]->ind[ti].tr+j );
			}

		/* copy the individual. */
		duplicate_individual ( mpop->pop[tp]->ind+ti, mpop->pop[fp]->ind+fi );

		/* reference the ERCs in the new individual. */
		for ( j = 0; j < tree_count; ++j )
			reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[j].data, 1 );

		/* mark the individual as just coming from an exchange. */
		mpop->pop[tp]->ind[ti].flags = FLAG_NEWEXCH;
		}
	else
		{
		/*** creating composite individuals. ***/
		/* dereference ERCs in old tree. */
		reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[ft].data, -1 );
		/* delete old tree. */
		free_tree ( mpop->pop[tp]->ind[ti].tr+ft );
		/* copy new tree. */
		copy_tree ( mpop->pop[tp]->ind[ti].tr+ft, mpop->pop[fp]->ind[fi].tr+ft );
		/* reference ERCs in new tree. */
                reference_ephem_constants ( mpop->pop[tp]->ind[ti].tr[ft].data, 1 );
		}

}


/* exchange_export_lowlevel()
 *
 * exports individuals to population not present on this node
 */

void exchange_export_lowlevel ( multipop *mpop, int exch_id, int exch, int tp, int fp, int fi, int ft )
{
int destination_node;
int gen;

/* Determine the node on which the population resides */
destination_node = population_mapping (tp);

gen = get_current_generation();

if (destination_node < 0)
	error (E_FATAL_ERROR, "In exchange_export() no node for population number %d", tp);


     /* are we copying whole individuals or creating composites? */
     if ( mpop->exch[exch].copywhole > -1 )
     {
     /*** copying whole individuals. ***/
     /* send the individual: exchange nr, pop, ind, ind ptr */
     send_individual ( destination_node, exch_id, exch, mpop->pop[fp]->ind+fi, gen );

     }
     else
     {
     /* send the tree: exchange nr, pop, ind, tree, tree ptr */
     send_tree ( destination_node, exch_id, exch, ft, mpop->pop[fp]->ind[fi].tr+ft, gen );

     }

return;
}


/* signal_master()
 *
 * send termination signal to the master
 */

void signal_master(int signal)
{
int low;
int high;
int ptid;

low = get_low();
high = get_high();

ptid = pvm_parent();

pvm_initsend(ENCODING);

if (pvm_pkint(&low, 1, 1))
	pvm_perror ("Error packing \"low\" in error()");

if (pvm_pkint(&high, 1, 1))
	pvm_perror ("Error packing \"high\" in error()");


pvm_send (ptid, signal);

}



/* build_exchange_list()
 *
 * this function examins the exchanges and determines the exchanges in more detail.
 */

Exchange_list build_exchange_list ( multipop *mpop, int exch_type )
{
Exchange_list ret;

int i, j, k;
int to, from;
int index;
int counter;
int low;

char *parameter;

low = get_low();
ret.size = 0;
index = 0;

parameter = get_parameter("multiple.exchanges");
if (parameter == NULL)
	error ( E_FATAL_ERROR, "get_parameter() failed for \"multiple.exchanges\" in build_exchange_list");


/* Allocate initial memory for the list (it will be BIG!!! cfr x2)*/
ret.max_size = atoi(parameter);;

ret.exchanges = (Exchange_item *) MALLOC ( ret.max_size * sizeof ( Exchange_item ) );

if (ret.exchanges == NULL)
	error ( E_FATAL_ERROR, "malloc failed for \"ret.exchanges\" in build_exchange_list");

/* Exchange counter : used to identify each exchange */
counter = 0;

/* Inspect the different exchanges */
for (i = 0; i < mpop->exchanges; ++i )
	{
	to = mpop->exch[i].to;

	if (mpop->exch[i].copywhole > -1)
		{
		/* Complete individuals */
		from = mpop->exch[i].copywhole;

		for (j = 0; j < mpop->exch[i].count; ++j )
			{
			if (exchange_test(to , from) == exch_type)
				{
				index = ret.size;

				ret.exchanges[index].exch = i;
				ret.exchanges[index].count = j;
				ret.exchanges[index].copywhole = from;
				ret.exchanges[index].tree = -1;
				ret.exchanges[index].ind_ptr = NULL;
				ret.exchanges[index].valid = 0;
				ret.exchanges[index].type = exch_type;
				ret.exchanges[index].id = counter;
				ret.exchanges[index].tocon = NULL;
				ret.exchanges[index].fromcon = NULL;
				ret.exchanges[index].context_set = 0;
				ret.size++;
				}

			/* 1 exchange more */
			counter++;

			/* Do we need to extend the list? */
			if ( (ret.max_size - ret.size) < mpop->size )
				{
				extend_exchange_list (mpop, &ret);
				}
			}
		}
	else
		{
		/* Trees */
		for (k = 0; k < tree_count; ++k )
			{
			from = mpop->exch[i].from[k];

			for (j = 0; j < mpop->exch[i].count; ++j )
				{
				if (exchange_test(to, from) == exch_type)
					{
					index = ret.size;

					ret.exchanges[index].exch = i;
					ret.exchanges[index].count = j;
					ret.exchanges[index].copywhole = -1;
					ret.exchanges[index].tree = k;
					ret.exchanges[index].valid = 0;
					ret.exchanges[index].type = exch_type;
					ret.exchanges[index].id = counter;
					ret.exchanges[index].tocon = NULL;
					ret.exchanges[index].fromcon = NULL;
					ret.exchanges[index].context_set = 0;
					ret.size++;
					}

				/* 1 exchange more */
				counter++;

				/* Do we need to extend the list? */
				if ( (ret.max_size - ret.size) < mpop->size )
					{
					extend_exchange_list (mpop, &ret);
					}

				}
			}
		}
	}

/* Reuse memory here, we do not get RAM for free ;-)  (We used too much memory remember)*/
ret.exchanges = (Exchange_item *) REALLOC ( ret.exchanges, ret.size * sizeof ( Exchange_item ) );

if (ret.exchanges == NULL)
	error ( E_FATAL_ERROR, "realloc failed for \"ret.exchanges\" in build_exchange_list (II)");


return ret;
}


/* no_import_nodes()
 *
 * this function examins the exchanges and determines the exchanges in more detail.
 */

int no_import_nodes ( multipop *mpop )
{
int ret;
int i, j;
int npops;

char *imports_array;

npops = mpop->size;
ret = 0;

/* Allocate initial memory for the list (it will be BIG!!! cfr x2)*/
imports_array = (char *) MALLOC ( npops * sizeof ( char ) );

if (imports_array == NULL)
	error ( E_FATAL_ERROR, "malloc failed for \"imports_array\" in no_imports_list()");

/* Set to ZERO */
for (i = 0; i < npops; ++i )
	imports_array[i] = 0;


/* Inspect the different exchanges */
for (i = 0; i < mpop->exchanges; ++i )
	{
	for (j = 0; j < mpop->exch[i].count; ++j )
		imports_array[mpop->exch[i].to] = 1;

	ret = 0;

	for (j = 0; j < npops; ++j )
		ret += imports_array[j];

	/* Save some time if possible */
	if (ret == npops)
		break;
	}

/* Deallocate memory here */
FREE(imports_array);

ret = npops- ret;

return ret;
}


/* next_exchange()
 *
 * returns the exchange that should be done first
 */

Exchange_item *next_exchange(Exchange_list *import, Exchange_list *normal, int *init_cursor_import, int *init_cursor_normal)
{
Exchange_item *ret;
int cursor_import, cursor_normal;
int choice = NOP;

/* Some initialisations */
cursor_import = *init_cursor_import;
cursor_normal = *init_cursor_normal;

ret = NULL;

/* So what do we need (long and boring...)*/

if (cursor_import >= import->size)
	{
	if (cursor_normal < normal->size)
		{
		ret = &(normal->exchanges[cursor_normal]);
		(*init_cursor_normal)++;

		return ret;
		}
	else
		error ( E_FATAL_ERROR, "Cursors do exceed list size in next_exchange() (I)");
	}

if (cursor_normal >= normal->size)
	{
	if (cursor_import < import->size)
		{
		ret = &(import->exchanges[cursor_import]);
		(*init_cursor_import)++;

		return ret;
		}
	else
		error ( E_FATAL_ERROR, "Cursors do exceed list size in next_exchange() (II)");
	}

if (import->exchanges[cursor_import].id < normal->exchanges[cursor_normal].id)
	choice = RECEIVE;

if (import->exchanges[cursor_import].id > normal->exchanges[cursor_normal].id)
	choice = NORMAL;


/* Return the exchange according to the choice we made */
switch (choice)
	{
	case RECEIVE:
			/* Use the import */
			ret = &(import->exchanges[cursor_import]);
			(*init_cursor_import)++;

			break;

	case NORMAL:
			/* Use the NORMAL exchange */
			ret = &(normal->exchanges[cursor_normal]);
			(*init_cursor_normal)++;

			break;

	default:
			error ( E_FATAL_ERROR, "Bad \"choice\" in switch of next_exchange()");
	}


return ret;
}


/* print_exchange_list()
 *
 * display all the elements in an exchange_list
 */

void print_exchange_list(Exchange_list list)
{
int i;
int stop;

stop = list.size;

for (i = 0; i< stop; i++)
	printf ("id: %d exch: %d count: %d copywhole: %d tree: %d type: %d valid: %d ind: %#lx\n",
		list.exchanges[i].id,
		list.exchanges[i].exch,
		list.exchanges[i].count,
		list.exchanges[i].copywhole,
		list.exchanges[i].tree,
		list.exchanges[i].type,
		list.exchanges[i].valid,
	(long)	list.exchanges[i].ind_ptr
		);

printf ("End of exchange_list\n");

return;
}


/* extend_exchange_lists()
 *
 * allocates additional memory for the exchange list
 */
void extend_exchange_list ( multipop *mpop, Exchange_list *list )
{

/* New size */
list->max_size += mpop->size;

list->exchanges = (Exchange_item *) REALLOC ( list->exchanges, list->max_size * sizeof ( Exchange_item ));

if (list->exchanges == NULL)
	error ( E_FATAL_ERROR, "realloc failed for \"ret.exchanges\" in extend_exchange_list ");

return;
}


/* free_exchange_lists()
 *
 * deallocate the memory used by the different exchange lists
 */

void free_exchange_lists( )
{

/* NEEDS to be more CLEVER */

if (export_list.size > 0)
	FREE(export_list.exchanges);

if (import_list.size > 0)
	FREE(import_list.exchanges);

if (normal_list.size > 0)
	FREE(normal_list.exchanges);

return;
}


/* set_exchange_list()
 *
 * sets the given exchange list
 */

void set_exchange_list( multipop *mpop, Exchange_list *list, int op )
{
sel_context *tocon;
sel_context *fromcon;
select_context_func_ptr select_con;

Exchange_item  tmp_exchange;

int i, j, k;
int to, from;
int stop;
int exch;

/* Exchange counter : used to identify each exchange */
stop = list->size;

/* Inspect the different exchanges */
i = 0;

while ( i < stop )
	{
	tmp_exchange = list->exchanges[i];
	exch = tmp_exchange.exch;

	to = mpop->exch[exch].to;

	switch (op)
		{
		case SELECT_CLEAN:
					if (tmp_exchange.type == SEND)
						{
						tocon = NULL;

						break;
						}

					if (tmp_exchange.context_set)
						{
						/* Delete a selection context */
						tmp_exchange.tocon->context_method ( SELECT_CLEAN, tmp_exchange.tocon, NULL, NULL );
						}
					else
						error ( E_FATAL_ERROR, "Context is not set in set_exchange_list() I");

					tocon = NULL;

					break;

		case SELECT_INIT:
					if (tmp_exchange.type == SEND)
						{
						tocon = NULL;

						break;
						}

					if (tmp_exchange.context_set == 0)
						{
						/* set up selection method to pick individuals to be replaced. */
					        select_con = get_select_context ( mpop->exch[exch].tosc );
					        tocon = select_con ( SELECT_INIT, NULL, mpop->pop[to], mpop->exch[exch].tosc );
						}
					else
						{
						error ( E_FATAL_ERROR, "Context IS set in set_exchange_list() I");
						tocon = NULL;
						}

					break;

		default:
					tocon = NULL;

					error ( E_FATAL_ERROR, "Unknown operation in set_exchange_list() I");
		}

	if (tmp_exchange.copywhole > -1)
		{
		/* Complete individuals */
		from = mpop->exch[exch].copywhole;

		switch (op)
			{
			case SELECT_CLEAN:
						if (tmp_exchange.type == RECEIVE)
							{
							fromcon = NULL;

							break;
							}

						if (tmp_exchange.context_set)
							{
							/* Delete a selection context */
							tmp_exchange.fromcon->context_method ( SELECT_CLEAN, tmp_exchange.fromcon, NULL, NULL );
							}
						else
							error ( E_FATAL_ERROR, "Context IS NOT set in set_exchange_list() II");

						fromcon = NULL;

						break;

			case SELECT_INIT:
						if (tmp_exchange.type == RECEIVE)
							{
							fromcon = NULL;

							break;
							}

						if (tmp_exchange.context_set == 0)
							{
							/* Setup a new selection context */
							/* selection method for choosing individuals from source
							   subpop. */
							select_con = get_select_context ( mpop->exch[exch].fromsc[0] );
							fromcon = select_con ( SELECT_INIT, NULL, mpop->pop[from], mpop->exch[exch].fromsc[0] );
							}
						else
							{
							error ( E_FATAL_ERROR, "Context IS set in set_exchange_list() II");
							fromcon = NULL;
							}

						break;

			default:
						fromcon = NULL;

						error ( E_FATAL_ERROR, "Unknown operation in set_exchange_list() II");
			}

		for (j = 0; j < mpop->exch[exch].count; ++j )
			{
			list->exchanges[i].tocon = tocon;
			list->exchanges[i].fromcon = fromcon;

			if ( op == SELECT_INIT )
				list->exchanges[i].context_set = 1;
			else
				list->exchanges[i].context_set = 0;

			i++;
			}
		}
	else
		{
		/* Trees */
		for (k = 0; k < tree_count; ++k )
			{
			from = mpop->exch[exch].from[k];

			switch (op)
				{
				case SELECT_CLEAN:
							if (tmp_exchange.type == RECEIVE)
								{
								fromcon = NULL;
                        	
								break;
								}

							if (tmp_exchange.context_set)
								{
								/* Delete a selection context */
								tmp_exchange.fromcon->context_method ( SELECT_CLEAN, tmp_exchange.fromcon, NULL, NULL );
								}
							else
								error ( E_FATAL_ERROR, "Context IS NOT set in set_exchange_list() III");

							fromcon = NULL;

							break;

				case SELECT_INIT:
							if (tmp_exchange.type == RECEIVE)
								{
								fromcon = NULL;
                        	
								break;
								}

							if (tmp_exchange.context_set == 0)
								{
								/* Setup a new selection context */
								/* does this tree need a context? */
								if ( mpop->exch[exch].fromsc[k] )
									{
									/* create it. */
									select_con = get_select_context ( mpop->exch[exch].fromsc[k] );
									fromcon = select_con ( SELECT_INIT, NULL, mpop->pop[mpop->exch[exch].from[k]], mpop->exch[exch].fromsc[k] );
									}
								else
									{
									/* don't need one. */
									fromcon = NULL;
									}
								}
							else
								{
								error ( E_FATAL_ERROR, "Context IS set in set_exchange_list() II");
								fromcon = NULL;
								}

							break;

				default:
							fromcon = NULL;

							error ( E_FATAL_ERROR, "Unknown operation in set_exchange_list() II");
				}


			for (j = 0; j < mpop->exch[exch].count; ++j )
				{
				list->exchanges[i].tocon = tocon;
				list->exchanges[i].fromcon = fromcon;

				if ( op == SELECT_INIT )
					list->exchanges[i].context_set = 1;
				else
					list->exchanges[i].context_set = 0;

				i++;
				}
			}

		}
	}


return;
}
	
#endif