/*
* Copyright (c) 2011-2015 EPFL DATA Laboratory
* Copyright (c) 2014-2015 The Squall Collaboration (see NOTICE)
*
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.epfl.data.squall.predicates;
import java.util.ArrayList;
import java.util.List;
import ch.epfl.data.squall.expressions.Addition;
import ch.epfl.data.squall.expressions.ValueExpression;
import ch.epfl.data.squall.expressions.ValueSpecification;
import ch.epfl.data.squall.types.IntegerType;
import ch.epfl.data.squall.types.NumericType;
import ch.epfl.data.squall.types.Type;
import ch.epfl.data.squall.visitors.PredicateVisitor;
public class ComparisonPredicate<T extends Comparable<T>> implements Predicate {
public static void main(String[] args) {
ComparisonPredicate<Integer> comparison = new ComparisonPredicate<Integer>(
ComparisonPredicate.SYM_BAND_WITH_BOUNDS_OP, 10,
new IntegerType());
int x1 = 0;
int y1 = 50;
int x2 = 10;
int y2 = 55;
System.out.println("1IsCandidate Should be false "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 10;
x2 = 49;
y2 = 23;
System.out.println("2IsCandidate Should be false "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 40;
x2 = 49;
y2 = 50;
System.out.println("3IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 50;
x2 = 49;
y2 = 50;
System.out.println("4IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 60;
x2 = 49;
y2 = 62;
System.out.println("5IsCandidate Should be false "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 59;
x2 = 49;
y2 = 162;
System.out.println("6IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 53;
x2 = 49;
y2 = 162;
System.out.println("7IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 1;
x2 = 49;
y2 = 34;
System.out.println("8IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 1;
x2 = 49;
y2 = 33;
System.out.println("9IsCandidate Should be false "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 1;
x2 = 49;
y2 = 36;
System.out.println("10IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 1;
x2 = 49;
y2 = 48;
System.out.println("11IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 1;
x2 = 88;
y2 = 48;
System.out.println("12IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
x1 = 44;
y1 = 54;
x2 = 44;
y2 = 54;
System.out.println("13IsCandidate Should be true "
+ comparison.isCandidateRegion(x1, y1, x2, y2));
}
private static final long serialVersionUID = 1L;
public static final int EQUAL_OP = 0;
public static final int NONEQUAL_OP = 1;
public static final int LESS_OP = 2;
public static final int NONLESS_OP = 3;
public static final int GREATER_OP = 4;
public static final int NONGREATER_OP = 5;
public static final int SYM_BAND_WITH_BOUNDS_OP = 6;
public static final int SYM_BAND_NO_BOUNDS_OP = 7;
public static final int BPLUSTREE = 0;
public static final int BALANCEDBINARYTREE = 1;
private Object _diff;
private int indexType; // Either B+tree or BBinarytree
private ValueExpression<T> _ve1, _ve2;
private Type<T> _wrapper;
private int _operation;
// for other operations
public ComparisonPredicate(int op) {
_operation = op;
}
// for band operations
public ComparisonPredicate(int op, int diff, Type<T> typeConversion) {
_operation = op;
_diff = diff;
_wrapper = typeConversion;
}
public ComparisonPredicate(int operation, ValueExpression<T> ve1,
ValueExpression<T> ve2) {
_operation = operation;
_ve1 = ve1;
_ve2 = ve2;
}
public ComparisonPredicate(int operation, ValueExpression<T> ve1,
ValueExpression<T> ve2, int difference) {
this(operation, ve1, ve2);
_diff = difference;
}
public ComparisonPredicate(int operation, ValueExpression<T> ve1,
ValueExpression<T> ve2, int difference, int inequalityIndexType) {
_operation = operation;
_ve1 = ve1;
_ve2 = new Addition(ve2, new ValueSpecification(new IntegerType(),
difference));
_diff = Integer.valueOf(-2 * difference);
indexType = inequalityIndexType;
}
public ComparisonPredicate(ValueExpression<T> ve1, ValueExpression<T> ve2) {
this(EQUAL_OP, ve1, ve2);
}
@Override
public void accept(PredicateVisitor pv) {
pv.visit(this);
}
public Object getDiff() {
return _diff;
}
public List<ValueExpression> getExpressions() {
final List<ValueExpression> result = new ArrayList<ValueExpression>();
result.add(_ve1);
result.add(_ve2);
return result;
}
public int getInclusiveDiff() {
if (_operation == ComparisonPredicate.EQUAL_OP) {
return 0;
} else if (_operation == ComparisonPredicate.SYM_BAND_NO_BOUNDS_OP) {
return ((Integer) _diff) - 1;
} else if (_operation == ComparisonPredicate.SYM_BAND_WITH_BOUNDS_OP) {
return (Integer) _diff;
} else {
throw new RuntimeException("Unsupported operation " + _operation);
}
}
public int getIndexType() {
return indexType;
}
@Override
public List<Predicate> getInnerPredicates() {
return new ArrayList<Predicate>();
}
// used in sampling matrix generation
public List<T> getJoinableKeys(T key) {
NumericType numWrapper = (NumericType) _wrapper;
List<T> joinableKeys = new ArrayList<T>();
switch (_operation) {
case EQUAL_OP:
joinableKeys.add(key);
break;
case SYM_BAND_WITH_BOUNDS_OP:
case SYM_BAND_NO_BOUNDS_OP:
int range = (Integer) _diff;
if (_operation == SYM_BAND_WITH_BOUNDS_OP) {
range += 1;
}
joinableKeys.add(key);
T decrementing = key;
T incrementing = key;
for (int i = 1; i < range; i++) {
decrementing = (T) numWrapper.minDecrement(decrementing);
joinableKeys.add(decrementing);
incrementing = (T) numWrapper.minIncrement(incrementing);
joinableKeys.add(incrementing);
}
break;
default:
throw new RuntimeException("Unsupported operation " + _operation);
}
return joinableKeys;
}
public int getOperation() {
return _operation;
}
private String getOperationStr() {
String result = null;
switch (_operation) {
case NONEQUAL_OP:
result = " != ";
break;
case EQUAL_OP:
result = " = ";
break;
case LESS_OP:
result = " < ";
break;
case NONLESS_OP:
result = " >= ";
break;
case GREATER_OP:
result = " > ";
break;
case NONGREATER_OP:
result = " <= ";
break;
}
return result;
}
public int getOperator(boolean inverse) {
int result = 0;
if (inverse)
switch (_operation) {
case NONEQUAL_OP:
result = NONEQUAL_OP;
break;
case EQUAL_OP:
result = EQUAL_OP;
break;
case LESS_OP:
result = GREATER_OP;
break;
case NONLESS_OP:
result = NONGREATER_OP;
break;
case GREATER_OP:
result = LESS_OP;
break;
case NONGREATER_OP:
result = NONLESS_OP;
break;
}
else
result = _operation;
return result;
}
public T getType() {
return (T) _ve1.getType().getInitialValue();
}
public Type<T> getwrapper() {
return _wrapper;
}
// used for direct key comparison
// ranges are inclusive , e.g. [x1, x2]
public boolean isCandidateRegion(T x1, T y1, T x2, T y2) {
final int comparedUpperLower = x2.compareTo(y1);
final int comparedLowerUpper = x1.compareTo(y2);
// x2 >= y1 && x1 <= y2
// equivalent to y1 <= x2 && y2 >= x1
boolean doesIntersect = (comparedUpperLower >= 0 && comparedLowerUpper <= 0);
boolean result = false;
switch (_operation) {
case EQUAL_OP:
result = doesIntersect;
break;
case NONEQUAL_OP:
result = true; // everyone is a candidate cell (assuming that each
// range has more than one join attribute
break;
case LESS_OP:
result = (comparedLowerUpper < 0);
break;
case NONLESS_OP:
result = (comparedUpperLower >= 0);
break;
case GREATER_OP:
result = (comparedUpperLower > 0);
break;
case NONGREATER_OP:
result = (comparedLowerUpper <= 0);
break;
case SYM_BAND_WITH_BOUNDS_OP:
case SYM_BAND_NO_BOUNDS_OP:
if (doesIntersect) {
result = true;
break;
}
// no intersection
double actualDiff12 = _wrapper.getDistance(y1, x2);
double actualDiff21 = _wrapper.getDistance(x1, y2);
if (_operation == SYM_BAND_WITH_BOUNDS_OP) {
// TODO generalize to more _diff types
result = (actualDiff12 >= 0 && actualDiff12 <= (Integer) _diff)
|| (actualDiff21 >= 0 && actualDiff21 <= (Integer) _diff);
} else if (_operation == SYM_BAND_NO_BOUNDS_OP) {
// TODO generalize to more _diff types
result = (actualDiff12 >= 0 && actualDiff12 < (Integer) _diff)
|| (actualDiff21 >= 0 && actualDiff21 < (Integer) _diff);
}
break;
default:
throw new RuntimeException("Unsupported operation " + _operation);
}
return result;
}
@Override
public boolean test(List<String> tupleValues) {
Comparable val1 = _ve1.eval(tupleValues);
Comparable val2 = _ve2.eval(tupleValues);
// All the Numeric types are converted to double,
// because different types cannot be compared
if (val1 instanceof Long)
val1 = (((Long) val1).doubleValue());
if (val2 instanceof Long)
val2 = (((Long) val2).doubleValue());
final int compared = val1.compareTo(val2);
boolean result = false;
switch (_operation) {
case EQUAL_OP:
result = (compared == 0);
break;
case NONEQUAL_OP:
result = (compared != 0);
break;
case LESS_OP:
result = (compared < 0);
break;
case NONLESS_OP:
result = (compared >= 0);
break;
case GREATER_OP:
result = (compared > 0);
break;
case NONGREATER_OP:
result = (compared <= 0);
break;
default:
throw new RuntimeException("Unsupported operation " + _operation);
}
return result;
}
@Override
public boolean test(List<String> firstTupleValues,
List<String> secondTupleValues) {
final Comparable val1 = _ve1.eval(firstTupleValues);
final Comparable val2 = _ve2.eval(secondTupleValues);
final int compared = val1.compareTo(val2);
boolean result = false;
switch (_operation) {
case EQUAL_OP:
result = (compared == 0);
break;
case NONEQUAL_OP:
result = (compared != 0);
break;
case LESS_OP:
result = (compared < 0);
break;
case NONLESS_OP:
result = (compared >= 0);
break;
case GREATER_OP:
result = (compared > 0);
break;
case NONGREATER_OP:
result = (compared <= 0);
break;
default:
throw new RuntimeException("Unsupported operation " + _operation);
}
return result;
}
// used for direct key comparison
public boolean test(T key1, T key2) {
final int compared = key1.compareTo(key2);
boolean result = false;
switch (_operation) {
case EQUAL_OP:
result = (compared == 0);
break;
case NONEQUAL_OP:
result = (compared != 0);
break;
case LESS_OP:
result = (compared < 0);
break;
case NONLESS_OP:
result = (compared >= 0);
break;
case GREATER_OP:
result = (compared > 0);
break;
case NONGREATER_OP:
result = (compared <= 0);
break;
case SYM_BAND_WITH_BOUNDS_OP:
case SYM_BAND_NO_BOUNDS_OP:
int actualDiff = Math.abs((int) _wrapper.getDistance(key1, key2));
if (_operation == SYM_BAND_WITH_BOUNDS_OP) {
// TODO generalize to more _diff types
result = (actualDiff <= (Integer) _diff);
} else if (_operation == SYM_BAND_NO_BOUNDS_OP) {
// TODO generalize to more _diff types
result = (actualDiff < (Integer) _diff);
}
break;
default:
throw new RuntimeException("Unsupported operation " + _operation);
}
return result;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(_ve1.toString());
sb.append(getOperationStr());
sb.append(_ve2.toString());
return sb.toString();
}
}