mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 05:11:04 +00:00
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:
1 parent
be3a144e43
commit
851f002b9a
7 files changed
+109
-47
No files matched your search
+50
-9
@@ -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.
|
||||
*
|
||||
|
||||
+1
@@ -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 {
|
||||
|
||||
+1
@@ -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 {
|
||||
|
||||
+15
-10
@@ -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());
|
||||
}
|
||||
}
|
||||
+30
-22
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+11
-5
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user