UDI: some code refactor, simple code when no index intersection is needed

This commit is contained in:
David Vaz 2013-01-02 11:20:54 +00:00
parent bae26c618b
commit 58962f2595
4 changed files with 213 additions and 181 deletions

238
C/udi.c
View File

@ -4,15 +4,14 @@
#include "Yap.h" #include "Yap.h"
#include "YapInterface.h" #include "YapInterface.h"
#include "clause.h" #include "clause.h"
#include "clause_list.h"
#include "udi_private.h" #include "udi_private.h"
/* to keep a vector of udi indexers */ /* to keep an array with the registered udi indexers */
UT_icd udicb_icd = {sizeof(UdiControlBlock), NULL, NULL, NULL}; UT_icd udicb_icd = {sizeof(UdiControlBlock), NULL, NULL, NULL};
UT_array *indexing_structures; UT_array *indexing_structures;
/* /*
* New user indexed predicate (used by the public udi interface) * Register a new user indexer
*/ */
void void
Yap_UdiRegister(UdiControlBlock cb){ Yap_UdiRegister(UdiControlBlock cb){
@ -33,8 +32,6 @@ p_new_udi( USES_REGS1 )
UdiInfo blk; UdiInfo blk;
int info; int info;
//fprintf(stderr,"new pred\n");
/* get the predicate from the spec, copied from cdmgr.c */ /* get the predicate from the spec, copied from cdmgr.c */
if (IsVarTerm(spec)) { if (IsVarTerm(spec)) {
Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1"); Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1");
@ -79,59 +76,63 @@ p_new_udi( USES_REGS1 )
/* this is the real work */ /* this is the real work */
blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info));
memset((void *) blk,0, sizeof(struct udi_info)); memset((void *) blk,0, sizeof(struct udi_info));
if (!blk) { if (!blk) {
Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1");
return FALSE; return FALSE;
} }
utarray_new(blk->clauselist, &cl_icd);
utarray_new(blk->args, &arg_icd);
blk->p = p;
HASH_ADD_UdiInfo(UdiControlBlocks, p, blk);
//fprintf(stderr,"PRED %p\n",p);
info = Yap_udi_args_init(spec, p->ArityOfPE, blk); /*Init UdiInfo */
if (!info) /*TODO: clear blk here*/ utarray_new(blk->args, &arg_icd);
utarray_new(blk->clauselist, &cl_icd);
blk->p = p;
/*Now Init args list*/
info = p_udi_args_init(spec, p->ArityOfPE, blk);
if (!info)
{
utarray_free(blk->args);
utarray_free(blk->clauselist);
Yap_FreeCodeSpace((char *) blk);
return FALSE; return FALSE;
}
/*Push into the hash*/
HASH_ADD_UdiInfo(UdiControlBlocks, p, blk);
p->PredFlags |= UDIPredFlag; p->PredFlags |= UDIPredFlag;
return TRUE; return TRUE;
} }
/* /*
* Here we initialize the arguments indexing * Here we initialize the arguments indexing
*/ */
int YAP_Int
Yap_udi_args_init(Term spec, int arity, UdiInfo blk) p_udi_args_init(Term spec, int arity, UdiInfo blk)
{ {
int i; int i;
Term arg; Term arg;
Atom idxtype; Atom idxtype;
UdiControlBlock *p; UdiControlBlock *cb;
struct udi_p_args p_arg; struct udi_p_args p_arg;
//fprintf(stderr,"udi init\n");
for (i = 1; i <= arity; i++) { for (i = 1; i <= arity; i++) {
arg = ArgOfTerm(i,spec); arg = ArgOfTerm(i,spec);
if (IsAtomTerm(arg)) { if (IsAtomTerm(arg)) {
idxtype = AtomOfTerm(arg); idxtype = AtomOfTerm(arg);
// fprintf(stderr,"%p-%s %p-%s\n",idxtype, YAP_AtomName(idxtype), if (idxtype == AtomMinus) //skip this argument
// AtomMinus, YAP_AtomName(AtomMinus));
if (idxtype == AtomMinus)
continue; continue;
p_arg.control = NULL; p_arg.control = NULL;
p = NULL; cb = NULL;
while ((p = (UdiControlBlock *) utarray_next(indexing_structures, p))) { while ((cb = (UdiControlBlock *) utarray_next(indexing_structures, cb))) {
//fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); if (idxtype == (*cb)->decl){
if (idxtype == (*p)->decl){
p_arg.arg = i; p_arg.arg = i;
p_arg.control = *p; p_arg.control = *cb;
p_arg.idxstr = (*p)->init(spec, i, arity); p_arg.idxstr = (*cb)->init(spec, i, arity);
utarray_push_back(blk->args, &p_arg); utarray_push_back(blk->args, &p_arg);
} }
} }
if (p_arg.control == NULL){ /* not "-" and not found*/ if (p_arg.control == NULL){ /* not "-" and not found */
fprintf(stderr, "Invalid Spec (%s)\n", AtomName(idxtype)); fprintf(stderr, "Invalid Spec (%s)\n", AtomName(idxtype));
return FALSE; return FALSE;
} }
@ -140,36 +141,54 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk)
return TRUE; return TRUE;
} }
/* just pass info to user, called from cdmgr.c */ /*
* From now on this is called in several places of yap
* when the predicate has the UDIPredFlag
* and is what actually triggers the insert/search/abolish of indexing structures
*/
/*
* Init Yap udi interface
*/
void
Yap_udi_init(void)
{
UdiControlBlocks = NULL;
/*init indexing structures array*/
utarray_new(indexing_structures, &udicb_icd);
Yap_InitCPred("$udi_init", 1, p_new_udi, 0);
/* TODO: decide if udi.yap should be loaded automaticaly in init.yap */
}
/* called from cdmgr.c
*
* for each assert of a udipredicate
* to pass info to user structure
*/
int int
Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t)
{ {
int i; int i;
UdiPArg parg; UdiPArg parg;
UdiInfo info; UdiInfo info;
int index; YAP_Int index;
// yamop **x;
/* try to find our structure*/ /* try to find our structure */
HASH_FIND_UdiInfo(UdiControlBlocks,p,info); HASH_FIND_UdiInfo(UdiControlBlocks,p,info);
if (!info) if (!info)
return FALSE; return FALSE;
/*insert into clauselist will be used latter*/ /* insert into clauselist */
utarray_push_back(info->clauselist, &cl); utarray_push_back(info->clauselist, &cl);
for (i = 0; i < utarray_len(info->args) ; i++) { for (i = 0; i < utarray_len(info->args) ; i++) {
parg = (UdiPArg) utarray_eltptr(info->args,i); parg = (UdiPArg) utarray_eltptr(info->args,i);
index = utarray_len(info->clauselist); index = (YAP_Int) utarray_len(info->clauselist);
// x = (yamop **) utarray_eltptr(info->clauselist, index);
// fprintf(stderr,"Insert (%p %p %d) %d - %p %p %p\n",
// info->clauselist,info->clauselist->d,info->clauselist->icd.sz,
// index,
// cl, *x, *((yamop **) utarray_eltptr(info->clauselist, index)));
parg->idxstr = parg->control->insert(parg->idxstr, t, parg->idxstr = parg->control->insert(parg->idxstr, t,
parg->arg, parg->arg,
(void *) index); (void *) index);
//info->cb = info->functions->insert(t, info->cb, (void *)cl);
} }
return TRUE; return TRUE;
} }
@ -187,69 +206,96 @@ static inline int callback(void *key, void *data, void *arg)
return TRUE; return TRUE;
} }
/* index, called from absmi.c */ /* index, called from absmi.c
*
* Returns:
* NULL (yap fallback) No usable indexing available
*
* Yap_FAILCODE() (fail) No result found
* Yap_CauseListToClause(cl) 1 solution found
* Yap_ClauseListCode(cl) 2+ solutions found
*/
yamop * yamop *
Yap_udi_search(PredEntry *p) Yap_udi_search(PredEntry *p)
{ {
int i, r; int r;
struct ClauseList clauselist; struct ClauseList clauselist;
// struct CallbackM cm;
// callback_m_t c;
UdiPArg parg; UdiPArg parg;
UdiInfo info; UdiInfo info;
Pvoid_t tmp, result;
Word_t count;
Word_t idx_r = 0L;
yamop **x;
/* find our structure*/ /* find our structure*/
HASH_FIND_UdiInfo(UdiControlBlocks,p,info); HASH_FIND_UdiInfo(UdiControlBlocks,p,info);
if (!info) if (!info || utarray_len(info->args) == 0)
return NULL; return NULL;
// /*TODO: handle intersection*/ if (utarray_len(info->args) == 1){ //simple case no intersection needed
// c = &cm; struct si_callback_h c;
// c->cl = Yap_ClauseListInit(&clauselist);
// c->pred = p; c.cl = Yap_ClauseListInit(&clauselist);
c.clauselist = info->clauselist;
c.pred = info->p;
if (!c.cl)
return NULL;
parg = (UdiPArg) utarray_eltptr(info->args,0);
r = parg->control->search(parg->idxstr, parg->arg, si_callback, (void *) &c);
Yap_ClauseListClose(c.cl);
if (r == -1) {
Yap_ClauseListDestroy(c.cl);
return NULL;
}
if (Yap_ClauseListCount(c.cl) == 0) {
Yap_ClauseListDestroy(c.cl);
return Yap_FAILCODE();
}
} else {//intersection needed using Judy1
/*TODO: do more tests to this algorithm*/
int i;
Pvoid_t tmp = (Pvoid_t) NULL;
Pvoid_t result = (Pvoid_t) NULL;
Word_t count = 0L;
Word_t idx_r = 0L;
Word_t idx_tmp = 0L;
int rc = 0;
yamop **x;
/* /*
* I will start with the simplest case * I will start with the simplest approach
* for each index create a set and intersect it with the * for each index create a set and intersect it with the
* next * next
*
* In the future it could pay to sort according to index type
* to improve intersection part
*/ */
result = (Pvoid_t) NULL;
tmp = (Pvoid_t) NULL;
r = -1;
for (i = 0; i < utarray_len(info->args) ; i++) { for (i = 0; i < utarray_len(info->args) ; i++) {
// fprintf(stderr,"Start Search\n");
parg = (UdiPArg) utarray_eltptr(info->args,i); parg = (UdiPArg) utarray_eltptr(info->args,i);
r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp);
if (r == -1) /*this arg does not prune search*/ if (r == -1) /*this arg does not prune search*/
continue; continue;
rc ++;
J1C(count, result, 0, -1); J1C(count, result, 0, -1);
if (r == 0) /* this arg gave 0 results -> FAIL*/
if (r == 0)
{ {
if (count > 0) // clear previous result if it exists if (count > 0) // clear previous result if they exists
J1FA(count, result); J1FA(count, result);
fprintf(stderr,"Search Failed");
return Yap_FAILCODE(); return Yap_FAILCODE();
} }
if (r > 0 && count == 0) // first result_set if (count == 0) // first result_set
{ {
result = tmp; result = tmp;
tmp = (Pvoid_t) NULL; tmp = (Pvoid_t) NULL;
} }
else else /*intersection*/
{/*intersection*/ {
Word_t idx_tmp = 0L; idx_tmp = 0L;
idx_r = 0L; idx_r = 0L;
J1F(count, result, idx_r);//succeeds one time at least J1F(count, result, idx_r); //succeeds one time at least
assert(count > 0);
J1F(count, tmp, idx_tmp); //succeeds one time at least J1F(count, tmp, idx_tmp); //succeeds one time at least
assert(count > 0);
while (count) while (count)
{ {
while (idx_r < idx_tmp) while (idx_r < idx_tmp)
@ -263,13 +309,13 @@ Yap_udi_search(PredEntry *p)
J1N(count, result, idx_r); //next J1N(count, result, idx_r); //next
if (! count) break; //end result set if (! count) break; //end result set
J1N(count, tmp, idx_tmp); //next tmp J1N(count, tmp, idx_tmp); //next tmp
//if (! count) break; //end tmp set //if (! count) break; //end tmp set will break while
} }
else // (idx_r > idx_tmp) else // (idx_r > idx_tmp)
{ {
idx_tmp = idx_r; // fast forward idx_tmp = idx_r; // fast forward
J1F(count, tmp, idx_tmp); // first starting in idx_r J1F(count, tmp, idx_tmp); // first starting in idx_r
if (! count) break; //end tmp set //if (! count) break; //end tmp set will break while
} }
} }
J1F(count, result, idx_r); // first starting in idx_r J1F(count, result, idx_r); // first starting in idx_r
@ -279,21 +325,25 @@ Yap_udi_search(PredEntry *p)
J1U(count, result, idx_r); //does not belong J1U(count, result, idx_r); //does not belong
J1N(count, result, idx_r); //next J1N(count, result, idx_r); //next
} }
J1FA(count, tmp); J1FA(count, tmp); //free tmp
}
}
if (rc == 0) /*no search performed*/
return NULL;
J1C(count, result, 0, -1);
if (count == 0) { /*result set empty -> FAIL */
J1FA(count, result);
return Yap_FAILCODE();
} }
} /*convert Juddy1 to clauselist*/
Yap_ClauseListInit(&clauselist); Yap_ClauseListInit(&clauselist);
idx_r = 0L; idx_r = 0L;
J1F(count, result, idx_r); J1F(count, result, idx_r);
while (count) while (count)
{ {
x = (yamop **) utarray_eltptr(info->clauselist, idx_r - 1); x = (yamop **) utarray_eltptr(info->clauselist, idx_r - 1);
// fprintf(stderr,"Clausule %d of %d: %p\n",
// idx_r, utarray_len(info->clauselist),
// *x);
Yap_ClauseListExtend( Yap_ClauseListExtend(
&clauselist, &clauselist,
*x, *x,
@ -301,22 +351,13 @@ Yap_udi_search(PredEntry *p)
J1N(count, result, idx_r); J1N(count, result, idx_r);
} }
J1FA(count,result); J1FA(count,result);
// fprintf(stderr,"J1 used space %d bytes for %d clausules\n", fprintf(stderr,"J1 used space %d bytes for %d clausules\n",
// count, Yap_ClauseListCount(&clauselist)); count, Yap_ClauseListCount(&clauselist));
Yap_ClauseListClose(&clauselist); Yap_ClauseListClose(&clauselist);
}
if (Yap_ClauseListCount(&clauselist) == 0)
{
Yap_ClauseListDestroy(&clauselist);
// fprintf(stderr,"Search Not needed\n");
return NULL; /*FAIL CODE handled before*/
}
if (Yap_ClauseListCount(&clauselist) == 1) if (Yap_ClauseListCount(&clauselist) == 1)
{
// fprintf(stderr,"Returning 1 value\n");
return Yap_ClauseListToClause(&clauselist); return Yap_ClauseListToClause(&clauselist);
}
// fprintf(stderr,"Returning Multiple values (%d)\n", Yap_ClauseListCount(&clauselist));
return Yap_ClauseListCode(&clauselist); return Yap_ClauseListCode(&clauselist);
} }
@ -326,18 +367,3 @@ Yap_udi_abolish(PredEntry *p)
{ {
/* tell the predicate destroy */ /* tell the predicate destroy */
} }
/*
* Init Yap udi interface
*/
void
Yap_udi_init(void)
{
UdiControlBlocks = NULL;
/*init indexing structures array*/
utarray_new(indexing_structures, &udicb_icd);
Yap_InitCPred("$udi_init", 1, p_new_udi, 0);
/* TODO: decide if udi.yap should be loaded automaticaly in init.yap */
}

View File

@ -332,8 +332,9 @@ Term STD_PROTO(Yap_LUInstance,(LogUpdClause *, UInt));
/* udi.c */ /* udi.c */
void STD_PROTO(Yap_udi_init,(void)); void STD_PROTO(Yap_udi_init,(void));
yamop *STD_PROTO(Yap_udi_search,(PredEntry *));
int STD_PROTO(Yap_new_udi_clause,(PredEntry *, yamop *, Term)); int STD_PROTO(Yap_new_udi_clause,(PredEntry *, yamop *, Term));
yamop *STD_PROTO(Yap_udi_search,(PredEntry *));
void STD_PROTO(Yap_udi_abolish,(PredEntry *p));
#ifdef DEBUG #ifdef DEBUG
void STD_PROTO(Yap_bug_location,(yamop *)); void STD_PROTO(Yap_bug_location,(yamop *));

View File

@ -11,10 +11,7 @@ struct udi_p_args {
typedef struct udi_p_args *UdiPArg; typedef struct udi_p_args *UdiPArg;
UT_icd arg_icd = {sizeof(struct udi_p_args), NULL, NULL, NULL }; UT_icd arg_icd = {sizeof(struct udi_p_args), NULL, NULL, NULL };
/* a pointer utarray list /* clauselist */
* This is a hack, becouse I do no know the real type of clauses
* Not completely used for now
*/
UT_icd cl_icd = {sizeof(yamop *), NULL, NULL, NULL }; UT_icd cl_icd = {sizeof(yamop *), NULL, NULL, NULL };
/* /*
@ -26,7 +23,7 @@ struct udi_info
PredEntry *p; //predicate (need to identify asserts) PredEntry *p; //predicate (need to identify asserts)
UT_array *clauselist; //clause list used on returns UT_array *clauselist; //clause list used on returns
UT_array *args; //indexed args UT_array *args; //indexed args
UT_hash_handle hh; UT_hash_handle hh; //uthash handle
}; };
typedef struct udi_info *UdiInfo; typedef struct udi_info *UdiInfo;
@ -36,20 +33,28 @@ typedef struct udi_info *UdiInfo;
#define HASH_ADD_UdiInfo(head,p,add) \ #define HASH_ADD_UdiInfo(head,p,add) \
HASH_ADD_KEYPTR(hh,head,p,sizeof(PredEntry *),add) HASH_ADD_KEYPTR(hh,head,p,sizeof(PredEntry *),add)
int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); /* used during init */
static YAP_Int p_new_udi( USES_REGS1 );
static YAP_Int p_udi_args_init(Term spec, int arity, UdiInfo blk);
///* temporary */ /*
//struct CallbackM * Indexing Search and intersection Helpers
//{ */
// clause_list_t cl;
// void * pred;
//};
//typedef struct CallbackM * callback_m_t;
//
//static inline int callback(void *key, void *data, void *arg)
//{
// callback_m_t x;
// x = (callback_m_t) arg;
// return Yap_ClauseListExtend(x->cl,data,x->pred);
//}
/* single indexing helpers (no intersection needed just create clauselist) */
#include "clause_list.h"
struct si_callback_h
{
clause_list_t cl;
UT_array *clauselist;
void * pred;
};
typedef struct si_callback_h * si_callback_h_t;
static inline int si_callback(void *key, void *data, void *arg)
{
si_callback_h_t c = (si_callback_h_t) arg;
yamop **cl = (yamop **) utarray_eltptr(c->clauselist, ((YAP_Int) data) - 1);
return Yap_ClauseListExtend(c->cl, *cl, c->pred);
}
/* Judy1 integer sparse set intersection */

View File

@ -52,7 +52,7 @@ typedef int (* Yap_UdiCallback)
/* Called upon search /* Called upon search
* *
* If there is any search to do with this struture should return >= 0 * If there is any search to do with this structure should return >= 0
* corresponding to the values found * corresponding to the values found
* *
* returns -1 if there is nothing to search with this indexing structure * returns -1 if there is nothing to search with this indexing structure
@ -64,7 +64,7 @@ typedef int (* Yap_UdiSearch)
Yap_UdiCallback f, /* callback on each found value */ Yap_UdiCallback f, /* callback on each found value */
void *args); /* auxiliary data to callback */ void *args); /* auxiliary data to callback */
/* Called upond abolish of the term /* Called upon abolish of the term
* to allow for a clean destroy of the indexing structures * to allow for a clean destroy of the indexing structures
*/ */
typedef int (* Yap_UdiDestroy) typedef int (* Yap_UdiDestroy)