381 lines
9.4 KiB
C
381 lines
9.4 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>
|
||
|
|
||
|
/* total counts of ERCs used and freed */
|
||
|
int ercused = 0;
|
||
|
int ercfree = 0;
|
||
|
int ercalloc = 0;
|
||
|
|
||
|
/* the active list. */
|
||
|
ephem_const *active_head;
|
||
|
int active_count;
|
||
|
|
||
|
/* the free list. */
|
||
|
ephem_const *free_head;
|
||
|
int free_count;
|
||
|
|
||
|
/* pointers for the allocated blocks for ERCs. */
|
||
|
ephem_const **block_list;
|
||
|
int block_list_size;
|
||
|
int block_count;
|
||
|
|
||
|
/* initialize_ephem_const()
|
||
|
*
|
||
|
* allocate and set up the first block of ERCs, the free list,
|
||
|
* etc.
|
||
|
*/
|
||
|
|
||
|
void initialize_ephem_const ( void )
|
||
|
{
|
||
|
int i;
|
||
|
int size;
|
||
|
|
||
|
oputs ( OUT_SYS, 30, " ephemeral random constants.\n" );
|
||
|
|
||
|
active_head = (ephem_const *)MALLOC ( sizeof ( ephem_const ) );
|
||
|
active_head->refcount = 1;
|
||
|
active_head->next = NULL;
|
||
|
|
||
|
free_head = (ephem_const *)MALLOC ( sizeof ( ephem_const ) );
|
||
|
free_head->refcount = 1;
|
||
|
free_head->next = NULL;
|
||
|
|
||
|
/** how many block >>pointers<< to allocate (not blocks). **/
|
||
|
block_list_size = EPHEM_METABLOCKSIZE;
|
||
|
block_list = (ephem_const **)MALLOC ( block_list_size *
|
||
|
sizeof ( ephem_const * ) );
|
||
|
|
||
|
/* allocate the first block. */
|
||
|
size = EPHEM_STARTSIZE;
|
||
|
block_count = 1;
|
||
|
block_list[0] = (ephem_const *)MALLOC ( size *
|
||
|
sizeof ( ephem_const ) );
|
||
|
free_count = ercalloc = size;
|
||
|
|
||
|
/* chain all the ERC records in the block together. */
|
||
|
for ( i = 0; i < size-1; ++i )
|
||
|
block_list[0][i].next = block_list[0]+i+1;
|
||
|
block_list[0][size-1].next = NULL;
|
||
|
|
||
|
/* add the chain to the free list. */
|
||
|
free_head->next = block_list[0];
|
||
|
}
|
||
|
|
||
|
/* free_ephem_const()
|
||
|
*
|
||
|
* free all the memory allocated to hold ERCs.
|
||
|
*/
|
||
|
|
||
|
void free_ephem_const ( void )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
ephem_const_gc();
|
||
|
|
||
|
for ( i = 0; i < block_count; ++i )
|
||
|
FREE ( block_list[i] );
|
||
|
FREE ( block_list );
|
||
|
|
||
|
FREE ( active_head );
|
||
|
FREE ( free_head );
|
||
|
}
|
||
|
|
||
|
/* enlarge_ephem_space()
|
||
|
*
|
||
|
* allocate a new block of ERCs, and add all the records in it
|
||
|
* to the free list.
|
||
|
*/
|
||
|
|
||
|
void enlarge_ephem_space ( void )
|
||
|
{
|
||
|
int i;
|
||
|
int size = EPHEM_GROWSIZE;
|
||
|
|
||
|
/** if we've allocated too many blocks, we need to lengthen the
|
||
|
list that holds block pointers. **/
|
||
|
if ( block_count == block_list_size )
|
||
|
{
|
||
|
block_list_size += EPHEM_METABLOCKSIZE;
|
||
|
block_list = (ephem_const **)REALLOC ( block_list,
|
||
|
block_list_size *
|
||
|
sizeof ( ephem_const *));
|
||
|
}
|
||
|
|
||
|
/* allocate the new block. */
|
||
|
block_list[block_count] =
|
||
|
(ephem_const *)MALLOC ( size * sizeof ( ephem_const ) );
|
||
|
free_count += size;
|
||
|
ercalloc += size;
|
||
|
|
||
|
/* chain together all the records in it. */
|
||
|
for ( i = 0; i < size-1; ++i )
|
||
|
block_list[block_count][i].next =
|
||
|
block_list[block_count]+i+1;
|
||
|
|
||
|
block_list[block_count][size-1].next = free_head->next;
|
||
|
free_head->next = block_list[block_count];
|
||
|
|
||
|
++block_count;
|
||
|
}
|
||
|
|
||
|
/* new_ephemeral_const()
|
||
|
*
|
||
|
* create a new ERC, corresponding to the given function.
|
||
|
*/
|
||
|
|
||
|
ephem_const *new_ephemeral_const ( function *f )
|
||
|
{
|
||
|
ephem_const *p;
|
||
|
|
||
|
/* make sure we have enough space. */
|
||
|
while ( free_count <= 0 )
|
||
|
enlarge_ephem_space();
|
||
|
|
||
|
/* take the next record off the free list. */
|
||
|
p = free_head->next;
|
||
|
free_head->next = free_head->next->next;
|
||
|
--free_count;
|
||
|
|
||
|
/* call user code to generate the constant, placing
|
||
|
the value in the new record. */
|
||
|
f->ephem_gen ( &(p->d) );
|
||
|
p->f = f;
|
||
|
|
||
|
/* no references yet. */
|
||
|
p->refcount = 0;
|
||
|
|
||
|
/* add this record to the linked list of active ERCs. */
|
||
|
p->next = active_head->next;
|
||
|
active_head->next = p;
|
||
|
++active_count;
|
||
|
|
||
|
++ercused;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
/* ephem_const_gc()
|
||
|
*
|
||
|
* traverse the linked list of active ERCs, removing those with
|
||
|
* a reference count of 0.
|
||
|
*/
|
||
|
|
||
|
void ephem_const_gc ( void )
|
||
|
{
|
||
|
ephem_const *p = active_head->next;
|
||
|
ephem_const *m = active_head;
|
||
|
|
||
|
while ( p != NULL )
|
||
|
{
|
||
|
if ( p->refcount == 0 )
|
||
|
{
|
||
|
/* patch the linked list to skip this record. */
|
||
|
m->next = p->next;
|
||
|
|
||
|
/* add this record to the free list. */
|
||
|
p->next = free_head->next;
|
||
|
free_head->next = p;
|
||
|
++free_count;
|
||
|
++ercfree;
|
||
|
--active_count;
|
||
|
|
||
|
p = m->next;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* move past this record. */
|
||
|
m = p;
|
||
|
p = p->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* read_ephem_list()
|
||
|
*
|
||
|
* read list of ERCs from a checkpoint file.
|
||
|
*/
|
||
|
|
||
|
ephem_const **read_ephem_list ( FILE *f )
|
||
|
{
|
||
|
ephem_const **ind;
|
||
|
ephem_const *p;
|
||
|
int count;
|
||
|
int i, j;
|
||
|
char *buffer;
|
||
|
|
||
|
/* read the count. */
|
||
|
fscanf ( f, "%*s %d\n", &count );
|
||
|
|
||
|
/** if no ERCs, do nothing and return a NULL pointer for the index. **/
|
||
|
if ( count == 0 )
|
||
|
return NULL;
|
||
|
|
||
|
/* somewhere to place (and ignore) the human-readable forms of
|
||
|
the ERCs after the hex blocks. */
|
||
|
buffer = (char *)MALLOC ( MAXCHECKLINELENGTH );
|
||
|
|
||
|
/* allocate the index translating integers --> addresses. */
|
||
|
ind = (ephem_const **)MALLOC ( count * sizeof ( ephem_const * ) );
|
||
|
|
||
|
/** allocate a new block to hold all the ERCs we read. **/
|
||
|
|
||
|
/* we shouldn't EVER need to lengthen the block list while reading
|
||
|
a checkpoint, but check anyway... */
|
||
|
if ( block_count == block_list_size )
|
||
|
{
|
||
|
block_list_size += EPHEM_METABLOCKSIZE;
|
||
|
block_list = (ephem_const **)REALLOC ( block_list,
|
||
|
block_list_size *
|
||
|
sizeof ( ephem_const *));
|
||
|
}
|
||
|
|
||
|
/* allocate the new block. */
|
||
|
block_list[block_count] =
|
||
|
(ephem_const *)MALLOC ( count * sizeof ( ephem_const ) );
|
||
|
ercalloc += count;
|
||
|
|
||
|
/* read the checkpointed ERCs into the new block. */
|
||
|
for ( i = 0; i < count; ++i )
|
||
|
{
|
||
|
p = block_list[block_count]+i;
|
||
|
fscanf ( f, "%d %d ", &j, &(p->refcount) );
|
||
|
ind[j] = p;
|
||
|
read_hex_block ( &(p->d), sizeof ( DATATYPE ), f );
|
||
|
fgets ( buffer, MAXCHECKLINELENGTH, f );
|
||
|
|
||
|
/* chain together all the records. */
|
||
|
block_list[block_count][i].next = block_list[block_count]+i+1;
|
||
|
}
|
||
|
/* add the chained block to the active list. */
|
||
|
block_list[block_count][count-1].next = active_head->next;
|
||
|
active_head->next = block_list[block_count];
|
||
|
active_count += count;
|
||
|
ercused += count;
|
||
|
|
||
|
++block_count;
|
||
|
|
||
|
FREE ( buffer );
|
||
|
|
||
|
return ind;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* write_ephem_list()
|
||
|
*
|
||
|
* write the active list of ERCs to a checkpoint file. returns an
|
||
|
* index listing for translating an ERC address to a unique integer.
|
||
|
* (we can't store the address directly in the checkpoint, since
|
||
|
* the ERCs won't be loaded in the same spot in memory on restart.)
|
||
|
*/
|
||
|
|
||
|
ephem_index *write_ephem_list ( FILE *f )
|
||
|
{
|
||
|
ephem_index *ind;
|
||
|
ephem_const *p = active_head->next;
|
||
|
int j;
|
||
|
|
||
|
ind = (ephem_index *)MALLOC ( active_count * sizeof ( ephem_index ) );
|
||
|
fprintf ( f, "erc-count: %d\n", active_count );
|
||
|
|
||
|
j = 0;
|
||
|
while ( p )
|
||
|
{
|
||
|
/* store the index entry. */
|
||
|
ind[j].e = p;
|
||
|
ind[j].i = j;
|
||
|
|
||
|
/* write the reference count and the value. */
|
||
|
fprintf ( f, "%d %d ", j, p->refcount );
|
||
|
write_hex_block ( &(p->d), sizeof(DATATYPE), f );
|
||
|
fprintf ( f, " %s %s\n", p->f->string, p->f->ephem_str ( p->d ) );
|
||
|
|
||
|
/* move down the list. */
|
||
|
p = p->next;
|
||
|
++j;
|
||
|
}
|
||
|
|
||
|
/* sort the index by address, so we can use binary searching
|
||
|
on it. */
|
||
|
qsort ( ind, active_count, sizeof(ephem_index), ephem_index_comp );
|
||
|
|
||
|
return ind;
|
||
|
}
|
||
|
|
||
|
/* lookup_ephem()
|
||
|
*
|
||
|
* look up an ERC (by address) in an index returned by write_ephem_list()
|
||
|
* and return its integer index.
|
||
|
*/
|
||
|
|
||
|
int lookup_ephem ( ephem_index *ind, ephem_const *e )
|
||
|
{
|
||
|
int low = 0;
|
||
|
int high = (ercused-ercfree);
|
||
|
int mid;
|
||
|
|
||
|
while ( low < high-1 )
|
||
|
{
|
||
|
mid = (low+high)/2;
|
||
|
if ( e >= ind[mid].e )
|
||
|
low = mid;
|
||
|
else
|
||
|
high = mid;
|
||
|
}
|
||
|
|
||
|
return ind[low].i;
|
||
|
}
|
||
|
|
||
|
/* ephem_index_comp()
|
||
|
*
|
||
|
* comparison function for using qsort() to order the ERC index by
|
||
|
* address.
|
||
|
*/
|
||
|
|
||
|
int ephem_index_comp ( const void *a, const void *b )
|
||
|
{
|
||
|
if ( ((ephem_index *)a)->e < ((ephem_index *)b)->e )
|
||
|
return -1;
|
||
|
else
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* get_ephem_stats()
|
||
|
*
|
||
|
* return ERC statistics.
|
||
|
*/
|
||
|
|
||
|
void get_ephem_stats ( int *used, int *free, int *blocks, int *alloc )
|
||
|
{
|
||
|
*used = ercused;
|
||
|
*free = ercfree;
|
||
|
*blocks = block_count;
|
||
|
*alloc = ercalloc;
|
||
|
}
|