From 48f393bedf7dec90283a0b17651d56fa31ff4a44 Mon Sep 17 00:00:00 2001 From: nunofonseca Date: Wed, 26 Mar 2008 23:05:22 +0000 Subject: [PATCH] RL-Trees module. git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@2169 b08c6af1-5177-4d33-ba66-4b1c6b8b522a --- library/rltree.yap | 21 + library/rltree/Makefile.in | 69 +++ library/rltree/range_list.c | 947 ++++++++++++++++++++++++++++++++++++ library/rltree/range_list.h | 166 +++++++ library/rltree/yap_rl.c | 446 +++++++++++++++++ 5 files changed, 1649 insertions(+) create mode 100644 library/rltree.yap create mode 100644 library/rltree/Makefile.in create mode 100644 library/rltree/range_list.c create mode 100644 library/rltree/range_list.h create mode 100644 library/rltree/yap_rl.c diff --git a/library/rltree.yap b/library/rltree.yap new file mode 100644 index 000000000..0ce45e8fb --- /dev/null +++ b/library/rltree.yap @@ -0,0 +1,21 @@ +/**************************************** + File: rltree.yap + Author: Nuno A. Fonseca + Comments: Range-List (RL) tree data structure implementation for YAP + version: $Id: rltree.yap,v 1.1 2008-03-26 23:05:22 nunofonseca Exp $ +****************************************/ + +:- module(rltree, [ + rl_new/2, %% (+Maximum Interval value, -Range-List Id) + rl_free/1, %% (+Range-List Id) + rl_size/2, %% (+Range-List Id,-Size in bytes) + rl_copy/2, %% (+Range-List Id,-New Range-List Id) - copies one rl_tree + rl_set_out/2, %%(+Range-List Id,+Number) - removes Number from the range-list + rl_in/2, %%(+Range-List Id,?Number) - checks if a number is in the rl-tree + rl_set_in/2, %%(+Range-List Id,+Number) + rl_set_all_in/1,%%(+Range-List Id) + rl_print/1, %%(+Range-List Id) + rl_freeze/1 %%(+Range-List Id) + ]). + +:- load_foreign_files([yap_rl], [], init_rl). diff --git a/library/rltree/Makefile.in b/library/rltree/Makefile.in new file mode 100644 index 000000000..51d72dd02 --- /dev/null +++ b/library/rltree/Makefile.in @@ -0,0 +1,69 @@ +# +# default base directory for YAP installation +# (EROOT for architecture-dependent files) +# +# +# default base directory for YAP installation +# (EROOT for architecture-dependent files) +# +prefix = @prefix@ +ROOTDIR = $(prefix) +EROOTDIR = @exec_prefix@ +# +# where the binary should be +# +BINDIR = $(EROOTDIR)/bin +# +# where YAP should look for libraries +# +LIBDIR=$(EROOTDIR)/lib/Yap +# +# +CC=@CC@ +MPI_CC=mpicc +CFLAGS= @CFLAGS@ $(YAP_EXTRAS) $(DEFS) -I$(srcdir) -I../.. -I$(srcdir)/../../include +# +# +# You shouldn't need to change what follows. +# +INSTALL=@INSTALL@ +INSTALL_DATA=@INSTALL_DATA@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +SHELL=/bin/sh +RANLIB=@RANLIB@ +srcdir=@srcdir@ +SHLIB_CFLAGS=@SHLIB_CFLAGS@ +SHLIB_SUFFIX=@SHLIB_SUFFIX@ +# + +OBJS=yap_rl.o range_list.o + +#in some systems we just create a single object, in others we need to +# create a libray +all: $(SOBJS) + +yap_rl.so: yap_rl.c range_list.o + $(CC) $(CFLAGS) -c yap_rl.c + ld $(LDFLAGS) -o yap_rl.so yap_rl.o range_list.o + +range_list.o: $(srcdir)/range_list.c $(srcdir)/range_list.h + $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/range_list.c -o range_list.o + +yap_rl.o: $(srcdir)/yap_rl.c + $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/yap_rl.c -o yap_rl.o + +@DO_SECOND_LD@%@SHLIB_SUFFIX@: %.o +@DO_SECOND_LD@ @SHLIB_LD@ -o $@ $< + +@DO_SECOND_LD@yap_mpi@SHLIB_SUFFIX@: $(OBJS) +@DO_SECOND_LD@ @SHLIB_LD@ $(MPILDF) -o yap_rl@SHLIB_SUFFIX@ $(OBJS) + +install: all + @if test "$(SOBJS)" = "no"; then echo ""; else $(INSTALL_PROGRAM) $(SOBJS) $(DESTDIR)$(LIBDIR); fi + +clean: + rm -f *.o *~ $(OBJS) $(SOBJS) *.BAK + +no: + @echo "YAP RL module not compiled." + diff --git a/library/rltree/range_list.c b/library/rltree/range_list.c new file mode 100644 index 000000000..f4bccb399 --- /dev/null +++ b/library/rltree/range_list.c @@ -0,0 +1,947 @@ +/******************************************************************************************* + +Copyright (C) 2004,2005,2006,2007,2008 (Nuno A. Fonseca) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +Last rev: $Id: range_list.c,v 1.1 2008-03-26 23:05:22 nunofonseca Exp $ +**************************************************************************/ + +#include +#include +#include +#include "range_list.h" + +/*****************************************************************************/ + + + +void set_num_bit(unsigned int number,char* storage,STATUS status); +BOOLEAN is_num_bit(unsigned int number,char *storage,STATUS status); + +static void set_quadrant(RL_Node* node,short quadrant,QUADRANT_STATUS status); +static QUADRANT_STATUS quadrant_status(RL_Node* node,short quadrant); + +static void quadrant_interval(RL_Tree *tree,short quadrant,NUM interval,NUM *quad_interval); +static NUM get_quadrant_node(RL_Tree* tree,NUM node,short quadrant,NUM interval); +static unsigned int tree_size(RL_Tree *tree,NUM node,NUM); + +int get_location(RL_Tree* tree,NUM node,short quadrant,NUM interval); + +long set_in(NUM number,NUM node, NUM node_num, NUM interval,NUM max,RL_Tree* tree,STATUS status); +long compact_node(RL_Tree*,NUM node,NUM next_node,NUM node_interval,NUM next_node_interval,NUM next_node_num,short quadrant,NUM max); + +BOOLEAN in_tree(NUM number,RL_Tree *tree,NUM node,NUM node_num,NUM interval); +void display_tree(RL_Tree *tree); +void idisplay_tree(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max); +static void display_leaf(RL_Tree* tree,NUM node,NUM node_num,NUM max); + +NUM new_node(RL_Tree* tree,NUM node_father,short quadrant,NUM node_num,NUM quad_min,NUM quad_max,STATUS); +static void root_intervals(RL_Tree* tree); + +NUM next_min(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max,NUM min); +NUM tree_minus(RL_Tree *r1,RL_Tree *r2,NUM node1,NUM node2,NUM node_num,NUM interval,NUM max); + +static void print_nodes(RL_Tree* tree); + +// +RL_Buffer* buffer=NULL; +unsigned int active_bits[16]={ + 1, + 3, + 7, + 15, + 31, + 63, + 127, + 255, + 511, + 1023, + 2047, + 4095, + 8191, + 16383, + 32767, + 65535 +}; + + +/*****************************************************************************/ +/* + * + * + */ +RL_Tree* new_rl(NUM max_size) { + + RL_Tree *new; + RL_Node *buf_ptr; + short q; + NUM qi,tmp; + + if ( max_size <2 ) + max_size=2; + + new=(RL_Tree*)malloc(sizeof(RL_Tree)); + if(new==NULL) + return NULL; + + new->range_max=max_size; + root_intervals(new); + + // alloc a block for the nodes + new->root=(RL_Node*)calloc(1,NODE_SIZE); + new->size=1; + new->mem_alloc=NODE_SIZE; // memory allocated + + // reset buffer + buf_ptr=new->root;//tree_buffer(); + ALL_OUT(&buf_ptr[0]); // Initialize all numbers as being out of the range/interval + buf_ptr[0].i_node.num_subnodes=1; + new->root=buf_ptr;// pointer to the buffer + + buf_ptr->i_node.num_subnodes=1; + quadrant_interval(new,1,max_size,&qi); + tmp=qi+1; + for(q=2;q<=BRANCH_FACTOR;++q) { + if ( max_size < qi*(q-1)+1 ) // 16 32 48 64 - 32 + set_quadrant(new->root,q,R_IGNORE); + tmp+=qi; // max_size=16 16+1 + } + + return new; +} +/* + * + * + */ +RL_Tree* copy_rl(RL_Tree *tree) { + + RL_Tree *new; + RL_Node *buf_ptr; + + new=(RL_Tree*)malloc(sizeof(RL_Tree)); + buf_ptr=(RL_Node*)calloc(tree->size,NODE_SIZE); + if( new==NULL ) { + printf("new==NULL"); + return NULL; + } + if( buf_ptr==NULL ) { + printf("buf_ptr==NULL---%lu",tree->size); + return NULL; + } + memcpy(new,tree,sizeof(RL_Tree)); + memcpy(buf_ptr,&tree->root[0],tree->size*NODE_SIZE); + new->root=buf_ptr; + new->mem_alloc=tree->size*NODE_SIZE; + return new; +} +/* + * + * + */ +void free_rl(RL_Tree* range) { + + // free nodes block + if(range->mem_alloc!=0) + free(range->root); + // + free(range); +} +/* + + */ +RL_Tree* set_in_rl(RL_Tree* tree,NUM number,STATUS status) { + + /* */ + if ( number >0 && number <=tree->range_max) + set_in(number,ROOT(tree),1,ROOT_INTERVAL(tree),tree->range_max,tree,status); +#ifdef DEBUG + printf("Setting: %d size=%d\n",number,tree->size); +#endif + /*if (status==IN && !in_rl(tree,number)) { + fprintf(stderr,"Error adding %lu to tree: size=%lu max=%lu\n",number,tree->size,tree->range_max); + display_tree(tree); + exit(1); + }*/ + return tree; +} +/* + * Mark all examples in range IN/OUT + */ +void rl_all(RL_Tree* tree,STATUS status) { + int i; + + for(i=1;i<=BRANCH_FACTOR;++i) + if (quadrant_status(NODE(tree,ROOT(tree)),i)!=R_IGNORE) { + if(status==IN) + set_quadrant(NODE(tree,ROOT(tree)),i,R_TOTALLY_IN_INTERVAL); + else + set_quadrant(NODE(tree,ROOT(tree)),i,R_NOT_IN_INTERVAL); + } + tree->size=1; +} +/* + * + * + */ +BOOLEAN in_rl(RL_Tree* tree,NUM number) { + if ( number <1 && number >tree->range_max) + return FALSE; + return in_tree(number,tree,ROOT(tree),1,ROOT_INTERVAL(tree)); +} +/* + * + * + */ +BOOLEAN freeze_rl(RL_Tree* range) { + + // reduce memory usage if possible + NUM s=range->size*NODE_SIZE; + if ( s < range->mem_alloc) { + range->root=(RL_Node*)realloc(range->root,s); + range->mem_alloc=s; + } + return TRUE; +} +/* + * Returns range1 without the numbers in range2 + * Constraint:range1->max==range2->max + */ +RL_Tree* minus_rl(RL_Tree* range1,RL_Tree* range2) { + if (range1->range_max!=range1->range_max) + return NULL; + //!!!!tree_minus(range1,range2,ROOT(range1),ROOT(range2),1,ROOT_INTERVAL(range1),range1->range_max); + return range1; +} + +/* + * Returns next number in tree bigger than min + */ +NUM rl_next_in_bigger(RL_Tree *tree,NUM min) { + if ( tree==NULL ) { + fprintf(stdout,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%lu\n",min); + } + return next_min(tree,ROOT(tree),1,ROOT_INTERVAL(tree),tree->range_max,min+1); +} +/* ****************************************************************************** + Private Functions + ****************************************************************************** */ +static void print_nodes(RL_Tree* tree) { + RL_Node* nodes=tree->root; + int j; + + for(j=0;jsize;++j) + printf("[%d]=%lu\n",j,(unsigned long int)nodes[j].leaf); + +} +// treeXquadrantXinterval->quadrant_minXquadrant_max +static void quadrant_interval(RL_Tree *tree,short quadrant,NUM interval,NUM *quad_interval) { + + if ( IS_ROOT(tree,interval) ) { + *quad_interval=tree->root_i; + } else { + *quad_interval=NEXT_INTERVAL(interval); + } +} + +// numberXtreeXinterval->quadrantXquadrant_minXquadrant_max +static void number_quadrant(NUM number,RL_Tree *tree,NUM node_interval,NUM node_num,short *quadrant,NUM *quad_min,NUM *quad_max) { + NUM tmp=node_num-1,quad_interval; + int i; + quadrant_interval(tree,1,node_interval,&quad_interval); + i=(number-node_num)/quad_interval+1; + tmp=node_num-1+quad_interval*i; + *quad_max=tmp; + *quadrant=i; + *quad_min=tmp-quad_interval+1; + //printf("number=%lu node num=%lu quad_interval=%lu-------> quadrant=%d quad_max=%lu\n",number,node_num,quad_interval,i,tmp); +} + +/* + * returns the index to the quadrant "quadrant" node + */ +static NUM get_quadrant_node(RL_Tree* tree,NUM node,short quadrant,NUM interval) { + int d=get_location(tree,node,quadrant,interval); + return node+d; +} +/* src s + * src= 1 2 3 4 5 6 _ _ + * offset= 2 + * nbytes=6 + * >>>src= 1 2 1 2 3 4 5 6 + * src s + */ +void shift_right(RL_Tree *tree,const NUM idx,const long nnodes){ + long n=idx+nnodes; + RL_Node *s=tree->root; + + if (nnodes<=0) return; + //print_nodes(tree); + while(n>=idx) { + s[n+1].leaf=s[n].leaf; + --n; + } + //print_nodes(tree); + //printf(">>----------------\n"); +} + +void shift_left(RL_Tree *tree,const NUM idx, const long nnodes){ + long n=idx; + RL_Node *s=tree->root; + + //printf("sfit left: idx=%u nnodes=%u max=%u\n",idx,nnodes,tree->size); + if ( nnodes<=0 ) // last element + return; + + // print_nodes(tree); + while(nroot; + NUM new_interval=+NEXT_INTERVAL(father_interval); + NUM times; + NUM new; + RL_Node* ptr; + new=get_quadrant_node(tree,node_father,quadrant,father_interval); + + if ( tree->mem_alloc!=0 ) { + // increase array size and shift elements right + if ( REALLOC_MEM(tree) ) { + //printf("new node:resizing memory: current %lu -> new %lu [%lu]\n",tree->mem_alloc,MEM_SIZE(tree),tree->size); + ptr=(RL_Node*)realloc(tree->root,MEM_SIZE(tree)); + if ( ptr==NULL ) { + fprintf(stderr,"Fatal error:range_list: Unable to allocate memory"); + exit(1); + } + tree->root=ptr; + tree->mem_alloc=MEM_SIZE(tree); + } + // SHIFT elements at the right and including the current node one position + times=tree->size-1-new; + shift_right(tree,new,times); + // SHIFT_NODES((void*)new,times*NODE_SIZE); + } + // update father reference + set_quadrant(NODE(tree,node_father),quadrant,R_PARCIALLY_IN_INTERVAL); + // initialize node + if ( status==IN) { + ALL_OUT(NODE(tree,new)); // clear all bits + if ( !IS_LEAF(new_interval) ) { + short q; + RL_Node* node_ptr=NODE(tree,new); + node_ptr->i_node.num_subnodes=1; + for(q=2;q<=BRANCH_FACTOR;++q) + if ( MIN(quad_max,tree->range_max) < quad_min+NEXT_INTERVAL(new_interval)*(q-1) ) //QUADRANT_MAX_VALUE( + set_quadrant(NODE(tree,new),q,R_IGNORE); + } + } else { + // status ==out + //SET_LEAF_IN(tree->range_max,NODE(tree,new),quad_min); + tree->root[new].leaf=ON_BITS(MIN(16,tree->range_max-quad_min+1)); + if ( !IS_LEAF(new_interval) ) { + short q; + RL_Node* node_ptr=NODE(tree,new); + node_ptr->i_node.num_subnodes=1; + node_ptr->i_node.quadrant_1=node_ptr->i_node.quadrant_2=node_ptr->i_node.quadrant_3=node_ptr->i_node.quadrant_4=R_TOTALLY_IN_INTERVAL; + for(q=2;q<=BRANCH_FACTOR;++q) + if ( MIN(quad_max,tree->range_max) < quad_min+NEXT_INTERVAL(new_interval)*(q-1) ) //QUADRANT_MAX_VALUE( + set_quadrant(NODE(tree,new),q,R_IGNORE); + } + } + // update tree size + tree->size++; + return new; +} + +/* + * returns the offset + * + */ +int get_location(RL_Tree* tree,NUM node,short quadrant,NUM node_interval) { + int i,c=1,tmp; + NUM next_node; + NUM next_interval; + + if (quadrant==1 || IS_LEAF(node_interval)) return 1; + + // + if ( LAST_LEVEL_INODE(node_interval) ) { + // 1 node = current + for(i=1;isize,compacted; + NUM interval=node_interval; + NUM quad_min,quad_max; + short quadrant; + NUM size; + /* */ + if ( IS_LEAF(interval) ) { + // current node is a leaf + set_num_bit(number-node_num,(char*)NODE(tree,node),status); + return 0; + } + // + number_quadrant(number,tree,node_interval,node_num,&quadrant,&quad_min,&quad_max); + interval=quad_max-quad_min+1; + // select next node + switch(status) { + case IN: + // move pointer to next node + if ( quadrant_status(NODE(tree,node),quadrant)==R_NOT_IN_INTERVAL ) { + // new node + //display_tree(tree); + next_node=new_node(tree,node,quadrant,node_interval,quad_min,quad_max,status); + }else if ( quadrant_status(NODE(tree,node),quadrant)==R_TOTALLY_IN_INTERVAL ) + return 0; + else + next_node=get_quadrant_node(tree,node,quadrant,node_interval); + break; + case OUT: + if ( quadrant_status(NODE(tree,node),quadrant)==R_TOTALLY_IN_INTERVAL ) { + // new node + next_node=new_node(tree,node,quadrant,node_interval,quad_min,quad_max,status); + } else if ( quadrant_status(NODE(tree,node),quadrant)==R_NOT_IN_INTERVAL ) + return 0; + else + next_node=get_quadrant_node(tree,node,quadrant,node_interval); + break; + default: + printf("set_in: invalid number status %d\n",status); + exit(1); + } + // insert in tree + set_in(number,next_node,quad_min,interval,quad_max,tree,status); + ret_val=tree->size-ret_val; // number of nodes added/removed + // compact tree: only if we didn't create new nodes + //compacted=compact_node(tree,node,next_node,node_interval,interval,quad_min,quadrant,MIN(quad_max,tree->range_max)); + compacted=0; + if ( compacted==-1 ) { + //NUM times=tree->size-1-next_node; // -1 because array position 0 + shift_left(tree,next_node,1); + // update tree size + tree->size+=compacted; + ret_val+=compacted; + //ret_val=0;//compacted; + } + // update subnodes number + if ( tree->root[node].i_node.num_subnodes ==255 ) + size=tree_size(tree,node,interval); + else + size=ret_val+tree->root[node].i_node.num_subnodes; // new subnodes value + + if ( size > 254 ) + tree->root[node].i_node.num_subnodes=255; + else + tree->root[node].i_node.num_subnodes=size; + + // if (size <0 ) exit(1); + return ret_val; +} +/* + * Check if can change quadrant color of node. If it changes, the node is deleted and all nodes at right in the array are shifted one position. + * + */ +long compact_node(RL_Tree *tree,NUM node,NUM next_node,NUM node_interval,NUM next_node_interval,NUM next_node_num,short quadrant,NUM max){ + unsigned int j; + + RL_Node* node_ptr=NODE(tree,next_node); // next node pointer + + // Try to compact a leaf + if ( IS_LEAF(next_node_interval) ) { +#ifdef DEBUG + fprintf(stderr,"compact_node: interval node\n"); +#endif + // ALL IN + if ( LEAF_ALL_IN(node_ptr->leaf) ) { + set_quadrant(NODE(tree,node),quadrant,R_TOTALLY_IN_INTERVAL); + return -1; + } + // ALL IN: part II + // The last node does not need to be all in + if ( max-next_node_num+1 <= LEAF_SIZE ) { + j=ON_BITS(max-next_node_num+1); //153,154,155,156,157,.,.,.,[158 -> valor do max=200 devia ser 158 + if ( node_ptr->leaf==j ) { + set_quadrant(NODE(tree,node),quadrant,R_TOTALLY_IN_INTERVAL); + return -1; + } + } + // ALL OUT + if ( LEAF_ALL_OUT(node_ptr->leaf) ) { + set_quadrant(NODE(tree,node),quadrant,R_NOT_IN_INTERVAL); +#ifdef DEBUG + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>compacted leaf1\n"); +#endif + return -1; + } + } else { +#ifdef DEBUG + fprintf(stderr,"compact_node:range node\n"); +#endif + // INODE - range list node + if ( node_ptr->i_node.num_subnodes>1 ) // unable to compact + return 0; + // ALL IN + for(j=1;j<=BRANCH_FACTOR;++j) + if ( quadrant_status(NODE(tree,next_node),j)!=R_IGNORE && quadrant_status(NODE(tree,next_node),j)!=R_TOTALLY_IN_INTERVAL ) + break; + + if (j>BRANCH_FACTOR) { + set_quadrant(NODE(tree,node),quadrant,R_TOTALLY_IN_INTERVAL); + return -1; + } + // ALL OUT + for(j=1;j<=BRANCH_FACTOR;++j) + if ( quadrant_status(NODE(tree,next_node),j)!=R_IGNORE && quadrant_status(NODE(tree,next_node),j)!=R_NOT_IN_INTERVAL ) + break; + + if (j>BRANCH_FACTOR) { + set_quadrant(NODE(tree,node),quadrant,R_NOT_IN_INTERVAL); + return -1; + } + } + return 0; +} + +/* + * interval: interval associated to the node + */ +static unsigned int tree_size(RL_Tree *tree,NUM node,NUM interval) { + unsigned int c=1,tmp; + int i=1; + short status; + NUM next_interval; + NUM next_node; + RL_Node* node_ptr=NODE(tree,node); + + if ( IS_LEAF(interval)) return 1; + + if ( node_ptr->i_node.num_subnodes==255) { + // compute the size of all subtrees + next_interval=NEXT_INTERVAL(interval); + for(i=1;i<=BRANCH_FACTOR;++i) { + status=quadrant_status(NODE(tree,node),i); + switch(status) { + case R_PARCIALLY_IN_INTERVAL: + next_node=node+c; // + tmp=tree_size(tree,next_node,next_interval); + c+=tmp; + // default: + } + } + } + else c=node_ptr->i_node.num_subnodes; + return c; +} +/* + * number >=1 && number <=16 + */ +void set_num_bit(unsigned int number,char *storage,STATUS status) { + if ( number >= 8 ) { + storage++; + number=number-8; // =-8 + } + if ( status==IN ) + BITMAP_insert(*storage,number); + else + BITMAP_delete(*storage,number); +} +/* + */ +BOOLEAN is_num_bit(unsigned int number,char *storage,STATUS status) { + if ( number >= 8 ) { + storage++; + number=number-8; // =-8 + } + if ( status==IN ) + return BITMAP_member(*storage,number); + else + return !BITMAP_member(*storage,number); +} +/* + * + */ +static void set_quadrant(RL_Node *node,short quadrant,QUADRANT_STATUS status){ + + switch(quadrant){ + case 1: + node->i_node.quadrant_1=status; + break; + case 2: + node->i_node.quadrant_2=status; + break; + case 3: + node->i_node.quadrant_3=status; + break; + case 4: + node->i_node.quadrant_4=status; + break; + default: + fprintf(stderr,"ERROR: set_quadrant: invalid quadrant %d(%d)\n",quadrant,status); + } +} +/* + * + */ +static QUADRANT_STATUS quadrant_status(RL_Node *node,short quadrant){ + + switch(quadrant){ + case 1: + return node->i_node.quadrant_1; + case 2: + return node->i_node.quadrant_2; + case 3: + return node->i_node.quadrant_3; + case 4: + return node->i_node.quadrant_4; + default: + fprintf(stderr,"ERROR: quadrant_status: invalid quadrant(%d)\n",quadrant); + } + return 0; +} +/* + * + * + */ +static BOOLEAN in_leaf(NUM number,RL_Tree *tree,NUM node,NUM node_num,NUM max) { + + if(is_num_bit(number-node_num,(char*)NODE(tree,node),IN)) + return TRUE; + return FALSE; +} + +/* + * + * + */ +BOOLEAN in_tree(NUM number,RL_Tree *tree,NUM node,NUM node_num,NUM node_interval) { + NUM next_node; + short quadrant; + NUM interval=node_interval; + NUM max=MIN(node_num+interval,tree->range_max); + NUM quad_min,quad_max; + + /* */ + if ( IS_LEAF(interval)) + // current node is a leaf + return in_leaf(number,tree,node,node_num,max); + + number_quadrant(number,tree,node_interval,node_num,&quadrant,&quad_min,&quad_max); + interval=quad_max-quad_min+1; + node_num=quad_min; + + if ( quadrant_status(NODE(tree,node),quadrant)==R_PARCIALLY_IN_INTERVAL ) { + next_node=get_quadrant_node(tree,node,quadrant,node_interval); + return in_tree(number,tree,next_node,node_num,interval); + } + if ( quadrant_status(NODE(tree,node),quadrant)==R_TOTALLY_IN_INTERVAL ) + return TRUE; + + return FALSE; +} + + +/* ************************************************************************************************* */ +/* I/O */ +/* ************************************************************************************************* */ + +/* + * + */ +static void display_leaf(RL_Tree *tree,NUM node,NUM node_num,NUM max) { + int i; + printf("|"); + //for(i=0;iroot; + + printf("Size:%lu -[1,%lu]\n",tree->size,tree->range_max); + qi=ROOT_INTERVAL(tree)/BRANCH_FACTOR; + //quadrant_interval(tree,1,tree->range_max,&qi); + for(i=1;i<=BRANCH_FACTOR;++i) { + tmp+=qi; + // + init=tmp-qi+1; + max=tmp; + status=quadrant_status(NODE(tree,0),i); + switch(status) { + case R_PARCIALLY_IN_INTERVAL: + next_node=get_quadrant_node(tree,ROOT(tree),i,qi*BRANCH_FACTOR); + idisplay_tree(tree,next_node,init,qi,max); + break; + case R_TOTALLY_IN_INTERVAL: + printf(",[%lu-%lu]",init,MIN(max,tree->range_max)); + break; + case R_IGNORE: + break; + default: + /* not in */ + printf(",]%lu-%lu[",init,MIN(max,tree->range_max)); + } + } + printf("\n"); +} +/* + * + * + */ +void idisplay_tree(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max) { + NUM next_node; + short quadrant; + NUM interval2; + NUM node_num2; + NUM quadrant_max; + short status; + + if ( IS_LEAF(interval) ) + return display_leaf(tree,node,node_num,MIN(max,tree->range_max)); + + interval2=NEXT_INTERVAL(interval); + // + for(quadrant=1;quadrant<=BRANCH_FACTOR;++quadrant){ + node_num2=node_num+(quadrant-1)*interval2; + quadrant_max=QUADRANT_MAX_VALUE(node_num,quadrant,interval2,max); + status=quadrant_status(NODE(tree,node),quadrant); + switch(status) { + case R_PARCIALLY_IN_INTERVAL: + next_node=get_quadrant_node(tree,node,quadrant,interval); + if ( IS_LEAF(interval2) ) + display_leaf(tree,next_node,node_num2,MIN(quadrant_max,tree->range_max)); + else + idisplay_tree(tree,next_node,node_num2,interval2,quadrant_max); + break; + case R_TOTALLY_IN_INTERVAL: + printf(",[%lu-%lu]",node_num2,MIN(node_num2+interval2-1,max)); + break; + case R_IGNORE: + break; + default: + printf(",]%lu-%lu[",node_num2,MIN(tree->range_max,node_num2+interval2-1)); + } + } +} + + +/* *************************************************************************************************** */ +static NUM next_in_leaf(RL_Tree *tree,NUM node,NUM node_num,NUM max,NUM min) { + NUM number; + number=node_num; + if ( numbernumber=%lu\n",node_num,max,min,number); + for (;number<=max;++number) + if(is_num_bit(number-node_num,(char*)NODE(tree,node),IN)) { + //fprintf(stdout,"next_in_leaf:[%lu,%lu]:min=%lu>>>>number=%lu\n",node_num,max,min,number); + return number; + } + //fprintf(stderr,"!next_in_leaf:[%lu,%lu]:min=%lu-->number=%lu\n",node_num,max,min,number); + return 0; +} + +/* + * Find next element bigger than min + * + */ +NUM next_min(RL_Tree *tree,NUM node,NUM node_num,NUM interval,NUM max,NUM min) { + NUM next_node; + short quadrant; + NUM interval2; + NUM node_num2; + NUM quadrant_max; + short status; + + if ( min > tree->range_max ) return 0; + if ( IS_LEAF(interval) ) + return next_in_leaf(tree,node,node_num,MIN(max,tree->range_max),min); + + interval2=NEXT_INTERVAL(interval); + // + for(quadrant=1;quadrant<=BRANCH_FACTOR;++quadrant){ + NUM found; + node_num2=node_num+(quadrant-1)*interval2; + quadrant_max=QUADRANT_MAX_VALUE(node_num,quadrant,interval2,max); + //------------------------------------------ + status=quadrant_status(NODE(tree,node),quadrant); + switch(status) { + case R_PARCIALLY_IN_INTERVAL: + next_node=get_quadrant_node(tree,node,quadrant,interval); + found=next_min(tree,next_node,node_num2,interval2,quadrant_max,min); + if ( found>0) return found; + break; + case R_TOTALLY_IN_INTERVAL: + if (min<=quadrant_max && min>=node_num2) + return min; + if ( min < node_num2 ) return node_num2; + } + + } + return 0; +} + +/* *******************************************************************************************************/ +/* + * + */ +void intersect_leafs(char *storage1,char *storage2) { + + BITMAP_difference(*storage1,*storage1,*storage2); + storage1++; storage2++; + BITMAP_difference(*storage1,*storage1,*storage2); +} +/* + * Removes the elements in tree1 that are in tree2 + * + */ +/*NUM tree_minus(RL_Tree *tree1,RL_Tree *tree2,NUM node1,NUM node2,NUM node_num,NUM interval,NUM max) { + NUM next_node1,next_node2; + short quadrant; + NUM interval2; + NUM node_num2; + NUM quadrant_max; + short status1,status2; + + + if ( IS_LEAF(interval) ) // + return intersect_leafs((char*)NODE(tree1,node1),(char*)NODE(tree2,node2)); + + interval2=NEXT_INTERVAL(interval); + // + for(quadrant=1;quadrant<=BRANCH_FACTOR;++quadrant){ + node_num2=node_num+(quadrant-1)*interval2; + quadrant_max=QUADRANT_MAX_VALUE(node_num,quadrant,interval2,max); + //------------------------------------------ + status1=quadrant_status(NODE(tree1,node1),quadrant); + status2=quadrant_status(NODE(tree2,node2),quadrant); + if (status2==R_IGNORE || status2==R_NOT_IN_INTERVAL) { + // do nothing + } else if ( status2==R_TOTALLY_IN_INTERVAL && (status1==R_IGNORE || status1==R_NOT_IN_INTERVAL )) { + // do nothing + } else if ( status2==R_TOTALLY_IN_INTERVAL && status1==R_TOTALLY_IN_INTERVAL ) { + // delete entire quadrant subtree in tree1 + } else if ( status2==R_PARTIALLY_IN_INTERVAL && status1==R_PARTIALLY_IN_INTERVAL){ + // call same function + next_node1=get_quadrant_node(tree1,node1,quadrant,interval); + next_node2=get_quadrant_node(tree1,node2,quadrant,interval); + tree_minus(tree1,tree2,next_node1,next_node2,node_num2,interval2,quadrant_max); + } else if ( status2==R_PARTIALLY_IN_INTERVAL && status1==R_TOTALLY_IN_INTERVAL) { + // foreach element of tree2, remove it in tree1 + + } else { + // this should never happen!!!! + } + switch(status) { + case R_PARCIALLY_IN_INTERVAL: + next_node=get_quadrant_node(tree,node,quadrant,interval); + found=next_min(tree,next_node,node_num2,interval2,quadrant_max,min); + if ( found>0) return found; + break; + case R_TOTALLY_IN_INTERVAL: + if (min<=quadrant_max && min>=node_num2) + return min; + if ( min < node_num2 ) return node_num2; + } + + } + return 0; +}*/ +/* *************************************************************************************************** */ +// root level +static NUM norm_tree_size(NUM interval){ + NUM tmp; + NUM j=BRANCH_FACTOR;; + + if ( interval<= LEAF_SIZE*BRANCH_FACTOR) return LEAF_SIZE; + while(1) { + tmp=LEAF_SIZE*j; + if ( tmp * BRANCH_FACTOR >= interval )break; + j*=BRANCH_FACTOR;; + } + return tmp; +} +// +static void root_intervals(RL_Tree* tree) { + NUM first_i; + + first_i=norm_tree_size(tree->range_max); + //k=tree->range_max/first_i+1; // number of large intervals + + tree->root_i=first_i; + + if ( tree->root_i*BRANCH_FACTOR < tree->range_max ) { + tree->root_i=tree->root_i*BRANCH_FACTOR; + //printf("%lu---->>%lu\n",tree->range_max,tree->root_i); + } +} + + diff --git a/library/rltree/range_list.h b/library/rltree/range_list.h new file mode 100644 index 000000000..bbda80f11 --- /dev/null +++ b/library/rltree/range_list.h @@ -0,0 +1,166 @@ +/******************************************************************************************* + +Copyright (C) 2004,2005,2006,2007,2008 (Nuno A. Fonseca) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +Last rev: $Id: range_list.h,v 1.1 2008-03-26 23:05:22 nunofonseca Exp $ +**************************************************************************/ + + +/* + Leaf + Each leaf uses 16 bits ( each bit represents one number ) + + */ +#define NUM unsigned long +/* + Node + Each node (non leaf) uses 8 bits. + - 8 bits are used to represent the state of the 4 subtrees ( subranges ). + - 2 bits are used to represent the state for each subtreee + + States of a subtree: + 00 (0) - range not in interval + 11 (3)- all range in interval + 10 (2)- range parcially in interval + + An extra byte is used to keep the number of nodes in the subtrees. + */ +struct s_node { + //short quadrant; + unsigned short int quadrant_1: 2; // + unsigned short int quadrant_2: 2; + unsigned short int quadrant_3: 2; + unsigned short int quadrant_4: 2; + unsigned short int num_subnodes: 8; +}; + +typedef enum { R_TOTALLY_IN_INTERVAL=3, R_PARCIALLY_IN_INTERVAL=2, R_NOT_IN_INTERVAL=0, R_IGNORE=1} QUADRANT_STATUS; + + +#define BRANCH_FACTOR 4 /* factor of division of the range */ +#define LEAF_SIZE 16 /* how many numbers are represented by a leaf */ + +#define NODE_SIZE sizeof(RL_Node) + +#define NODE(tree,idx) (RL_Node*)&tree->root[idx] +#define ROOT(tree) 0 + +#define IS_ROOT(tree,interval) (tree->range_max<=interval) +#define ROOT_INTERVAL(tree) (tree->root_i*BRANCH_FACTOR) + +#define MIN(a,b) ((aLEAF_SIZE)?1:0) + +#define REALLOC_MEM(tree) (tree->mem_alloc < (tree->size+1)*NODE_SIZE) +#define MEM_SIZE(tree) (tree->size+2)*NODE_SIZE + + +#define TREE_SIZE(tree) tree->mem_alloc+sizeof(RL_Tree) + + +typedef union { + struct s_node i_node; + unsigned short int leaf; +} RL_Node; /* A node is a internal node (inode) or a leaf depending on their depth in the tree */ + + +/* + Range_List + Contains the root node, max range size, +*/ +struct rl_struct { + RL_Node* root; + NUM size; // number of nodes + NUM mem_alloc; // memory allocated for *root + NUM range_max; // maximum value of the interval + NUM root_i; // root interval +}; +typedef struct rl_struct RL_Tree; + + +/* Buffer */ +struct s_buffer { + RL_Node* root_node; + unsigned long size; // memory (in bytes) allocated for root_node +}; +typedef struct s_buffer RL_Buffer; + +//---------------------------------------------------------------- +// Bits operations +#define BITMAP_empty(b) ((b) == 0) +#define BITMAP_member(b,n) (((b) & (1<<(n))) != 0) +#define BITMAP_alone(b,n) ((b) == (1<<(n))) +#define BITMAP_subset(b1,b2) (((b1) & (b2)) == b2) +#define BITMAP_same(b1,b2) ((b1) == (b2)) + +#define BITMAP_on_all(b) ((b) = 255) + +#define BITMAP_clear(b) ((b) = 0) +#define BITMAP_and(b1,b2) ((b1) &= (b2)) +#define BITMAP_minus(b1,b2) ((b1) &= ~(b2)) +#define BITMAP_insert(b,n) ((b) |= (1<<(n))) +#define BITMAP_delete(b,n) ((b) &= (~(1<<(n)))) +#define BITMAP_copy(b1,b2) ((b1) = (b2)) +#define BITMAP_intersection(b1,b2,b3) ((b1) = ((b2) & (b3))) +#define BITMAP_difference(b1,b2,b3) ((b1) = ((b2) & (~(b3)))) + +# +//---------------------------------------------------------------- +typedef enum { TRUE=1, FALSE=0} BOOLEAN; +typedef enum { IN=1, OUT=0} STATUS; + +// +#define BUFFER_SIZE 1000 +/* ********************************************************************************** */ +/* API */ +RL_Tree* new_rl(NUM max_size); +RL_Tree* copy_rl(RL_Tree *tree); +void free_rl(RL_Tree* range); + +void rl_all(RL_Tree* tree,STATUS status); +void display_tree(RL_Tree *tree); +RL_Tree* set_in_rl(RL_Tree* tree,NUM number,STATUS status); +BOOLEAN in_rl(RL_Tree* range,NUM number); +BOOLEAN freeze_rl(RL_Tree* tree); /* write operations on the range are finishe */ +RL_Tree* intersect_rl(RL_Tree* range1,RL_Tree* range2); + +NUM rl_next_in_bigger(RL_Tree *tree,NUM min); /* Returns next number in tree bigger than min */ + +#define IS_FREEZED(tree) (tree->mem_alloc!=0) + diff --git a/library/rltree/yap_rl.c b/library/rltree/yap_rl.c new file mode 100644 index 000000000..2894d2795 --- /dev/null +++ b/library/rltree/yap_rl.c @@ -0,0 +1,446 @@ +/******************************************************************************************* + +Copyright (C) 2004,2005,2006,2007,2008 (Nuno A. Fonseca) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +Last rev: $Id: yap_rl.c,v 1.1 2008-03-26 23:05:22 nunofonseca Exp $ +**************************************************************************/ + +#include +#include + +#include "range_list.h" +#include + +#define IDTYPE long +#define PTR2ID(ptr) (IDTYPE)ptr +#define ID2PTR(id) (RL_Tree*)id + + +/* ############################################################ */ +unsigned long int memory_usage=0; +unsigned long int tree_mem=0; + +#define STORE_TREE_SIZE(tree) tree_mem=tree->mem_alloc +#define UPDATE_MEM_USAGE(tree) memory_usage+=(tree->mem_alloc>0?tree->mem_alloc-tree_mem:0) +#define FREE_MEM_USAGE(tree) (memory_usage-=tree->mem_alloc) +#define ADD_MEM_USAGE(tree) (memory_usage+=tree->mem_alloc) + +/* + */ +static +int +p_rl_new(void) { + YAP_Term t1=YAP_Deref(YAP_ARG1); + YAP_Term t2=YAP_Deref(YAP_ARG2); + RL_Tree* new_tree; + IDTYPE newid; + + // Check args + if (!YAP_IsIntTerm(t1) || !YAP_IsVarTerm(t2)) { + fprintf(stderr,"Error in rl_new arguments\n"); + return(FALSE); + } + // + new_tree=new_rl(YAP_IntOfTerm(t1)); + if(new_tree==NULL) { + fprintf(stderr,"Error creating new rl."); + return (FALSE); + } + //printf("New rl %d %p--%u\n",PTR2ID(new_tree),new_tree,(int)new_tree,YAP_IntOfTerm(t1)); + // return reference + newid=YAP_MkIntTerm(PTR2ID(new_tree)); + if(!YAP_Unify(YAP_Deref(YAP_ARG2),newid)) + return (FALSE); + + return(TRUE); +} +/* + * + * + */ +static +int +p_rl_copy(void) { + YAP_Term t1=YAP_Deref(YAP_ARG1); // src + YAP_Term t2=YAP_Deref(YAP_ARG2); // dest + RL_Tree* new_tree; + IDTYPE id1,newid; + RL_Tree* tree; + + // Check args + if (!YAP_IsIntTerm(t1)) + return(FALSE); + if (!YAP_IsVarTerm(t2)) + return(FALSE); + // + id1=YAP_IntOfTerm(t1); + tree=ID2PTR(id1); + new_tree=copy_rl(tree); + + if(new_tree==NULL) { + fprintf(stderr,"Error creating new rl."); + return (FALSE); + } + // +#ifdef STATS + ADD_MEM_USAGE(new_tree); +#endif + + // return list reference + newid=YAP_MkIntTerm(PTR2ID(new_tree)); + if(!YAP_Unify(YAP_Deref(YAP_ARG2),newid)) + return (FALSE); + return(TRUE); +} +/* + * + * + */ +static +int +p_rl_size(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1),t2=YAP_Deref(YAP_ARG2),t_size; + IDTYPE id; + RL_Tree* tree; + unsigned int size; + + if (YAP_IsVarTerm(t1)) + return(FALSE); + + id = YAP_IntOfTerm(t1); + tree=ID2PTR(id); + + size=tree->size*sizeof(RL_Node)+sizeof(RL_Tree); + t_size=YAP_MkIntTerm(size); + if(!YAP_Unify(YAP_Deref(YAP_ARG2),t_size) ) + return (FALSE); + + return(TRUE); +} +/* + * + * + */ +static +int +p_rl_mem_usage(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + + if(!YAP_Unify(t1,YAP_MkIntTerm(memory_usage)) ) + return (FALSE); + + return(TRUE); +} + +/* + */ +static +int +p_rl_free(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + IDTYPE id; + RL_Tree* tree; + + // Check args + if (YAP_IsVarTerm(t1)) + return(FALSE); + + id=YAP_IntOfTerm(t1); + tree=ID2PTR(id); +#ifdef STATS + FREE_MEM_USAGE(tree); +#endif + + free_rl(tree); + + return (TRUE); +} + +/* + * + * + */ +static +int +p_rl_set_in(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + YAP_Term t2=YAP_Deref(YAP_ARG2); + IDTYPE id; + NUM val; + RL_Tree *tree; + + // Check args + if (YAP_IsVarTerm(t1) || YAP_IsVarTerm(t2) ) + return(FALSE); + + id = YAP_IntOfTerm(t1); + val = YAP_IntOfTerm(t2); + + tree=ID2PTR(id); + +#ifdef STATS + STORE_TREE_SIZE(tree); + set_in_rl(tree,val,IN); + UPDATE_MEM_USAGE(tree); +#else + set_in_rl(tree,val,IN); +#endif + return (TRUE); +} + /* + * + * + */ +static +int +p_rl_in(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + YAP_Term t2=YAP_Deref(YAP_ARG2); + IDTYPE id; + NUM val; + RL_Tree *tree; + + // Check args + if (YAP_IsVarTerm(t1) || YAP_IsVarTerm(t2) ) + return(FALSE); + + id = YAP_IntOfTerm(t1); + val = YAP_IntOfTerm(t2); + + tree=ID2PTR(id); + + if ( in_rl(tree,val) ) + return (TRUE); + return (FALSE); +} +/* + * + * + */ +static +int +p_rl_set_out(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + YAP_Term t2=YAP_Deref(YAP_ARG2); + IDTYPE id; + NUM val; + RL_Tree *tree; + + // Check args + if (YAP_IsVarTerm(t1) || YAP_IsVarTerm(t2) ) + return(FALSE); + + id = YAP_IntOfTerm(t1); + val = YAP_IntOfTerm(t2); + + tree=ID2PTR(id); +#ifdef STATS + STORE_TREE_SIZE(tree); + set_in_rl(tree,val,OUT); + UPDATE_MEM_USAGE(tree); +#else + set_in_rl(tree,val,OUT); +#endif + return (TRUE); +} +/* + * + * + */ +static +int +p_rl_freeze(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + IDTYPE id; + RL_Tree *tree; + + // Check args + if (YAP_IsVarTerm(t1) ) + return(FALSE); + + id = YAP_IntOfTerm(t1); + tree=ID2PTR(id); + + +#ifdef STATS + STORE_TREE_SIZE(tree); + freeze_rl(tree); + UPDATE_MEM_USAGE(tree); +#else + freeze_rl(tree); +#endif + + return (TRUE); +} +/* + * + * + */ +static +int +p_rl_set_all_in(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + IDTYPE id; + RL_Tree *tree; + + // Check args + if (YAP_IsVarTerm(t1) ) + return(FALSE); + + id = YAP_IntOfTerm(t1); + tree=ID2PTR(id); + + +#ifdef STATS + STORE_TREE_SIZE(tree); + rl_all(tree,IN); + freeze_rl(tree); + UPDATE_MEM_USAGE(tree); +#else + rl_all(tree,IN); + freeze_rl(tree); +#endif + + return (TRUE); +} +/* + * + * + */ +static +int +p_rl_print(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + IDTYPE id; + RL_Tree *tree; + + // Check args + if (YAP_IsVarTerm(t1) ) { + fprintf(stderr,"Error printing tree.."); + return(FALSE); + } + id = YAP_IntOfTerm(t1); + tree=ID2PTR(id); + + display_tree(tree); + + return (TRUE); +} + + +/* ============================================================================== + * + * + */ +typedef struct { + YAP_Term last_solution; /* the last solution */ +} yap_back_data_type; + +yap_back_data_type *back_data; + +/* + * + * + */ +static +int +p_rl_b_in2(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + YAP_Term t2=YAP_Deref(YAP_ARG2); + IDTYPE id; + NUM val; + RL_Tree *tree; + + YAP_PRESERVED_DATA(back_data,yap_back_data_type); + id = YAP_IntOfTerm(t1); + tree=ID2PTR(id); + val=YAP_IntOfTerm(back_data->last_solution); + val=rl_next_in_bigger(tree,val); + if ( val > 0 && YAP_Unify(YAP_Deref(YAP_ARG2),YAP_MkIntTerm(val))) { + back_data->last_solution=YAP_MkIntTerm(val); + return TRUE; + } + YAP_cut_fail(); + return (FALSE); +} +static +int +p_rl_b_in1(void) { + + YAP_Term t1=YAP_Deref(YAP_ARG1); + YAP_Term t2=YAP_Deref(YAP_ARG2); + IDTYPE id; + NUM val; + RL_Tree *tree; + + // Check args + if (!YAP_IsIntTerm(t1)) { + YAP_cut_fail(); + return(FALSE); + } + if ( YAP_IsVarTerm(t2) ) { + // return all in through backtracking + YAP_PRESERVE_DATA(back_data,yap_back_data_type); + back_data->last_solution = YAP_MkIntTerm(0); + return p_rl_b_in2(); + } else { + id = YAP_IntOfTerm(t1); + tree=ID2PTR(id); + val = YAP_IntOfTerm(t2); + if ( in_rl(tree,val) ) { + YAP_cut_succeed(); + return (TRUE); + } + YAP_cut_fail(); + return (FALSE); + } +} +/* ******************************************************* */ +void init_rl(){ + + + YAP_UserCPredicate("rl_new", p_rl_new,2); // Maximum -> RangeID + YAP_UserCPredicate("rl_free", p_rl_free,1); // RangeId -> + YAP_UserCPredicate("rl_size", p_rl_size,2); // RangeId -> Size (in bytes) + YAP_UserCPredicate("rl_mem", p_rl_mem_usage,1); // -> TotalMemory (in bytes) + + YAP_UserCPredicate("rl_copy", p_rl_copy,2); // RangeId -> NewRangeId + YAP_UserCPredicate("rl_set_out", p_rl_set_out,2);// RangeId x Number -> + YAP_UserBackCPredicate("rl_in", p_rl_b_in1,p_rl_b_in2,2,sizeof(yap_back_data_type)); // +RangeId x ?Number + //YAP_UserCPredicate("rl_in", p_rl_in,2); // RangeId x Number -> + YAP_UserCPredicate("rl_set_in", p_rl_set_in,2); // RangeIdxNumber -> + YAP_UserCPredicate("rl_set_all_in", p_rl_set_all_in,1); // RangeId -> + + YAP_UserCPredicate("rl_print", p_rl_print,1); // RangeId -> + + YAP_UserCPredicate("rl_freeze", p_rl_freeze,1); // RangeId + + // fprintf(stderr,"Range list module succesfully loaded."); + //fflush(stderr); +}