224 lines
5.6 KiB
HTML
224 lines
5.6 KiB
HTML
|
<HTML>
|
||
|
<HEAD>
|
||
|
<TITLE>
|
||
|
lil-gp Bug Patches
|
||
|
</TITLE>
|
||
|
</HEAD>
|
||
|
<BODY bgcolor=white>
|
||
|
<H1> lil-gp Bug Patches</h1>
|
||
|
<p> I have identified two chief bugs in lil-gpl 1.1 beta while working in multi-threaded mode. Until they are resolved, here are (ugly) patches to the code which should work nicely.
|
||
|
|
||
|
<a href="http://www.daimi.aau.dk/~ptr/">Peter Anderson</a> has also identified a bug in lilgp's ERC facility; I've not verified this bug, but his patch is located <a href="peters-patch.html">here</a>.
|
||
|
|
||
|
<h2>The Tree Evaluation Facility</h2>
|
||
|
<p> This appears to be a <b>very</b> serious bug; all the function <tt>set_current_individual()</tt> does is modify a global static pointer. This creates a very dangerous race condition when individuals are being evaluated simultaneously. The patch is to move this global variable into the thread-safe globaldata structure. This means you will have to first add to your <b>globaldata</b> structure the line...
|
||
|
|
||
|
<p><tt>individual* current_individual;</tt>
|
||
|
|
||
|
<p>You should not access this line in your evaluation code, even though it's in the globaldata structure. Once this line has been added, follow the following patch instructions.
|
||
|
|
||
|
<p><b>Open the file <tt>eval.c</tt>. Change the passage...</b>
|
||
|
|
||
|
<P><pre><tt>
|
||
|
static individual * current_individual;
|
||
|
|
||
|
void set_current_individual ( individual *ind )
|
||
|
{
|
||
|
current_individual = ind;
|
||
|
}
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b>...to...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
#if !defined(POSIX_MT) && !defined(SOLARIS_MT)
|
||
|
static individual * current_individual;
|
||
|
#define CURRENT_INDIVIDUAL current_individual
|
||
|
#else
|
||
|
#define CURRENT_INDIVIDUAL ((get_globaldata())->current_individual)
|
||
|
#endif
|
||
|
|
||
|
void set_current_individual ( individual *ind )
|
||
|
{
|
||
|
CURRENT_INDIVIDUAL = ind;
|
||
|
}
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b>...next, there are THREE passages you'll need to change. They're all identical. All three times it occurs, change...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
arg->d = evaluate_tree ( current_individual->tr[f->evaltree].data,
|
||
|
f->evaltree );
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b>...to...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
arg->d = evaluate_tree ( CURRENT_INDIVIDUAL->tr[f->evaltree].data,
|
||
|
f->evaltree );
|
||
|
</tt></pre>
|
||
|
|
||
|
|
||
|
<h2>The Random Facility</h2>
|
||
|
<p> lil-gp's random facility is not threadsafe and cannot be called from your evaluation code in multi-threaded mode without some patching. The patch for this wraps the random facility in a mutex so only one thread can call the random function at a time. Assuming threads aren't re-seeing the generator, the only function that needs to be wrapped is <tt>random_double()</tt> because the other random functions operate on it. <b>Note that this patch only works for POSIX Threads</b>. You'll have to code your own Solaris Threads patch, sorry. Here are the patch instructions.
|
||
|
|
||
|
<p><b>First open <tt>main.c</tt>, and change the passage</b>
|
||
|
|
||
|
<P><pre><tt>
|
||
|
/* maximum number of nodes per individual. -1 if no limit is
|
||
|
enforced. */
|
||
|
int ind_nodelimit;
|
||
|
|
||
|
int main ( int argc, char **argv )
|
||
|
{
|
||
|
|
||
|
multipop *mpop;
|
||
|
int startgen;
|
||
|
char *param;
|
||
|
event start, end, diff;
|
||
|
event eval, breed;
|
||
|
int startfromcheckpoint;
|
||
|
|
||
|
#ifdef MEMORY_LOG
|
||
|
/* dump all memory allocations to a file. */
|
||
|
mlog = fopen ( "memory.log", "w" );
|
||
|
#endif
|
||
|
</tt></pre>
|
||
|
|
||
|
<p> <b>...to...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
/* maximum number of nodes per individual. -1 if no limit is
|
||
|
enforced. */
|
||
|
int ind_nodelimit;
|
||
|
|
||
|
extern pthread_mutex_t random_mutex; /* Mutexes the random code */
|
||
|
|
||
|
int main ( int argc, char **argv )
|
||
|
{
|
||
|
|
||
|
multipop *mpop;
|
||
|
int startgen;
|
||
|
char *param;
|
||
|
event start, end, diff;
|
||
|
event eval, breed;
|
||
|
int startfromcheckpoint;
|
||
|
|
||
|
pthread_mutex_init(&random_mutex,NULL); /* Initialize the random mutex */
|
||
|
|
||
|
#ifdef MEMORY_LOG
|
||
|
/* dump all memory allocations to a file. */
|
||
|
mlog = fopen ( "memory.log", "w" );
|
||
|
#endif
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b> Then modify the passage (at the end of <tt>main()</tt>)...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
/* print memory/time statistics and close output files. */
|
||
|
output_system_stats ( &diff, &eval, &breed );
|
||
|
close_output_streams();
|
||
|
|
||
|
#ifdef MEMORY_LOG
|
||
|
fclose ( mlog );
|
||
|
#endif
|
||
|
|
||
|
/* all done. */
|
||
|
return 0;
|
||
|
}
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b>...to...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
/* print memory/time statistics and close output files. */
|
||
|
output_system_stats ( &diff, &eval, &breed );
|
||
|
close_output_streams();
|
||
|
|
||
|
#ifdef MEMORY_LOG
|
||
|
fclose ( mlog );
|
||
|
#endif
|
||
|
|
||
|
pthread_mutex_destroy(&random_mutex); /* Destroy random mutex */
|
||
|
|
||
|
/* all done. */
|
||
|
return 0;
|
||
|
}
|
||
|
</tt></pre>
|
||
|
|
||
|
|
||
|
<p><b> Next, open the file <tt>random.c</tt> Change the passage </b>
|
||
|
|
||
|
|
||
|
<p><pre><tt>
|
||
|
static double mz = 0.0;
|
||
|
static double ma[55]; /* the number 55 is special -- see Knuth. */
|
||
|
static int inext, inextp;
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b> ...to...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
static double mz = 0.0;
|
||
|
static double ma[55]; /* the number 55 is special -- see Knuth. */
|
||
|
static int inext, inextp;
|
||
|
|
||
|
pthread_mutex_t random_mutex;
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b> and change the function...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
double random_double ( void )
|
||
|
{
|
||
|
|
||
|
double mj;
|
||
|
double res;
|
||
|
|
||
|
inext = (inext+1)%55;
|
||
|
inextp = (inextp+1)%55;
|
||
|
|
||
|
mj = ma[inext] - ma[inextp];
|
||
|
if ( mj < mz )
|
||
|
mj = mj + mbig;
|
||
|
ma[inext] = mj;
|
||
|
|
||
|
res=mbig;
|
||
|
|
||
|
return mj/res;
|
||
|
}
|
||
|
</tt></pre>
|
||
|
|
||
|
<p><b> ...to...</b>
|
||
|
|
||
|
<p><pre><tt>
|
||
|
double random_double ( void )
|
||
|
{
|
||
|
/* There's a race condition on this, so we need to mutex it! */
|
||
|
|
||
|
double mj;
|
||
|
double res;
|
||
|
|
||
|
pthread_mutex_lock(&random_mutex);
|
||
|
|
||
|
inext = (inext+1)%55;
|
||
|
inextp = (inextp+1)%55;
|
||
|
|
||
|
mj = ma[inext] - ma[inextp];
|
||
|
if ( mj < mz )
|
||
|
mj = mj + mbig;
|
||
|
ma[inext] = mj;
|
||
|
|
||
|
res=mbig;
|
||
|
|
||
|
pthread_mutex_unlock(&random_mutex);
|
||
|
return mj/res;
|
||
|
}
|
||
|
</tt></pre>
|
||
|
|
||
|
|
||
|
</BODY>
|
||
|
</HTML>
|
||
|
|
||
|
|