package org.streaminer.stream.quantile.rss; import java.io.Serializable; import java.util.BitSet; import java.util.Random; /** * This class is part of the rss algorithm. It covers a data-structure that represents a * set of intervals of a specified dyadic width and covers a range up to a choosable maximum. * * @author Carsten Przyluczky * */ public class Subset implements Serializable { private static final long serialVersionUID = 1L; private int valuesInSubsetCount = 0; private int level = 0; int intervallWidth = 0; int intervalCount = 0; int maxValue = 0; BitSet intervallBitVector; // ---------------------------------------------------------------------------------- constructor /** * The constructor calculates needed interval count, and selects intervals randomly * * @param level the dyadic level the subset shall handle * @param maxValue the highest value the subset must represent */ public Subset(int level, int maxValue){ intervallBitVector = new BitSet(); this.level = level; intervallWidth = (int)Math.pow(2.0d, (double)level); this.maxValue = maxValue; int logOfValue = (int) (Math.log10((double)maxValue) / Math.log10(2.0)) + 1; while(!selectSubsets((int)Math.pow(2, (double)logOfValue))){ // just try again } } // ---------------------------------------------------------------------------------- main functions /** * this method randomly selects intervals to compose the subset * it permits empty subsets * * @param newMaxValue * @return true if a subset has been selected, false otherwise */ boolean selectSubsets(int newMaxValue){ int lowerBound = 0; //int upperBound = Math.max(intervallWidth,1); // currently not used Random random = new Random(); boolean bIntervalselected = false; intervalCount = (int)((double)(newMaxValue - lowerBound) / (double)intervallWidth); for(int i = 0; i < intervalCount; i++){ double event = random.nextDouble(); if(event >= 0.5){ intervallBitVector.set(i); bIntervalselected = true; } lowerBound += intervallWidth; //upperBound += intervallWidth; // currently not used } return bIntervalselected; } /** * this method adds a value to the subset * * @param value the value of the new element */ public void addElement(double value){ int lowerBound = 0; int upperBound = Math.max(intervallWidth,1); for(int i = 0; i < intervalCount; i++){ if(intervallBitVector.get(i)){ if( value >= (double)lowerBound && value <= (double)(upperBound - 1)){ this.valuesInSubsetCount++; //System.out.println("value " + value + " fits into "+interval ); return; } } lowerBound += intervallWidth; upperBound += intervallWidth; } } /** * A better toString, to gain more information */ @Override public String toString() { String output = "Subset level = " + level + " valuesInSubsetCount = " + valuesInSubsetCount + " intervall width " + intervallWidth + "\n intervalls:\n " ; int count = 0; int lowerBound = 0; int upperBound = Math.max(intervallWidth,1); for(int i = 0; i < intervalCount; i++){ if(intervallBitVector.get(i)){ output = output + lowerBound + " - " + (upperBound - 1) + "\n" ; count++; } lowerBound += intervallWidth; upperBound += intervallWidth; } return output + " count = " + count; } /** * Checks if the specified interval is selected in our subset * * @param lowerBound the lower bound of the interval the needs to be checked * @param upperBound the upper bound of the interval the needs to be checked */ public boolean canHandleInterval(int lowerBound, int upperBound){ int lower = 0; int upper = Math.max(intervallWidth,1); for(int i = 0; i < intervalCount; i++){ if(intervallBitVector.get(i)){ if( lower == lowerBound && (upper - 1) == upperBound){ return true; } } lower += intervallWidth; upper += intervallWidth; } return false; } // ---------------------------------------------------------------------------------- get/set public int getValuesInSubsetCount() { return valuesInSubsetCount; } public int getIntercalWidth(){ return this.intervallWidth; } }