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