From 58962f259589d1b794d4a5a49105dc69813ae7f7 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Wed, 2 Jan 2013 11:20:54 +0000 Subject: [PATCH] UDI: some code refactor, simple code when no index intersection is needed --- C/udi.c | 338 ++++++++++++++++++++++++++---------------------- H/clause.h | 3 +- H/udi_private.h | 47 ++++--- include/udi.h | 6 +- 4 files changed, 213 insertions(+), 181 deletions(-) diff --git a/C/udi.c b/C/udi.c index ea2303d80..b91b59f3e 100644 --- a/C/udi.c +++ b/C/udi.c @@ -4,15 +4,14 @@ #include "Yap.h" #include "YapInterface.h" #include "clause.h" -#include "clause_list.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_array *indexing_structures; /* - * New user indexed predicate (used by the public udi interface) + * Register a new user indexer */ void Yap_UdiRegister(UdiControlBlock cb){ @@ -33,8 +32,6 @@ p_new_udi( USES_REGS1 ) UdiInfo blk; int info; - //fprintf(stderr,"new pred\n"); - /* get the predicate from the spec, copied from cdmgr.c */ if (IsVarTerm(spec)) { Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1"); @@ -79,59 +76,63 @@ p_new_udi( USES_REGS1 ) /* this is the real work */ blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); memset((void *) blk,0, sizeof(struct udi_info)); - if (!blk) { Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); 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); - if (!info) /*TODO: clear blk here*/ - return FALSE; + /*Init UdiInfo */ + 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; + } + + /*Push into the hash*/ + HASH_ADD_UdiInfo(UdiControlBlocks, p, blk); p->PredFlags |= UDIPredFlag; + return TRUE; } /* * Here we initialize the arguments indexing */ -int -Yap_udi_args_init(Term spec, int arity, UdiInfo blk) +YAP_Int +p_udi_args_init(Term spec, int arity, UdiInfo blk) { int i; Term arg; Atom idxtype; - UdiControlBlock *p; + UdiControlBlock *cb; struct udi_p_args p_arg; - //fprintf(stderr,"udi init\n"); - for (i = 1; i <= arity; i++) { arg = ArgOfTerm(i,spec); if (IsAtomTerm(arg)) { idxtype = AtomOfTerm(arg); -// fprintf(stderr,"%p-%s %p-%s\n",idxtype, YAP_AtomName(idxtype), -// AtomMinus, YAP_AtomName(AtomMinus)); - if (idxtype == AtomMinus) + if (idxtype == AtomMinus) //skip this argument continue; p_arg.control = NULL; - p = NULL; - while ((p = (UdiControlBlock *) utarray_next(indexing_structures, p))) { - //fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); - if (idxtype == (*p)->decl){ + cb = NULL; + while ((cb = (UdiControlBlock *) utarray_next(indexing_structures, cb))) { + if (idxtype == (*cb)->decl){ p_arg.arg = i; - p_arg.control = *p; - p_arg.idxstr = (*p)->init(spec, i, arity); + p_arg.control = *cb; + p_arg.idxstr = (*cb)->init(spec, i, arity); 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)); return FALSE; } @@ -140,36 +141,54 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) 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 Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) { int i; UdiPArg parg; UdiInfo info; - int index; -// yamop **x; + YAP_Int index; - /* try to find our structure*/ + /* try to find our structure */ HASH_FIND_UdiInfo(UdiControlBlocks,p,info); if (!info) return FALSE; - /*insert into clauselist will be used latter*/ + /* insert into clauselist */ utarray_push_back(info->clauselist, &cl); for (i = 0; i < utarray_len(info->args) ; i++) { parg = (UdiPArg) utarray_eltptr(info->args,i); - index = 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))); + index = (YAP_Int) utarray_len(info->clauselist); parg->idxstr = parg->control->insert(parg->idxstr, t, parg->arg, (void *) index); - //info->cb = info->functions->insert(t, info->cb, (void *)cl); } return TRUE; } @@ -187,136 +206,158 @@ static inline int callback(void *key, void *data, void *arg) 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 * Yap_udi_search(PredEntry *p) { - int i, r; + int r; struct ClauseList clauselist; -// struct CallbackM cm; -// callback_m_t c; UdiPArg parg; UdiInfo info; - Pvoid_t tmp, result; - Word_t count; - Word_t idx_r = 0L; - yamop **x; /* find our structure*/ HASH_FIND_UdiInfo(UdiControlBlocks,p,info); - if (!info) + if (!info || utarray_len(info->args) == 0) return NULL; -// /*TODO: handle intersection*/ -// c = &cm; -// c->cl = Yap_ClauseListInit(&clauselist); -// c->pred = p; + if (utarray_len(info->args) == 1){ //simple case no intersection needed + struct si_callback_h c; - /* - * I will start with the simplest case - * for each index create a set and intersect it with the - * next - */ - result = (Pvoid_t) NULL; - tmp = (Pvoid_t) NULL; - r = -1; - for (i = 0; i < utarray_len(info->args) ; i++) { -// fprintf(stderr,"Start Search\n"); - parg = (UdiPArg) utarray_eltptr(info->args,i); - r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); + c.cl = Yap_ClauseListInit(&clauselist); + c.clauselist = info->clauselist; + c.pred = info->p; + if (!c.cl) + return NULL; - if (r == -1) /*this arg does not prune search*/ - continue; + parg = (UdiPArg) utarray_eltptr(info->args,0); + r = parg->control->search(parg->idxstr, parg->arg, si_callback, (void *) &c); + Yap_ClauseListClose(c.cl); - J1C(count, result, 0, -1); + if (r == -1) { + Yap_ClauseListDestroy(c.cl); + return NULL; + } - if (r == 0) - { - if (count > 0) // clear previous result if it exists - J1FA(count, result); - fprintf(stderr,"Search Failed"); + 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; - if (r > 0 && count == 0) // first result_set - { - result = tmp; - tmp = (Pvoid_t) NULL; - } - else - {/*intersection*/ - Word_t idx_tmp = 0L; - - idx_r = 0L; - J1F(count, result, idx_r);//succeeds one time at least - J1F(count, tmp, idx_tmp); //succeeds one time at least - while (count) + /* + * I will start with the simplest approach + * for each index create a set and intersect it with the + * next + * + * In the future it could pay to sort according to index type + * to improve intersection part + */ + for (i = 0; i < utarray_len(info->args) ; i++) { + parg = (UdiPArg) utarray_eltptr(info->args,i); + r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); + if (r == -1) /*this arg does not prune search*/ + continue; + rc ++; + J1C(count, result, 0, -1); + if (r == 0) /* this arg gave 0 results -> FAIL*/ { - while (idx_r < idx_tmp) + if (count > 0) // clear previous result if they exists + J1FA(count, result); + return Yap_FAILCODE(); + } + + if (count == 0) // first result_set + { + result = tmp; + tmp = (Pvoid_t) NULL; + } + else /*intersection*/ + { + idx_tmp = 0L; + idx_r = 0L; + J1F(count, result, idx_r); //succeeds one time at least + assert(count > 0); + J1F(count, tmp, idx_tmp); //succeeds one time at least + assert(count > 0); + while (count) + { + while (idx_r < idx_tmp) + { + J1U(count, result, idx_r); //does not belong + J1N(count, result, idx_r); //next + if (! count) break; //end result set + } + if(idx_r == idx_tmp) + { + J1N(count, result, idx_r); //next + if (! count) break; //end result set + J1N(count, tmp, idx_tmp); //next tmp + //if (! count) break; //end tmp set will break while + } + else // (idx_r > idx_tmp) + { + idx_tmp = idx_r; // fast forward + J1F(count, tmp, idx_tmp); // first starting in idx_r + //if (! count) break; //end tmp set will break while + } + } + J1F(count, result, idx_r); // first starting in idx_r + //clear up the rest + while (idx_r > idx_tmp && count) //result has more setted values { J1U(count, result, idx_r); //does not belong J1N(count, result, idx_r); //next - if (! count) break; //end result set - } - if(idx_r == idx_tmp) - { - J1N(count, result, idx_r); //next - if (! count) break; //end result set - J1N(count, tmp, idx_tmp); //next tmp - //if (! count) break; //end tmp set - } - else // (idx_r > idx_tmp) - { - idx_tmp = idx_r; // fast forward - J1F(count, tmp, idx_tmp); // first starting in idx_r - if (! count) break; //end tmp set } + J1FA(count, tmp); //free tmp } - J1F(count, result, idx_r); // first starting in idx_r - //clear up the rest - while (idx_r > idx_tmp && count) //result has more setted values - { - J1U(count, result, idx_r); //does not belong - J1N(count, result, idx_r); //next - } - J1FA(count, 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); + idx_r = 0L; + J1F(count, result, idx_r); + while (count) + { + x = (yamop **) utarray_eltptr(info->clauselist, idx_r - 1); + Yap_ClauseListExtend( + &clauselist, + *x, + info->p); + J1N(count, result, idx_r); + } + J1FA(count,result); + fprintf(stderr,"J1 used space %d bytes for %d clausules\n", + count, Yap_ClauseListCount(&clauselist)); + Yap_ClauseListClose(&clauselist); } - - Yap_ClauseListInit(&clauselist); - idx_r = 0L; - J1F(count, result, idx_r); - while (count) - { - 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( - &clauselist, - *x, - info->p); - J1N(count, result, idx_r); - } - J1FA(count,result); -// fprintf(stderr,"J1 used space %d bytes for %d clausules\n", -// count, Yap_ClauseListCount(&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) - { -// fprintf(stderr,"Returning 1 value\n"); return Yap_ClauseListToClause(&clauselist); - } -// fprintf(stderr,"Returning Multiple values (%d)\n", Yap_ClauseListCount(&clauselist)); return Yap_ClauseListCode(&clauselist); } @@ -326,18 +367,3 @@ Yap_udi_abolish(PredEntry *p) { /* 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 */ -} diff --git a/H/clause.h b/H/clause.h index 49e6da61d..d80e14002 100644 --- a/H/clause.h +++ b/H/clause.h @@ -332,8 +332,9 @@ Term STD_PROTO(Yap_LUInstance,(LogUpdClause *, UInt)); /* udi.c */ void STD_PROTO(Yap_udi_init,(void)); -yamop *STD_PROTO(Yap_udi_search,(PredEntry *)); 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 void STD_PROTO(Yap_bug_location,(yamop *)); diff --git a/H/udi_private.h b/H/udi_private.h index e77455ae5..9e0bf8597 100644 --- a/H/udi_private.h +++ b/H/udi_private.h @@ -11,10 +11,7 @@ struct udi_p_args { typedef struct udi_p_args *UdiPArg; UT_icd arg_icd = {sizeof(struct udi_p_args), NULL, NULL, NULL }; -/* a pointer utarray list - * This is a hack, becouse I do no know the real type of clauses - * Not completely used for now - */ +/* clauselist */ UT_icd cl_icd = {sizeof(yamop *), NULL, NULL, NULL }; /* @@ -26,30 +23,38 @@ struct udi_info PredEntry *p; //predicate (need to identify asserts) UT_array *clauselist; //clause list used on returns UT_array *args; //indexed args - UT_hash_handle hh; + UT_hash_handle hh; //uthash handle }; typedef struct udi_info *UdiInfo; /* to ease code for a UdiInfo hash table*/ -#define HASH_FIND_UdiInfo(head,find,out) \ +#define HASH_FIND_UdiInfo(head,find,out) \ HASH_FIND(hh,head,find,sizeof(PredEntry *),out) #define HASH_ADD_UdiInfo(head,p,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 -//{ -// 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); -//} +/* + * Indexing Search and intersection Helpers + */ +/* 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 */ diff --git a/include/udi.h b/include/udi.h index d7df3d96f..a7b428ec9 100644 --- a/include/udi.h +++ b/include/udi.h @@ -52,7 +52,7 @@ typedef int (* Yap_UdiCallback) /* 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 * * returns -1 if there is nothing to search with this indexing structure @@ -62,9 +62,9 @@ typedef int (* Yap_UdiSearch) (void * control, /* indexing structure opaque handle */ int arg, /* argument regarding this call */ 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 */ typedef int (* Yap_UdiDestroy)