/* lil-gp Genetic Programming System, version 1.0, 11 July 1995
* Copyright (C) 1995 Michigan State University
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Douglas Zongker (zongker@isl.cps.msu.edu)
* Dr. Bill Punch (punch@isl.cps.msu.edu)
*
* Computer Science Department
* A-714 Wells Hall
* Michigan State University
* East Lansing, Michigan 48824
* USA
*
*/
#include <lilgp.h>
/* 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)
{
exchange_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 )
{
/** 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 );
/* 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 )
{
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_filter()
*
* does a traversal of all the exchanges and invoke the appropriate functions
*/
void exchange_filter ( multipop *mpop )
{
int i, j, k;
sel_context **fromcon;
select_context_func_ptr select_con;
int tp, *fp;
int *fi;
int exch_type;
int low;
int high;
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 ) );
for ( i = 0; i < mpop->exchanges; ++i )
{
/* where individuals are going. */
tp = mpop->exch[i].to;
/* 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;
exch_type = exchange_test(tp, fp[0]);
if ( (exch_type == NOP) || (exch_type == RECEIVE))
continue;
/* 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 )
{
/* pick an individual from the source subpop. */
fi[0] = fromcon[0]->select_method ( fromcon[0] );
/* We know the: populations,, ind */
exchange_dispatch(mpop, exch_type, i, tp, fp[0], fi[0], -1);
}
/* 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 )
{
exch_type = exchange_test(tp, mpop->exch[i].from[j]);
if ( (exch_type == NOP) || (exch_type == RECEIVE))
continue;
/* 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 )
{
/** 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];
exch_type = exchange_test(tp, fp[j]);
if ( (exch_type == NOP) || (exch_type == RECEIVE))
continue;
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;
exch_type = exchange_test(tp, fp[0]);
if ( (exch_type == NOP) || (exch_type == RECEIVE))
continue;
exchange_dispatch(mpop, exch_type, i, tp, fp[j], fi[j], j);
}
/*
Is hier OK voor lokale uitwisselingen maar niet voor export toestanden
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 );
}
}
/* 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;
FREE ( fromcon );
FREE ( fp );
FREE ( fi );
/* Are there any tree or individuals send from other populations? */
exchange_import( mpop );
}
/* exchange_dispatch()
*
* invokes the appropriate functions based on source and destination
*/
void exchange_dispatch(multipop *mpop, int exch_type, int exch, int tp, int fp, int fi, int ft)
{
switch(exch_type)
{
case NOP:
{
#ifdef PDEBUG
printf ("\t NOP \n");
#endif
/* Nothing to do this happens on another node */
break;
}
case SEND:
{
#ifdef PDEBUG
printf ("\tEXPORTING TO %d\n", tp);
#endif
/* Export a tree or and individual */
exchange_export ( mpop, exch, tp, fp, fi, ft);
break;
}
case RECEIVE:
{
#ifdef PDEBUG
printf ("\t RECEIVE \n");
#endif
/* Do nothing yet */
break;
}
case NORMAL:
{
#ifdef PDEBUG
printf ("\tNORMAL from %d to %d\n", fp, tp);
#endif
/* Both and destination are on this node */
exchange_normal( mpop, exch, tp, fp, fi, ft);
break;
}
default:
{
error ( E_FATAL_ERROR, "Exchange number %d is not valid", exch);
break;
}
}
return;
}
/* exchange_normal
*
* should do the same as the initial exchange function
*/
void exchange_normal ( multipop *mpop, int exch, int tp, int fp, int fi, int ft )
{
const int i = exch;
int j;
sel_context *tocon;
select_context_func_ptr select_con;
int ti;
{
/* 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. ***/
/** 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 );
/** 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. ***/
{
/** 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 );
/* 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 );
}
}
/* destroy destination selection context. */
tocon->context_method ( SELECT_CLEAN, tocon, NULL, NULL );
}
}
/* exchange_export()
*
* exports individuals to population not present on this node
*/
void exchange_export ( multipop *mpop, int exch, int tp, int fp, int fi, int ft )
{
int destination_node;
/* Determine the node on which the population resides */
destination_node = population_mapping (tp);
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, mpop->pop[fp]->ind+fi );
}
else
{
/* send the tree: exchange nr, pop, ind, tree, tree ptr */
send_tree ( destination_node, exch, ft, mpop->pop[fp]->ind[fi].tr+ft );
}
return;
}
/* exchange_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_import ( multipop *mpop )
{
int i, j, k;
int count;
int tmp;
sel_context *tocon;
select_context_func_ptr select_con;
int ti;
int ft;
int bufid;
int exch;
int tp;
int bytes;
int msgtg;
int tid;
individual *ind_ptr;
tree tmp_tree;
#ifdef PDEBUG
printf ("Receiving\n");
#endif
while ( (bufid = pvm_nrecv(-1, -1)) )
{
pvm_bufinfo ( bufid, &bytes, &msgtg, &tid );
/* Intermediate reset */
ft = -1;
#ifdef PDEBUG_IMPORT
printf ("GOT FROM tid[%x]\n", tid);
#endif
switch (msgtg)
{
case TERM_REQUEST_TAG:
{
/* Force the user termination criterium */
set_term(1);
return;
break; /* Useless, yes I know. */
}
case IND_TAG:
{
/* Extract exchange_number and all the trees */
receive_individual ( &exch, &ind_ptr );
break;
}
case TREE_TAG:
{
/* Extract exchange_number, destination pop. the tree and the tree number */
receive_tree ( &exch, &ft, &tmp_tree );
break;
}
default:
{
error (E_FATAL_ERROR, "Unkown tag in exchange_import() value = %d", msgtg);
}
}
/* Reuse the variable "i" from the original code :-) */
i = exch;
#ifdef PDEBUG_IMPORT
printf ("Exchange nr. %d dest. pop %d from tree %d \n", i, mpop->exch[i].to, ft);
#endif
{
/* where individuals are going. */
tp = mpop->exch[i].to;
/* 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);
/* 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. ***/
/** pick an individual to be replaced that has not already
been replaced during this exchange cycle. **/
count = 0;
tmp = mpop->pop[tp]->size;
do
{
ti = tocon->select_method ( tocon );
count++;
if (count > tmp)
{
/* No individual left to be selected! */
printf("exchange_import: no ind. left for replacement 1\n");
return;
}
#ifdef PDEBUG_IMPORT_XXXX
printf ("exch: search ind ti %d \n", ti);
printf ("pop size is %d\n", mpop->pop[tp]->size);
#endif
}
while ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH );
/** 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. */
#ifdef PDEBUG
printf("dup ind ...");
fflush(stdout);
#endif
duplicate_individual ( mpop->pop[tp]->ind+ti, ind_ptr );
#ifdef PDEBUG
printf("dup ind ended\n");
#endif
/* 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. ***/
{
/** select an individual to be replaced that hasn't already
been during this exchange cycle. **/
count = 0;
tmp = mpop->pop[tp]->size;
do
{
ti = tocon->select_method ( tocon );
if (count > tmp)
{
/* No individual left to be selected! */
printf("exchange_import: no ind. left for replacement 2\n");
return;
}
}
while ( mpop->pop[tp]->ind[ti].flags & FLAG_NEWEXCH );
/* 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 );
}
}
/* destroy destination selection context. */
tocon->context_method ( SELECT_CLEAN, tocon, NULL, NULL );
}
}
return;
}
/* signal_master()
*
* send termination signal to the master
*/
void signal_master(int signal)
{
int ptid;
ptid = pvm_parent();
pvm_initsend(ENCODING);
pvm_send (ptid, signal);
}
/* pack_individual()
*
* pack an individual in order to send it
*/
void pack_individual( individual *ind_ptr)
{
int i;
/* First pack the individual's information */
if (pvm_pkdouble(&(ind_ptr->r_fitness), 1, 1))
pvm_perror ("send_individual() error packing \"r_fitness\"");
if (pvm_pkdouble(&(ind_ptr->s_fitness), 1, 1))
pvm_perror ("send_individual() error packing \"s_fitness\"");
if (pvm_pkdouble(&(ind_ptr->a_fitness), 1, 1))
pvm_perror ("send_individual() error packing \"a_fitness\"");
if (pvm_pkint(&(ind_ptr->hits), 1, 1))
pvm_perror ("send_individual() error packing \"hits\"");
if (pvm_pkint(&(ind_ptr->evald), 1, 1))
pvm_perror ("send_individual() error packing \"evald\"");
if (pvm_pkint(&(ind_ptr->flags), 1, 1))
pvm_perror ("send_individual() error packing \"flags\"");
/* 2nd pack its trees */
for (i=0; i<tree_count; i++)
pack_tree(&(ind_ptr->tr[i]));
return;
}
/* unpack_individual()
*
* unpack an individual and allocates the memory for it ...
*/
void unpack_individual ( individual **ind_ptr )
{
int i;
individual *tmp_ind;
tmp_ind = (individual *) MALLOC (sizeof(individual));
tmp_ind->tr = (tree *) MALLOC (sizeof(tree)*tree_count);
/* First unpack the individual's information */
if (pvm_upkdouble(&(tmp_ind->r_fitness), 1, 1))
pvm_perror ("receive_individual() error unpacking \"r_fitness\"")
;
if (pvm_upkdouble(&(tmp_ind->s_fitness), 1, 1))
pvm_perror ("receive_individual() error unpacking \"s_fitness\"");
if (pvm_upkdouble(&(tmp_ind->a_fitness), 1, 1))
pvm_perror ("receive_individual() error unpacking \"a_fitness\"");
if (pvm_upkint(&(tmp_ind->hits), 1, 1))
pvm_perror ("receive_individual() error unpacking \"hits\"");
if (pvm_upkint(&(tmp_ind->evald), 1, 1))
pvm_perror ("receive_individual() error unpacking \"evald\"");
if (pvm_upkint(&(tmp_ind->flags), 1, 1))
pvm_perror ("receive_individual() error unpacking \"flags\"");
/* 2nd unpack it trees */
for (i=0; i<tree_count; i++)
unpack_tree(&tmp_ind->tr[i]);
/* 3d put into the pointer */
*ind_ptr = tmp_ind;
return;
}
/* send_individual()
*
* send an entire individual
*/
void send_individual ( int destination_node, int exch, individual *ind_ptr )
{
#ifdef PDEBUG
printf("send_individiual() to %x\n", destination_node);
#endif
pvm_initsend(ENCODING);
/* Zero pack the exchange number */
if (pvm_pkint(&exch, 1, 1))
pvm_perror ("send_individual() error packing \"exch\"");
pack_individual(ind_ptr);
/* Send */
if (pvm_send (destination_node, IND_TAG))
pvm_perror ("send_individual() error sending");
#ifdef PDEBUG
printf("finished send_individual()\n");
#endif
}
/* receive_individual()
*
* receives an individual.
*/
void receive_individual ( int *exch, individual **ind_ptr )
{
#ifdef PDEBUG
printf("receive_individiual()\n");
#endif
/* Zero pack the exchange number */
if (pvm_upkint(exch, 1, 1))
pvm_perror ("send_individual() error unpacking \"exch\"");
/* First unpack the individual's information */
unpack_individual(ind_ptr);
#ifdef PDEBUG
printf("finished receive_individual()\n");
#endif
}
#endif