package xxl.core.spatial.spatialBPlusTree;
import java.util.Iterator;
import java.util.List;
import xxl.core.collections.MappedList;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Functional.BinaryFunction;
import xxl.core.functions.Functional.UnaryFunction;
import xxl.core.spatial.rectangles.DoublePointRectangle;
/**
*
* @author d
*
*/
public class ZValueDistributionGenerator {
public static class Bucket{
double cost = 0;
int start = 0;
int end = 0;
Bucket predecessor = null;
int number = 0;
public Bucket(double cost, int start, int end,
Bucket predecessor,
int number) {
super();
this.cost = cost;
this.start = start;
this.end = end;
this.predecessor = predecessor;
this.number = number;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public Bucket getPredecessor() {
return predecessor;
}
public void setPredecessor(Bucket predecessor) {
this.predecessor = predecessor;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public String toString() {
return "Bucket [cost=" + cost + ", end=" + end + ", number="
+ number + ", predecessor=" + predecessor + ", start="
+ start + "]";
}
}
/**
*
* @param rectangles
* @param sfcMappingFunction
* @param costFunction
* @param b
* @param B
* @param n
* @return
*/
@SuppressWarnings("serial")
public static int[] computeDistribution(
List<DoublePointRectangle> rectangles,
final UnaryFunction<DoublePointRectangle, Long> sfcMappingFunction,
BinaryFunction<Long, Long, Double> costFunction, int b, int B, int n){
Bucket bucket = computeDistribution( new MappedList<DoublePointRectangle, Long>(rectangles,
new AbstractFunction<DoublePointRectangle, Long>() {
@Override
public Long invoke(DoublePointRectangle argument) {
return sfcMappingFunction.invoke(argument);
}
}),
createCostFunction(),
b, B, n);
int[] distr = getDistribution(bucket);
return distr;
}
/**
*
* @param rectangles
* @param sfcMappingFunction
* @param costFunction
* @param b
* @param B
* @param n
* @return
*/
@SuppressWarnings("serial")
public static int[] computeZKeysDistribution(
List<Long> zKeys,
int b,
int B,
int n){
Bucket bucket = computeDistribution(zKeys,
createCostFunction(),
b, B, n);
int[] distr = getDistribution(bucket);
return distr;
}
/**
*
* @param rectangles
* @param sfcMappingFunction
* @param costFunction
* @param b
* @param B
* @param n
* @return
*/
@SuppressWarnings("serial")
public static int[] computeZKeysDistributionApprox(
List<Long> zKeys,
int b,
int B){
Bucket bucket = computeDistributionApprox(zKeys,
createCostFunction(),
b, B);
int[] distr = getDistribution(bucket);
return distr;
}
/**
*
* @param zCodes
* @param costFunction
* @param b
* @param B
* @param n
* @return
*/
public static <T> Bucket computeDistribution(List<T> zCodes,
BinaryFunction<T, T, Double> costFunction,
int b, int B, int n){
// allocate array
Bucket[][] matrix = new Bucket[zCodes.size()][n];
//FIXME change to lazy computation assure that the input list is array!
double[] costs = precomputeCosts( zCodes,
costFunction, b);
// initialize first entries
for(int i = 0; i < B; i++){
matrix[i][0] = (i < b-1) ?
new Bucket(Double.MAX_VALUE, 0, i, null, 1) :
new Bucket(0, 0, i,null, 1);
}
//
for(int i = 1; i < n; i++){
//
int nMin = ((i+1) * b)-1;
int nMax = ((i+1) * B)-1;
// compute best cost for given j and i
for(int j = nMin; j < nMax && j < matrix.length ; j++){
// search for minimal cost
double minCost = Double.MAX_VALUE;
for(int l = b; j-l >= b && l < B; l++){
if (matrix[j - l-1][i-1] != null ){
double newNewCost = costs[j-l];
double lastRowCost = matrix[j-l-1][i-1].getCost();
double candidateCosts = lastRowCost + newNewCost;
if (candidateCosts < minCost){
minCost = candidateCosts;
matrix[j][i] = new Bucket(minCost, j - l, j,
matrix[j - l-1][i-1] ,
matrix[j - l-1][i-1].number + 1);
}
}
// otherwise there is no assignment possible for current j and n
}
}
}
if(matrix[zCodes.size()-1][n-1] == null){
throw new RuntimeException("No assignment Possible");
}
return matrix[zCodes.size()-1][n-1];
}
/**
*
* @param zCodes
* @param costFunction
* @param b
* @param B
* @param n
* @return
*/
public static <T> Bucket computeDistributionApprox(List<T> zCodes,
BinaryFunction<T, T, Double> costFunction,
int b, int B){
Bucket[] binCosts = new Bucket[zCodes.size()];
double[] costs = precomputeCosts(zCodes, costFunction, b);
// initialize first [b, B] buckets
// initialize first entries
for(int i = 0; i < B; i++){
binCosts[i] = (i < b-1) ?
new Bucket(Double.MAX_VALUE, 0, i, null, 1) :
new Bucket(0, 0, i,null, 1);
}
// compute costs
for(int i = 2*b-1; i < zCodes.size(); i ++){
// search for best costs strating from pos i
double bestCost = (binCosts[i] == null) ? Double.MAX_VALUE :
binCosts[i].cost;
for(int l = b; i-l >= b && l < B; l++){
double prefixCost = costs[i-l-1];
double binCost = binCosts[i-l-1].cost;
double candidateCost = prefixCost + binCost;
if( candidateCost < bestCost){
bestCost = candidateCost;
binCosts[i] = new Bucket(bestCost, i-l, i,
binCosts[i-l-1],
binCosts[i-l-1].number+1);
}
}
}
return binCosts[zCodes.size()-1];
}
/**
* computes array
* @param bucket
* @return
*/
public static int[] getDistribution(Bucket bucket){
int[] array = new int[bucket.number];
Bucket next = bucket;
for(int i = array.length-1; i >= 0 ; i--){
array[i] = next.end - next.start +1;
next = next.predecessor;
}
return array;
}
/**
* compute prefix as a cost function
* @return
*/
public static BinaryFunction<Long, Long, Double> createCostFunction(){
return new BinaryFunction<Long, Long, Double>() {
@Override
public Double invoke(Long arg0, Long arg1) {
// compute
long mask= 1L << 63;
int i;
for( i = 64; ((mask & arg0) == (mask & arg1)) & i >= 0; i--, mask = mask >> 1 );
return (double)(64-i);
}
};
}
/**
*
* @param <T>
* @param zCodes
* @param costFunction
* @param b
* @return
*/
protected static <T> double[] precomputeCosts(List<T> zCodes,
BinaryFunction<T, T, Double> costFunction, int b){
double[] costs = new double[zCodes.size()-1];
Iterator<T> zCodeIt = zCodes.iterator();
T currentzCode = null;
if(zCodeIt.hasNext()){
currentzCode = zCodeIt.next();
}else
throw new RuntimeException("z codes are empty!");
int index = 0;
while(zCodeIt.hasNext()){
T nextZcode = zCodeIt.next();
if(index >= b-1){
costs[index] = costFunction.invoke(currentzCode, nextZcode);
}
currentzCode = nextZcode;
index++;
}
return costs;
}
// /**
// * @param args
// */
// public static void main(String[] args) {
// BinaryFunction< Long, Long, Double> function = createCostFunction();
// double prefix = function.invoke(8L, 16L);
// System.out.println(prefix);
// }
}