COSC-4P82-Final-Project/lib/lilgp/kernel_c/ephem.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;
}