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
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 );
|
|
}
|
|
|