madagascar/clausedb.c

492 lines
11 KiB
C

/* 2012 (C) Jussi Rintanen, jrintanen.jr@gmail.com */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "main.h"
#include "interface.h"
#include "clausedb.h"
#include "clausesets.h"
#include "printplan.h"
#include "asyntax.h"
#include "ordintsets.h"
#include "operators.h"
#include "translate2sat.h"
#define noDEBUG
#define noASSERTS
#define noALIGNMENT /* There is a problem: the padding is not handled by GC! */
typedef struct _clausedblist {
int *block;
int permanent;
int blockptr;
struct _clausedblist *nextblock;
} clausedblist;
#if defined(__LP64__)
#define BLOCKSIZE 1024*1024*8
#else
#define BLOCKSIZE 1024*1024*2
#endif
clausedblist *cdb;
int CDBclauses;
/* Given an int *, calculate the number of sizeof(int) to the
next 64 byte alignment boundary. This is to align data structures
with cache line boundaries.
*/
int ptr2intpad(int *ptr) {
int alignment = (((int)ptr)&63) >> 2;
if(alignment) return 16-alignment;
else return 0;
}
void check_malloc_success(void *ptr,int i) {
if(ptr == NULL) {
fprintf(stderr,"ERROR: Could not allocate more memory %i.\n",i);
exit(1);
}
}
/* Clauses in the clause data base:
location content
-3 activity
-2 SAT instance number
-1 # of literals in clause
0 1st literal
1 2nd literal
. .
. .
n-1 last literal
n -1
WARNING: These should always be accessed with the indices PREFIX_xxxx
defined in clausedb.h.
*/
void initclausedb() {
cdb = (clausedblist *)malloc(sizeof(struct _clausedblist));
check_malloc_success(cdb,1);
cdb->block = (int *)malloc(BLOCKSIZE*sizeof(int));
check_malloc_success(cdb->block,2);
allocatedbyCDB = BLOCKSIZE*sizeof(int);
cdb->blockptr = 0;
cdb->permanent = 1;
cdb->nextblock = NULL;
#ifdef DEBUG
printf("FIRST CBD BLOCK %i\n",(int)cdb);
#endif
CDBclauses = 0;
clausecount = 0;
GCaggressiveness = 0; /* Remove only very old clauses. */
}
/* Update clause activity counter. The pointer is to the first literal. */
void updateactivity(int *c,int act) {
c[PREFIX_ACTIVITY] = act;
}
/* Set the LBD field of a clause. */
void setLBD(int *c,int lbd) {
c[PREFIX_LBD] = lbd;
}
/* Allocate a clause. If permflag is 1, space allocated for
the clause won't be freed or reused. */
int *allocc(int inst,int len,int permflag) {
clausedblist *cls,*temp;
int *ptr;
#ifdef ALIGNMENT
int alignment;
#endif
#ifdef MULTICORE
#pragma omp critical
#endif
{
CDBclauses += 1;
clausecount += 1;
cls = cdb;
while(cls != NULL
&& (cls->permanent != permflag
|| cls->blockptr+len+PREFIXWORDS+5 > BLOCKSIZE))
{
cls = cls->nextblock;
}
if(cls == NULL) { /* Allocate a new block. */
#ifdef DEBUG
printf("NEW CDB BLOCK (total of %i clauses now).\n",CDBclauses);
#endif
temp = cdb;
cdb = (clausedblist *)malloc(sizeof(struct _clausedblist));
check_malloc_success(cdb,3);
cdb->block = (int *)malloc(BLOCKSIZE*sizeof(int));
check_malloc_success(cdb->block,4);
allocatedbyCDB += BLOCKSIZE*sizeof(int);
cdb->permanent = permflag;
cdb->nextblock = temp;
cdb->blockptr = 0;
cls = cdb;
printf("\t\t\t\tAllocated %i MB %s(total %i MB)\n",
BLOCKSIZE/1024/1024*sizeof(int),
(permflag ? "permanent " : ""),
(int)(memoryused()));
}
#ifdef DEBUG
printf("Allocating clause %i of length %i\n",cdb->blockptr,len);
#endif
/* Allocate it from an existing block. */
#ifdef DEBUG
printf("Allocating clause %i of length %i\n",cls->blockptr,len);
#endif
/* Clauses should be aligned with cache line boundaries (16x4Bs?).
Add something to cls->blockptr to make it align.
*/
#ifdef ALIGNMENT
cls->blockptr += ptr2intpad(&(cls->block[cls->blockptr]));
#endif
ptr = &(cls->block[cls->blockptr+PREFIXWORDS]);
}
cls->block[cls->blockptr+PREFIXWORDS+PREFIX_ACTIVITY] = 0;
cls->block[cls->blockptr+PREFIXWORDS+PREFIX_LBD] = 0;
cls->block[cls->blockptr+PREFIXWORDS+PREFIX_INSTANCE] = inst;
cls->block[cls->blockptr+PREFIXWORDS+PREFIX_CLAUSELEN] = len;
cls->block[cls->blockptr+len+PREFIXWORDS] = -1;
cls->blockptr += len+1+PREFIXWORDS;
return ptr;
}
/* Extract information from a clause pointed to by ptr (the first literal.) */
int clauselen(int *ptr) {
return ptr[PREFIX_CLAUSELEN];
}
int SATinstance(int *ptr) {
return ptr[PREFIX_INSTANCE];
}
/* Allocate space for a non-permanent clause. */
int *allocpermclause(int inst,int len) { return allocc(inst,len,1); }
int *allocclause(int inst,int len) { return allocc(inst,len,0); }
/* The following has not been tested after the -2 and -3 fields were added. */
void showclauses(satinstance sati) {
clausedblist *cls;
int i,j,b;
printf("All clauses in clause db:\n");
cls = cdb;
b=0;
while(cls != NULL) {
i = 0;
while(i < cls->blockptr) {
printf("Clause at %i.%i:",b,i);
for(j=i+PREFIXWORDS;j<i+PREFIXWORDS+(cls->block[i+PREFIXWORDS+PREFIX_CLAUSELEN]);j++) {
printf(" [%i]:",cls->block[j]); printTlit(sati,cls->block[j]);
}
printf("\n");
i = i+(cls->block[i+PREFIXWORDS+PREFIX_CLAUSELEN])+PREFIXWORDS+1;
}
cls = cls->nextblock;
b += 1;
}
}
#ifdef LBD
int nofclausesinblock(clausedblist *block) {
int n = 0;
int i = 0;
while(i < block->blockptr) {
n++;
i = i+(block->block[i+PREFIXWORDS+PREFIX_CLAUSELEN])+PREFIXWORDS+1;
}
return n;
}
int nofnoninputclauses() {
clausedblist *block = cdb;
int n = 0;
while(block) {
if(block->permanent == 0) n += nofclausesinblock(block);
block = block->nextblock;
}
return n;
}
int intCmp0(int *a,int *b) {
if(*a > *b) return 1;
else return 0;
}
int medianLBD() {
int n = nofnoninputclauses();
{
int i,j;
int tmp[n];
clausedblist *block = cdb;
j = 0;
while(block != NULL) {
if(block->permanent == 0) {
i = 0;
while(i < block->blockptr) {
tmp[j++] = block->block[i+PREFIXWORDS+PREFIX_LBD];
i = i+(block->block[i+PREFIXWORDS+PREFIX_CLAUSELEN])+PREFIXWORDS+1;
}
}
block = block->nextblock;
}
qsort(tmp,j,sizeof(int),intCmp0);
return tmp[j >> 1];
}
}
#endif
/***********************************************************************/
/*** Garbage collection: reclaim space used by useless clauses. ***/
/***********************************************************************/
int uselessp(satinstance sati,int *c,int lbdbound) {
int len,age,lbd;
len = c[PREFIXWORDS+PREFIX_CLAUSELEN];
lbd = c[PREFIXWORDS+PREFIX_LBD];
age = sati->conflicts - c[PREFIXWORDS+PREFIX_ACTIVITY];
if(len <= 5) return 0;
if(age > 200000) return 1;
if(lbd < lbdbound) return 0;
if(lbd == lbdbound && age < 500) return 0;
return 1;
}
PTRINT *nextwlelement(satinstance sati,int lit,int *ls) {
if(ls[0] == lit) return &(ls[PREFIX_WATCHA]);
else {
#ifdef ASSERTS
assert(ls[1] == lit);
#endif
return &(ls[PREFIX_WATCHB]);
}
}
void findinlist(satinstance sati,int lit,int *c) {
int *ls;
if(sati->value == 0) return; /* Instance is not used any more. */
ls = sati->lits[lit].watches;
do {
if(ls == c) {
printf("Clause %ld found in the list of %i.\n",(PTRINT)c,lit);
return;
}
ls = *(nextwlelement(sati,lit,ls));
} while(ls != NULL);
printf("Clause not found!!!\n");
}
/* Remove a clause from the list of clauses in which a literal is watched. */
void removefromwlist(satinstance sati,int lit,int *c) {
int *ls;
int **prev;
if(sati->value == 0) return; /* Instance is not used any more. */
ls = sati->lits[lit].watches;
prev = &(sati->lits[lit].watches);
do {
if(ls == c) {
*prev = *(nextwlelement(sati,lit,ls));
return;
}
prev = nextwlelement(sati,lit,ls);
ls = *prev;
#ifdef ASSERTS
assert(ls != NULL);
#endif
} while(1==1);
}
/* Replace a clause by another one in the list of clauses. */
void replaceinwlist(satinstance sati,int lit,int *c1,int *c2) {
int *ls;
if(sati->value == 0) return; /* Instance is not used any more. */
ls = sati->lits[lit].watches;
if(ls==c1) {
sati->lits[lit].watches = c2;
return;
}
do {
if(ls[0] == lit) {
if(c1 == lsACCESS_WATCHA) {
lsASSIGN_WATCHA = c2;
return;
}
ls = lsACCESS_WATCHA;
} else {
#ifdef ASSERTS
assert(ls[1] == lit);
#endif
if(c1 == lsACCESS_WATCHB) {
lsASSIGN_WATCHB = c2;
return;
}
ls = lsACCESS_WATCHB;
}
#ifdef ASSERTS
assert(ls != NULL);
#endif
} while(1==1);
}
/* Delete useless clauses and free the space used by them. */
int garbagecollection() {
int i;
int freed,inst;
int ptr,fill,bytes;
clausedblist *blocks;
float freedMB;
#ifdef LBD
int lbdbound = medianLBD();
#endif
#ifdef LBD
/* printf("\t\t\t\t\t\tMedian LBD: %i\n",lbdbound); */
#endif
printf("\t\t\t\t\t\tGC:"); fflush(stdout);
freed = 0; /* Number of bytes freed. */
blocks = cdb;
while(blocks != NULL) {
ptr = 0;
fill = 0; /* Where to move clauses when compacting. */
#ifdef DEBUG
printf("Fill factor %i/%i (%.2f %, %.2f MB)",blocks->blockptr,BLOCKSIZE,((double)blocks->blockptr)*100.0/((double)BLOCKSIZE),((double)blocks->blockptr)*4.0/1024.0/1024.0);
#endif
while(ptr < blocks->blockptr) {
inst = blocks->block[ptr+PREFIXWORDS+PREFIX_INSTANCE];
bytes = blocks->block[ptr+PREFIXWORDS+PREFIX_CLAUSELEN]+PREFIXWORDS+1;
/* Test integrity */
// findinlist(seqs[inst].sati,
// blocks->block[ptr+PREFIXWORDS],
// &(blocks->block[ptr+PREFIXWORDS]));
// findinlist(seqs[inst].sati,
// blocks->block[ptr+PREFIXWORDS+1],
// &(blocks->block[ptr+PREFIXWORDS]));
if((seqs[inst].sati->value == 0)
|| (!blocks->permanent && (uselessp(seqs[inst].sati,blocks->block+ptr,lbdbound)))) { /* Useless clause? */
removefromwlist(seqs[inst].sati,
blocks->block[ptr+PREFIXWORDS],
blocks->block+ptr+PREFIXWORDS);
removefromwlist(seqs[inst].sati,
blocks->block[ptr+PREFIXWORDS+1],
blocks->block+ptr+PREFIXWORDS);
freed += bytes;
} else { /* Otherwise shift it. */
if(fill < ptr) {
replaceinwlist(seqs[inst].sati,
blocks->block[ptr+PREFIXWORDS],
blocks->block+ptr+PREFIXWORDS,
blocks->block+fill+PREFIXWORDS);
replaceinwlist(seqs[inst].sati,
blocks->block[ptr+PREFIXWORDS+1],
blocks->block+ptr+PREFIXWORDS,
blocks->block+fill+PREFIXWORDS);
for(i=0;i<bytes;i++) blocks->block[fill+i] = blocks->block[ptr+i];
}
fill += bytes;
}
ptr += bytes; /* Next clause */
}
#ifdef DEBUG
printf(" -> (%.2f %, %.2f MB).\n",
((double)fill)*100/((double)BLOCKSIZE),
((double)fill)*4.0/1024.0/1024.0);
#endif
blocks->blockptr = fill;
blocks = blocks->nextblock;
}
freedMB = ((float)freed) / (1024.0*256.0);
printf(" %.2f MB\n",freedMB); fflush(stdout);
return (int)freedMB;
}