Commit 62f68c71 authored by Lukas Jelonek's avatar Lukas Jelonek
Browse files

Added long interval support, no tests yet

parent b7267380
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.cebitec.common</groupId>
<artifactId>intervals</artifactId>
<version>0.7.1-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>Intervals library</name>
<description>
Library for handling integer intervals.
</description>
<licenses>
<license>
<url>http://www.gnu.org/licenses/gpl-3.0.html</url>
</license>
</licenses>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.3.2</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions/>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>17.0</version>
</dependency>
</dependencies>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.cebitec.common</groupId>
<artifactId>intervals</artifactId>
<version>0.8.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>Intervals library</name>
<description>
Library for handling integer intervals.
</description>
<licenses>
<license>
<url>http://www.gnu.org/licenses/gpl-3.0.html</url>
</license>
</licenses>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.3.2</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions/>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>17.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -17,7 +17,6 @@
package de.cebitec.common.sequencetools.intervals;
import com.google.common.collect.Iterables;
import static de.cebitec.common.sequencetools.intervals.Intervals.operations;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
......@@ -213,10 +212,10 @@ public class IntegerIntervalOperations implements IntervalOperations<Integer> {
Interval<Integer> previous = null;
for (Interval<Integer> interval : parts) {
if (operations().contains(interval, reference)) {
if (contains(interval, reference)) {
return Collections.<Interval<Integer>>emptyList();
} else {
Interval<Integer> intersection = operations().intersection(reference, interval);
Interval<Integer> intersection = intersection(reference, interval);
Interval<Integer> complementInterval;
if (previous == null) {
complementInterval = Intervals.createInterval(reference.getStart(), intersection.getStart());
......
......@@ -166,6 +166,6 @@ public interface IntervalOperations<L extends Number> {
* @param intervals
* @return
*/
Interval<Integer> enclose(Iterable<? extends Interval<Integer>> intervals);
Interval<L> enclose(Iterable<? extends Interval<L>> intervals);
}
/*
* Copyright (C) 2012 Lukas Jelonek <ljelonek at cebitec.uni-bielefeld.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.cebitec.common.sequencetools.intervals;
import de.cebitec.common.sequencetools.intervals.Interval.Type;
import java.util.Comparator;
import java.util.List;
/**
* Helper and factory class for intervals.
*
* @author Lukas Jelonek {@literal <ljelonek at cebitec.uni-bielefeld.de>}
*/
public class IntervalsL {
public static final Interval<Long> EMPTY = emptyInterval();
public static final LongIntervalOperations integerIntervalOperations = new LongIntervalOperations();
public static Interval<Long> emptyInterval() {
if (EMPTY == null) {
return createInterval(0, 0);
}
return EMPTY;
}
/**
* Creates an interval for the coordinates given in zeroOpen coordinates.
*
* @param start
* @param end
* @return
*/
public static Interval<Long> createInterval(long start, long end) {
return createInterval(start, end, Type.ZeroOpen);
}
/**
* Creates an interval ranging from start to end in zeroOpen coordinates. If type is not ZeroOpen the start and end
* positions of the interval will be transformed to be ZeroOpen.
*
* @param start The start of the interval.
* @param end The end of the interval.
* @param type The type coordinate system of start and stop
* @return An interval in ZeroOpen coordinates.
*/
public static Interval<Long> createInterval(long start, long end, Type type) {
// if (start > end) {
// throw new IllegalArgumentException("Start must be lower than end.");
// }
return new SerializableIntervalL(normalizeStart(start, type), normalizeEnd(end, type), Type.ZeroOpen);
}
/**
* Transforms an interval into another coordinate system.
*
* @param interval The interval.
* @param targetType The target coordinate system.
* @return
*/
public static Interval<Long> transfromInterval(Interval<Long> interval, Type targetType) {
Interval<Long> normalized = normalize(interval);
return new SerializableIntervalL(
deNormalizeStart(normalized.getStart(), targetType),
deNormalizeEnd(normalized.getEnd(), targetType),
targetType);
}
/**
* Normalizes an interval to a zeroOpen interval.
*
* @param interval
* @return
*/
public static Interval<Long> normalize(Interval<Long> interval) {
if (Type.ZeroOpen.equals(interval.getType())) {
return interval;
} else {
return createInterval(interval.getStart(), interval.getEnd(), interval.getType());
}
}
public static IntervalFormatterBuilder<Long> newFormatter() {
return new IntervalFormatterBuilder<>();
}
public static IntervalOperations<Long> operations() {
return integerIntervalOperations;
}
/**
* Corrects the start depending on the type so that it can be used with a java String.
*
* @param start
* @param t
* @return
*/
static long normalizeStart(final long start, Type t) {
switch (t) {
case OneClosed:
return start - 1;
case OneOpen:
return start - 1;
default:
return start;
}
}
/**
* Corrects the end depending on the type so that it can be used with a java String.
*
* @param end an end position
* @param t the source type
* @return the new end respective to the java String implementation
*/
static long normalizeEnd(final long end, final Type t) {
switch (t) {
case ZeroClosed:
return end + 1;
case OneOpen:
return end - 1;
default:
return end;
}
}
/**
* Inverse operation for normalizeStart.
*
* @param start An start position in ZeroOpen coordinates
* @param t The target coordinate system
* @return The transformed end
*/
static long deNormalizeStart(final long start, Type t) {
switch (t) {
case OneClosed:
return start + 1;
case OneOpen:
return start + 1;
default:
return start;
}
}
/**
* Inverse operation for normalizeEnd.
*
* @param end An end position in ZeroOpen coordinates
* @param t The target coordinate system
* @return The transformed end
*/
static long deNormalizeEnd(final long end, final Type t) {
switch (t) {
case ZeroClosed:
return end - 1;
case OneOpen:
return end + 1;
default:
return end;
}
}
/**
* Sums up the total length of a list of intervals.
*
* @param totalLength
* @return
*/
public static Long totalLength(List<? extends Interval<Long>> totalLength) {
long i = 0;
for (Interval<Long> interval : totalLength) {
i += interval.getLength();
}
return i;
}
/**
* Compares the invervals by start position.
*/
public static class IntervalComparator implements Comparator<Interval<Long>> {
@Override
public int compare(Interval<Long> o1, Interval<Long> o2) {
return o1.getStart().compareTo(o2.getStart());
}
}
private IntervalsL() {
}
}
/*
* Copyright (C) 2013 Lukas Jelonek <ljelonek at cebitec.uni-bielefeld.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.cebitec.common.sequencetools.intervals;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
/**
*
* @author Lukas Jelonek {@literal <ljelonek at cebitec.uni-bielefeld.de>}
*/
public class LongIntervalOperations implements IntervalOperations<Long> {
@Override
public boolean beginsWith(Interval<Long> fst, Interval<Long> snd) {
return Objects.equals(fst.as(Interval.Type.ZeroOpen).getStart(), snd.as(Interval.Type.ZeroOpen).getStart());
}
@Override
public boolean endsWith(Interval<Long> fst, Interval<Long> snd) {
return Objects.equals(fst.as(Interval.Type.ZeroOpen).getEnd(), snd.as(Interval.Type.ZeroOpen).getEnd());
}
@Override
public boolean contains(Interval<Long> fst, Interval<Long> snd) {
fst = fst.as(Interval.Type.ZeroOpen);
snd = snd.as(Interval.Type.ZeroOpen);
return fst.getStart() <= snd.getStart() && fst.getEnd() >= snd.getEnd() // inside borders
&& snd.getStart() < fst.getEnd(); // for empty snd interval
}
@Override
public boolean overlap(Interval<Long> fst, Interval<Long> snd) {
if (fst.isEmpty() || snd.isEmpty()) {
return false;
}
// normalize
fst = fst.as(Interval.Type.ZeroOpen);
snd = snd.as(Interval.Type.ZeroOpen);
if (fst.getStart() > snd.getStart()) {
Interval<Long> tmp = fst;
fst = snd;
snd = tmp;
}
return fst.equals(snd) || !(fst.getEnd() - 1 < snd.getStart());
}
@Override
public boolean adjacent(Interval<Long> fst, Interval<Long> snd) {
// normalize
fst = fst.as(Interval.Type.ZeroOpen);
snd = snd.as(Interval.Type.ZeroOpen);
if (overlap(fst, snd)) {
return false;
}
// sort by start
if (fst.getStart() > snd.getStart()) {
Interval<Long> tmp = fst;
fst = snd;
snd = tmp;
}
return distance(fst, snd) == 0;
}
@Override
public boolean overlapOrAdjacent(Interval<Long> fst, Interval<Long> snd) {
return overlap(fst, snd) || adjacent(fst, snd);
}
@Override
public Long distance(Interval<Long> fst, Interval<Long> snd) {
long startDist = fst.getStart() - snd.getStart();
long endDist = fst.getEnd() - snd.getEnd();
long startEndDist = fst.getStart() - snd.getEnd();
long endStartDist = fst.getEnd() - snd.getStart();
long min = Long.MAX_VALUE;
if (Math.abs(startDist) < Math.abs(min)) {
min = startDist;
}
if (Math.abs(endDist) < Math.abs(min)) {
min = endDist;
}
if (Math.abs(startEndDist) < Math.abs(min)) {
min = startEndDist;
}
if (Math.abs(endStartDist) < Math.abs(min)) {
min = endStartDist;
}
return min;
}
@Override
public Interval<Long> union(Interval<Long> fst, Interval<Long> snd) {
if (!overlapOrAdjacent(fst, snd)) {
throw new IllegalArgumentException("Can't union the non overlapping and non adjacent intervals. " + fst + "; " + snd);
}
// normalize
fst = fst.as(Interval.Type.OneClosed);
snd = snd.as(Interval.Type.OneClosed);
// sort by start
if (fst.getStart() > snd.getStart()) {
Interval<Long> tmp = fst;
fst = snd;
snd = tmp;
}
long nstart = fst.getStart();
long nend = fst.getEnd() > snd.getEnd() ? fst.getEnd() : snd.getEnd();
return IntervalsL.createInterval(nstart, nend, Interval.Type.OneClosed);
}
@Override
public Interval<Long> intersection(Interval<Long> fst, Interval<Long> snd) {
if (!overlap(fst, snd)) {
return IntervalsL.EMPTY;
}
// normalize
fst = fst.as(Interval.Type.OneClosed);
snd = snd.as(Interval.Type.OneClosed);
// sort by start
if (fst.getStart() > snd.getStart()) {
Interval<Long> tmp = fst;
fst = snd;
snd = tmp;
}
long nstart = snd.getStart() > fst.getStart() ? snd.getStart() : fst.getStart();
long nend = fst.getEnd() < snd.getEnd() ? fst.getEnd() : snd.getEnd();
return IntervalsL.createInterval(nstart, nend, Interval.Type.OneClosed);
}
@Override
public Interval<Long> complement(Interval<Long> fst, Interval<Long> snd) {
if (!overlap(fst, snd)) {
return fst;
}
if (fst.equals(snd)) {
return IntervalsL.EMPTY;
}
// normalize
fst = fst.as(Interval.Type.OneClosed);
snd = snd.as(Interval.Type.OneClosed);
return IntervalsL.createInterval(fst.getStart(), snd.getStart() - 1, Interval.Type.OneClosed);
}
@Override
public Interval<Long> shift(Interval<Long> i, Long by) {
Interval<Long> as = i.as(Interval.Type.ZeroOpen);
return IntervalsL.createInterval(as.getStart() + by, as.getEnd() + by);
}
@Override
public boolean leftOf(Interval<Long> fst, Interval<Long> snd) {
// normalize
fst = fst.as(Interval.Type.OneClosed);
snd = snd.as(Interval.Type.OneClosed);
if (overlap(fst, snd)) {
return false;
} else {
return fst.getEnd() < snd.getStart();
}
}
@Override
public boolean rightOf(Interval<Long> fst, Interval<Long> snd) {
// normalize
fst = fst.as(Interval.Type.OneClosed);
snd = snd.as(Interval.Type.OneClosed);
if (overlap(fst, snd)) {