package edu.stanford.nlp.util;
/**
* A FuzzyInterval is an extension of Interval where not all endpoints are always
* specified or comparable. It is assumed that most endpoints will be comparable
* so that there is some meaningful relationship between most FuzzyIntervals
* @param <E> The type of the endpoint used in the FuzzyInterval.
*/
public class FuzzyInterval<E extends FuzzyInterval.FuzzyComparable<E>> extends Interval<E> {
/**
* Interface with a looser ordering than Comparable.
*
* If two objects are clearly comparable, compareTo will return -1,1,0 as before
* If two objects are not quite comparable, compareTo will return it's best guess
*
* @param <T> Type of the object to be compared
*/
public static interface FuzzyComparable<T> extends Comparable<T> {
/**
* Returns whether this object is comparable with another object
* @param other
* @return Returns true if two objects are comparable, false otherwise
*/
boolean isComparable(T other);
}
private FuzzyInterval(E a, E b, int flags) {
super(a,b,flags);
}
public static <E extends FuzzyComparable<E>> FuzzyInterval<E> toInterval(E a, E b) {
return toInterval(a,b,0);
}
public static <E extends FuzzyComparable<E>> FuzzyInterval<E> toInterval(E a, E b, int flags) {
int comp = a.compareTo(b);
if (comp <= 0) {
return new FuzzyInterval<>(a, b, flags);
} else {
return null;
}
}
public static <E extends FuzzyComparable<E>> FuzzyInterval<E> toValidInterval(E a, E b) {
return toValidInterval(a,b,0);
}
public static <E extends FuzzyComparable<E>> FuzzyInterval<E> toValidInterval(E a, E b, int flags) {
int comp = a.compareTo(b);
if (comp <= 0) {
return new FuzzyInterval<>(a, b, flags);
} else {
return new FuzzyInterval<>(b, a, flags);
}
}
public int getRelationFlags(Interval<E> other)
{
if (other == null) return 0;
int flags = 0;
boolean hasUnknown = false;
if (this.first.isComparable(other.first())) {
int comp11 = this.first.compareTo(other.first()); // 3 choices
flags |= toRelFlags(comp11, REL_FLAGS_SS_SHIFT);
} else {
flags |= REL_FLAGS_SS_UNKNOWN;
hasUnknown = true;
}
if (this.second.isComparable(other.second())) {
int comp22 = this.second.compareTo(other.second()); // 3 choices
flags |= toRelFlags(comp22, REL_FLAGS_EE_SHIFT);
} else {
flags |= REL_FLAGS_EE_UNKNOWN;
hasUnknown = true;
}
if (this.first.isComparable(other.second())) {
int comp12 = this.first.compareTo(other.second()); // 3 choices
flags |= toRelFlags(comp12, REL_FLAGS_SE_SHIFT);
} else {
flags |= REL_FLAGS_SE_UNKNOWN;
hasUnknown = true;
}
if (this.second.isComparable(other.first())) {
int comp21 = this.second.compareTo(other.first()); // 3 choices
flags |= toRelFlags(comp21, REL_FLAGS_ES_SHIFT);
} else {
flags |= REL_FLAGS_ES_UNKNOWN;
hasUnknown = true;
}
if (hasUnknown) {
flags = restrictFlags(flags);
}
flags = addIntervalRelationFlags(flags, hasUnknown);
return flags;
}
private int restrictFlags(int flags) {
// Eliminate inconsistent choices in flags
int f11 = extractRelationSubflags(flags, REL_FLAGS_SS_SHIFT);
int f22 = extractRelationSubflags(flags, REL_FLAGS_EE_SHIFT);
int f12 = extractRelationSubflags(flags, REL_FLAGS_SE_SHIFT);
int f21 = extractRelationSubflags(flags, REL_FLAGS_ES_SHIFT);
if (f12 == REL_FLAGS_AFTER ) {
f11 = f11 & REL_FLAGS_AFTER;
f21 = f21 & REL_FLAGS_AFTER;
f22 = f22 & REL_FLAGS_AFTER;
} else if ((f12 & REL_FLAGS_BEFORE) == 0) {
f11 = f11 & (REL_FLAGS_SAME | REL_FLAGS_AFTER);
f21 = f21 & (REL_FLAGS_SAME | REL_FLAGS_AFTER);
f22 = f22 & (REL_FLAGS_SAME | REL_FLAGS_AFTER);
}
if (f11 == REL_FLAGS_AFTER) {
f21 = f21 & REL_FLAGS_AFTER;
} else if (f11 == REL_FLAGS_BEFORE) {
f12 = f12 & REL_FLAGS_BEFORE;
} else if ((f11 & REL_FLAGS_BEFORE) == 0) {
f21 = f21 & (REL_FLAGS_SAME | REL_FLAGS_AFTER);
} else if ((f11 & REL_FLAGS_AFTER) == 0) {
f12 = f12 & (REL_FLAGS_SAME | REL_FLAGS_BEFORE);
}
if (f21 == REL_FLAGS_BEFORE) {
f11 = f11 & REL_FLAGS_BEFORE;
f12 = f12 & REL_FLAGS_BEFORE;
f22 = f22 & REL_FLAGS_BEFORE;
} else if ((f12 & REL_FLAGS_AFTER) == 0) {
f11 = f11 & (REL_FLAGS_SAME | REL_FLAGS_BEFORE);
f12 = f12 & (REL_FLAGS_SAME | REL_FLAGS_BEFORE);
f22 = f22 & (REL_FLAGS_SAME | REL_FLAGS_BEFORE);
}
if (f22 == REL_FLAGS_AFTER) {
f21 = f21 & REL_FLAGS_AFTER;
} else if (f22 == REL_FLAGS_BEFORE) {
f12 = f12 & REL_FLAGS_BEFORE;
} else if ((f22 & REL_FLAGS_BEFORE) == 0) {
f21 = f21 & (REL_FLAGS_SAME | REL_FLAGS_AFTER);
} else if ((f22 & REL_FLAGS_AFTER) == 0) {
f12 = f12 & (REL_FLAGS_SAME | REL_FLAGS_BEFORE);
}
return ((f11 << REL_FLAGS_SS_SHIFT) & (f12 << REL_FLAGS_SE_SHIFT)
& (f21 << REL_FLAGS_ES_SHIFT) & (f22 << REL_FLAGS_EE_SHIFT));
}
public RelType getRelation(Interval<E> other)
{
if (other == null) return RelType.NONE;
int flags = getRelationFlags(other);
if ((flags & REL_FLAGS_INTERVAL_FUZZY) != 0) {
return RelType.UNKNOWN;
} else if ((flags & REL_FLAGS_INTERVAL_UNKNOWN) != 0) {
return RelType.BEFORE;
} else if ((flags & REL_FLAGS_INTERVAL_BEFORE) != 0) {
return RelType.AFTER;
} else if ((flags & REL_FLAGS_INTERVAL_AFTER) != 0) {
return RelType.EQUAL;
} else if ((flags & REL_FLAGS_INTERVAL_INSIDE) != 0) {
return RelType.INSIDE;
} else if ((flags & REL_FLAGS_INTERVAL_CONTAIN) != 0) {
return RelType.CONTAIN;
} else if ((flags & REL_FLAGS_INTERVAL_OVERLAP) != 0) {
return RelType.OVERLAP;
} else {
return RelType.UNKNOWN;
}
}
private static final long serialVersionUID = 1;
}