I've been trying to get my head around the problem, but haven't managed to do so.
In short, I have written a bee hive algorithm, where one of it's premutations is sorting block of points, by distance to a point preceding the block sorted.
This permutation uses a Comparator
public class PointDistanceComparator implements Comparator {
@Override
public int compare(Object arg0, Object arg1) {
double resultDouble = ((Point) arg1).getSortUsageDistance()-((Point) arg0).getSortUsageDistance();
if(resultDouble>0){
return 1;
}
else if(resultDouble==0){
return 0;
}
else{
return -1;
}
}
}
I calculate distances to preceding point for every point in block:
List<Point> pointsVector = new ArrayList<Point>();
double distance = 0;
Point point2 = pointsToVisit.get(visitedPoints.get(visitedPointsPossibleInputStartingIndex));
for(int k = visitedPointsPossibleInputStartingIndex+1; k < visitedPointsPossibleInputEndingIndex; k++){
Point point = pointsToVisit.get(visitedPoints.get(k));
distance = Utils.getDistanceKm(point2, point);
point.setSortUsageDistance(distance);
pointsVector.add(point);
}
And I try to sort it:
try{
PointDistanceComparator pdComparator = new PointDistanceComparator();
pointsVector.sort(pdComparator);
int pointsVectorIndex = 0;
for(int k = visitedPointsPossibleInputStartingIndex+1; k < visitedPointsPossibleInputEndingIndex; k++){
visitedPoints.set(k, pointsVector.get(pointsVectorIndex).getIndex());
pointsVectorIndex++;
}
}
catch(Exception e){
System.out.println("Unsortable route: ");
for(Point point : pointsVector){
System.out.println(point.getSortUsageDistance());
}
e.printStackTrace();
}
And the result I get (for high amount of points) is:
Unsortable route:
2.409437209114269
4.195074884990501
0.9691536825922977
1.1818593906071124
3.7959341231055044
1.344833460712328
2.7808472396551256
2.3341362332820377
3.0826195327369685
5.981871507031457
4.096491609253349
2.6730445628945447
3.6026805136626736
5.070192970603796
6.525798962460061
2.437658869598336
2.3249264696009666
2.22717482314044
1.3205919751367337
1.4326093612218957
5.032187900596256
2.6186056819000028
3.715867402052429
2.905908208286016
1.25868451375791
1.5362377319604628
3.4961506217046376
2.961495413336175
1.9345437912998407
4.49333274460376
3.2997943500252442
4.5252963191878175
5.336224710120464
Which even excel can sort just fine (needs swapping . for ,).
Stack trace:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.ArrayList.sort(Unknown Source)
at beeAlgorithm.BeeHive.sortBlockByDistanceToPrecedingPoint(BeeHive.java:334)
at beeAlgorithm.BeeHive.permuteRoute(BeeHive.java:172)
at beeAlgorithm.BeeHive.searchRouteNeighbourhood(BeeHive.java:144)
at beeAlgorithm.BeeHive.iterateOverRoute(BeeHive.java:130)
at beeAlgorithm.BeeHive.iterateOverAllRoutes(BeeHive.java:123)
at beeAlgorithmAgents.BeeHiveAgent$1.action(BeeHiveAgent.java:114)
at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1552)
at jade.core.Agent.run(Agent.java:1491)
at java.lang.Thread.run(Unknown Source)
This is run on a multithreaded environment (JADE agents).
Seems like my compare method has a hole, but I just can't find it. Any clues?
Edit (fixed):
Seems like generating my points list was the issue. I don't have a single clue as to why it didn't work with:
List<Point> points = new ArrayList<Point>();
for(int l = 0; l < algInputParameters.getPointsAmount(); l++){
Point point = null;
if(l == 0){
point = new Point(0, 24*1024, 0, 0, 0, 0, 0);
if(algInputParameters.isCityCiechanow()){
point.generatePositionForCiechanow(random);
}
else if(algInputParameters.isCityTorun()){
point.generatePositionForTorun(random);
}
else{
point.generatePositionForWarsaw(random);
}
}
else{
point = new Point(0, 0, l, visitTime, 0, 0, 0);
point.generateHours(random, startHour, endHour, duration);
if(algInputParameters.isCityCiechanow()){
point.generatePositionForCiechanow(random);
}
else if(algInputParameters.isCityTorun()){
point.generatePositionForTorun(random);
}
else{
point.generatePositionForWarsaw(random);
}
}
points.add(point);
}
But worked with:
List<Point> points = new ArrayList<Point>();
for(int l = 0; l <algInputParameters.getBeeAmount(); l++){
if(l == 0){
Point point = new Point(0, 24*1024, 0, 0, 0, 0, 0);
if(algInputParameters.isCityCiechanow()){
point.generatePositionForCiechanow(random);
}
else if(algInputParameters.isCityTorun()){
point.generatePositionForTorun(random);
}
else if(algInputParameters.isCityWarszawa()){
point.generatePositionForWarsaw(random);
}
points.add(point);
}
else{
Point point = new Point(0, 0, l, visitTime, 0, 0, 0);
point.generateHours(random, startHour, endHour, duration);
if(algInputParameters.isCityCiechanow()){
point.generatePositionForCiechanow(random);
}
else if(algInputParameters.isCityTorun()){
point.generatePositionForTorun(random);
}
else if(algInputParameters.isCityWarszawa()){
point.generatePositionForWarsaw(random);
}
points.add(point);
}
}
Honestly, no single idea . There is no concurrency when creating the pool of Points, though even if a Point stayed as "null", I'd get a null pointer exception sooner. Perhaps some people will encounter the same problem, just leaving it here.
Accepted the answer with BigDecimal usage, as it is most likely to answer any of the possible future searches