/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lupos.optimizations.logical.statistics;
import java.util.ArrayList;
import java.util.List;
import lupos.datastructures.items.literal.LazyLiteral;
import lupos.datastructures.items.literal.Literal;
import lupos.misc.Tuple;
public class VarBucket implements Cloneable {
public Literal minimum = null;
public Literal maximum = null;
public List<Entry> selectivityOfInterval = new ArrayList<Entry>();
public double getSum() {
double sum = 0.0;
for (final Entry e : selectivityOfInterval) {
sum += e.selectivity;
}
return sum;
}
public double getSumDistinctLiterals() {
double sum = 0.0;
for (final Entry e : selectivityOfInterval) {
sum += e.distinctLiterals;
}
return sum;
}
public void multiplySelectivities(final double d) {
for (final Entry e : selectivityOfInterval) {
e.selectivity *= d;
e.distinctLiterals *= d;
}
}
public void multiplySelectivities(final VarBucket vb, final int factor) {
Literal lowerLimit = null;
boolean first = true;
int index = 0;
final List<Entry> le = new ArrayList<Entry>(selectivityOfInterval
.size());
for (final Entry e : selectivityOfInterval) {
final Tuple<Integer, Double> result;
if (first) {
result = vb.getEstimatedSelectivity(this, e, lowerLimit);
first = false;
} else
result = vb.getEstimatedSelectivity(this, e, lowerLimit, index);
final double estSel = result.getSecond();
index = result.getFirst() - 1;
final double div = (factor == 0) ? estSel : estSel / factor;
e.selectivity *= div;
e.distinctLiterals *= div;
lowerLimit = e.literal;
if (e.selectivity > 0.0)
le.add(e);
}
selectivityOfInterval = le;
}
private int searchLowerLimit(final Literal literal, final int left,
final int right) {
if (right - left == 0) {
final int comp = this.selectivityOfInterval.get(left).literal
.compareToNotNecessarilySPARQLSpecificationConform(literal);
if (comp == 0 || comp < 0)
return left;
else
// if(comp>0)
return left - 1;
} else if (right - left == 1) {
final int comp = this.selectivityOfInterval.get(left).literal
.compareToNotNecessarilySPARQLSpecificationConform(literal);
if (comp == 0)
return left;
else if (comp > 0)
return left - 1;
return right;
} else {
final int middle = (left + right) / 2;
final int comp = this.selectivityOfInterval.get(middle).literal
.compareToNotNecessarilySPARQLSpecificationConform(literal);
if (comp == 0) {
return middle;
} else if (comp < 0) {
return searchLowerLimit(literal, middle + 1, right);
} else {
return searchLowerLimit(literal, left, middle - 1);
}
}
}
protected Tuple<Integer, Double> getEstimatedSelectivity(
final VarBucket vb, final Entry e, final Literal lowerLimit) {
double result = 0.0;
int overlappedInterval = -1;
if (lowerLimit != null) {
// first determine the interval, which overlaps with the lower
// limit
overlappedInterval = searchLowerLimit(lowerLimit, 0,
this.selectivityOfInterval.size() - 1);
final Literal lowerLimit2 = (overlappedInterval < 0) ? null
: this.selectivityOfInterval.get(overlappedInterval).literal;
if (overlappedInterval + 1 < this.selectivityOfInterval.size()) {
final Entry e3 = this.selectivityOfInterval
.get(overlappedInterval + 1);
if (e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(lowerLimit) > 0) {
int intervalSize;
if (lowerLimit2 == null)
intervalSize = distance(e3.literal, null);
else
intervalSize = distance(e3.literal, lowerLimit2);
int fraction;
// does e3 completely contain e?
if (e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(e.literal) > 0) {
fraction = distance(e.literal, lowerLimit);
double sel = (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
sel *= (intervalSize == 0) ? fraction
: (double) fraction / intervalSize;
return new Tuple<Integer, Double>(
overlappedInterval + 1, sel);
} else {
fraction = distance(e3.literal, lowerLimit);
}
double sel = (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
sel *= (intervalSize == 0) ? fraction : (double) fraction
/ intervalSize;
result = sel;
}
}
}
// then all intervals, which are completely contained in the given
// interval
Literal lowerLimit2 = null;
int index = overlappedInterval + 1;
boolean next = (lowerLimit == null);
while (index < this.selectivityOfInterval.size()) {
final Entry e3 = this.selectivityOfInterval.get(index);
if (next) {
final int comp = e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(e.literal);
if (comp > 0) {
// at last the interval, which overlaps with the upper
// limit
int intervalSize;
if (lowerLimit2 == null)
intervalSize = distance(e3.literal, null);
else
intervalSize = distance(e3.literal, lowerLimit2);
final int fraction = distance(e.literal, lowerLimit);
double sel = (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
sel *= (intervalSize == 0) ? fraction : (double) fraction
/ intervalSize;
result *= sel;
break;
} else {
result = (e3.distinctLiterals == 0) ? result
+ e3.selectivity : result
+ (e3.selectivity / e3.distinctLiterals);
}
if (comp == 0)
break;
} else if (e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(lowerLimit) > 0) {
next = true;
}
lowerLimit2 = e3.literal;
index++;
}
return new Tuple<Integer, Double>(index, result);
}
protected Tuple<Integer, Double> getEstimatedSelectivity(
final VarBucket vb, final Entry e, final Literal lowerLimit,
int overlappedInterval) {
double result = 0.0;
if (lowerLimit != null) {
while (overlappedInterval + 1 < this.selectivityOfInterval.size()) {
// first determine the interval, which overlaps with the
// lower
// limit
final Literal lowerLimit2 = (overlappedInterval < 0) ? null
: this.selectivityOfInterval.get(overlappedInterval).literal;
final Entry e3 = this.selectivityOfInterval
.get(overlappedInterval + 1);
if (e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(lowerLimit) > 0) {
int intervalSize;
if (lowerLimit2 == null)
intervalSize = distance(e3.literal, null);
else
intervalSize = distance(e3.literal, lowerLimit2);
int fraction;
// does e3 completely contain e?
if (e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(e.literal) > 0) {
fraction = distance(e.literal, lowerLimit);
double sel = (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
sel *= (intervalSize == 0) ? fraction
: (double) fraction / intervalSize;
return new Tuple<Integer, Double>(
overlappedInterval + 1, sel);
} else {
fraction = distance(e3.literal, lowerLimit);
}
final double sel = (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
result = sel
* ((intervalSize == 0) ? fraction
: (double) fraction / intervalSize);
break;
}
overlappedInterval++;
}
}
// then all intervals, which are completely contained in the given
// interval
Literal lowerLimit2 = null;
int index = overlappedInterval + 1;
boolean next = (lowerLimit == null);
while (index < this.selectivityOfInterval.size()) {
final Entry e3 = this.selectivityOfInterval.get(index);
if (next) {
final int comp = e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(e.literal);
if (comp > 0) {
// at last the interval, which overlaps with the upper
// limit
int intervalSize;
if (lowerLimit2 == null)
intervalSize = distance(e3.literal, null);
else
intervalSize = distance(e3.literal, lowerLimit2);
final int fraction = distance(e.literal, lowerLimit);
double sel = (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
sel *= (intervalSize == 0) ? fraction : fraction
/ intervalSize;
result += sel;
break;
} else {
result += (e3.distinctLiterals == 0.0) ? e3.selectivity
: e3.selectivity / e3.distinctLiterals;
}
if (comp == 0)
break;
} else if (e3.literal
.compareToNotNecessarilySPARQLSpecificationConform(lowerLimit) > 0) {
next = true;
}
lowerLimit2 = e3.literal;
index++;
}
return new Tuple<Integer, Double>(index, result);
}
public int distance(final Literal la, final Literal lb) {
if (la == null) {
if (lb == null)
return 0;
else
return distance(lb, la);
}
if (la instanceof LazyLiteral) {
if (lb == null)
return ((LazyLiteral) la).getCode();
else
return Math.abs(((LazyLiteral) la).getCode()
- ((LazyLiteral) lb).getCode());
} else {
final String a = (la == null) ? "" : la.toString();
final String b = (lb == null) ? "" : lb.toString();
for (int i = 0; i < a.length(); i++) {
if (i + 1 > b.length())
return a.charAt(i);
if (a.charAt(i) != b.charAt(i)) {
return Math.abs(b.charAt(i) - a.charAt(i));
}
}
return 0;
}
}
@Override
public Object clone() {
final VarBucket vb = new VarBucket();
vb.maximum = this.maximum;
vb.minimum = this.minimum;
for (final Entry e : selectivityOfInterval) {
vb.selectivityOfInterval.add((Entry) e.clone());
}
return vb;
}
public void add(final VarBucket vb) {
Literal lowerLimit = null;
boolean first = true;
int index = 0;
for (final Entry e : selectivityOfInterval) {
final Tuple<Integer, Double> result;
if (first) {
result = vb.getEstimatedSelectivity(this, e, lowerLimit);
first = false;
} else
result = vb.getEstimatedSelectivity(this, e, lowerLimit, index);
final double estSel = result.getSecond();
index = result.getFirst();
e.selectivity *= estSel;
e.distinctLiterals *= estSel;
lowerLimit = e.literal;
}
}
};