All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rdfhdt.hdt.compact.bitmap.Bitmap375 Maven / Gradle / Ivy

/*
 * File: $HeadURL: https://hdt-java.googlecode.com/svn/trunk/hdt-java/src/org/rdfhdt/hdt/compact/bitmap/Bitmap375.java $
 * Revision: $Rev: 129 $
 * Last modified: $Date: 2013-01-21 00:08:27 +0000 (lun, 21 ene 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:               [email protected]
 *   Javier D. Fernandez:       [email protected]
 *   Miguel A. Martinez-Prieto: [email protected]
 */

package org.rdfhdt.hdt.compact.bitmap;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import org.rdfhdt.hdt.hdt.HDTVocabulary;
import org.rdfhdt.hdt.listener.ProgressListener;
import org.rdfhdt.hdt.util.BitUtil;
import org.rdfhdt.hdt.util.io.IOUtil;

/**
 * Implements an index on top of the Bitmap64 to solve select and rank queries more efficiently.
 * 
 * index -> O(n)
 * rank1 -> O(1)
 * select1 -> O(log log n)
 * 
 * @author mario.arias
 *
 */
public class Bitmap375 extends Bitmap64 implements ModifiableBitmap {
	// Constants
	private static final int BLOCKS_PER_SUPER = 4;
	
	// Variables
	private long pop;
	private long [] superBlocksLong;
	private int [] superBlocksInt;
	private byte [] blocks;
	private boolean indexUpToDate;
    
	public Bitmap375() {
		super();
	}
	
	public Bitmap375(long nbits) {
		super(nbits);
	}
	
	public Bitmap375(long nbits, InputStream in) throws IOException {
		this.numbits = nbits;
		int numwords = (int)numWords(numbits);
		words = new long[numwords];
		for(int i=0;i0) {
			// Read only used bits from last entry (byte aligned, little endian)
			int lastWordUsedBits = lastWordNumBits(numbits);
			words[numwords-1] = BitUtil.readLowerBitsByteAligned(lastWordUsedBits, in);
		}
	}
	
	public void dump() {
		int count = (int) numWords(this.numbits);
		for(int i=0;iInteger.MAX_VALUE) {
			superBlocksLong = new long[1+(words.length-1)/BLOCKS_PER_SUPER];
		} else {
			superBlocksInt = new int[1+(words.length-1)/BLOCKS_PER_SUPER];
		}
		blocks = new byte[words.length];
	
		long countBlock=0, countSuperBlock=0;
		int blockIndex=0, superBlockIndex=0;
		
		while(blockIndex=words.length) {
        	return false;
        }
        
        return (words[wordIndex] & (1L << bitIndex)) != 0;
	}
	
	@Override
	public void set(long bitIndex, boolean value) {
		indexUpToDate=false;
		super.set(bitIndex, value);
	}

	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#rank1(long)
	 */
	@Override
	public long rank1(long pos) {
		if(pos<0) {
			return 0;
		}
		if(!indexUpToDate) {
			updateIndex();
		}
		if(pos>=numbits) {
			return pop;
		}
		
		long superBlockIndex = pos/(BLOCKS_PER_SUPER*W);
		long superBlockRank;
		if(superBlocksLong!=null) {
			superBlockRank = superBlocksLong[(int)superBlockIndex];
		} else {
			superBlockRank = superBlocksInt[(int)superBlockIndex];
		}
		
		long blockIndex = pos/W;
		long blockRank = 0xFF & blocks[(int)blockIndex];
		
		long chunkIndex = W-1-pos%W;
		long block = words[(int)blockIndex] << chunkIndex;
		long chunkRank = Long.bitCount(block);
		
		return superBlockRank + blockRank + chunkRank;
	}

	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#rank0(long)
	 */
	@Override
	public long rank0(long pos) {
		return pos+1L-rank1(pos);
	}
	
    private static int binarySearch0(long[] a, int fromIndex, int toIndex, long key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            long midVal = mid * BLOCKS_PER_SUPER * W-a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }
    
    private static int binarySearch0(int[] a, int fromIndex, int toIndex, long key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            long midVal = mid * BLOCKS_PER_SUPER * W-a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#select0(long)
	 */
	@Override
	public long select0(long x) {
		//System.out.println("\t**Select0 for: "+ x);

		if(x<0) {
			return -1;
		}
		if(!indexUpToDate) {
			updateIndex();
		}
		if(x>numbits-pop) {
			return numbits;
		}

		// Search superblock (binary Search)
		int superBlockIndex;
		if(superBlocksLong!=null) {
			superBlockIndex = binarySearch0(superBlocksLong, 0, superBlocksLong.length, x);
		} else {
			superBlockIndex = binarySearch0(superBlocksInt, 0, superBlocksInt.length, x);
		}
		if(superBlockIndex<0) {
			// Not found exactly, gives the position where it should be inserted
			superBlockIndex = -superBlockIndex-2;
		} else if(superBlockIndex>0){
			// If found exact, we need to check previous block.
			superBlockIndex--;
		}
		
		long countdown;
		
		if(superBlocksLong!=null) {
			// If there is a run of many ones, two correlative superblocks may have the same value,
			// We need to position at the first of them.
			while(superBlockIndex>0 && (superBlockIndex*BLOCKS_PER_SUPER*W-superBlocksLong[superBlockIndex]>=x)) {
				superBlockIndex--;
			}

			countdown = x-(superBlockIndex*BLOCKS_PER_SUPER*W-superBlocksLong[superBlockIndex]);
		} else {
			// If there is a run of many ones, two correlative superblocks may have the same value,
			// We need to position at the first of them.
			while(superBlockIndex>0 && (superBlockIndex*BLOCKS_PER_SUPER*W-superBlocksInt[superBlockIndex]>=x)) {
				superBlockIndex--;
			}

			countdown = x-(superBlockIndex*BLOCKS_PER_SUPER*W-superBlocksInt[superBlockIndex]);
		}
		int blockIdx = superBlockIndex * BLOCKS_PER_SUPER;
	
		// Search block
		while(true) {
			if(blockIdx>= (superBlockIndex+1) * BLOCKS_PER_SUPER || blockIdx>=blocks.length) {
				blockIdx--;
				break;
			}
			if((0xFF & (W*(blockIdx%BLOCKS_PER_SUPER) - blocks[blockIdx]))>=countdown) {
				// We found it!
				blockIdx--;
				break;
			}
			blockIdx++;
		}
		if(blockIdx<0) {
			blockIdx=0;
		}
		countdown = countdown - (0xFF & ((blockIdx%BLOCKS_PER_SUPER)*W - blocks[blockIdx]));
		
		// Search bit inside block
		int bitpos = BitUtil.select0(words[blockIdx], (int)countdown);
		
		return ((long)blockIdx) * W + bitpos - 1;
	}
	
	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#select1(long)
	 */
	@Override
	public long select1(long x) {
		//System.out.println("\t**Select1 for: "+ x);
		
		if(x<0) {
			return -1;
		}
		if(!indexUpToDate) {
			updateIndex();
		}
		if(x>pop) {
			return numbits;
		}
		if(numbits==0) {
			return 0;
		}
		
		// Search superblock (binary Search)
		int superBlockIndex;
		if(superBlocksLong!=null) {
			superBlockIndex = Arrays.binarySearch(superBlocksLong, x);
		} else {
			superBlockIndex = Arrays.binarySearch(superBlocksInt, (int)x);
		}
		if(superBlockIndex<0) {
			// Not found exactly, gives the position where it should be inserted
			superBlockIndex = -superBlockIndex-2;
		} else if(superBlockIndex>0){
			// If found exact, we need to check previous block.
			superBlockIndex--;
		}
		
		long countdown;
		if(superBlocksLong!=null) {
			// If there is a run of many zeros, two correlative superblocks may have the same value,
			// We need to position at the first of them.
			while(superBlockIndex>0 && (superBlocksLong[superBlockIndex]>=x)) {
				superBlockIndex--;
			}
			countdown = x-superBlocksLong[superBlockIndex];
		} else {
			// If there is a run of many zeros, two correlative superblocks may have the same value,
			// We need to position at the first of them.
			while(superBlockIndex>0 && (superBlocksInt[superBlockIndex]>=x)) {
				superBlockIndex--;
			}
			countdown = x-superBlocksInt[superBlockIndex];			
		}
		int blockIdx = superBlockIndex * BLOCKS_PER_SUPER;

		// Search block
		while(true) {
			if(blockIdx>= (superBlockIndex+1) * BLOCKS_PER_SUPER || blockIdx>=blocks.length) {
				blockIdx--;
				break;
			}
			if((0xFF & blocks[blockIdx])>=countdown) {
				// We found it!
				blockIdx--;
				break;
			}
			blockIdx++;
		}
		if(blockIdx<0) {
			blockIdx=0;
		}
		countdown = countdown - (0xFF & blocks[blockIdx]);
		
		// Search bit inside block
		int bitpos = BitUtil.select1(words[blockIdx], (int)countdown);
		
		return ((long)blockIdx) * W + bitpos - 1;
	}
	
	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#countOnes()
	 */
	@Override
	public long countOnes() {
		return rank1(numbits);
	}

	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#countZeros()
	 */
	@Override
	public long countZeros() {
		return numbits-countOnes();
	}
	
	@Override
	public long getRealSizeBytes() {
		updateIndex();
		
		long accum = super.getRealSizeBytes();
		
		if(superBlocksLong!=null) {
			accum+=superBlocksLong.length*8;
		}
		
		if(superBlocksInt!=null) {
			accum+=superBlocksInt.length*4;
		}
		
		accum+=blocks.length;
		
		return accum;
	}
	
	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#getType()
	 */
	@Override
	public String getType() {
		return HDTVocabulary.BITMAP_TYPE_PLAIN;
	}

	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#save(java.io.OutputStream, hdt.listener.ProgressListener)
	 */
	@Override
	public void save(OutputStream output, ProgressListener listener) throws IOException {
		super.save(output, listener);
	}

	/* (non-Javadoc)
	 * @see hdt.compact.bitmap.Bitmap#load(java.io.InputStream, hdt.listener.ProgressListener)
	 */
	@Override
	public void load(InputStream input, ProgressListener listener) throws IOException {
		super.load(input, listener);
		updateIndex();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy