643 lines
24 KiB
C
643 lines
24 KiB
C
|
/* 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;
|
||
|
|
||
|
/** 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 )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf ( "working on exch[%d]\n", i+1 );
|
||
|
#endif
|
||
|
|
||
|
/* 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] );
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
printf ( "COPYING WHOLE INDIVIDUAL: ind %d subpop %d --> ind %d subpop %d\n",
|
||
|
fi[0], fp[0], ti, tp );
|
||
|
#endif
|
||
|
|
||
|
/** 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] )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf ( "getting selection context for tree %d (%s)\n",
|
||
|
j, mpop->exch[i].fromsc[j] );
|
||
|
#endif
|
||
|
/* 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 );
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
printf ( "SELECTED TREE %d FOR REPLACEMENT.\n", ti );
|
||
|
print_individual ( mpop->pop[tp]->ind+ti, stdout );
|
||
|
#endif
|
||
|
/** 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]] );
|
||
|
#ifdef DEBUG
|
||
|
printf ( "selecting using (%s) from subpop %d (for tree %d): individual %d\n",
|
||
|
mpop->exch[i].fromsc[j], fp[j], j, fi[j] );
|
||
|
print_individual ( mpop->pop[fp[j]]->ind+fi[j], stdout );
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** 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]];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
printf ( "the fp,fi arrays are:\n" );
|
||
|
for ( j = 0; j < tree_count; ++j )
|
||
|
printf ( " %3d: fp = %3d fi = %4d\n", j, fp[j], fi[j] );
|
||
|
#endif
|
||
|
|
||
|
/** 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 );
|
||
|
}
|
||
|
#ifdef COEVOLUTION
|
||
|
error ( E_FATAL_ERROR, "Can't do COEVOLUTION and multi-pop experiments\n together at this time, sorry.\n");
|
||
|
#else
|
||
|
/* evaluate the fitness of the new composite individual. */
|
||
|
app_eval_fitness ( mpop->pop[tp]->ind+ti );
|
||
|
#endif
|
||
|
mpop->pop[tp]->ind[ti].flags = FLAG_NEWEXCH;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
printf ( "the new individual is:\n" );
|
||
|
print_individual ( mpop->pop[tp]->ind+ti, stdout );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* 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 );
|
||
|
}
|