You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1058 lines
26 KiB

#define CODE_lp_utils
#include <string.h>
#include "commonlib.h"
#include "lp_lib.h"
#include "lp_utils.h"
#include <time.h>
#include <sys/timeb.h>
#include "lp_bit.h"
#ifdef FORTIFY
# include "lp_fortify.h"
#endif
/*
Miscellaneous utilities as implemented for lp_solve v5.0+
----------------------------------------------------------------------------------
Author: Kjell Eikland
Contact: kjell.eikland@broadpark.no
License terms: GLPL.
Requires: lp_utils.h, lp_lib.h
Release notes:
v1.0.0 1 January 2003 Memory allocation, sorting, searching, time and
doubly linked list functions.
v1.1.0 15 May 2004 Added vector packing functionality
v1.2.0 10 January 2005 Added vector pushing/popping functionality
Modified return values and fixed problem in
linked list functions.
----------------------------------------------------------------------------------
*/
STATIC MYBOOL allocCHAR(lprec *lp, char **ptr, int size, MYBOOL clear)
{
if(clear == TRUE)
*ptr = (char *) calloc(size, sizeof(**ptr));
else if(clear & AUTOMATIC) {
*ptr = (char *) realloc(*ptr, size * sizeof(**ptr));
if(clear & TRUE)
MEMCLEAR(*ptr, size);
}
else
*ptr = (char *) malloc(size * sizeof(**ptr));
if(((*ptr) == NULL) && (size > 0)) {
lp->report(lp, CRITICAL, "alloc of %d 'char' failed\n", size);
lp->spx_status = NOMEMORY;
return( FALSE );
}
else
return( TRUE );
}
STATIC MYBOOL allocMYBOOL(lprec *lp, MYBOOL **ptr, int size, MYBOOL clear)
{
if(clear == TRUE)
*ptr = (MYBOOL *) calloc(size, sizeof(**ptr));
else if(clear & AUTOMATIC) {
*ptr = (MYBOOL *) realloc(*ptr, size * sizeof(**ptr));
if(clear & TRUE)
MEMCLEAR(*ptr, size);
}
else
*ptr = (MYBOOL *) malloc(size * sizeof(**ptr));
if(((*ptr) == NULL) && (size > 0)) {
lp->report(lp, CRITICAL, "alloc of %d 'MYBOOL' failed\n", size);
lp->spx_status = NOMEMORY;
return( FALSE );
}
else
return( TRUE );
}
STATIC MYBOOL allocINT(lprec *lp, int **ptr, int size, MYBOOL clear)
{
if(clear == TRUE)
*ptr = (int *) calloc(size, sizeof(**ptr));
else if(clear & AUTOMATIC) {
*ptr = (int *) realloc(*ptr, size * sizeof(**ptr));
if(clear & TRUE)
MEMCLEAR(*ptr, size);
}
else
*ptr = (int *) malloc(size * sizeof(**ptr));
if(((*ptr) == NULL) && (size > 0)) {
lp->report(lp, CRITICAL, "alloc of %d 'INT' failed\n", size);
lp->spx_status = NOMEMORY;
return( FALSE );
}
else
return( TRUE );
}
STATIC MYBOOL allocREAL(lprec *lp, REAL **ptr, int size, MYBOOL clear)
{
if(clear == TRUE)
*ptr = (REAL *) calloc(size, sizeof(**ptr));
else if(clear & AUTOMATIC) {
*ptr = (REAL *) realloc(*ptr, size * sizeof(**ptr));
if(clear & TRUE)
MEMCLEAR(*ptr, size);
}
else
*ptr = (REAL *) malloc(size * sizeof(**ptr));
if(((*ptr) == NULL) && (size > 0)) {
lp->report(lp, CRITICAL, "alloc of %d 'REAL' failed\n", size);
lp->spx_status = NOMEMORY;
return( FALSE );
}
else
return( TRUE );
}
STATIC MYBOOL allocLREAL(lprec *lp, LREAL **ptr, int size, MYBOOL clear)
{
if(clear == TRUE)
*ptr = (LREAL *) calloc(size, sizeof(**ptr));
else if(clear & AUTOMATIC) {
*ptr = (LREAL *) realloc(*ptr, size * sizeof(**ptr));
if(clear & TRUE)
MEMCLEAR(*ptr, size);
}
else
*ptr = (LREAL *) malloc(size * sizeof(**ptr));
if(((*ptr) == NULL) && (size > 0)) {
lp->report(lp, CRITICAL, "alloc of %d 'LREAL' failed\n", size);
lp->spx_status = NOMEMORY;
return( FALSE );
}
else
return( TRUE );
}
STATIC MYBOOL allocFREE(lprec *lp, void **ptr)
{
MYBOOL status = TRUE;
if(*ptr != NULL) {
free(*ptr);
*ptr = NULL;
}
else {
status = FALSE;
lp->report(lp, CRITICAL, "free() failed on line %d of file %s\n",
__LINE__, __FILE__);
}
return(status);
}
/* Do hoops to provide debugging info with FORTIFY */
#undef CODE_lp_utils
#include "lp_utils.h"
/* alloc-routines should always be before this line! */
int comp_bits(MYBOOL *bitarray1, MYBOOL *bitarray2, int items)
{
int i, items4, left = 0, right = 0;
MYBOOL comp1;
unsigned long comp4;
/* Convert items count to 8-bit representation, if necessary */
if(items > 0) {
i = items % 8;
items /= 8;
if(i)
items++;
}
else
items = -items;
/* Do the wide unsigned integer part for speed */
items4 = items / sizeof(unsigned long);
i = 0;
while(i < items4) {
comp4 = ((unsigned long *) bitarray1)[i] & ~((unsigned long *) bitarray2)[i];
if(comp4)
left++;
comp4 = ((unsigned long *) bitarray2)[i] & ~((unsigned long *) bitarray1)[i];
if(comp4)
right++;
i++;
}
/* Do the trailing slow narrow unsigned integer part */
i *= sizeof(unsigned long);
i++;
while(i < items) {
comp1 = bitarray1[i] & ~bitarray2[i];
if(comp1)
left++;
comp1 = bitarray2[i] & ~bitarray1[i];
if(comp1)
right++;
i++;
}
/* Determine set comparison outcomes */
if((left > 0) && (right == 0)) /* array1 is a superset of array2 */
i = 1;
else if((left == 0) && (right > 0)) /* array2 is a superset of array1 */
i = -1;
else if((left == 0) && (right == 0)) /* array1 and array2 are identical */
i = 0;
else
i = -2; /* indicate all other outcomes */
return( i );
}
STATIC workarraysrec *mempool_create(lprec *lp)
{
workarraysrec *temp;
temp = (workarraysrec *) calloc(1, sizeof(workarraysrec));
temp->lp = lp;
return( temp );
}
STATIC char *mempool_obtainVector(workarraysrec *mempool, int count, int unitsize)
{
char *newmem = NULL;
MYBOOL *bnewmem = NULL;
int *inewmem = NULL, size, i, ib, ie, memMargin = 0;
REAL *rnewmem = NULL;
/* First find the iso-sized window (binary search) */
size = count*unitsize;
memMargin += size;
ib = 0;
ie = mempool->count-1;
while(ie >= ib) {
i = (ib+ie) / 2;
if(abs(mempool->vectorsize[i]) > memMargin)
ie = i-1;
else if(abs(mempool->vectorsize[i]) < size)
ib = i+1;
else {
/* Find the beginning of the exact-sized array group */
do {
ib = i;
i--;
} while((i >= 0) && (abs(mempool->vectorsize[i]) >= size));
break;
}
}
/* Check if we have a preallocated unused array of sufficient size */
ie = mempool->count-1;
for(i = ib; i <= ie; i++)
if(mempool->vectorsize[i] < 0)
break;
/* Obtain and activate existing, unused vector if we are permitted */
if(i <= ie) {
#ifdef Paranoia
if((mempool->vectorsize[i] > 0) || (abs(mempool->vectorsize[i]) < size)) {
lprec *lp = mempool->lp;
lp->report(lp, SEVERE, "mempool_obtainVector: Invalid %s existing vector selected\n",
(ie < 0 ? "too small" : "occupied"));
lp->spx_status = NOMEMORY;
lp->bb_break = TRUE;
return( newmem );
}
#endif
newmem = mempool->vectorarray[i];
mempool->vectorsize[i] *= -1;
}
/* Otherwise allocate a new vector */
else if(unitsize == sizeof(MYBOOL)) {
allocMYBOOL(mempool->lp, &bnewmem, count, TRUE);
newmem = (char *) bnewmem;
}
else if(unitsize == sizeof(int)) {
allocINT(mempool->lp, &inewmem, count, TRUE);
newmem = (char *) inewmem;
}
else if(unitsize == sizeof(REAL)) {
allocREAL(mempool->lp, &rnewmem, count, TRUE);
newmem = (char *) rnewmem;
}
/* Insert into master array if necessary (maintain sort by ascending size) */
if((i > ie) && (newmem != NULL)) {
mempool->count++;
if(mempool->count >= mempool->size) {
mempool->size += 10;
mempool->vectorarray = (char **) realloc(mempool->vectorarray,
sizeof(*(mempool->vectorarray))*mempool->size);
mempool->vectorsize = (int *) realloc(mempool->vectorsize,
sizeof(*(mempool->vectorsize))*mempool->size);
}
ie++;
i = ie + 1;
if(i < mempool->count) {
MEMMOVE(mempool->vectorarray+i, mempool->vectorarray+ie, 1);
MEMMOVE(mempool->vectorsize+i, mempool->vectorsize+ie, 1);
}
mempool->vectorarray[ie] = newmem;
mempool->vectorsize[ie] = size;
}
return( newmem );
}
STATIC MYBOOL mempool_releaseVector(workarraysrec *mempool, char *memvector, MYBOOL forcefree)
{
int i;
#if 0
forcefree = TRUE;
#endif
for(i = mempool->count-1; i >= 0; i--)
if(mempool->vectorarray[i] == memvector)
break;
if((i < 0) || (mempool->vectorsize[i] < 0))
return( FALSE );
if(forcefree) {
FREE(mempool->vectorarray[i]);
mempool->count--;
for(; i < mempool->count; i++)
mempool->vectorarray[i] = mempool->vectorarray[i+1];
}
else
mempool->vectorsize[i] *= -1;
return( TRUE );
}
STATIC MYBOOL mempool_free(workarraysrec **mempool)
{
int i = (*mempool)->count;
while(i > 0) {
i--;
if((*mempool)->vectorsize[i] < 0) /* Handle unused vectors */
(*mempool)->vectorsize[i] *= -1;
mempool_releaseVector(*mempool, (*mempool)->vectorarray[i], TRUE);
}
FREE((*mempool)->vectorarray);
FREE((*mempool)->vectorsize);
FREE(*mempool);
return( TRUE );
}
REAL *cloneREAL(lprec *lp, REAL *origlist, int size)
{
REAL *newlist;
size += 1;
if(allocREAL(lp, &newlist, size, FALSE))
MEMCOPY(newlist, origlist, size);
return(newlist);
}
MYBOOL *cloneMYBOOL(lprec *lp, MYBOOL *origlist, int size)
{
MYBOOL *newlist;
size += 1;
if(allocMYBOOL(lp, &newlist, size, FALSE))
MEMCOPY(newlist, origlist, size);
return(newlist);
}
int *cloneINT(lprec *lp, int *origlist, int size)
{
int *newlist;
size += 1;
if(allocINT(lp, &newlist, size, FALSE))
MEMCOPY(newlist, origlist, size);
return(newlist);
}
STATIC void roundVector(LREAL *myvector, int endpos, LREAL roundzero)
{
if(roundzero > 0)
for(; endpos >= 0; myvector++, endpos--)
if(fabs(*myvector) < roundzero)
*myvector = 0;
}
STATIC REAL normalizeVector(REAL *myvector, int endpos)
/* Scale the ingoing vector so that its norm is unit, and return the original length */
{
int i;
REAL SSQ;
/* Cumulate squares */
SSQ = 0;
for(i = 0; i <= endpos; myvector++, i++)
SSQ += (*myvector) * (*myvector);
/* Normalize */
SSQ = sqrt(SSQ);
if(SSQ > 0)
for(myvector--; i > 0; myvector--, i--)
(*myvector) /= SSQ;
return( SSQ );
}
/* ---------------------------------------------------------------------------------- */
/* Other general utilities */
/* ---------------------------------------------------------------------------------- */
STATIC void swapINT(int *item1, int *item2)
{
int hold = *item1;
*item1 = *item2;
*item2 = hold;
}
STATIC void swapREAL(REAL *item1, REAL *item2)
{
REAL hold = *item1;
*item1 = *item2;
*item2 = hold;
}
STATIC void swapPTR(void **item1, void **item2)
{
void *hold;
hold = *item1;
*item1 = *item2;
*item2 = hold;
}
STATIC REAL restoreINT(REAL valREAL, REAL epsilon)
{
REAL valINT, fracREAL, fracABS;
fracREAL = modf(valREAL, &valINT);
fracABS = fabs(fracREAL);
if(fracABS < epsilon)
return(valINT);
else if(fracABS > 1-epsilon) {
if(fracREAL < 0)
return(valINT-1);
else
return(valINT+1);
}
return(valREAL);
}
STATIC REAL roundToPrecision(REAL value, REAL precision)
{
#if 1
REAL vmod;
int vexp2, vexp10;
LLONG sign;
if(precision == 0)
return(value);
sign = my_sign(value);
value = fabs(value);
/* Round to integer if possible */
if(value < precision)
return( 0 );
else if(value == floor(value))
return( value*sign );
else if((value < (REAL) MAXINT64) &&
(modf((REAL) (value+precision), &vmod) < precision)) {
/* sign *= (LLONG) (value+precision); */
sign *= (LLONG) (value+0.5);
return( (REAL) sign );
}
/* Optionally round with base 2 representation for additional precision */
#define roundPrecisionBase2
#ifdef roundPrecisionBase2
value = frexp(value, &vexp2);
#else
vexp2 = 0;
#endif
/* Convert to desired precision */
vexp10 = (int) log10(value);
precision *= pow(10.0, vexp10);
modf(value/precision+0.5, &value);
value *= sign*precision;
/* Restore base 10 representation if base 2 was active */
if(vexp2 != 0)
value = ldexp(value, vexp2);
#endif
return( value );
}
/* ---------------------------------------------------------------------------------- */
/* Searching function specialized for lp_solve */
/* ---------------------------------------------------------------------------------- */
STATIC int searchFor(int target, int *attributes, int size, int offset, MYBOOL absolute)
{
int beginPos, endPos;
int newPos, match;
/* Set starting and ending index offsets */
beginPos = offset;
endPos = beginPos + size - 1;
/* Do binary search logic based on a sorted attribute vector */
newPos = (beginPos + endPos) / 2;
match = attributes[newPos];
if(absolute)
match = abs(match);
while(endPos - beginPos > LINEARSEARCH) {
if(match < target) {
beginPos = newPos + 1;
newPos = (beginPos + endPos) / 2;
match = attributes[newPos];
if(absolute)
match = abs(match);
}
else if(match > target) {
endPos = newPos - 1;
newPos = (beginPos + endPos) / 2;
match = attributes[newPos];
if(absolute)
match = abs(match);
}
else {
beginPos = newPos;
endPos = newPos;
}
}
/* Do linear (unsorted) search logic */
if(endPos - beginPos <= LINEARSEARCH) {
match = attributes[beginPos];
if(absolute)
match = abs(match);
while((beginPos < endPos) && (match != target)) {
beginPos++;
match = attributes[beginPos];
if(absolute)
match = abs(match);
}
if(match == target)
endPos = beginPos;
}
/* Return the index if a match was found, or signal failure with a -1 */
if((beginPos == endPos) && (match == target))
return(beginPos);
else
return(-1);
}
/* ---------------------------------------------------------------------------------- */
/* Other supporting math routines */
/* ---------------------------------------------------------------------------------- */
STATIC MYBOOL isINT(lprec *lp, REAL value)
{
#if 0
return( (MYBOOL) (modf(fabs(value)+lp->epsint, &value) < 2*lp->epsint) );
#elif 1
value = fabs(value)+lp->epsint;
return( (MYBOOL) (my_reldiff(value, floor(value)) < 2*lp->epsint) );
#elif 0
REAL hold;
value = fabs(value);
hold = pow(10, MIN(-2, log10(value+1)+log10(lp->epsint)));
return( (MYBOOL) (modf(value+lp->epsint, &value) < 2*hold) );
#elif 0
value -= (REAL)floor(value);
return( (MYBOOL) ((value < lp->epsint) || (value > (1 - lp->epsint)) );
#else
value += lp->epsint;
return( (MYBOOL) (fabs(value-floor(value)) < 2*lp->epsint) );
#endif
}
STATIC MYBOOL isOrigFixed(lprec *lp, int varno)
{
return( (MYBOOL) (lp->orig_upbo[varno] - lp->orig_lowbo[varno] <= lp->epsmachine) );
}
STATIC void chsign_bounds(REAL *lobound, REAL *upbound)
{
REAL temp;
temp = *upbound;
if(fabs(*lobound) > 0)
*upbound = -(*lobound);
else
*upbound = 0;
if(fabs(temp) > 0)
*lobound = -temp;
else
*lobound = 0;
}
/* ---------------------------------------------------------------------------------- */
/* Define randomization routine */
/* ---------------------------------------------------------------------------------- */
STATIC REAL rand_uniform(lprec *lp, REAL range)
{
static MYBOOL randomized = FALSE; /* static ok here for reentrancy/multithreading */
if(!randomized) {
randomized = TRUE;
srand((unsigned) time( NULL ));
}
range *= (REAL) rand() / (REAL) RAND_MAX;
return( range );
}
/* ---------------------------------------------------------------------------------- */
/* Define routines for doubly linked lists of integers */
/* ---------------------------------------------------------------------------------- */
STATIC int createLink(int size, LLrec **linkmap, MYBOOL *usedpos)
{
int i, j;
MYBOOL reverse;
*linkmap = (LLrec *) calloc(1, sizeof(**linkmap));
if(*linkmap == NULL)
return( -1 );
reverse = (MYBOOL) (size < 0);
if(reverse)
size = -size;
(*linkmap)->map = (int *) calloc(2*(size + 1), sizeof(int));
if((*linkmap)->map == NULL)
return( -1 );
(*linkmap)->size = size;
j = 0;
if(usedpos == NULL)
(*linkmap)->map[0] = 0;
else {
for(i = 1; i <= size; i++)
if(!usedpos[i] ^ reverse) {
/* Set the forward link */
(*linkmap)->map[j] = i;
/* Set the backward link */
(*linkmap)->map[size+i] = j;
j = i;
if((*linkmap)->count == 0)
(*linkmap)->firstitem = i;
(*linkmap)->lastitem = i;
(*linkmap)->count++;
}
}
(*linkmap)->map[2*size+1] = j;
return( (*linkmap)->count );
}
STATIC MYBOOL freeLink(LLrec **linkmap)
{
MYBOOL status = TRUE;
if((linkmap == NULL) || (*linkmap == NULL))
status = FALSE;
else {
if((*linkmap)->map != NULL)
free((*linkmap)->map);
free(*linkmap);
*linkmap = NULL;
}
return( status );
}
STATIC int sizeLink(LLrec *linkmap)
{
return(linkmap->size);
}
STATIC MYBOOL isActiveLink(LLrec *linkmap, int itemnr)
{
if((linkmap->map[itemnr] != 0) ||
(linkmap->map[linkmap->size+itemnr] != 0) ||
(linkmap->map[0] == itemnr))
return( TRUE );
else
return( FALSE );
}
STATIC int countActiveLink(LLrec *linkmap)
{
return(linkmap->count);
}
STATIC int countInactiveLink(LLrec *linkmap)
{
return(linkmap->size-linkmap->count);
}
STATIC int firstActiveLink(LLrec *linkmap)
{
return(linkmap->map[0]);
}
STATIC int lastActiveLink(LLrec *linkmap)
{
return(linkmap->map[2*linkmap->size+1]);
}
STATIC MYBOOL appendLink(LLrec *linkmap, int newitem)
{
int k, size;
size = linkmap->size;
if(linkmap->map[newitem] != 0)
return( FALSE );
/* Link forward */
k = linkmap->map[2*size+1];
linkmap->map[k] = newitem;
/* Link backward */
linkmap->map[size+newitem] = k;
linkmap->map[2*size+1] = newitem;
/* Update count and return */
if(linkmap->count == 0)
linkmap->firstitem = newitem;
linkmap->lastitem = newitem;
linkmap->count++;
return( TRUE );
}
STATIC MYBOOL insertLink(LLrec *linkmap, int afteritem, int newitem)
{
int k, size;
size = linkmap->size;
if(linkmap->map[newitem] != 0)
return( FALSE );
if(afteritem == linkmap->map[2*size+1])
appendLink(linkmap, newitem);
else {
/* Link forward */
k = linkmap->map[afteritem];
linkmap->map[afteritem] = newitem;
linkmap->map[newitem] = k;
/* Link backward */
linkmap->map[size+k] = newitem;
linkmap->map[size+newitem] = afteritem;
/* Update count */
SETMIN(linkmap->firstitem, newitem);
SETMAX(linkmap->lastitem, newitem);
linkmap->count++;
}
return( TRUE );
}
STATIC MYBOOL setLink(LLrec *linkmap, int newitem)
{
if(isActiveLink(linkmap, newitem))
return( FALSE );
else
return( insertLink(linkmap, prevActiveLink(linkmap, newitem), newitem) );
}
STATIC MYBOOL fillLink(LLrec *linkmap)
{
int k, size;
size = linkmap->size;
k = firstActiveLink(linkmap);
if(k != 0)
return( FALSE );
for(k = 1; k <= size; k++)
appendLink(linkmap, k);
return( TRUE );
}
STATIC int nextActiveLink(LLrec *linkmap, int backitemnr)
{
if((backitemnr < 0) || (backitemnr > linkmap->size))
return( -1 );
else {
if(backitemnr < linkmap->lastitem)
while((backitemnr > linkmap->firstitem) && (linkmap->map[backitemnr] == 0))
backitemnr--;
return(linkmap->map[backitemnr]);
}
}
STATIC int prevActiveLink(LLrec *linkmap, int forwitemnr)
{
if((forwitemnr <= 0) || (forwitemnr > linkmap->size+1))
return( -1 );
else {
if(forwitemnr > linkmap->lastitem)
return( linkmap->lastitem);
if(forwitemnr > linkmap->firstitem) {
forwitemnr += linkmap->size;
while((forwitemnr < linkmap->size + linkmap->lastitem) && (linkmap->map[forwitemnr] == 0))
forwitemnr++;
}
else
forwitemnr += linkmap->size;
return(linkmap->map[forwitemnr]);
}
}
STATIC int firstInactiveLink(LLrec *linkmap)
{
int i, n;
if(countInactiveLink(linkmap) == 0)
return( 0 );
n = 1;
i = firstActiveLink(linkmap);
while(i == n) {
n++;
i = nextActiveLink(linkmap, i);
}
return( n );
}
STATIC int lastInactiveLink(LLrec *linkmap)
{
int i, n;
if(countInactiveLink(linkmap) == 0)
return( 0 );
n = linkmap->size;
i = lastActiveLink(linkmap);
while(i == n) {
n--;
i = prevActiveLink(linkmap, i);
}
return( n );
}
STATIC int nextInactiveLink(LLrec *linkmap, int backitemnr)
{
do {
backitemnr++;
} while((backitemnr <= linkmap->size) && isActiveLink(linkmap, backitemnr));
if(backitemnr <= linkmap->size)
return( backitemnr );
else
return( 0 );
}
STATIC int prevInactiveLink(LLrec *linkmap, int forwitemnr)
{
return( 0 );
}
STATIC int removeLink(LLrec *linkmap, int itemnr)
{
int size, prevnr, nextnr = -1;
size = linkmap->size;
if((itemnr <= 0) || (itemnr > size))
return( nextnr );
#ifdef Paranoia
if(!isActiveLink(linkmap, itemnr))
return( nextnr );
#endif
/* Get link data at the specified position */
nextnr = linkmap->map[itemnr];
prevnr = linkmap->map[size+itemnr];
if(itemnr == linkmap->firstitem)
linkmap->firstitem = nextnr;
if(itemnr == linkmap->lastitem)
linkmap->lastitem = prevnr;
/* Update forward link */
linkmap->map[prevnr] = linkmap->map[itemnr];
linkmap->map[itemnr] = 0;
/* Update backward link */
if(nextnr == 0)
linkmap->map[2*size+1] = prevnr;
else
linkmap->map[size+nextnr] = linkmap->map[size+itemnr];
linkmap->map[size+itemnr] = 0;
/* Decrement the count */
linkmap->count--;
/* Return the next active item */
return( nextnr );
}
STATIC LLrec *cloneLink(LLrec *sourcemap, int newsize, MYBOOL freesource)
{
LLrec *testmap = NULL;
if((newsize == sourcemap->size) || (newsize <= 0)) {
createLink(sourcemap->size, &testmap, NULL);
MEMCOPY(testmap->map, sourcemap->map, 2*(sourcemap->size+1));
testmap->firstitem = sourcemap->firstitem;
testmap->lastitem = sourcemap->lastitem;
testmap->size = sourcemap->size;
testmap->count = sourcemap->count;
}
else {
int j;
createLink(newsize, &testmap, NULL);
for(j = firstActiveLink(sourcemap); (j != 0) && (j <= newsize); j = nextActiveLink(sourcemap, j))
appendLink(testmap, j);
}
if(freesource)
freeLink(&sourcemap);
return(testmap);
}
STATIC int compareLink(LLrec *linkmap1, LLrec *linkmap2)
{
int test;
test = memcmp(&linkmap1->size, &linkmap2->size, sizeof(int));
if(test == 0)
test = memcmp(&linkmap1->count, &linkmap2->count, sizeof(int));
if(test == 0)
test = memcmp(linkmap1->map, linkmap2->map, sizeof(int)*(2*linkmap1->size+1));
return( test );
}
STATIC MYBOOL verifyLink(LLrec *linkmap, int itemnr, MYBOOL doappend)
{
LLrec *testmap;
testmap = cloneLink(linkmap, -1, FALSE);
if(doappend) {
appendLink(testmap, itemnr);
removeLink(testmap, itemnr);
}
else {
int previtem = prevActiveLink(testmap, itemnr);
removeLink(testmap, itemnr);
insertLink(testmap, previtem, itemnr);
}
itemnr = compareLink(linkmap, testmap);
freeLink(&testmap);
return((MYBOOL) (itemnr == 0));
}
/* Packed vector routines */
STATIC PVrec *createPackedVector(int size, REAL *values, int *workvector)
{
int i, k;
REGISTER REAL ref;
PVrec *newPV = NULL;
MYBOOL localWV = (MYBOOL) (workvector == NULL);
if(localWV)
workvector = (int *) malloc((size+1)*sizeof(*workvector));
/* Tally equal-valued vector entries - also check if it is worth compressing */
k = 0;
workvector[k] = 1;
ref = values[1];
for(i = 2; i <= size; i++) {
if(fabs(ref - values[i]) > DEF_EPSMACHINE) {
k++;
workvector[k] = i;
ref = values[i];
}
}
if(k > size / 2) {
if(localWV)
FREE(workvector);
return( newPV );
}
/* Create the packing object, adjust the position vector and allocate value vector */
newPV = (PVrec *) malloc(sizeof(*newPV));
k++; /* Adjust from index to to count */
newPV->count = k;
if(localWV)
newPV->startpos = (int *) realloc(workvector, (k + 1)*sizeof(*(newPV->startpos)));
else {
newPV->startpos = (int *) malloc((k + 1)*sizeof(*(newPV->startpos)));
MEMCOPY(newPV->startpos, workvector, k);
}
newPV->startpos[k] = size + 1; /* Store terminal index + 1 for searching purposes */
newPV->value = (REAL *) malloc(k*sizeof(*(newPV->value)));
/* Fill the values vector before returning */
for(i = 0; i < k; i++)
newPV->value[i] = values[newPV->startpos[i]];
return( newPV );
}
STATIC MYBOOL unpackPackedVector(PVrec *PV, REAL **target)
{
int i, ii, k;
REGISTER REAL ref;
/* Test for validity of the target and create it if necessary */
if(target == NULL)
return( FALSE );
if(*target == NULL)
allocREAL(NULL, target, PV->startpos[PV->count], FALSE);
/* Expand the packed vector into the target */
i = PV->startpos[0];
for(k = 0; k < PV->count; k++) {
ii = PV->startpos[k+1];
ref = PV->value[k];
while (i < ii) {
(*target)[i] = ref;
i++;
}
}
return( TRUE );
}
STATIC REAL getvaluePackedVector(PVrec *PV, int index)
{
index = searchFor(index, PV->startpos, PV->count, 0, FALSE);
index = abs(index)-1;
if(index >= 0)
return( PV->value[index] );
else
return( 0 );
}
STATIC MYBOOL freePackedVector(PVrec **PV)
{
if((PV == NULL) || (*PV == NULL))
return( FALSE );
FREE((*PV)->value);
FREE((*PV)->startpos);
FREE(*PV);
return( TRUE );
}
STATIC void pushPackedVector(PVrec *PV, PVrec *parent)
{
PV->parent = parent;
}
STATIC PVrec *popPackedVector(PVrec *PV)
{
PVrec *parent = PV->parent;
freePackedVector(&PV);
return( parent );
}