bug5043: avoid filtering out candidates for fixed mark passings in StationarySequence

This commit is contained in:
Axel Uhl committed 2019-05-18 18:47:30 +02:00
1 parent 8109d94ddf
commit 9ec982c19f
6 files changed
+56 -19

No files matched your search

@@ -19,26 +19,26 @@ public class MostProbableCandidatesInSmallTimeRangeFilterTest extends AbstractCa
@Test
public void testGetTimeWiseContiguousDistanceCandidates() {
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, c3, /* includeStartFrom */ true);
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, c3, /* includeStartFrom */ true);
assertContainsExactly(result, c1, c2, c3, c4, c5);
}
@Test
public void testGetTimeWiseContiguousDistanceCandidatesOnRightBorder() {
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, c5, /* includeStartFrom */ true);
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, c5, /* includeStartFrom */ true);
assertContainsExactly(result, c1, c2, c3, c4, c5);
}
@Test
public void testGetTimeWiseContiguousDistanceCandidatesOnLeftBorder() {
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, c6, /* includeStartFrom */ true);
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, c6, /* includeStartFrom */ true);
assertContainsExactly(result, c6, c7, c8, c9, c10);
}
@Test
public void testGetTimeWiseContiguousDistanceCandidatesInMiddleOfGapNotInserted() {
final Candidate middleOfGap = candidate(c5.getTimePoint().plus(c5.getTimePoint().until(c6.getTimePoint()).divide(2)), "gap");
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, middleOfGap,
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, middleOfGap,
/* includeStartFrom */ true);
assertContainsExactly(result, c1, c2, c3, c4, c5, middleOfGap, c6, c7, c8, c9, c10);
}
@@ -46,7 +46,7 @@ public class MostProbableCandidatesInSmallTimeRangeFilterTest extends AbstractCa
@Test
public void testGetTimeWiseContiguousDistanceCandidatesInMiddleOfGapNotInsertedDontIncludeStartFrom() {
final Candidate middleOfGap = candidate(c5.getTimePoint().plus(c5.getTimePoint().until(c6.getTimePoint()).divide(2)), "gap");
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, middleOfGap,
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, middleOfGap,
/* includeStartFrom */ false);
assertContainsExactly(result, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10);
}
@@ -55,7 +55,7 @@ public class MostProbableCandidatesInSmallTimeRangeFilterTest extends AbstractCa
public void testGetTimeWiseContiguousDistanceCandidatesInMiddleOfGapInserted() {
final Candidate middleOfGap = candidate(c5.getTimePoint().plus(c5.getTimePoint().until(c6.getTimePoint()).divide(2)), "gap");
competitorCandidates.add(middleOfGap);
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, middleOfGap,
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, middleOfGap,
/* includeStartFrom */ true);
assertContainsExactly(result, c1, c2, c3, c4, c5, middleOfGap, c6, c7, c8, c9, c10);
}
@@ -65,7 +65,7 @@ public class MostProbableCandidatesInSmallTimeRangeFilterTest extends AbstractCa
competitorCandidates.remove(c5);
competitorCandidates.remove(c6);
final Candidate middleOfGap = candidate(c5.getTimePoint().plus(c5.getTimePoint().until(c6.getTimePoint()).divide(2)), "gap");
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousDistanceCandidates(competitorCandidates, middleOfGap,
final NavigableSet<Candidate> result = filter.getTimeWiseContiguousCandidates(competitorCandidates, middleOfGap,
/* includeStartFrom */ true);
assertContainsExactly(result, middleOfGap);
}
@@ -20,6 +20,13 @@ import com.sap.sse.common.Timed;
public interface Candidate extends Comparable<CandidateImpl>, Timed {
Waypoint getWaypoint();
/**
* Is this a candidate for a fixed mark passing?
*/
default boolean isFixed() {
return false;
}
int getOneBasedIndexOfWaypoint();
@@ -474,7 +474,7 @@ public class CandidateChooserImpl implements CandidateChooser {
public void setFixedPassing(Competitor c, Integer zeroBasedIndexOfWaypoint, TimePoint t) {
LockUtil.lockForWrite(perCompetitorLocks.get(c));
try {
Candidate fixedCan = new CandidateImpl(zeroBasedIndexOfWaypoint + 1, t, 1, Util.get(race.getRace().getCourse().getWaypoints(), zeroBasedIndexOfWaypoint));
Candidate fixedCan = new CandidateForFixedMarkPassingImpl(zeroBasedIndexOfWaypoint + 1, t, 1, Util.get(race.getRace().getCourse().getWaypoints(), zeroBasedIndexOfWaypoint));
NavigableSet<Candidate> fixed = fixedPassings.get(c);
if (fixed != null) { // can only set the mark passing if the competitor is still part of this race
if (!fixed.add(fixedCan)) {
@@ -0,0 +1,17 @@
package com.sap.sailing.domain.markpassingcalculation.impl;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sse.common.TimePoint;
public class CandidateForFixedMarkPassingImpl extends CandidateImpl {
private static final long serialVersionUID = 3657502693032556232L;
public CandidateForFixedMarkPassingImpl(int oneBasedIndexOfWaypoint, TimePoint p, double probability, Waypoint w) {
super(oneBasedIndexOfWaypoint, p, probability, w);
}
@Override
public boolean isFixed() {
return true;
}
}
@@ -102,7 +102,7 @@ public class MostProbableCandidatesInSmallTimeRangeFilter {
while (!newCandidatesModifiableCopy.isEmpty()) {
final Candidate nextNewCandidate = newCandidatesModifiableCopy.iterator().next();
newCandidatesModifiableCopy.remove(nextNewCandidate);
final NavigableSet<Candidate> contiguousSequenceForNextNewCandidate = getTimeWiseContiguousDistanceCandidates(competitorCandidates, nextNewCandidate, /* includeStartFrom */ true);
final NavigableSet<Candidate> contiguousSequenceForNextNewCandidate = getTimeWiseContiguousCandidates(competitorCandidates, nextNewCandidate, /* includeStartFrom */ true);
disjointSequencesAffectedByNewAndRemovedCandidates.add(contiguousSequenceForNextNewCandidate);
// remove the candidate grouped in the sequence from the remaining new candidates to consider
// because they have been "scooped up" by this sequence already and need no further consideration:
@@ -122,7 +122,7 @@ public class MostProbableCandidatesInSmallTimeRangeFilter {
while (!removedCandidatesModifiableCopy.isEmpty()) {
final Candidate nextRemovedCandidate = removedCandidatesModifiableCopy.iterator().next();
removedCandidatesModifiableCopy.remove(nextRemovedCandidate);
final NavigableSet<Candidate> contiguousSequenceForNextRemovedCandidate = getTimeWiseContiguousDistanceCandidates(competitorCandidates, nextRemovedCandidate, /* includeStartFrom */ false);
final NavigableSet<Candidate> contiguousSequenceForNextRemovedCandidate = getTimeWiseContiguousCandidates(competitorCandidates, nextRemovedCandidate, /* includeStartFrom */ false);
removeAllRemovedCandidatesInOrNearSequence(contiguousSequenceForNextRemovedCandidate, removedCandidatesModifiableCopy);
// If adjacent sequences were added before and after the removed candidate,
// we need to distinguish whether the gap around the removed candidate was greater
@@ -233,7 +233,7 @@ public class MostProbableCandidatesInSmallTimeRangeFilter {
* @param includeStartFrom
* whether or not to include {@code startFrom} in the resulting set
*/
public NavigableSet<Candidate> getTimeWiseContiguousDistanceCandidates(NavigableSet<Candidate> competitorCandidates, Candidate startFrom, boolean includeStartFrom) {
public NavigableSet<Candidate> getTimeWiseContiguousCandidates(NavigableSet<Candidate> competitorCandidates, Candidate startFrom, boolean includeStartFrom) {
final NavigableSet<Candidate> result = new TreeSet<>(candidateComparator);
if (includeStartFrom) {
result.add(startFrom);
@@ -89,7 +89,7 @@ public class StationarySequence {
// borders of this sequence:
final TimeRange timeRangeNoLongerPassingFilter = getExtendedEndBorderRange(extendedBy);
if (timeRangeNoLongerPassingFilter != null) {
removeFromFilterResult(timeRangeNoLongerPassingFilter, candidatesEffectivelyAdded, candidatesEffectivelyRemoved);
removeFromFilterResultUnlessFixed(timeRangeNoLongerPassingFilter, candidatesEffectivelyAdded, candidatesEffectivelyRemoved);
}
}
return bounds != null;
@@ -158,7 +158,7 @@ public class StationarySequence {
// borders of this sequence:
final TimeRange timeRangeNoLongerPassingFilter = getExtendedStartBorderRange(extendedBy);
if (timeRangeNoLongerPassingFilter != null) {
removeFromFilterResult(timeRangeNoLongerPassingFilter, candidatesEffectivelyAdded, candidatesEffectivelyRemoved);
removeFromFilterResultUnlessFixed(timeRangeNoLongerPassingFilter, candidatesEffectivelyAdded, candidatesEffectivelyRemoved);
}
}
return bounds != null;
@@ -204,11 +204,15 @@ public class StationarySequence {
return result;
}
private void removeFromFilterResult(final TimeRange timeRangeNoLongerPassingFilter, Set<Candidate> candidatesEffectivelyAdded,
private void removeFromFilterResultUnlessFixed(final TimeRange timeRangeNoLongerPassingFilter, Set<Candidate> candidatesEffectivelyAdded,
Set<Candidate> candidatesEffectivelyRemoved) {
final SortedSet<Candidate> candidatesNoLongerPassingFilter = getCandidatesInTimeRange(timeRangeNoLongerPassingFilter);
candidatesEffectivelyAdded.removeAll(candidatesNoLongerPassingFilter);
candidatesEffectivelyRemoved.addAll(candidatesNoLongerPassingFilter);
for (final Candidate candidate : candidatesNoLongerPassingFilter) {
if (!candidate.isFixed()) {
candidatesEffectivelyAdded.removeAll(candidatesNoLongerPassingFilter);
candidatesEffectivelyRemoved.addAll(candidatesNoLongerPassingFilter);
}
}
}
private SortedSet<Candidate> getCandidatesInTimeRange(final TimeRange timeRange) {
@@ -219,7 +223,16 @@ public class StationarySequence {
}
public Iterable<Candidate> getValidCandidates() {
return ()->candidates.stream().filter(c->isCloseEnoughToSequenceBorder(c)).iterator();
return ()->candidates.stream().filter(c->isValidCandidate(c)).iterator();
}
/**
* A candidate that is part of this stationary sequence is considered valid if it is time-wise close
* enough to one of the sequence's borders (see {@link #CANDIDATE_FILTER_TIME_WINDOW}) or if it is
* a candidate for a {@link Candidate#isFixed() fixed mark passing}.
*/
private boolean isValidCandidate(Candidate c) {
return c.isFixed() || isCloseEnoughToSequenceBorder(c);
}
private boolean isCloseEnoughToSequenceBorder(Candidate candidate) {
@@ -246,7 +259,7 @@ public class StationarySequence {
assert !candidates.contains(candidate) && !getFirst().getTimePoint().after(candidate.getTimePoint()) &&
!getLast().getTimePoint().before(candidate.getTimePoint());
candidates.add(candidate);
if (isCloseEnoughToSequenceBorder(candidate)) {
if (isValidCandidate(candidate)) {
candidatesEffectivelyAdded.add(candidate);
candidatesEffectivelyRemoved.remove(candidate);
}
@@ -269,7 +282,7 @@ public class StationarySequence {
void remove(Candidate candidate, Set<Candidate> candidatesEffectivelyAdded, Set<Candidate> candidatesEffectivelyRemoved,
NavigableSet<StationarySequence> stationarySequenceSetToUpdate) {
assert candidates.contains(candidate);
final boolean wasValidCandidate = isCloseEnoughToSequenceBorder(candidate);
final boolean wasValidCandidate = isValidCandidate(candidate);
final boolean wasFirst = candidate == getFirst();
final boolean wasLast = candidate == getLast();
if (wasFirst || size() == 2) { // if size() == 2 then it will shrink to 1 and this sequence shall be removed