710 lines
23 KiB
C
710 lines
23 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>
|
|
|
|
typedef struct
|
|
{
|
|
int keep_trying;
|
|
int num_times; /* Number of times we should keep trying. If 0, infinity. --Sean */
|
|
double internal;
|
|
double external;
|
|
double *tree; /* probability that a given tree
|
|
will be selected for crossover. */
|
|
double *treecumul; /* running sum of "tree" field. */
|
|
double treetotal; /* total of all tree fields. */
|
|
double *func; /* probability that a given function
|
|
set will be selected for crossover. */
|
|
char *sname;
|
|
sel_context *sc;
|
|
char *sname2;
|
|
sel_context *sc2;
|
|
} crossover_data;
|
|
|
|
|
|
|
|
/* operator_crossver_init()
|
|
*
|
|
* called to parse crossover options and initialize one record
|
|
* of a breedphase table appropriately.
|
|
*/
|
|
|
|
int operator_crossover_init ( char *options, breedphase *bp )
|
|
{
|
|
int errors = 0;
|
|
crossover_data *cd;
|
|
int i, j, k, m;
|
|
double r;
|
|
char **argv, **targv;
|
|
int internalset = 0, externalset = 0;
|
|
char *cp;
|
|
|
|
cd = (crossover_data *)MALLOC ( sizeof ( crossover_data ) );
|
|
|
|
/* place values into the breedphase table record. */
|
|
bp->gp_operator = OPERATOR_CROSSOVER;
|
|
bp->data = (void *)cd;
|
|
bp->operator_free = operator_crossover_free;
|
|
bp->operator_start = operator_crossover_start;
|
|
bp->operator_end = operator_crossover_end;
|
|
bp->operator_operate = operator_crossover;
|
|
|
|
/* default values for all the crossover options. */
|
|
cd->keep_trying = 0;
|
|
cd->num_times = 0;
|
|
cd->internal = 0.9;
|
|
cd->external = 0.1;
|
|
cd->tree = (double *)MALLOC ( tree_count * sizeof ( double ) );
|
|
cd->treecumul = (double *)MALLOC ( tree_count * sizeof ( double ) );
|
|
for ( j = 0; j < tree_count; ++j )
|
|
cd->tree[j] = 0.0;
|
|
cd->treetotal = 0.0;
|
|
cd->func = (double *)MALLOC ( fset_count * sizeof ( double ) );
|
|
cd->sname = NULL;
|
|
cd->sname2 = NULL;
|
|
|
|
/* break the options string into an argv-style array of strings. */
|
|
j = parse_o_rama ( options, &argv );
|
|
|
|
for ( i = 0; i < j; ++i )
|
|
{
|
|
/* parse "keep_trying" option. */
|
|
if ( strcmp ( "keep_trying", argv[i] ) == 0 )
|
|
{
|
|
/* translate a string into a binary value. returns -1 if
|
|
the string is not one of the valid strings meaning
|
|
yes or no. */
|
|
cd->keep_trying = translate_binary ( argv[++i] );
|
|
if ( cd->keep_trying == -1 )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is not a valid setting for \"keep_trying\".",
|
|
argv[i] );
|
|
}
|
|
}
|
|
/* parse number of times to try */
|
|
else if (strcmp ("num_times", argv[i]) == 0)
|
|
{
|
|
cd->num_times = translate_binary(argv[++i]);
|
|
if (cd->num_times < 0 )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is not a valid setting for \"num_times\".",
|
|
argv[i] );
|
|
}
|
|
}
|
|
/* parse "internal" option. */
|
|
else if ( strcmp ( "internal", argv[i] ) == 0 )
|
|
{
|
|
internalset = 1;
|
|
cd->internal = strtod ( argv[++i], NULL );
|
|
if ( cd->internal < 0.0 )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"internal\" must be nonnegative." );
|
|
}
|
|
}
|
|
/* parse "external" option. */
|
|
else if ( strcmp ( "external", argv[i] ) == 0 )
|
|
{
|
|
externalset = 1;
|
|
cd->external = strtod ( argv[++i], NULL );
|
|
if ( cd->external < 0.0 )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"external\" must be nonnegative." );
|
|
}
|
|
}
|
|
/* parse "select" option. */
|
|
else if ( strcmp ( "select", argv[i] ) == 0 )
|
|
{
|
|
if ( !exists_select_method ( argv[++i] ) )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is not a known selection method.",
|
|
argv[i] );
|
|
}
|
|
FREE ( cd->sname );
|
|
cd->sname = (char *)MALLOC ( (strlen(argv[i])+1) * sizeof ( char ) );
|
|
strcpy ( cd->sname, argv[i] );
|
|
if ( cd->sname2 == NULL )
|
|
cd->sname2 = cd->sname;
|
|
}
|
|
/* parse "select2" option. */
|
|
else if ( strcmp ( "select2", argv[i] ) == 0 )
|
|
{
|
|
if ( !exists_select_method ( argv[++i] ) )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is not a known selection method.",
|
|
argv[i] );
|
|
}
|
|
if ( cd->sname2 && cd->sname != cd->sname2 )
|
|
FREE ( cd->sname2 );
|
|
cd->sname2 = (char *)MALLOC ( (strlen(argv[i])+1) * sizeof ( char ) );
|
|
strcpy ( cd->sname2, argv[i] );
|
|
}
|
|
/* parse "tree" option. */
|
|
else if ( strcmp ( "tree", argv[i] ) == 0 )
|
|
{
|
|
k = parse_o_rama ( argv[++i], &targv );
|
|
if ( k != tree_count )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: wrong number of tree fields: \"%s\".",
|
|
argv[i] );
|
|
}
|
|
else
|
|
{
|
|
for ( m = 0; m < k; ++m )
|
|
{
|
|
cd->tree[m] = strtod ( targv[m], &cp );
|
|
if ( *cp )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is not a number.",
|
|
targv[m] );
|
|
}
|
|
}
|
|
}
|
|
|
|
free_o_rama ( k, &targv );
|
|
}
|
|
/* parse "tree#" option. */
|
|
else if ( strncmp ( "tree", argv[i], 4 ) == 0 )
|
|
{
|
|
k = strtol ( argv[i]+4, &cp, 10 );
|
|
if ( *cp )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: unknown option \"%s\".",
|
|
argv[i] );
|
|
}
|
|
if ( k < 0 || k >= tree_count )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is out of range.",
|
|
argv[i] );
|
|
}
|
|
else
|
|
{
|
|
cd->tree[k] = strtod ( argv[++i], &cp );
|
|
if ( *cp )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: \"%s\" is not a number.",
|
|
argv[i] );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: unknown option \"%s\".",
|
|
argv[i] );
|
|
}
|
|
}
|
|
|
|
free_o_rama ( j, &argv );
|
|
|
|
if ( internalset && !externalset )
|
|
cd->external = 0.0;
|
|
else if ( !internalset && externalset )
|
|
cd->internal = 0.0;
|
|
|
|
if ( cd->sname == NULL )
|
|
{
|
|
++errors;
|
|
error ( E_ERROR, "crossover: no selection method specified." );
|
|
}
|
|
|
|
/** compute "func" array from the "tree" array. **/
|
|
|
|
for ( j = 0; j < tree_count; ++j )
|
|
cd->treetotal += cd->tree[j];
|
|
if ( cd->treetotal == 0.0 )
|
|
{
|
|
for ( j = 0; j < tree_count; ++j )
|
|
cd->tree[j] = 1.0;
|
|
cd->treetotal = tree_count;
|
|
}
|
|
|
|
for ( j = 0; j < fset_count; ++j )
|
|
cd->func[j] = 0.0;
|
|
for ( j = 0; j < tree_count; ++j )
|
|
cd->func[tree_map[j].fset] += cd->tree[j];
|
|
|
|
r = 0.0;
|
|
for ( j = 0; j < fset_count; ++j )
|
|
r = (cd->func[j] += r);
|
|
|
|
#ifdef DEBUG
|
|
if ( !errors )
|
|
{
|
|
printf ( "crossover options:\n" );
|
|
printf ( " internal: %lf external: %lf\n", cd->internal, cd->external );
|
|
printf ( " keep_trying: %d\n", cd->keep_trying );
|
|
printf ( " primary selection: %s\n", cd->sname==NULL?"NULL":cd->sname );
|
|
printf ( " second selection: %s\n", cd->sname2==NULL?"NULL":(cd->sname2==cd->sname?"same as primary":cd->sname2) );
|
|
printf ( " tree total: %lf\n", cd->treetotal );
|
|
for ( j = 0; j < tree_count; ++j )
|
|
printf ( " tree %d: %lf\n", j, cd->tree[j] );
|
|
for ( j = 0; j < fset_count; ++j )
|
|
printf ( " fset %d: %lf\n", j, cd->func[j] );
|
|
}
|
|
#endif
|
|
|
|
return errors;
|
|
}
|
|
|
|
/* operator_crossover_free()
|
|
*
|
|
* free the crossover-specific data structure.
|
|
*/
|
|
|
|
void operator_crossover_free ( void *data )
|
|
{
|
|
crossover_data * cd;
|
|
|
|
cd = (crossover_data *)data;
|
|
|
|
FREE ( cd->sname );
|
|
if ( cd->sname != cd->sname2 )
|
|
FREE ( cd->sname2 );
|
|
FREE ( cd->tree );
|
|
FREE ( cd->treecumul );
|
|
FREE ( cd->func );
|
|
FREE ( cd );
|
|
}
|
|
|
|
/* operator_crossover_start()
|
|
*
|
|
* called at the start of the breeding process each generation.
|
|
* initializes the selection contexts for this phase.
|
|
*/
|
|
|
|
void operator_crossover_start ( population *oldpop, void *data )
|
|
{
|
|
crossover_data * cd;
|
|
select_context_func_ptr select_con;
|
|
|
|
cd = (crossover_data *)data;
|
|
|
|
select_con = get_select_context ( cd->sname );
|
|
cd->sc = select_con ( SELECT_INIT, NULL, oldpop, cd->sname );
|
|
|
|
/* if there is a separate selection method specified for the
|
|
second parent... */
|
|
if ( cd->sname2 != cd->sname )
|
|
{
|
|
/* ...then initialize it too. */
|
|
select_con = get_select_context ( cd->sname2 );
|
|
cd->sc2 = select_con ( SELECT_INIT, NULL, oldpop, cd->sname2 );
|
|
}
|
|
else
|
|
/* ...otherwise use the first context. */
|
|
cd->sc2 = cd->sc;
|
|
}
|
|
|
|
/* operator_crossover_end()
|
|
*
|
|
* called when breeding is finished each generation. frees up selection
|
|
* contexts for this phase.
|
|
*/
|
|
|
|
void operator_crossover_end ( void *data )
|
|
{
|
|
crossover_data * cd;
|
|
|
|
cd = (crossover_data *)data;
|
|
|
|
cd->sc->context_method ( SELECT_CLEAN, cd->sc, NULL, NULL );
|
|
if ( cd->sname != cd->sname2 )
|
|
cd->sc2->context_method ( SELECT_CLEAN, cd->sc2, NULL, NULL );
|
|
}
|
|
|
|
/* operator_crossover()
|
|
*
|
|
* performs the crossover, inserting one or both offspring into the
|
|
* new population.
|
|
*/
|
|
|
|
void operator_crossover ( population *oldpop, population *newpop,
|
|
void *data )
|
|
{
|
|
crossover_data * cd;
|
|
int p1, p2;
|
|
int ps1, ps2;
|
|
int l1, l2;
|
|
lnode *st[3];
|
|
int sts1, sts2;
|
|
int ns1, ns2;
|
|
int badtree1, badtree2;
|
|
double total;
|
|
int forceany1, forceany2;
|
|
int repcount;
|
|
int f, t1, t2, j;
|
|
double r, r2;
|
|
int totalnodes1, totalnodes2;
|
|
int i;
|
|
int count=0; /* Number of attempts */
|
|
|
|
/* get the crossover-specific data structure. */
|
|
cd = (crossover_data *)data;
|
|
total = cd->internal + cd->external;
|
|
|
|
/* choose a function set. */
|
|
r = random_double(&globrand) * cd->treetotal;
|
|
for ( f = 0; r >= cd->func[f]; ++f );
|
|
|
|
/* fill in the "treecumul" array, zeroing all trees which
|
|
don't use the selected function set. */
|
|
r = 0.0;
|
|
t1 = 0;
|
|
for ( j = 0; j < tree_count; ++j )
|
|
{
|
|
if ( tree_map[j].fset == f )
|
|
r = (cd->treecumul[j] = r + cd->tree[j]);
|
|
else
|
|
cd->treecumul[j] = r;
|
|
}
|
|
|
|
/* select the first and second trees. */
|
|
r2 = random_double(&globrand) * r;
|
|
for ( t1 = 0; r2 >= cd->treecumul[t1]; ++t1 );
|
|
r2 = random_double(&globrand) * r;
|
|
for ( t2 = 0; r2 >= cd->treecumul[t2]; ++t2 );
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
printf ( "selected function set %d --> t1: %d; t2: %d\n", f, t1, t2 );
|
|
#endif
|
|
|
|
/* choose two parents */
|
|
p1 = cd->sc->select_method ( cd->sc );
|
|
ps1 = oldpop->ind[p1].tr[t1].nodes;
|
|
/* if the tree only has one node, we obviously can't do
|
|
fucntionpoint crossover. use anypoint instead. */
|
|
forceany1 = (ps1==1||total==0.0);
|
|
|
|
p2 = cd->sc2->select_method ( cd->sc2 );
|
|
ps2 = oldpop->ind[p2].tr[t2].nodes;
|
|
forceany2 = (ps2==1||total==0.0);
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "parent 1 is:\n" );
|
|
print_individual ( oldpop->ind+p1, stderr );
|
|
fprintf ( stderr, "parent 2 is:\n" );
|
|
print_individual ( oldpop->ind+p2, stderr );
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
count++;
|
|
badtree1=0; /* Moved up here so they don't overwrite my claims --strong typing */
|
|
badtree2=0;
|
|
|
|
/* choose two crossover points */
|
|
|
|
if ( forceany1 )
|
|
{
|
|
/* choose any point. */
|
|
l1 = random_int ( &globrand, ps1 );
|
|
st[1] = get_subtree ( oldpop->ind[p1].tr[t1].data, l1 );
|
|
/* print_tree(st[1],stdout);*/
|
|
}
|
|
else if ( total*random_double(&globrand) < cd->internal )
|
|
{
|
|
/* choose an internal point. */
|
|
l1 = random_int ( &globrand, tree_nodes_internal (oldpop->ind[p1].tr[t1].data) );
|
|
st[1] = get_subtree_internal ( oldpop->ind[p1].tr[t1].data, l1 );
|
|
/*print_tree(st[1],stdout);*/
|
|
}
|
|
else
|
|
{
|
|
/* choose an external point. */
|
|
l1 = random_int ( &globrand, tree_nodes_external (oldpop->ind[p1].tr[t1].data) );
|
|
st[1] = get_subtree_external ( oldpop->ind[p1].tr[t1].data, l1 );
|
|
/*print_tree(st[1],stdout);*/
|
|
}
|
|
|
|
if ( forceany2 )
|
|
{
|
|
/* choose any point on second parent. */
|
|
l2 = random_int ( &globrand, ps2 );
|
|
st[2] = get_subtree ( oldpop->ind[p2].tr[t2].data, l2 );
|
|
/*print_tree(st[2],stdout);*/
|
|
}
|
|
else if ( total*random_double(&globrand) < cd->internal )
|
|
{
|
|
/* choose internal point. */
|
|
l2 = random_int ( &globrand, tree_nodes_internal (oldpop->ind[p2].tr[t2].data) );
|
|
st[2] = get_subtree_internal ( oldpop->ind[p2].tr[t2].data, l2 );
|
|
/*print_tree(st[2],stdout);*/
|
|
}
|
|
else
|
|
{
|
|
/* choose external point. */
|
|
l2 = random_int ( &globrand, tree_nodes_external (oldpop->ind[p2].tr[t2].data) );
|
|
st[2] = get_subtree_external ( oldpop->ind[p2].tr[t2].data, l2 );
|
|
/*print_tree(st[2],stdout);*/
|
|
}
|
|
|
|
/** validate the second offspring with regards to the first
|
|
offspring. **/
|
|
|
|
if ( st[1]->f->return_type != st[2]->f->return_type)
|
|
{badtree2=1; badtree1=1;} /* Needs to be *both*--don't know if either
|
|
is valid with regards to new children;
|
|
the simple way out is to just say they're
|
|
both bad. This is a better randomization
|
|
anyway... */
|
|
|
|
/* if we're supposed to keep trying, skip up and choose new crossover
|
|
points. */
|
|
if ( cd->keep_trying && badtree2 &&
|
|
(cd->num_times==0 ||
|
|
cd->num_times > count) )
|
|
continue;
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
printf ( "subtree 1 is: " );
|
|
print_tree ( st[1], stdout );
|
|
printf ( "subtree 2 is: " );
|
|
print_tree ( st[2], stdout );
|
|
#endif
|
|
|
|
/* count the nodes in the selected subtrees. */
|
|
sts1 = tree_nodes ( st[1] );
|
|
sts2 = tree_nodes ( st[2] );
|
|
|
|
/* calculate the sizes of the offspring. */
|
|
ns1 = ps1 - sts1 + sts2;
|
|
ns2 = ps2 - sts2 + sts1;
|
|
|
|
totalnodes1 = ns1;
|
|
totalnodes2 = ns2;
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
printf ( "newtree 1 has size %d; limit is %d\n",
|
|
ns1, tree_map[t1].nodelimit );
|
|
#endif
|
|
|
|
/** validate the first offspring against the tree node and depth
|
|
limits; set "badtree1" if any are violated. **/
|
|
|
|
/*badtree1 = 0; moved to the while() loop */
|
|
if ( tree_map[t1].nodelimit > -1 && ns1 > tree_map[t1].nodelimit )
|
|
badtree1 |= 1;
|
|
else if ( tree_map[t1].depthlimit > -1 )
|
|
{
|
|
ns1 = tree_depth_to_subtree ( oldpop->ind[p1].tr[t1].data, st[1] ) +
|
|
tree_depth ( st[2] );
|
|
#ifdef DEBUG_CROSSOVER
|
|
printf ( "newtree 1 has depth %d; limit is %d\n",
|
|
ns1, tree_map[t1].depthlimit );
|
|
#endif
|
|
if ( ns1 > tree_map[t1].depthlimit )
|
|
badtree1 |= 1;
|
|
}
|
|
|
|
/* if we're supposed to keep trying, skip up and choose new crossover
|
|
points. */
|
|
if ( cd->keep_trying && badtree1 &&
|
|
(cd->num_times==0 ||
|
|
cd->num_times > count) )
|
|
continue;
|
|
|
|
/** validate the second offspring against the tree node and depth
|
|
limits; set "badtree2" if any are violated. **/
|
|
|
|
/* badtree2 = 0; moved to the while() loop */
|
|
if ( tree_map[t2].nodelimit > -1 && ns2 > tree_map[t2].nodelimit )
|
|
badtree2 |= 1;
|
|
else if ( tree_map[t2].depthlimit > -1 )
|
|
{
|
|
ns2 = tree_depth_to_subtree ( oldpop->ind[p2].tr[t2].data, st[2] ) +
|
|
tree_depth ( st[1] );
|
|
if ( ns2 > tree_map[t2].depthlimit )
|
|
badtree2 |= 1;
|
|
}
|
|
|
|
/* if we're supposed to keep trying, skip up and choose new crossover
|
|
points. */
|
|
|
|
if ( cd->keep_trying && badtree2 &&
|
|
(cd->num_times==0 ||
|
|
cd->num_times > count) )
|
|
continue;
|
|
|
|
/* check both offspring against the individual node limits, set
|
|
badtree1 and/or badtree2 if either is too big. */
|
|
|
|
if ( ind_nodelimit > -1 )
|
|
{
|
|
for ( i = 0; i < tree_count; ++i )
|
|
{
|
|
if ( i != t1 )
|
|
totalnodes1 += oldpop->ind[p1].tr[i].nodes;
|
|
if ( i != t2 )
|
|
totalnodes2 += oldpop->ind[p2].tr[i].nodes;
|
|
}
|
|
badtree1 |= (totalnodes1 > ind_nodelimit);
|
|
badtree2 |= (totalnodes2 > ind_nodelimit);
|
|
#ifdef DEBUG_CROSSOVER
|
|
printf ( "newind 1 has %d nodes; limit is %d\n",
|
|
totalnodes1, ind_nodelimit );
|
|
#endif
|
|
}
|
|
|
|
/* choose new crossover points if either tree is too big. */
|
|
if ( cd->keep_trying && (badtree1 || badtree2) &&
|
|
(cd->num_times==0 ||
|
|
cd->num_times > count))
|
|
continue;
|
|
|
|
/* copy the first parent to the first offspring position */
|
|
duplicate_individual ( newpop->ind+newpop->next,
|
|
oldpop->ind+p1 );
|
|
if ( !badtree1 )
|
|
{
|
|
/* if the first offspring is allowable... */
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "offspring 1 is allowable.\n" );
|
|
#endif
|
|
|
|
/* make a copy of the crossover tree, replacing the
|
|
selected subtree with the crossed-over subtree. */
|
|
copy_tree_replace_many ( 0, oldpop->ind[p1].tr[t1].data,
|
|
st+1, st+2, 1, &repcount );
|
|
if ( repcount != 1 )
|
|
{
|
|
/* this can't happen, but check anyway. */
|
|
error ( E_FATAL_ERROR,
|
|
"botched crossover: this can't happen" );
|
|
}
|
|
|
|
/* free the appropriate tree of the new individual */
|
|
free_tree ( newpop->ind[newpop->next].tr+t1 );
|
|
/* copy the crossovered tree to the freed space */
|
|
gensp_dup_tree ( 0, newpop->ind[newpop->next].tr+t1 );
|
|
|
|
/* the new individual's fitness fields are of course invalid. */
|
|
newpop->ind[newpop->next].evald = EVAL_CACHE_INVALID;
|
|
newpop->ind[newpop->next].flags = FLAG_NONE;
|
|
}
|
|
else
|
|
{
|
|
/* offspring too big but keep_trying not set, just leave the copied
|
|
parent 1 in the offspring position. */
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "offspring 1 is too big; copying parent 1.\n" );
|
|
#endif
|
|
}
|
|
|
|
/* we've just filled in one member of the new population. */
|
|
++newpop->next;
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "offspring 1:" );
|
|
if ( newpop->ind[newpop->next-1].evald == EVAL_CACHE_VALID )
|
|
fprintf ( stderr, " (valid)\n" );
|
|
else
|
|
fprintf ( stderr, " (invalid)\n" );
|
|
print_individual ( newpop->ind+(newpop->next-1), stderr );
|
|
#endif
|
|
|
|
/* if the new population needs another member (it's not full) */
|
|
if ( newpop->next < newpop->size )
|
|
{
|
|
/* copy the second parent to the second offspring position. */
|
|
duplicate_individual ( newpop->ind+newpop->next,
|
|
oldpop->ind+p2 );
|
|
if ( !badtree2 )
|
|
{
|
|
/* if the second offspring is allowable... */
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "offspring 2 is allowable.\n" );
|
|
#endif
|
|
/* then make a copy of the tree, replacing the crossover
|
|
subtree. */
|
|
copy_tree_replace_many ( 0, oldpop->ind[p2].tr[t2].data,
|
|
st+2, st+1, 1, &repcount );
|
|
if ( repcount != 1 )
|
|
{
|
|
error ( E_FATAL_ERROR,
|
|
"bad crossover: this can't happen" );
|
|
}
|
|
|
|
/* free the old tree in the new individual, and replace
|
|
it with the crossover tree. */
|
|
free_tree ( newpop->ind[newpop->next].tr+t2 );
|
|
gensp_dup_tree ( 0, newpop->ind[newpop->next].tr+t2 );
|
|
|
|
newpop->ind[newpop->next].evald = EVAL_CACHE_INVALID;
|
|
newpop->ind[newpop->next].flags = FLAG_NONE;
|
|
}
|
|
else
|
|
{
|
|
/* offspring too big but keep_trying not set; just leave
|
|
the copy of parent 2 where it is. */
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "offspring 2 is big; copying parent 2.\n" );
|
|
#endif
|
|
}
|
|
|
|
++newpop->next;
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
fprintf ( stderr, "offspring 2:" );
|
|
if ( newpop->ind[newpop->next-1].evald == EVAL_CACHE_VALID )
|
|
fprintf ( stderr, " (valid)\n" );
|
|
else
|
|
fprintf ( stderr, " (invalid)\n" );
|
|
print_individual ( newpop->ind+(newpop->next-1), stderr );
|
|
#endif
|
|
|
|
}
|
|
#ifdef DEBUG_CROSSOVER
|
|
else
|
|
{
|
|
/* the first offspring filled the population, discard the
|
|
second. */
|
|
fprintf ( stderr, "offspring 2 not needed.\n\n" );
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_CROSSOVER
|
|
printf ( "CROSSOVER COMPLETE.\n\n\n" );
|
|
#endif
|
|
|
|
}
|
|
|