Commit d730328f authored by Lukas Jelonek's avatar Lukas Jelonek
Browse files

Added a complement operation for complementing an interval with a list of intervals

parent 3401b196
......@@ -16,6 +16,12 @@
*/
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;
/**
*
* @author Lukas Jelonek <ljelonek at cebitec.uni-bielefeld.de>
......@@ -198,4 +204,40 @@ public class IntegerIntervalOperations implements IntervalOperations<Integer> {
return snd.getEnd() < fst.getStart();
}
}
@Override
public List<Interval<Integer>> complement(Interval<Integer> reference, Iterable<? extends Interval<Integer>> parts) {
if (Iterables.isEmpty(parts)) {
return Collections.singletonList(reference);
}
List<Interval<Integer>> output = new LinkedList<>();
Interval<Integer> previous = null;
for (Interval<Integer> interval : parts) {
if (operations().contains(interval, reference)) {
return Collections.<Interval<Integer>>emptyList();
} else {
Interval<Integer> intersection = operations().intersection(reference, interval);
Interval<Integer> complementInterval;
if (previous == null) {
complementInterval = Intervals.createInterval(reference.getStart(), intersection.getStart());
} else {
complementInterval = Intervals.createInterval(previous.getEnd(), intersection.getStart());
}
if (!complementInterval.isEmpty()) {
output.add(complementInterval);
}
previous = intersection;
}
}
if (previous != null) {
Interval<Integer> complementInterval = Intervals.createInterval(previous.getEnd(), reference.getEnd());
if (!complementInterval.isEmpty()) {
output.add(complementInterval);
}
}
return output;
}
}
......@@ -16,6 +16,8 @@
*/
package de.cebitec.common.sequencetools.intervals;
import java.util.List;
/**
* This class defines operations on intervals. Internally the operations should operate on ZeroOpen intervals to allow
* the handling of empty intervals.
......@@ -138,7 +140,7 @@ public interface IntervalOperations<L extends Number> {
* @return
*/
boolean leftOf(Interval<L> fst, Interval<L> snd);
/**
* Checks if the fst interval does not overlap with the snd interval and is right of it
*
......@@ -147,5 +149,14 @@ public interface IntervalOperations<L extends Number> {
* @return
*/
boolean rightOf(Interval<L> fst, Interval<L> snd);
/**
* Calculates the complement for one interval and a list of intervals.
*
* @param fst
* @param snd
* @return An empty list if there is no complement, otherwise a list of intervals contained in fst, but not in snd.
*/
List<Interval<L>> complement(Interval<L> fst, Iterable<? extends Interval<L>> snd);
}
/*
* 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 java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
/**
*
* @author Lukas Jelonek <ljelonek at cebitec.uni-bielefeld.de>
*/
public class IntegerIntervalListComplementOperationTest {
private IntegerIntervalOperations ops = new IntegerIntervalOperations();
@Test
public void testEmptyCollection() {
Interval<Integer> wanted = Intervals.createInterval(0, 100);
List<Interval<Integer>> given = Collections.<Interval<Integer>>emptyList();
List<Interval<Integer>> result = ops.complement(wanted, given);
List<Interval<Integer>> expected = Collections.singletonList(wanted);
assertThat(result, equalTo(expected));
}
@Test
public void testCompleteOverlap() {
Interval<Integer> wanted = Intervals.createInterval(0, 100);
List<Interval<Integer>> given = Collections.singletonList(wanted);
List<Interval<Integer>> result = ops.complement(wanted, given);
assertThat(result, empty());
}
@Test
public void testPartOfLargeInterval() {
Interval<Integer> wanted = Intervals.createInterval(10, 100);
List<Interval<Integer>> given = Collections.singletonList(Intervals.createInterval(0, 200));
List<Interval<Integer>> result = ops.complement(wanted, given);
assertThat(result, empty());
}
@Test
public void testLeftOverlap() {
Interval<Integer> wanted = Intervals.createInterval(10, 100);
List<Interval<Integer>> given = Collections.singletonList(Intervals.createInterval(0, 20));
List<Interval<Integer>> result = ops.complement(wanted, given);
List<Interval<Integer>> expected = Collections.singletonList(Intervals.createInterval(20, 100));
assertThat(result, equalTo(expected));
}
@Test
public void testRightOverlap() {
Interval<Integer> wanted = Intervals.createInterval(10, 100);
List<Interval<Integer>> given = Collections.singletonList(Intervals.createInterval(90, 200));
List<Interval<Integer>> result = ops.complement(wanted, given);
List<Interval<Integer>> expected = Collections.singletonList(Intervals.createInterval(10, 90));
assertThat(result, equalTo(expected));
}
@Test
public void testMiddleOverlap() {
Interval<Integer> wanted = Intervals.createInterval(0, 100);
List<Interval<Integer>> given = Collections.singletonList(Intervals.createInterval(20, 30));
List<Interval<Integer>> result = ops.complement(wanted, given);
List<Interval<Integer>> expected = Arrays.asList(Intervals.createInterval(0, 20),
Intervals.createInterval(30, 100));
assertThat(result, equalTo(expected));
}
@Test
public void testMultipleOverlaps() {
Interval<Integer> wanted = Intervals.createInterval(0, 100);
List<Interval<Integer>> given = Arrays.asList(
Intervals.createInterval(0, 10),
Intervals.createInterval(20, 30),
Intervals.createInterval(90, 200)
);
List<Interval<Integer>> result = ops.complement(wanted, given);
List<Interval<Integer>> expected = Arrays.asList(Intervals.createInterval(10, 20),
Intervals.createInterval(30, 90));
assertThat(result, equalTo(expected));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment