/**
* File: $HeadURL: https://hdt-java.googlecode.com/svn/trunk/hdt-java/src/org/rdfhdt/hdt/compact/bitmap/AdjacencyList.java $
* Revision: $Rev: 191 $
* Last modified: $Date: 2013-03-03 11:41:43 +0000 (dom, 03 mar 2013) $
* Last modified by: $Author: mario.arias $
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Contacting the authors:
* Mario Arias: mario.arias@deri.org
* Javier D. Fernandez: jfergar@infor.uva.es
* Miguel A. Martinez-Prieto: migumar2@infor.uva.es
* Alejandro Andres: fuzzy.alej@gmail.com
*/
package org.rdfhdt.hdt.compact.bitmap;
import org.rdfhdt.hdt.compact.sequence.Sequence;
import org.rdfhdt.hdt.exceptions.NotFoundException;
/**
* @author mario.arias
*
*/
public class AdjacencyList {
private Sequence array;
private Bitmap bitmap;
/**
* @param array
* @param bitmap
*/
public AdjacencyList(Sequence array, Bitmap bitmap) {
super();
this.array = array;
this.bitmap = bitmap;
if(array.getNumberOfElements()!=bitmap.getNumBits()) {
throw new IllegalArgumentException("Adjacency list bitmap and array should have the same size");
}
}
/**
* Find pos of the list x
* @param x
* @return
*/
public final long find(long x) {
return x<=0 ? 0 : bitmap.select1(x)+1;
}
public final long findNext(long pos) {
return bitmap.selectNext1(pos);
}
/**
* Find the last pos of the list x
* @param x
* @return
*/
public final long last(long x) {
return bitmap.select1(x+1);
}
/**
* Find element y, in the list x
* @param x
* @param y
* @return
* @throws NotFoundException
*/
public final long find(long x, long y) throws NotFoundException {
// Find first and last element of the list.
long begin = find(x);
long end = last(x);
// Binary search y within the list
return binSearch(y, begin, end);
}
/**
* Find to which list x does the element at globalpos belongs
* @param globalpos
* @return
*/
public final long findListIndex(long globalpos) {
return bitmap.rank1(globalpos-1);
}
/**
* Count how many lists there are
* @return
*/
public final long countListsX() {
return bitmap.countOnes();
}
/**
* Count the number of items in list x
* @param x
* @return
*/
public long countItemsY(long x) {
return last(x)-find(x)+1;
}
public long search(long element, long begin, long end) throws NotFoundException {
if(end-begin>10) {
return binSearch(element, begin, end);
} else {
return linSearch(element, begin, end);
}
}
public long binSearch(long element, long begin, long end) throws NotFoundException {
while(begin<=end) {
long mid = (begin+end)/2;
long read = array.get(mid);
if(element>read) {
begin = mid+1;
} else if(element<read) {
end = mid-1;
} else {
return mid;
}
}
throw new NotFoundException();
}
public long linSearch(long element, long begin, long end) throws NotFoundException {
while(begin<=end) {
long read = array.get(begin);
if(read==element) {
return begin;
}
begin++;
}
throw new NotFoundException();
}
public final long get(long pos) {
return array.get(pos);
}
public final long getNumberOfElements() {
return array.getNumberOfElements();
}
/**
* Finds the next appearance of the element "element" starting at global pos: "oldpos" inclusive.
* @param oldpos Old global position to start searching.
* @param element Element to be searched
* @return Position of the next appearance, -1 if no more appearances.
*/
public long findNextAppearance(long oldpos, long element) {
// Keep doing binary search within each list until we find it.
// while(true) {
// long next = bitmap.selectNext1(oldpos+1);
// if(next==-1) {
// return -1;
// }
//// System.out.println("Current: "+oldpos+ " Next: "+next);
// try {
// long pos = binSearch(element, oldpos, next);
// return pos;
// } catch (NotFoundException e) {
// oldpos=next;
// }
// }
// Sequential approach (Faster if lists are short due to caching).
long pos = oldpos;
long y;
while(pos<array.getNumberOfElements()) {
y = array.get(pos);
if(y==element) {
return pos;
}
pos++;
}
return -1;
}
/**
* Finds the previous appearance of the element "element" starting at global pos: "oldpos" inclusive.
* @param oldpos Old global position to start searching.
* @param element Element to be searched
* @return Position of the next appearance, -1 if no more appearances.
*/
public long findPreviousAppearance(long old, long element) {
long y;
do {
y = array.get(old--);
} while(old>=0 && y!=element);
// No previous appearances of predicate
if(old<0) {
return -1;
}
return old+1;
}
public void dump() {
for(long i=0;i<getNumberOfElements();i++) {
System.out.print(" "+get(i));
if(i!=getNumberOfElements()) {
System.out.println(",");
}
}
System.out.println("");
for(long i=0;i<countListsX() && i<100; i++) {
System.out.print("List "+i+" [");
long base = find(i);
long items = countItemsY(i);
for(long j=0;j<countItemsY(i) && j<100; j++) {
System.out.print(get(base+j));
if(j!=items-1) {
System.out.print(',');
}
}
System.out.println("] ");
}
System.out.println();
}
}