/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2013 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
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 3 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, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.indexStructures.rtrees;
import java.util.HashMap;
import java.util.Map;
import xxl.core.functions.Functional.UnaryFunction;
import xxl.core.spatial.rectangles.DoublePointRectangle;
import xxl.core.spatial.rectangles.Rectangle;
/**
* This class implements generic partitioning methods.
*
*
*
* @see D Achakeev, B Seeger and P Widmayer:
* "Sort-based query-adaptive loading of R-trees" in CIKM 2012
*
*/
public class GenericPartitioner {
/**
* new Interface List Processor Interface for OPT computation
*
*
*/
public static interface CostFunctionArrayProcessor<T extends Rectangle>{ //TODO
/**
* Computes costs of starting from position startIndex
* @param rectangles
* @param b
* @param B
* @param startIndex
* @return output of cost array [startIndex, startIndex-1, ... , startIndex-B]
*/
public double[] processList(
T[] rectangles,
int b,
int B,
int startIndex);
/**
* Computes initial costs starting from 0
*
*
* @param rectangles
* @param b
* @param B
* @return output of cost array [1, 2, ... ,B]
*/
public double[] processInitialList( T[] rectangles, int b, int B);
/**
*
* returns costs array for each sub sequence i,j
* [i][j] is a cost for a sub sequence (i, ..., j) with i <= j
* @param rectangles TODO
*
* @return
* @throws UnsupportedOperationException
*/
public double[][] precomputeAllCosts(T[] rectangles) throws UnsupportedOperationException;
public void reset();
}
/**
* Bucket object to represent current costs
*
*/
public static class Bucket{
public double cost;
public int start;
public int end;
public Bucket predecessor;
public int number = 0;
public Rectangle rec;
/**
*
* @param cost
* @param start
* @param end
* @param predecessor
*/
public Bucket(double cost, int start, int end, Bucket predecessor) {
this(cost, start, end, predecessor, 0);
}
/**
*
* @param cost
* @param start
* @param end
* @param predecessor
* @param number
*/
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;
}
@Override
public String toString() {
return "Bucket [cost=" + cost + ", end=" + end + ", number="
+ number + ", predecessor=" + predecessor + ", start="
+ start + "]";
}
}
/**
*
* @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;
}
/***************************************************************************************************
* Partitioner:
**************************************************************************************************/
/**
* unbounded variant
* Thorsten Suel algorithm
* Time Complexity k*N*N
*
* nopt(i,k) = max_0<=j<=i {nopt(i-j, k-1) + costF([i-j+1, i]) }
*
*/
@SuppressWarnings("rawtypes")
public static Bucket[][] computeNOPT(DoublePointRectangle[] rectangles, int n,
CostFunctionArrayProcessor processor){
Bucket[][] costMatrix = new Bucket[n][rectangles.length];
double[][] allCosts = processor.precomputeAllCosts(rectangles);
// step 1 compute cost forward as starting point of n = 1
for(int i = 0; i < rectangles.length; i++){
costMatrix[0][i] = new Bucket(allCosts[0][i], 0, i, null, 1);
}
// process main loop
for(int i = 1; i < n; i++){
// compute best cost for given j and i
for(int j = i; j < rectangles.length; j++){
// search for minimal cost
double minCost = Double.MAX_VALUE;
for(int l = j; l >= i; l--){
double newNewCost = allCosts[l][j];
double lastRowCost = costMatrix[i-1][l-1].cost;
double candidateCosts = lastRowCost + newNewCost;
if (candidateCosts < minCost){
minCost = candidateCosts;
costMatrix[i][j] = new Bucket(minCost, l, j,
costMatrix[i-1][l-1],
costMatrix[i-1][l-1].number+1);
}
}
}
}
return costMatrix;
}
/**
* non weighted version
* @param rectangles
* @param b
* @param B
* @param n
* @param processor
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Bucket[][] computeOPTF(DoublePointRectangle[] rectangles, int b, int B, int n,
CostFunctionArrayProcessor processor){
Bucket[][] costMatrix = new Bucket[n][rectangles.length];
double[] costs = processor.processInitialList(rectangles, b, B);
for(int i = 0; i < B; i++){
costMatrix[0][i] = (i < b-1) ? // TODO
new Bucket(Double.MAX_VALUE, 0, i, null, 1) :
new Bucket(costs[i], 0, i, null, 1);
}
for(int i = 1; i < n; i++){
int nMin = ((i+1) * b)-1;
int nMax = (((i+1) * B)-1 >= rectangles.length) ? rectangles.length-1 : ((i+1) * B)-1 ;
// compute best cost for given j and i
for(int j = nMin; j <= nMax ; j++){
// search for minimal cost
double minCost = Double.MAX_VALUE;
costs = processor.processList(rectangles, b, B, j);
for(int l = b-1; j-l >= b && l < B; l++){
// check if it possible assignment exists
if (costMatrix[i-1][j-l-1] != null ){
double newNewCost = costs[l];
double lastRowCost = costMatrix[i-1][j-l-1].cost;
double candidateCosts = lastRowCost + newNewCost;
if (candidateCosts < minCost){
minCost = candidateCosts;
costMatrix[i][j] = new Bucket(minCost, j-l, j,
costMatrix[i-1][j-l-1] ,
costMatrix[i-1][j-l-1].number+1);
}
}
// otherwise there is no assignment possible for current j and n
}
}
}
return costMatrix;
}
/**
*
*
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Bucket[] computeGOPT(DoublePointRectangle[] rectangles,
int b, int B,
CostFunctionArrayProcessor arrayProcessor){
Bucket[] costArray = new Bucket[rectangles.length];
Bucket dummy = new Bucket(Double.MAX_VALUE, 0, 0, null);
int index = 0;
for(int t = index; t < b; t++ ){ // TODO initial computation
costArray[t]= dummy;
index = t;
}
for(int t = index; t < rectangles.length; t ++ ){
double[] costs = arrayProcessor.processList(rectangles, b, B, t);
double mincost = (costArray[t] != null) ? costArray[t].cost : dummy.cost;
int st = 0;
int et = 0;
Bucket argMin = null; // look back for a better costs
for(int j= b-1 ; j < B ; j++){
if(t-j == 0){
Bucket interval = new Bucket(costs[j], 0, t, null);
interval.number += 1;
costArray[t]= interval;
}else if (t-j > 0){
Bucket candidate = costArray[t-j-1];
double costOfBucket = costs[j];
double costOfExtension = candidate.cost + costOfBucket;
if(costOfExtension < mincost){
// overwrite
argMin = candidate;
mincost = costOfExtension;
st = t-j;
et = t;
// overwrite
Bucket newBck = new Bucket(mincost, st, et, argMin, argMin.number +1);
costArray[t]= newBck;
}
}
}
}
return costArray;
}
/*****************************************************************************************************
* Array Processors
****************************************************************************************************/
/**
*
* Default generic OPT list processor. Parameterized with a UnarayFunction DoublePointRectangle Double
*
*/
public static class DefaultArrayProcessor implements CostFunctionArrayProcessor<DoublePointRectangle>{
final UnaryFunction< DoublePointRectangle, Double> costFunction;
Map<Integer, double[]> costs = null;
double[][] cArray = null;
boolean mode = false;
int n = 0;
public DefaultArrayProcessor (
UnaryFunction<DoublePointRectangle, Double> costFunction) {
super();
this.costFunction = costFunction;
costs = new HashMap<Integer, double[]>();
}
public DefaultArrayProcessor (
UnaryFunction<DoublePointRectangle, Double> costFunction, int n) {
super();
this.costFunction = costFunction;
cArray = new double[n][];
this.n = n;
}
public DefaultArrayProcessor (
UnaryFunction<DoublePointRectangle, Double> costFunction, boolean mode) {
super();
this.costFunction = costFunction;
this.mode = mode;
costs = new HashMap<Integer, double[]>();
}
@Override
public double[] processList(
DoublePointRectangle[] rectangles,
int b,
int B,
int startIndex) {
if (mode)
return processListWithout(
rectangles,
b,
B,
startIndex);
if(cArray !=null)
return processListArray(
rectangles,
b,
B,
startIndex);
if (!costs.containsKey(startIndex)){
double[] array = new double[B];
DoublePointRectangle universe = null;
for(int i = 0, j = startIndex; j >=0 && i < B ; i++, j--){
if(universe == null)
universe = new DoublePointRectangle(rectangles[j]);
else
universe.union(rectangles[j]);
if (i >=b-1 ){
array[i] = costFunction.invoke(universe);
}
}
costs.put(startIndex, array);
return array;
}
return costs.get(new Integer(startIndex));
}
private double[] processListArray(DoublePointRectangle[] rectangles,
int b,
int B,
int startIndex){
if (cArray[startIndex]==null){
double[] array = new double[B];
DoublePointRectangle universe = null;
for(int i = 0, j = startIndex; j >=0 && i < B ; i++, j--){
if(universe == null)
universe = new DoublePointRectangle(rectangles[j]);
else
universe.union(rectangles[j]);
if (i >=b-1 ){
array[i] = costFunction.invoke(universe);
}
}
cArray[startIndex] = array;
return array;
}
return cArray[startIndex];
}
private double[] processListWithout(
DoublePointRectangle[] rectangles,
int b,
int B,
int startIndex){
double[] array = new double[B];
DoublePointRectangle universe = null;
for(int i = 0, j = startIndex; j >=0 && i < B ; i++, j-- ){
if(universe == null)
universe = new DoublePointRectangle(rectangles[j]);
else
universe.union(rectangles[j]);
if (i >=b-1 ){
array[i] = costFunction.invoke(universe);
}
}
return array;
}
public void reset(){
costs = new HashMap<Integer, double[]>();
if(cArray != null){
cArray = new double[n][];
}
}
public double[] processInitialList( DoublePointRectangle[] rectangles, int b, int B){
double[] array = new double[B];
DoublePointRectangle universe = null;
for(int i = 0;i < B ; i++ ){
if(universe == null)
universe = new DoublePointRectangle(rectangles[i]);
else
universe.union(rectangles[i]);
array[i] = costFunction.invoke(universe);
}
return array;
}
@Override
public double[][] precomputeAllCosts(DoublePointRectangle[] rectangles)
throws UnsupportedOperationException {
double[][] costs = new double[rectangles.length][rectangles.length];
for(int i = 0; i < rectangles.length; i++){
DoublePointRectangle rec = null;
for(int j = i ; j <rectangles.length; j++){
if(rec == null){
rec = new DoublePointRectangle(rectangles[j]);
}
else{
rec.union(rectangles[j]);
}
costs[i][j] = costFunction.invoke(rec);
}
}
return costs;
}
}
}