/* 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