New work on UDI

This commit is contained in:
David Vaz 2012-12-17 20:23:03 +00:00
parent 45b6263f85
commit bd25c61fbf
13 changed files with 409 additions and 936 deletions

3
.gitmodules vendored
View File

@ -43,3 +43,6 @@
[submodule "packages/odbc"]
path = packages/odbc
url = git://yap.git.sourceforge.net/gitroot/yap/odbc
[submodule "packages/udi"]
path = packages/udi
url = https://github.com/davidvaz/yap-udi-indexers.git

266
C/udi.c
View File

@ -1,169 +1,229 @@
#include <stdio.h>
#include "Yap.h"
#include "YapInterface.h"
#include "clause.h"
#include "udi.h"
#include "utarray.h"
/* to keep a vector of udi indexers */
UT_icd udicb_icd = {sizeof(UdiControlBlock), NULL, NULL, NULL};
UT_array *indexing_structures;
#include "rtree_udi.h"
/*
* New user indexed predicate:
* first argument is the decl term.
* second argument is the init call with the structure
*/
void
Yap_UdiRegister(UdiControlBlock cb){
/*TODO: check structure integrity and duplicates */
utarray_push_back(indexing_structures, &cb);
}
/* we can have this stactic because it is written once */
static struct udi_control_block RtreeCmd;
struct udi_p_args {
void *idxstr; //user indexing structure
UdiControlBlock control; //user indexing structure functions
};
/* a pointer utarray list
* This is a hack, becouse I do no know the real type of clauses*/
UT_icd ptr_icd = {sizeof(void *), NULL, NULL, NULL };
#define UDI_MI 10
/******
All the info we need to enter user indexed code:
predicate
the user control block
functions used, in case we have different schema (maybe should part of previous)
All the info we need to enter user indexed code:
right now, this is just a linked list....
******/
typedef struct udi_info
{
PredEntry *p;
void *cb;
UdiControlBlock functions;
PredEntry *p; //predicate (need to identify asserts)
UT_array *clauselist; //clause list used on returns
struct udi_p_args args[UDI_MI]; //indexed args only the first UDI_MI
struct udi_info *next;
} *UdiInfo;
int Yap_udi_args_init(Term spec, int arity, UdiInfo blk);
/******
we now have one extra user indexed predicate. We assume these
are few, so we can do with a linked list.
******/
static int
add_udi_block(void *info, PredEntry *p, UdiControlBlock cmd)
{
UdiInfo blk = (UdiInfo)Yap_AllocCodeSpace(sizeof(struct udi_info));
if (!blk)
return FALSE;
blk->next = UdiControlBlocks;
UdiControlBlocks = blk;
blk->p = p;
blk->functions = cmd;
blk->cb = info;
return TRUE;
}
//static int
//add_udi_block(PredEntry *p, void *info, UdiControlBlock cmd)
//{
// UdiInfo blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info));
// if (!blk)
// return FALSE;
// blk->next = UdiControlBlocks;
// UdiControlBlocks = blk;
// blk->p = p;
// blk->functions = cmd;
// blk->cb = info;
// return TRUE;
//}
/******
new user indexed predicate;
the type right now is just rtrees, but in the future we'll have more.
the second argument is the term.
******/
/*
* New user indexed predicate:
* the first argument is the term.
*/
static Int
p_new_udi( USES_REGS1 )
{
Term spec = Deref(ARG2), udi_type = Deref(ARG1);
PredEntry *p;
UdiControlBlock cmd;
Atom udi_t;
void *info;
Term spec = Deref(ARG1);
PredEntry *p;
// UdiControlBlock cmd;
// Atom udi_t;
UdiInfo blk;
int info;
fprintf(stderr,"new pred\n");
/* fprintf(stderr,"new pred babe\n");*/
/* get the predicate from the spec, copied from cdmgr.c */
if (IsVarTerm(spec)) {
Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1");
return FALSE;
Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1");
return FALSE;
} else if (!IsApplTerm(spec)) {
Yap_Error(TYPE_ERROR_COMPOUND,spec,"new user index/1");
return FALSE;
Yap_Error(TYPE_ERROR_COMPOUND,spec,"new user index/1");
return FALSE;
} else {
Functor fun = FunctorOfTerm(spec);
Term tmod = CurrentModule;
Functor fun = FunctorOfTerm(spec);
Term tmod = CurrentModule;
while (fun == FunctorModule) {
tmod = ArgOfTerm(1,spec);
if (IsVarTerm(tmod) ) {
Yap_Error(INSTANTIATION_ERROR, spec, "new user index/1");
return FALSE;
}
if (!IsAtomTerm(tmod) ) {
Yap_Error(TYPE_ERROR_ATOM, spec, "new user index/1");
return FALSE;
}
spec = ArgOfTerm(2, spec);
fun = FunctorOfTerm(spec);
}
p = RepPredProp(PredPropByFunc(fun, tmod));
while (fun == FunctorModule) {
tmod = ArgOfTerm(1,spec);
if (IsVarTerm(tmod) ) {
Yap_Error(INSTANTIATION_ERROR, spec, "new user index/1");
return FALSE;
}
if (!IsAtomTerm(tmod) ) {
Yap_Error(TYPE_ERROR_ATOM, spec, "new user index/1");
return FALSE;
}
spec = ArgOfTerm(2, spec);
fun = FunctorOfTerm(spec);
}
p = RepPredProp(PredPropByFunc(fun, tmod));
}
if (!p)
return FALSE;
return FALSE;
/* boring, boring, boring! */
if ((p->PredFlags & (DynamicPredFlag|LogUpdatePredFlag|UserCPredFlag|CArgsPredFlag|NumberDBPredFlag|AtomDBPredFlag|TestPredFlag|AsmPredFlag|CPredFlag|BinaryPredFlag)) ||
(p->ModuleOfPred == PROLOG_MODULE)) {
Yap_Error(PERMISSION_ERROR_MODIFY_STATIC_PROCEDURE, spec, "udi/2");
return FALSE;
if ((p->PredFlags
& (DynamicPredFlag|LogUpdatePredFlag|UserCPredFlag|CArgsPredFlag|NumberDBPredFlag|AtomDBPredFlag|TestPredFlag|AsmPredFlag|CPredFlag|BinaryPredFlag))
|| (p->ModuleOfPred == PROLOG_MODULE)) {
Yap_Error(PERMISSION_ERROR_MODIFY_STATIC_PROCEDURE, spec, "udi/2");
return FALSE;
}
if (p->PredFlags & (DynamicPredFlag|LogUpdatePredFlag|TabledPredFlag)) {
Yap_Error(PERMISSION_ERROR_ACCESS_PRIVATE_PROCEDURE, spec, "udi/2");
return FALSE;
}
/* just make sure we're looking at the right user type! */
if (IsVarTerm(udi_type)) {
Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1");
return FALSE;
} else if (!IsAtomTerm(udi_type)) {
Yap_Error(TYPE_ERROR_ATOM,spec,"new user index/1");
return FALSE;
}
udi_t = AtomOfTerm(udi_type);
if (udi_t == AtomRTree) {
cmd = &RtreeCmd;
} else {
Yap_Error(TYPE_ERROR_ATOM,spec,"new user index/1");
return FALSE;
Yap_Error(PERMISSION_ERROR_ACCESS_PRIVATE_PROCEDURE, spec, "udi/2");
return FALSE;
}
/* TODO: remove AtomRTree from atom list */
/* this is the real work */
info = cmd->init(spec, (void *)p, p->ArityOfPE);
blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info));
if (!blk) {
Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1");
return FALSE;
}
blk->next = UdiControlBlocks;
blk->clauselist = NULL;
blk->p = p;
info = Yap_udi_args_init(spec, p->ArityOfPE, blk);
if (!info)
return FALSE;
/* add to table */
if (!add_udi_block(info, p, cmd)) {
Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1");
return FALSE;
}
p->PredFlags |= UDIPredFlag;
return TRUE;
}
/*
* Here we initialize the arguments indexing
*/
int
Yap_udi_args_init(Term spec, int arity, UdiInfo blk)
{
int i;
Term arg;
Atom idxtype;
UdiControlBlock *p;
fprintf(stderr,"udi init\n");
for (i = 1; i <= arity && i <= UDI_MI ; i++) {
blk->args[i-1].idxstr = NULL;
blk->args[i-1].control = NULL;
fprintf(stderr,"%d\n",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)
continue;
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){
blk->args[i-1].idxstr = NULL;
blk->args[i-1].control = *p;
}
}
if (blk->args[i-1].control == NULL){ /* not "-" and not found*/
fprintf(stderr, "Invalid Spec (%s)\n", AtomName(idxtype));
return FALSE;
}
}
}
return TRUE;
}
/* just pass info to user, called from cdmgr.c */
int
Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t)
{
struct udi_info *info = UdiControlBlocks;
while (info->p != p && info)
info = info->next;
if (!info)
return FALSE;
info->cb = info->functions->insert(t, info->cb, (void *)cl);
return TRUE;
/* find our structure*/
struct udi_info *info = UdiControlBlocks;
while (info->p != p && info)
info = info->next;
if (!info)
return FALSE;
/* do the actual insertion */
fprintf(stderr,"udi insert\n");
// info->cb = info->functions->insert(t, info->cb, (void *)cl);
return TRUE;
}
/* index, called from absmi.c */
yamop *
Yap_udi_search(PredEntry *p)
{
struct udi_info *info = UdiControlBlocks;
while (info->p != p && info)
info = info->next;
if (!info)
return NULL;
return info->functions->search(info->cb);
struct udi_info *info = UdiControlBlocks;
while (info->p != p && info)
info = info->next;
if (!info)
return NULL;
return NULL; /*info->functions->search(info->cb);*/
}
/* index, called from absmi.c */
void
Yap_udi_abolish(PredEntry *p)
{
/* tell the predicate destroy */
/* tell the predicate destroy */
}
void
Yap_udi_init(void)
{
UdiControlBlocks = NULL;
/* to be filled in by David */
RtreeCmd.init = RtreeUdiInit;
RtreeCmd.insert = RtreeUdiInsert;
RtreeCmd.search = RtreeUdiSearch;
RtreeCmd.destroy = RtreeUdiDestroy;
Yap_InitCPred("$udi_init", 2, p_new_udi, 0);
/*init indexing structures array*/
utarray_new(indexing_structures, &udicb_icd);
Yap_InitCPred("$udi_init", 1, p_new_udi, 0);
/* TODO: decide if yap.udi should be loaded automaticaly in init.yap */
}

233
H/utarray.h Normal file
View File

@ -0,0 +1,233 @@
/*
Copyright (c) 2008-2013, Troy D. Hanson http://uthash.sourceforge.net
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* a dynamic array implementation using macros
* see http://uthash.sourceforge.net/utarray
*/
#ifndef UTARRAY_H
#define UTARRAY_H
#define UTARRAY_VERSION 1.9.7
#ifdef __GNUC__
#define _UNUSED_ __attribute__ ((__unused__))
#else
#define _UNUSED_
#endif
#include <stddef.h> /* size_t */
#include <string.h> /* memset, etc */
#include <stdlib.h> /* exit */
#define oom() exit(-1)
typedef void (ctor_f)(void *dst, const void *src);
typedef void (dtor_f)(void *elt);
typedef void (init_f)(void *elt);
typedef struct {
size_t sz;
init_f *init;
ctor_f *copy;
dtor_f *dtor;
} UT_icd;
typedef struct {
unsigned i,n;/* i: index of next available slot, n: num slots */
UT_icd icd; /* initializer, copy and destructor functions */
char *d; /* n slots of size icd->sz*/
} UT_array;
#define utarray_init(a,_icd) do { \
memset(a,0,sizeof(UT_array)); \
(a)->icd=*_icd; \
} while(0)
#define utarray_done(a) do { \
if ((a)->n) { \
if ((a)->icd.dtor) { \
size_t _ut_i; \
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
} \
} \
free((a)->d); \
} \
(a)->n=0; \
} while(0)
#define utarray_new(a,_icd) do { \
a=(UT_array*)malloc(sizeof(UT_array)); \
utarray_init(a,_icd); \
} while(0)
#define utarray_free(a) do { \
utarray_done(a); \
free(a); \
} while(0)
#define utarray_reserve(a,by) do { \
if (((a)->i+by) > ((a)->n)) { \
while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \
} \
} while(0)
#define utarray_push_back(a,p) do { \
utarray_reserve(a,1); \
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
} while(0)
#define utarray_pop_back(a) do { \
if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
else { (a)->i--; } \
} while(0)
#define utarray_extend_back(a) do { \
utarray_reserve(a,1); \
if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
(a)->i++; \
} while(0)
#define utarray_len(a) ((a)->i)
#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) )))
#define utarray_insert(a,p,j) do { \
utarray_reserve(a,1); \
if (j > (a)->i) break; \
if ((j) < (a)->i) { \
memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
((a)->i - (j))*((a)->icd.sz)); \
} \
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
(a)->i++; \
} while(0)
#define utarray_inserta(a,w,j) do { \
if (utarray_len(w) == 0) break; \
if (j > (a)->i) break; \
utarray_reserve(a,utarray_len(w)); \
if ((j) < (a)->i) { \
memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
_utarray_eltptr(a,j), \
((a)->i - (j))*((a)->icd.sz)); \
} \
if ((a)->icd.copy) { \
size_t _ut_i; \
for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
(a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \
} \
} else { \
memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
utarray_len(w)*((a)->icd.sz)); \
} \
(a)->i += utarray_len(w); \
} while(0)
#define utarray_resize(dst,num) do { \
size_t _ut_i; \
if (dst->i > (size_t)(num)) { \
if ((dst)->icd.dtor) { \
for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \
(dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \
} \
} \
} else if (dst->i < (size_t)(num)) { \
utarray_reserve(dst,num-dst->i); \
if ((dst)->icd.init) { \
for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \
(dst)->icd.init(utarray_eltptr(dst,_ut_i)); \
} \
} else { \
memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \
} \
} \
dst->i = num; \
} while(0)
#define utarray_concat(dst,src) do { \
utarray_inserta((dst),(src),utarray_len(dst)); \
} while(0)
#define utarray_erase(a,pos,len) do { \
if ((a)->icd.dtor) { \
size_t _ut_i; \
for(_ut_i=0; _ut_i < len; _ut_i++) { \
(a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \
} \
} \
if ((a)->i > (pos+len)) { \
memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \
(((a)->i)-(pos+len))*((a)->icd.sz)); \
} \
(a)->i -= (len); \
} while(0)
#define utarray_renew(a,u) do { \
if (a) utarray_clear(a); \
else utarray_new((a),(u)); \
} while(0)
#define utarray_clear(a) do { \
if ((a)->i > 0) { \
if ((a)->icd.dtor) { \
size_t _ut_i; \
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
} \
} \
(a)->i = 0; \
} \
} while(0)
#define utarray_sort(a,cmp) do { \
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
} while(0)
#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd.sz) : -1)
/* last we pre-define a few icd for common utarrays of ints and strings */
static void utarray_str_cpy(void *dst, const void *src) {
char **_src = (char**)src, **_dst = (char**)dst;
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
}
static void utarray_str_dtor(void *elt) {
char **eltc = (char**)elt;
if (*eltc) free(*eltc);
}
static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL};
#endif /* UTARRAY_H */

View File

@ -111,7 +111,6 @@ INTERFACE_HEADERS = \
$(srcdir)/include/clause_list.h \
$(srcdir)/include/dswiatoms.h \
$(srcdir)/include/udi.h \
$(srcdir)/include/rtree_udi.h \
$(srcdir)/include/yap_structs.h \
$(srcdir)/include/YapInterface.h \
$(srcdir)/include/SWI-Prolog.h \
@ -262,8 +261,6 @@ C_SOURCES= \
$(srcdir)/C/threads.c \
$(srcdir)/C/tracer.c $(srcdir)/C/unify.c $(srcdir)/C/userpreds.c \
$(srcdir)/C/udi.c \
$(srcdir)/packages/udi/rtree.c \
$(srcdir)/packages/udi/rtree_udi.c \
$(srcdir)/C/utilpreds.c $(srcdir)/C/write.c $(srcdir)/console/yap.c \
$(srcdir)/C/yap-args.c \
$(srcdir)/C/ypstdio.c \
@ -370,7 +367,7 @@ ENGINE_OBJECTS = \
parser.o qlyr.o qlyw.o range.o \
save.o scanner.o sort.o stdpreds.o \
sysbits.o threads.o tracer.o \
udi.o rtree.o rtree_udi.o\
udi.o\
unify.o userpreds.o utilpreds.o \
yap-args.o write.o \
blobs.o swi.o ypstdio.o $(IOLIB_OBJECTS) @MPI_OBJS@
@ -474,12 +471,6 @@ sysbits.o: $(srcdir)/C/sysbits.c config.h
udi.o: $(srcdir)/C/udi.c config.h
$(CC) -c $(C_INTERF_FLAGS) $(srcdir)/C/udi.c -o $@
rtree.o: $(srcdir)/packages/udi/rtree.c config.h
$(CC) -c $(C_INTERF_FLAGS) $(srcdir)/packages/udi/rtree.c -o $@
rtree_udi.o: $(srcdir)/packages/udi/rtree_udi.c config.h
$(CC) -c $(C_INTERF_FLAGS) $(srcdir)/packages/udi/rtree_udi.c -o $@
yap.o: $(srcdir)/console/yap.c config.h
$(CC) -c $(CFLAGS) -I$(srcdir)/include $(srcdir)/console/yap.c -o $@

View File

@ -1,24 +0,0 @@
#ifndef _RTREE_UDI_
#define _RTREE_UDI_
#ifndef _RTREE_
typedef void control_t;
#endif
/*Prolog term from :- udi(a(-,+,+)).
User defined index announce
*/
extern control_t *RtreeUdiInit (Term spec,
void *pred,
int arity);
/*this is called in each asserted term that was declared to udi_init*/
extern control_t *RtreeUdiInsert (Term term, /*asserted term*/
control_t *control,
void *clausule); /*to store in tree and return
in search*/
extern void *RtreeUdiSearch (control_t *control);
extern int RtreeUdiDestroy(control_t *control);
#endif /* _RTREE_UDI_ */

View File

@ -1,4 +1,3 @@
/*chamada a cada index/2
controi estrutura de control, para definir a indexação, contem a
rtree p.e.
@ -6,13 +5,13 @@
*/
typedef void *
(* Yap_UdiInit)(
Term spec, /* mode spec */
YAP_Term spec, /* mode spec */
void *pred, /* pass predicate information */
int arity);
/*chamada a cada assert*/
typedef void *
(* Yap_UdiInsert)(Term t, /* termo asserted */
(* Yap_UdiInsert)(YAP_Term t, /* termo asserted */
void *control, /* estrutura de control*/
void *clausule); /* valor a guardar na arvore, para retornar na pesquisa */
@ -37,9 +36,12 @@ typedef int
(* Yap_UdiDestroy)(void * control);
typedef struct udi_control_block {
YAP_Atom decl; //atom that triggers this indexing structure
Yap_UdiInit init;
Yap_UdiInsert insert;
Yap_UdiSearch search;
Yap_UdiDestroy destroy;
} *UdiControlBlock;
/* used to register the new indexing structure */
void Yap_UdiRegister(UdiControlBlock);

1
packages/udi Submodule

@ -0,0 +1 @@
Subproject commit 10522b20e6b061d9f68a8e08e800ff0eb9814755

View File

@ -1,7 +0,0 @@
This directory contains support for user defined indexers, currently:
- RTrees
For Examples and Tests proceed as follows:
git clone git://yap.dcc.fc.up.pt/udi-examples

View File

@ -1,524 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <float.h>
#include "rtree.h"
static node_t RTreeNewNode (void);
static void RTreeDestroyNode (node_t);
static void RTreeNodeInit (node_t);
static int RTreeSearchNode (node_t, rect_t, SearchHitCallback, void *);
static int RTreeInsertNode (node_t, int, rect_t,void *,node_t *);
static int RTreePickBranch (rect_t, node_t);
static int RTreeAddBranch(node_t, branch_t, node_t *);
static void RTreeSplitNode (node_t, branch_t, node_t *);
static void RTreePickSeeds(partition_t *, node_t, node_t);
static void RTreeNodeAddBranch(rect_t *, node_t, branch_t);
static void RTreePickNext(partition_t *, node_t, node_t);
static rect_t RTreeNodeCover(node_t);
static double RectArea (rect_t);
static rect_t RectCombine (rect_t, rect_t);
static int RectOverlap (rect_t, rect_t);
static void RectPrint (rect_t);
static partition_t PartitionNew (void);
static void PartitionPush (partition_t *, branch_t);
static branch_t PartitionPop (partition_t *);
static branch_t PartitionGet (partition_t *, int);
rtree_t RTreeNew (void)
{
rtree_t t;
t = RTreeNewNode();
t->level = 0; /*leaf*/
return t;
}
void RTreeDestroy (rtree_t t)
{
if (t)
RTreeDestroyNode (t);
}
static node_t RTreeNewNode (void)
{
node_t n;
n = (node_t) malloc (sizeof(*n));
assert(n);
RTreeNodeInit(n);
return n;
}
static void RTreeDestroyNode (node_t node)
{
int i;
if (node->level == 0) /* leaf level*/
{
for (i = 0; i < MAXCARD; i++)
if (node->branch[i].child)
;/* allow user free data*/
else
break;
}
else
{
for (i = 0; i < MAXCARD; i++)
if (node->branch[i].child)
RTreeDestroyNode (node->branch[i].child);
else
break;
}
free (node);
}
static void RTreeNodeInit (node_t n)
{
memset((void *) n,0, sizeof(*n));
n->level = -1;
}
int RTreeSearch (rtree_t t, rect_t s, SearchHitCallback f, void *arg)
{
assert(t);
return RTreeSearchNode(t,s,f,arg);
}
static int RTreeSearchNode (node_t n, rect_t s, SearchHitCallback f, void *arg)
{
int i;
int c = 0;
if (n->level > 0)
{
for (i = 0; i < MAXCARD; i++)
if (n->branch[i].child &&
RectOverlap (s,n->branch[i].mbr))
c += RTreeSearchNode ((node_t) n->branch[i].child, s, f, arg);
}
else
{
for (i = 0; i < MAXCARD; i++)
if (n->branch[i].child &&
RectOverlap (s,n->branch[i].mbr))
{
c ++;
if (f)
if ( !f(n->branch[i].mbr,n->branch[i].child,arg))
return c;
}
}
return c;
}
void RTreeInsert (rtree_t *t, rect_t r, void *data)
{
node_t n2;
node_t new_root;
branch_t b;
assert(t && *t);
if (RTreeInsertNode(*t, 0, r, data, &n2))
/* deal with root split */
{
new_root = RTreeNewNode();
new_root->level = (*t)->level + 1;
b.mbr = RTreeNodeCover(*t);
b.child = (void *) *t;
RTreeAddBranch(new_root, b, NULL);
b.mbr = RTreeNodeCover(n2);
b.child = (void *) n2;
RTreeAddBranch(new_root, b, NULL);
*t = new_root;
}
}
static int RTreeInsertNode (node_t n, int level,
rect_t r, void *data,
node_t *new_node)
{
int i;
node_t n2;
branch_t b;
assert(n && new_node);
assert(level >= 0 && level <= n->level);
if (n->level > level)
{
i = RTreePickBranch(r,n);
if (!RTreeInsertNode((node_t) n->branch[i].child, level,
r, data,&n2)) /* not split */
{
n->branch[i].mbr = RectCombine(r,n->branch[i].mbr);
return FALSE;
}
else /* node split */
{
n->branch[i].mbr = RTreeNodeCover(n->branch[i].child);
b.child = n2;
b.mbr = RTreeNodeCover(n2);
return RTreeAddBranch(n, b, new_node);
}
}
else /*insert level*/
{
b.mbr = r;
b.child = data;
return RTreeAddBranch(n, b, new_node);
}
}
static int RTreeAddBranch(node_t n, branch_t b, node_t *new_node)
{
int i;
assert(n);
if (n->count < MAXCARD) /*split not necessary*/
{
for (i = 0; i < MAXCARD; i++)
if (n->branch[i].child == NULL)
{
n->branch[i] = b;
n->count ++;
break;
}
return FALSE;
}
else /*needs to split*/
{
assert(new_node);
RTreeSplitNode (n, b, new_node);
return TRUE;
}
}
static int RTreePickBranch (rect_t r, node_t n)
{
int i;
double area;
double inc_area;
rect_t tmp;
int best_i;
double best_inc;
double best_i_area;
best_i = 0;
best_inc = DBL_MAX; /* double Max value */
best_i_area = DBL_MAX;
for (i = 0; i < MAXCARD; i++)
if (n->branch[i].child)
{
area = RectArea (n->branch[i].mbr);
tmp = RectCombine (r, n->branch[i].mbr);
inc_area = RectArea (tmp) - area;
if (inc_area < best_inc)
{
best_inc = inc_area;
best_i = i;
best_i_area = area;
}
else if (inc_area == best_inc && best_i_area > area)
{
best_inc = inc_area;
best_i = i;
best_i_area = area;
}
}
else
break;
return best_i;
}
static void RTreeSplitNode (node_t n, branch_t b, node_t *new_node)
{
partition_t p;
int level;
int i;
assert(n);
assert(new_node);
p = PartitionNew();
for (i = 0; i < MAXCARD; i ++)
PartitionPush(&p,n->branch[i]);
PartitionPush(&p,b);
level = n->level;
RTreeNodeInit(n);
n->level = level;
*new_node = RTreeNewNode();
(*new_node)->level = level;
RTreePickSeeds(&p, n, *new_node);
while (p.n)
if (n->count + p.n <= MINCARD)
/* first group (n) needs all entries */
RTreeNodeAddBranch(&(p.cover[0]), n, PartitionPop(&p));
else if ((*new_node)->count + p.n <= MINCARD)
/* second group (new_node) needs all entries */
RTreeNodeAddBranch(&(p.cover[1]), *new_node, PartitionPop(&p));
else
RTreePickNext(&p, n, *new_node);
}
static void RTreePickNext(partition_t *p, node_t n1, node_t n2)
/* linear version */
{
branch_t b;
double area[2], inc_area[2];
rect_t tmp;
b = PartitionPop(p);
area[0] = RectArea (p->cover[0]);
tmp = RectCombine (p->cover[0], b.mbr);
inc_area[0] = RectArea (tmp) - area[0];
area[1] = RectArea (p->cover[1]);
tmp = RectCombine (p->cover[1], b.mbr);
inc_area[1] = RectArea (tmp) - area[1];
if (inc_area[0] < inc_area[1] ||
(inc_area[0] == inc_area[1] && area[0] < area[1]))
RTreeNodeAddBranch(&(p->cover[0]),n1,b);
else
RTreeNodeAddBranch(&(p->cover[1]),n2,b);
}
static void RTreePickSeeds(partition_t *p, node_t n1, node_t n2)
/* puts in index 0 of each node the resulting entry, forming the two
groups
This is the linear version
*/
{
int dim,high, i;
int highestLow[NUMDIMS], lowestHigh[NUMDIMS];
double width[NUMDIMS];
int seed0, seed1;
double sep, best_sep;
assert(p->n == MAXCARD + 1);
for (dim = 0; dim < NUMDIMS; dim++)
{
high = dim + NUMDIMS;
highestLow[dim] = lowestHigh[dim] = 0;
for (i = 1; i < MAXCARD +1; i++)
{
if (p->buffer[i].mbr.coords[dim] >
p->buffer[highestLow[dim]].mbr.coords[dim])
highestLow[dim] = i;
if (p->buffer[i].mbr.coords[high] <
p->buffer[lowestHigh[dim]].mbr.coords[high])
lowestHigh[dim] = i;
}
width[dim] = p->cover_all.coords[high] - p->cover_all.coords[dim];
assert(width[dim] >= 0);
}
seed0 = lowestHigh[0];
seed1 = highestLow[0];
best_sep = 0;
for (dim = 0; dim < NUMDIMS; dim ++)
{
high = dim + NUMDIMS;
sep = (p->buffer[highestLow[dim]].mbr.coords[dim] -
p->buffer[lowestHigh[dim]].mbr.coords[high]) / width[dim];
if (sep > best_sep)
{
seed0 = lowestHigh[dim];
seed1 = highestLow[dim];
best_sep = sep;
}
}
/* assert (seed0 != seed1); */
if (seed0 > seed1)
{
RTreeNodeAddBranch(&(p->cover[0]),n1,PartitionGet(p,seed0));
RTreeNodeAddBranch(&(p->cover[1]),n2,PartitionGet(p,seed1));
}
else if (seed0 < seed1)
{
RTreeNodeAddBranch(&(p->cover[0]),n1,PartitionGet(p,seed1));
RTreeNodeAddBranch(&(p->cover[1]),n2,PartitionGet(p,seed0));
}
}
static void RTreeNodeAddBranch(rect_t *r, node_t n, branch_t b)
{
int i;
assert(n);
assert(n->count < MAXCARD);
for (i = 0; i < MAXCARD; i++)
if (n->branch[i].child == NULL)
{
n->branch[i] = b;
n->count ++;
break;
}
*r = RectCombine(*r,b.mbr);
}
void RTreePrint(node_t t)
{
int i;
/* printf("rtree([_,_,_,_,_]).\n"); */
printf("rtree(%p,%d,[",t,t->level);
for (i = 0; i < MAXCARD; i++)
{
if (t->branch[i].child != NULL)
{
printf("(%p,",t->branch[i].child);
RectPrint(t->branch[i].mbr);
printf(")");
}
else
{
printf("nil");
}
if (i < MAXCARD-1)
printf(",");
}
printf("]).\n");
if (t->level != 0)
for (i = 0; i < MAXCARD; i++)
if (t->branch[i].child != NULL)
RTreePrint((node_t) t->branch[i].child);
else
break;
}
/*
* Partition related
*/
static partition_t PartitionNew (void)
{
partition_t p;
memset((void *) &p,0, sizeof(p));
p.cover[0] = p.cover[1] = p.cover_all = RectInit();
return p;
}
static void PartitionPush (partition_t *p, branch_t b)
{
assert(p->n < MAXCARD + 1);
p->buffer[p->n] = b;
p->n ++;
p->cover_all = RectCombine(p->cover_all,b.mbr);
}
static branch_t PartitionPop (partition_t *p)
{
assert(p->n > 0);
p->n --;
return p->buffer[p->n];
}
static branch_t PartitionGet (partition_t *p, int n)
{
branch_t b;
assert (p->n > n);
b = p->buffer[n];
p->buffer[n] = PartitionPop(p);
return b;
}
/*
* Rect related
*/
rect_t RectInit (void)
{
rect_t r = {{DBL_MAX, DBL_MAX, DBL_MIN, DBL_MIN}};
return (r);
}
static double RectArea (rect_t r)
{
int i;
double area;
for (i = 0,area = 1; i < NUMDIMS; i++)
area *= r.coords[i+NUMDIMS] - r.coords[i];
/* area = (r.coords[1] - r.coords[0]) * */
/* (r.coords[3] - r.coords[2]); */
return area;
}
static rect_t RectCombine (rect_t r, rect_t s)
{
int i;
rect_t new_rect;
for (i = 0; i < NUMDIMS; i++)
{
new_rect.coords[i] = MIN(r.coords[i],s.coords[i]);
new_rect.coords[i+NUMDIMS] = MAX(r.coords[i+NUMDIMS],s.coords[i+NUMDIMS]);
}
return new_rect;
}
static int RectOverlap (rect_t r, rect_t s)
{
int i;
for (i = 0; i < NUMDIMS; i++)
if (r.coords[i] > s.coords[i + NUMDIMS] ||
s.coords[i] > r.coords[i + NUMDIMS])
return FALSE;
return TRUE;
}
static rect_t RTreeNodeCover(node_t n)
{
int i;
rect_t r = RectInit();
for (i = 0; i < MAXCARD; i++)
if (n->branch[i].child)
{
r = RectCombine (r, n->branch[i].mbr);
}
else
break;
return r;
}
static void RectPrint (rect_t r)
{
int i;
printf("[");
for (i = 0; i < 2*NUMDIMS; i++)
{
printf("%f",r.coords[i]);
if ( i < 2*NUMDIMS - 1)
printf(",");
}
printf("]");
}

View File

@ -1,63 +0,0 @@
#ifndef _RTREE_
#define _RTREE_
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE !FALSE
#endif
#define NUMDIMS 2 /* 2d */
struct Rect
{
double coords[2*NUMDIMS]; /* x1min, y1min, ... , x1max, y1max, ...*/
};
typedef struct Rect rect_t;
struct Branch
{
rect_t mbr;
void * child; /*void * so user can store whatever he needs, in case
of non-leaf ndes it stores the child-pointer*/
};
typedef struct Branch branch_t;
#define PGSIZE 196
#define MAXCARD (int)((PGSIZE-(2*sizeof(int)))/ sizeof(struct Branch))
#define MINCARD (MAXCARD / 2)
struct Node
{
int count;
int level;
branch_t branch[MAXCARD];
};
typedef struct Node * node_t;
typedef node_t rtree_t;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
/* CallBack to search function */
typedef int (*SearchHitCallback)(rect_t r, void *data, void *arg);
extern rtree_t RTreeNew (void);
extern void RTreeInsert (rtree_t *, rect_t, void *);
extern int RTreeSearch (rtree_t, rect_t, SearchHitCallback, void *);
extern void RTreeDestroy (rtree_t);
extern void RTreePrint(node_t);
extern rect_t RectInit (void);
struct Partition
{
branch_t buffer[MAXCARD+1];
int n;
rect_t cover_all;
rect_t cover[2];
};
typedef struct Partition partition_t;
#endif /* _RTREE_ */

View File

@ -1,179 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <YapInterface.h>
#include "Yap.h"
#include "rtree.h"
#include "clause_list.h"
#include "rtree_udi_i.h"
#include "rtree_udi.h"
static int YAP_IsNumberTermToFloat (Term term, YAP_Float *n)
{
if (YAP_IsIntTerm (term) != FALSE)
{
if (n != NULL)
*n = (YAP_Float) YAP_IntOfTerm (term);
return (TRUE);
}
if (YAP_IsFloatTerm (term) != FALSE)
{
if (n != NULL)
*n = YAP_FloatOfTerm (term);
return (TRUE);
}
return (FALSE);
}
static rect_t RectOfTerm (Term term)
{
YAP_Term tmp;
rect_t rect;
int i;
if (!YAP_IsPairTerm(term))
return (RectInit());
for (i = 0; YAP_IsPairTerm(term) && i < 4; i++)
{
tmp = YAP_HeadOfTerm (term);
if (!YAP_IsNumberTermToFloat(tmp,&(rect.coords[i])))
return (RectInit());
term = YAP_TailOfTerm (term);
}
return (rect);
}
control_t *RtreeUdiInit (Term spec,
void * pred,
int arity){
control_t *control;
YAP_Term arg;
int i, c;
/* YAP_Term mod; */
/* spec = Yap_StripModule(spec, &mod); */
if (! YAP_IsApplTerm(spec))
return (NULL);
control = (control_t *) malloc (sizeof(*control));
assert(control);
memset((void *) control,0, sizeof(*control));
c = 0;
for (i = 1; i <= arity; i ++)
{
arg = YAP_ArgOfTerm(i,spec);
if (YAP_IsAtomTerm(arg)
&& strcmp("+",YAP_AtomName(YAP_AtomOfTerm(arg))) == 0)
{
(*control)[c].pred = pred;
(*control)[c++].arg = i;
}
}
/* for (i = 0; i < NARGS; i++)
printf("%d,%p\t",(*control)[i].arg,(*control)[i].tree);
printf("\n"); */
return control;
}
control_t *RtreeUdiInsert (Term term,control_t *control,void *clausule)
{
int i;
rect_t r;
assert(control);
for (i = 0; i < NARGS && (*control)[i].arg != 0 ; i++)
{
r = RectOfTerm(YAP_ArgOfTerm((*control)[i].arg,term));
if (!(*control)[i].tree)
(*control)[i].tree = RTreeNew();
RTreeInsert(&(*control)[i].tree,r,clausule);
}
/* printf("insert %p\n", clausule); */
return (control);
}
static int callback(rect_t r, void *data, void *arg)
{
callback_m_t x;
x = (callback_m_t) arg;
return Yap_ClauseListExtend(x->cl,data,x->pred);
}
/*ARGS ARE AVAILABLE*/
void *RtreeUdiSearch (control_t *control)
{
rect_t r;
int i;
struct ClauseList clauselist;
struct CallbackM cm;
callback_m_t c;
YAP_Term Constraints;
/*RTreePrint ((*control)[0].tree);*/
for (i = 0; i < NARGS && (*control)[i].arg != 0 ; i++) {
YAP_Term t = YAP_A((*control)[i].arg);
if (YAP_IsAttVar(t))
{
fprintf(stderr,"i=%ld\n",i);
/*get the constraits rect*/
Constraints = YAP_AttsOfVar(t);
/* Yap_DebugPlWrite(Constraints); */
r = RectOfTerm(YAP_ArgOfTerm(2,Constraints));
c = &cm;
c->cl = Yap_ClauseListInit(&clauselist);
c->pred = (*control)[i].pred;
if (!c->cl)
return NULL; /*? or fail*/
RTreeSearch((*control)[i].tree, r, callback, c);
Yap_ClauseListClose(c->cl);
if (Yap_ClauseListCount(c->cl) == 0)
{
Yap_ClauseListDestroy(c->cl);
return Yap_FAILCODE();
}
if (Yap_ClauseListCount(c->cl) == 1)
{
return Yap_ClauseListToClause(c->cl);
}
return Yap_ClauseListCode(c->cl);
}
}
return NULL; /*YAP FALLBACK*/
}
int RtreeUdiDestroy(control_t *control)
{
int i;
assert(control);
for (i = 0; i < NARGS && (*control)[i].arg != 0; i++)
{
if ((*control)[i].tree)
RTreeDestroy((*control)[i].tree);
}
free(control);
control = NULL;
return TRUE;
}

View File

@ -1,20 +0,0 @@
#ifndef _RTREE_UDI_I_
#define _RTREE_UDI_I_
#define NARGS 5
struct Control
{
int arg;
void *pred;
rtree_t tree;
};
typedef struct Control control_t[NARGS];
struct CallbackM
{
clause_list_t cl;
void * pred;
};
typedef struct CallbackM * callback_m_t;
#endif /* _RTREE_UDI_I_ */

View File

@ -9,7 +9,7 @@
**************************************************************************
* *
* File: udi.yap *
* Last rev: 8/2/88 *
* Last rev: 17/12/2012 *
* mods: *
* comments: support user defined indexing *
* *
@ -22,5 +22,5 @@
******************/
udi(Pred) :-
'$udi_init'(rtree, Pred).
writeln(('udi.yap ',Pred)),
'$udi_init'(Pred).