Fix in Chooser and different penalties for missing waypoints in the middle or et the end of races => Races missing starttimes work ok.

This commit is contained in:
Nick Klose committed 2014-02-04 16:00:02 +01:00
1 parent be3a144e43
commit 851f002b9a
7 files changed
+109 -47

No files matched your search

@@ -19,6 +19,7 @@ import junit.framework.Assert;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.markpassingcalculation.Candidate;
import com.sap.sailing.domain.markpassingcalculation.CandidateChooser;
@@ -73,8 +74,8 @@ public class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
int incorrectPasses = 0;
boolean printRight = false;
boolean printWrong = true;
boolean printResult = true;
boolean printWrong = false;
boolean printResult = false;
for (Competitor c : getRace().getCompetitors()) {
numberOfCompetitors++;
@@ -100,8 +101,7 @@ public class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
System.out.println("Both null" + "\n");
}
} else {
long timedelta = givenPasses.get(c).get(w).getTimePoint().asMillis()
- computedPasses.get(c).get(w).getTimePoint().asMillis();
long timedelta = givenPasses.get(c).get(w).getTimePoint().asMillis() - computedPasses.get(c).get(w).getTimePoint().asMillis();
if ((Math.abs(timedelta) < tolerance)) {
correctPasses++;
if (printRight) {
@@ -124,8 +124,7 @@ public class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
}
int totalMarkPasses = numberOfCompetitors * waypoints.size();
assertEquals(totalMarkPasses, incorrectPasses + correctPasses + wronglyNotComputed + correctlyNotComputed
+ wronglyComputed);
assertEquals(totalMarkPasses, incorrectPasses + correctPasses + wronglyNotComputed + correctlyNotComputed + wronglyComputed);
double accuracy = (double) (correctPasses + correctlyNotComputed) / totalMarkPasses;
if (printResult) {
System.out.println("Total theoretical Passes: " + totalMarkPasses);
@@ -144,13 +143,13 @@ public class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
CandidateFinder finder = new CandidateFinder(getTrackedRace());
CandidateChooser chooser = new CandidateChooser(getTrackedRace());
int mistakes = 0;
TimePoint t = getTrackedRace().getStartOfRace();
for (Competitor c : getRace().getCompetitors()) {
List<GPSFix> fixes = new ArrayList<GPSFix>();
try {
getTrackedRace().getTrack(c).lockForRead();
for (GPSFixMoving fix : getTrackedRace().getTrack(c).getFixes()) {
if (fix.getTimePoint().minus(120000).before(getTrackedRace().getStartOfRace())) {
if (fix.getTimePoint().minus(120000).before(t)) {
fixes.add(fix);
}
}
@@ -163,7 +162,7 @@ public class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
boolean gotFirst = false;
boolean gotOther = false;
for (Waypoint w : getRace().getCourse().getWaypoints()) {
System.out.println(getTrackedRace().getMarkPassing(c, w));
// System.out.println(getTrackedRace().getMarkPassing(c, w));
if (w == w1) {
gotFirst = (getTrackedRace().getMarkPassing(c, w) != null) ? true : false;
} else {
@@ -179,6 +178,48 @@ public class AbstractMarkPassingTest extends OnlineTracTracBasedTest {
Assert.assertTrue(mistakes == 0);
}
protected void testFirstTwoWaypoints() {
CandidateFinder finder = new CandidateFinder(getTrackedRace());
CandidateChooser chooser = new CandidateChooser(getTrackedRace());
int mistakes = 0;
TimePoint t = getTrackedRace().getStartOfRace();
for (Competitor c : getRace().getCompetitors()) {
List<GPSFix> fixes = new ArrayList<GPSFix>();
try {
getTrackedRace().getTrack(c).lockForRead();
for (GPSFixMoving fix : getTrackedRace().getTrack(c).getFixes()) {
if (fix.getTimePoint().minus(360000).before(t)) {
fixes.add(fix);
}
}
} finally {
getTrackedRace().getTrack(c).unlockAfterRead();
}
Pair<List<Candidate>, List<Candidate>> f = finder.getCandidateDeltas(c, fixes);
chooser.calculateMarkPassDeltas(c, f);
Waypoint w1 = getRace().getCourse().getFirstWaypoint();
Waypoint w2 = getRace().getCourse().getFirstLeg().getTo();
boolean gotFirst = false;
boolean gotSecond = false;
boolean gotOther = false;
for (Waypoint w : getRace().getCourse().getWaypoints()) {
// System.out.println(getTrackedRace().getMarkPassing(c, w));
if (w == w1) {
gotFirst = (getTrackedRace().getMarkPassing(c, w) != null) ? true : false;
} else if (w == w2) {
gotSecond = (getTrackedRace().getMarkPassing(c, w) != null) ? true : false;
} else if (getTrackedRace().getMarkPassing(c, w) != null) {
gotOther = true;
}
}
if (!gotFirst|| !gotSecond || gotOther) {
mistakes++;
}
}
Assert.assertTrue(mistakes == 0);
}
/**
* Loads stored data for the given raceID or returns false if no data is present.
*
@@ -43,6 +43,7 @@ public class FlorianopolisMarkPassingTest extends AbstractMarkPassingTest {
setUp("529a4150-2dd0-0131-2830-60a44ce903c3");
testRace();
testStartOfRace();
testFirstTwoWaypoints();
}
protected void setUp(String raceID) throws IOException, InterruptedException, URISyntaxException {
@@ -25,6 +25,7 @@ public class OBMRMarkPassingTest extends AbstractMarkPassingTest {
setUp("65099a64-245d-11e2-9635-10bf48d758ce");
testRace();
testStartOfRace();
testFirstTwoWaypoints();
}
protected void setUp(String raceID) throws IOException, InterruptedException, URISyntaxException {
@@ -9,22 +9,21 @@ import com.sap.sailing.domain.common.TimePoint;
* {@link Waypoint}) and the one-based(!) ID of this Waypoint. The ID is one based because the standard implemantation
* of {@link AbstractCandidateChooser} (see {@link CandidateChooser}) uses a proxy Candidates at the end and the
* beginning of the race, the one at the beginning recieves the ID 0. Candidates are created in an
* {@link AbstractCandidateFinder}, which determines where a passing could be and assigns them
* {@link AbstractCandidateFinder}, which determines where a passing could be and assigns them
*
* @author Nicolas Klose
*
*/
public class Candidate {
public class Candidate implements Comparable<Candidate> {
private Waypoint w;
private TimePoint p;
private double distanceProbability;
private int id;
private Integer id;
private boolean rightSide;
private String type;
// TODO Boolean for right side of waypoint and right rounding way for waypoint
public Candidate(int id, TimePoint p, double distanceProbability, Waypoint w, boolean rightSide, String type){
public Candidate(int id, TimePoint p, double distanceProbability, Waypoint w, boolean rightSide, String type) {
this.w = w;
this.p = p;
this.distanceProbability = distanceProbability;
@@ -32,7 +31,7 @@ public class Candidate {
this.rightSide = rightSide;
this.type = type;
}
public int getID() {
return id;
}
@@ -41,15 +40,21 @@ public class Candidate {
return p;
}
public double getProbability() {
double cost = rightSide?distanceProbability:distanceProbability*0.3;
public Double getProbability() {
double cost = rightSide ? distanceProbability : distanceProbability * 0.3;
return cost;
}
public Waypoint getWaypoint() {
return w;
}
public String toString(){
return type + "-Candidate for " + id + " with cost "+ getProbability() + "and Timepoint " + p;
public String toString() {
return type + "-Candidate for " + id + " with cost " + getProbability() + "and Timepoint " + p;
}
@Override
public int compareTo(Candidate arg0) {
return id != arg0.getID() ? id.compareTo(arg0.getID()) : p != arg0.getTimePoint() ? p.compareTo(arg0.getTimePoint()) : getProbability().compareTo(arg0.getProbability());
}
}
@@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -35,8 +37,8 @@ public class CandidateChooser implements AbstractCandidateChooser {
private static final Logger logger = Logger.getLogger(CandidateChooser.class.getName());
private LinkedHashMap<Competitor, LinkedHashMap<Waypoint, MarkPassing>> currentMarkPasses = new LinkedHashMap<>();
private LinkedHashMap<Competitor, List<Edge>> allEdges = new LinkedHashMap<>();
private LinkedHashMap<Competitor, List<Candidate>> candidates = new LinkedHashMap<>();
private LinkedHashMap<Competitor, Set<Edge>> allEdges = new LinkedHashMap<>();
private LinkedHashMap<Competitor, Set<Candidate>> candidates = new LinkedHashMap<>();
private TimePoint raceStartTime;
private Candidate start;
private Candidate end;
@@ -53,9 +55,9 @@ public class CandidateChooser implements AbstractCandidateChooser {
end = new Candidate(race.getRace().getCourse().getIndexOfWaypoint(race.getRace().getCourse().getLastWaypoint()) + 2, null, 1, null, true, "Proxy");
candidates = new LinkedHashMap<>();
for (Competitor c : race.getRace().getCompetitors()) {
candidates.put(c, new ArrayList<Candidate>());
candidates.put(c, new TreeSet<Candidate>());
currentMarkPasses.put(c, new LinkedHashMap<Waypoint, MarkPassing>());
allEdges.put(c, new ArrayList<Edge>());
allEdges.put(c, new TreeSet<Edge>());
addCandidates(Arrays.asList(start, end), c);
}
}
@@ -67,6 +69,7 @@ public class CandidateChooser implements AbstractCandidateChooser {
@Override
public void calculateMarkPassDeltas(Competitor c, Pair<List<Candidate>, List<Candidate>> candidateDeltas) {
if (race.getStartOfRace() != raceStartTime) {
raceStartTime = race.getStartOfRace();
for (Competitor com : allEdges.keySet()) {
@@ -77,6 +80,7 @@ public class CandidateChooser implements AbstractCandidateChooser {
addCandidates(Arrays.asList(start), com);
}
}
removeCandidates(candidateDeltas.getB(), c);
addCandidates(candidateDeltas.getA(), c);
findShortestPath(c);
@@ -92,16 +96,19 @@ public class CandidateChooser implements AbstractCandidateChooser {
late = newCan;
}
if (raceStartTime != null) {
if (late == end) {
if (late == end && early != end) {
allEdges.get(co).add(new Edge(early, late, 1));
} else if (!(early.getID() == late.getID()) && !late.getTimePoint().before(early.getTimePoint()) && estimatedDistance(co, early, late) > penaltyForSkipping) {
Edge e = new Edge(early, late, estimatedDistance(co, early, late));
allEdges.get(co).add(e);
}
} else {
/*if (early == start && late.getID() == 1 && numberOfCloseStarts(late.getTimePoint()) > penaltyForSkipping) {
allEdges.get(co).add(new Edge(early, late, numberOfCloseStarts(late.getTimePoint())));
} else*/ if (late == end || early == start) {
/*
* if (early == start && late.getID() == 1 && numberOfCloseStarts(late.getTimePoint()) >
* penaltyForSkipping) { allEdges.get(co).add(new Edge(early, late,
* numberOfCloseStarts(late.getTimePoint()))); } else
*/if ((late == end || early == start) && early != late) {
allEdges.get(co).add(new Edge(early, late, 1));
} else if (!(early.getID() == late.getID()) && late.getTimePoint().after(early.getTimePoint()) && estimatedDistance(co, early, late) > penaltyForSkipping) {
allEdges.get(co).add(new Edge(early, late, estimatedDistance(co, early, late)));
@@ -117,32 +124,34 @@ public class CandidateChooser implements AbstractCandidateChooser {
for (Edge e : allEdges.get(co)) {
all.add(e);
}
LinkedHashMap<Candidate, Candidate> candidateWithParent = new LinkedHashMap<>();
candidateWithParent.put(start, null);
Edge newMostLikelyEdge = null;
LinkedHashMap<Candidate, Pair<Candidate, Double>> candidateWithParent = new LinkedHashMap<>();
candidateWithParent.put(start, new Pair<Candidate, Double>(null, 0.0));
Pair<Edge, Double> currentMostLikelyEdge = null;
while (!candidateWithParent.containsKey(end)) {
newMostLikelyEdge = null;
currentMostLikelyEdge = null;
for (Edge e : all) {
if (candidateWithParent.containsKey(e.getStart())) {
if (newMostLikelyEdge == null) {
newMostLikelyEdge = e;
} else if (e.getProbability() < newMostLikelyEdge.getProbability()) {
newMostLikelyEdge = e;
Double cost = candidateWithParent.get(e.getStart()).getB() + e.getProbability();
if (currentMostLikelyEdge == null) {
currentMostLikelyEdge = new Pair<Edge, Double>(e, cost);
} else if (cost < currentMostLikelyEdge.getB()) {
currentMostLikelyEdge = new Pair<Edge, Double>(e, cost);
}
}
}
if (!candidateWithParent.containsKey(newMostLikelyEdge.getEnd())) {
candidateWithParent.put(newMostLikelyEdge.getEnd(), newMostLikelyEdge.getStart());
if (!candidateWithParent.containsKey(currentMostLikelyEdge.getA().getEnd())
|| candidateWithParent.get(currentMostLikelyEdge.getA().getEnd()).getB() > currentMostLikelyEdge.getB()) {
candidateWithParent.put(currentMostLikelyEdge.getA().getEnd(), new Pair<Candidate, Double>(currentMostLikelyEdge.getA().getStart(), currentMostLikelyEdge.getB()));
}
all.remove(newMostLikelyEdge);
all.remove(currentMostLikelyEdge.getA());
}
Candidate marker = candidateWithParent.get(end);
Candidate marker = candidateWithParent.get(end).getA();
while (!(marker == start)) {
if (currentMarkPasses.get(co).get(marker.getWaypoint()) == null || currentMarkPasses.get(co).get(marker.getWaypoint()).getTimePoint() != marker.getTimePoint()) {
currentMarkPasses.get(co).put(marker.getWaypoint(), new MarkPassingImpl(marker.getTimePoint(), marker.getWaypoint(), co));
changed = true;
}
marker = candidateWithParent.get(marker);
marker = candidateWithParent.get(marker).getA();
}
if (changed) {
logger.info("New MarkPasses for " + co);
@@ -242,7 +251,6 @@ public class CandidateChooser implements AbstractCandidateChooser {
/*
* if (c.getID() == 1 && race.getStartOfRace() == null) { reEvaluateStartingEdges(); }
*/
// TODO Work without starting time
}
createNewEdges(co, newCandidates);
}
@@ -383,7 +383,7 @@ public class CandidateFinder implements AbstractCandidateFinder {
private double getDistanceLikelyhood(Waypoint w, Position p, TimePoint t) {
double distance = calculateDistance(p, w, t);
double legLength = getLegLength(t, w);
double result = 1 / (15 * Math.abs( distance/legLength ) + 1);
double result = 1 / (10 * Math.abs( distance/legLength ) + 1);
// Auch NormalVerteilung??!
return result;
}
@@ -13,11 +13,12 @@ import com.sap.sailing.domain.base.Waypoint;
*
*/
public class Edge {
public class Edge implements Comparable<Edge> {
private Candidate start;
private Candidate end;
private static int numberOfWaypoints;
private static double penaltyForSkipped = 0.6;
private static double penaltyForSkipped = 0.8;
private static double penaltyForSkippedToEnd = 0.7;
private double timeEstimationOrCloseStartsProbability;
public Edge(Candidate start, Candidate end, double timeEstimationOrStartAnalysis) {
@@ -34,9 +35,9 @@ public class Edge {
numberOfWaypoints = number;
}
public double getProbability() {
double penalty = end.getID() == numberOfWaypoints + 1 ? penaltyForSkipped : 0.9;
return 1 - (start.getProbability() * end.getProbability() * timeEstimationOrCloseStartsProbability) + 2 * penalty * (end.getID() - start.getID() - 1);
public Double getProbability() {
double penalty = end.getID() == numberOfWaypoints + 1 ? penaltyForSkippedToEnd : penaltyForSkipped;
return 1-(start.getProbability() * end.getProbability() * timeEstimationOrCloseStartsProbability) + 2 * penalty * (end.getID() - start.getID() - 1);
}
public Candidate getStart() {
@@ -50,4 +51,9 @@ public class Edge {
public String toString() {
return "From ID " + start.getID() + " to " + end.getID() + ": " + getProbability();
}
@Override
public int compareTo(Edge o) {
return start != o.getStart() ? start.compareTo(o.getStart()) : end != o.getEnd() ? end.compareTo(o.getEnd()) : getProbability().compareTo(o.getProbability());
}
}