diff --git a/.vscode/launch.json b/.vscode/launch.json index 19b9e6e914d5104afd0e03c031105f1c9708fac7..2d3f6be09d5825cba590575e3f935560f4b22b71 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "request": "launch", "mainClass": "cvrp_ls", "projectName": "optialgos_92db6011", - "args": ["C:\\Users\\Jule Behrens\\Documents\\JonahAlgos\\optialgos\\src\\instances\\Loggi-n401-k23.vrp", "taboo_search", "3600", "50"] + "args": ["C:\\Users\\Jule Behrens\\Documents\\JonahAlgos\\optialgos\\src\\instances\\Loggi-n401-k23.vrp", "taboo_search", "14400"] } ] } \ No newline at end of file diff --git a/README.md b/README.md index c78d38a05364e8295cc25f361b9a72d06c6b4ec9..91abf4da088ec691a74822d693ec669b251c34fe 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ zeigen muss. Das Programm gibt die Kosten für die Initial ermittelte Lösung mit einem Greedy-Approach und die mit basic local search ohne Zeitlimit optimierte Lösung und anschließend die Lösungen selbst im .sol Format aus. Alternativ kann ein Algorithmus spezifiziert werden mit "java cvrp_ls *absolutePath* *algorithm*". Dabei sind die Optionen für *algorithm* "basic_local_serach", "taboo_search" und "ant_colony". -Für "taboo_search" und "ant_colony" muss zudem eine maximale Laufzeit für die Optimierung in vollen Sekunden angegeben werden ("java cvrp_ls *absolutePath* *algorithm* *maxTimeInSeconds*"). Für "basic_local_serach" ist das optional. +Für "taboo_search" und "ant_colony" muss zudem eine maximale Laufzeit (integer) für die Optimierung in vollen Sekunden angegeben werden ("java cvrp_ls *absolutePath* *algorithm* *maxTimeInSeconds*"). Für "basic_local_search" ist das optional. -"taboo_search" kann optional ein weiterer Parameter mitgegeben werden: Die Anzahl der Taboos. Der Standardwert liegt bei *Anzahl der Knoten/3* abgerundet. Ein möglicher Aufruf wäre: "java cvrp_ls *absolutePath* taboo_search *maxTimeInSeconds* *numberOfTaboos*". \ No newline at end of file +"taboo_search" kann optional ein weiterer Parameter mitgegeben werden: Die Anzahl der Taboos (integer). Der Standardwert liegt bei *Anzahl der Knoten/2* abgerundet. Ein möglicher Aufruf wäre: "java cvrp_ls *absolutePath* taboo_search *maxTimeInSeconds* *numberOfTaboos*". + +"ant_colony" können optional weitere Parameter mitgegeben werden: Die Anzahl der Ameisen (Standardwert: *Anzahl der Knoten x 5*), Anzahl der Pheromone, die eine Ameise zu einer Kante addiert (Standardwert: 10, integer), Anzahl der Pheromone, die in einer minor round verloren gehen (Standardwert: 1, integer), ob die Pheromone zwischen major rounds zurückgesetzt werden sollen (Standard: 0 (nein), integer[0 = nein, alles andere = ja]) und die Strategie zur Auswahl des ersten Knotens der Ameisen ("depot" oder "even", mit Standard "even"). Dabei bedeutet "depot", dass alle Ameisen vom Depot aus starten, während "even" bedeutet, dass die Ameisen gleichmäßig verteilt auf den Knoten starten, wobei ein erster Weg vom Depot aus impliziert ist. Ein möglicher Aufruf wäre: "java cvrp_ls *absolutePath* ant_colony *maxTimeInSeconds* *numberOfAnts* *numberOfPheromonesAdded* *numberOfPheromonesDecayes* *resetPheromonesBetweenMajorRounds* *antDeployStrategy*". \ No newline at end of file diff --git a/bin/Algorithms.class b/bin/Algorithms.class index b6ae11b222029b818ae7893b44664a06c8973154..35d59ae45df963d6188d6319629084a5f37e3b36 100644 Binary files a/bin/Algorithms.class and b/bin/Algorithms.class differ diff --git a/bin/Ant.class b/bin/Ant.class new file mode 100644 index 0000000000000000000000000000000000000000..3de4d524734dece42485a07e8a9cb06237c50480 Binary files /dev/null and b/bin/Ant.class differ diff --git a/bin/Node.class b/bin/Node.class index 05e69ee717aba2ef28568fa6305e7e5f8f7250fa..42144557dfcd10696d3f49782dc4f89c50bb3dbe 100644 Binary files a/bin/Node.class and b/bin/Node.class differ diff --git a/bin/Solution.class b/bin/Solution.class index 2cf9957a6dd60cf27a03de8ecc06e93c2f4377c3..89ae1e30c6e273bfdc0d9a6b53c5c1867ac05895 100644 Binary files a/bin/Solution.class and b/bin/Solution.class differ diff --git a/bin/cvrp_ls.class b/bin/cvrp_ls.class index b881a47e3112097351bffd1753ab79d4097b2e25..0be1a074a6884820ab71538bbe23f451418625d5 100644 Binary files a/bin/cvrp_ls.class and b/bin/cvrp_ls.class differ diff --git a/src/Algorithms.class b/src/Algorithms.class index fb297dc91aaf997c811fb976fbe8cf4dc18fc6f2..c69bede3dd854a0925a39002e23dfdc2475cb6b4 100644 Binary files a/src/Algorithms.class and b/src/Algorithms.class differ diff --git a/src/Algorithms.java b/src/Algorithms.java index 590b7d1d279c00ea4516a0b8b404490ee34f01a2..37db3350d736ab0960d4fe2874474d17dca54f92 100644 --- a/src/Algorithms.java +++ b/src/Algorithms.java @@ -3,8 +3,13 @@ import java.util.Arrays; public class Algorithms { + int pheromonesStrength = -1; + String antStartStrategy = ""; + int pheromonesDecayStrength = -1; String algorithmType; + boolean resetPheromones = false; int maxRuntimeInSeconds = -1; + int numberOfAnts = -1; int numberOfTaboos = -1; public Algorithms(){} public Algorithms(String algorithmType, String[] optionalParams) throws Exception{ @@ -20,8 +25,29 @@ public class Algorithms { this.algorithmType = "basic_local_search"; break; case "ant_colony": + try { + this.numberOfAnts = Integer.valueOf(optionalParams[1]); + this.pheromonesStrength = Integer.valueOf(optionalParams[2]); + this.pheromonesDecayStrength = Integer.valueOf(optionalParams[3]); + if(Integer.valueOf(optionalParams[4]) == 0){ + this.resetPheromones = false; + } else { + this.resetPheromones = true; + } + this.antStartStrategy = optionalParams[4]; + } catch (Exception e) { + + } if(maxRuntimeInSeconds <= 0) throw new Exception(); + if(this.pheromonesStrength <= 0) + System.out.println("Using standard value for pheromone strength."); + if(this.antStartStrategy.equals("")) + System.out.println("Using standard value for ant start strategy."); + if(this.pheromonesDecayStrength <= 0) + System.out.println("Using standard value for pheromone decay strength."); + if(this.numberOfAnts <= 0) + System.out.println("Using standard value for number of ants."); break; case "taboo_search": try { @@ -45,6 +71,15 @@ public class Algorithms { case "greedy": return generateInitialSolutionGreedy(instance); case "ant_colony": + //setting default parameters if needed + if(this.numberOfAnts <= 0) + numberOfAnts = Math.multiplyExact(instance.getDimension(),5); + if(this.pheromonesDecayStrength <= 0) + pheromonesDecayStrength = 1; + if(this.pheromonesStrength <= 0) + pheromonesStrength = 10; + if(this.antStartStrategy.equals("")) + antStartStrategy = "even"; return generateInitialSolutionAnt(instance); default: return null; @@ -58,20 +93,21 @@ public class Algorithms { case "greedy": return generateInitialSolutionGreedy(solution.instance); case "taboo_search": + //setting default parameters if needed if(this.numberOfTaboos <= 0) numberOfTaboos = solution.instance.getDimension()/3; return tabooSearch(solution); case "ant_colony": - return generateInitialSolutionAnt(solution.instance); + return generateSolution(solution.instance); default: - return null; + return localSearch(solution); } } private Solution tabooSearch(Solution solution) { int[] state = {2,0,0,0}; int newBestCount = 0; - + int time =0; Solution currentSolution = solution; Solution bestSolutionSeen = solution; @@ -86,10 +122,28 @@ public class Algorithms { while(maxRuntimeInSeconds > 0 && System.currentTimeMillis()<end){ - if(possibleBetterNeighbor.getCost() < currentBestNeighbor.getCost()){ - currentBestNeighbor = possibleBetterNeighbor; - currentBestNeighborNodeChanged = state[0]; + if(System.currentTimeMillis()>start+1000 && time == 0){ + try{System.out.println("1 Sekunde: " + bestSolutionSeen.getCost());}catch(Exception e){} + time++; + } + if(System.currentTimeMillis()>start+10000 && time == 1){ + try{System.out.println("10 Sekunde: " + bestSolutionSeen.getCost());}catch(Exception e){} + time++; } + if(System.currentTimeMillis()>start+60000 && time == 2){ + try{System.out.println("60 Sekunde: " + bestSolutionSeen.getCost());}catch(Exception e){} + time++; + } + try { + if(possibleBetterNeighbor.getCost() < currentBestNeighbor.getCost()){ + currentBestNeighbor = possibleBetterNeighbor; + currentBestNeighborNodeChanged = state[0]; + } + } catch (Exception e) { + + + } + //permutate state to get another neighbor which is not taboo state[0]++; while(taboos.contains(state[0])){ @@ -111,17 +165,22 @@ public class Algorithms { if(state[3] == 2){ currentSolution = currentBestNeighbor; //System.out.println("Made a step, taboos: "+taboos.size()); - if(currentSolution.getCost() < bestSolutionSeen.getCost()){ - bestSolutionSeen = currentSolution; - - System.out.println("Found new best solution "+(++newBestCount) + ": All "+taboos.size()+" taboos dropped"); - taboos.clear(); - } else { - taboos.add(currentBestNeighborNodeChanged); - if(taboos.size() > numberOfTaboos){ - taboos.remove(0); + try { + if(currentSolution.getCost() < bestSolutionSeen.getCost()){ + bestSolutionSeen = currentSolution; + + System.out.println("Found new best solution "+(++newBestCount) + ": All "+taboos.size()+" taboos dropped"); + taboos.clear(); + } else { + taboos.add(currentBestNeighborNodeChanged); + if(taboos.size() > numberOfTaboos){ + taboos.remove(0); + } } + } catch (Exception e) { + } + int[] help = {2,0,0,0}; state = help; currentBestNeighbor = getOtherNeighbor(state, currentSolution); @@ -136,8 +195,116 @@ public class Algorithms { } private Solution generateInitialSolutionAnt(Instance instance) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'generateInitialSolutionAnt'"); + Solution bestSeenSolution = null; + int time = 0; + int newBestSolutionCount = 0; + int[][] pheromonesOnEdge = new int[instance.getDimension()+1][instance.getDimension()+1]; + //initialize all edges with phermone score 1 + for (int i = 0; i < pheromonesOnEdge.length; i++) { + for (int j = 0; j < pheromonesOnEdge[i].length; j++) { + pheromonesOnEdge[i][j] = 1; + } + } + + long start = System.currentTimeMillis(); + long end = start + this.maxRuntimeInSeconds * 1000; + + while(maxRuntimeInSeconds > 0 && System.currentTimeMillis()<end){ + //if optional parameter is set, reset pheromones inbetween major rounds + if(System.currentTimeMillis()>start+1000 && time == 0){ + try{System.out.println("1 Sekunde: " + bestSeenSolution.getCost());}catch(Exception e){} + time++; + } + if(System.currentTimeMillis()>start+10000 && time == 1){ + try{System.out.println("10 Sekunde: " + bestSeenSolution.getCost());}catch(Exception e){} + time++; + } + if(System.currentTimeMillis()>start+60000 && time == 2){ + try{System.out.println("60 Sekunde: " + bestSeenSolution.getCost());}catch(Exception e){} + time++; + } + if(resetPheromones) { + for (int i = 0; i < pheromonesOnEdge.length; i++) { + for (int j = 0; j < pheromonesOnEdge[i].length; j++) { + pheromonesOnEdge[i][j] = 1; + } + } + } + + ArrayList<Ant> ants = new ArrayList<Ant>(); + for (int i = 0; i < numberOfAnts; i++) { + switch (antStartStrategy) { + case "depot": + ants.add(new Ant(instance)); + break; + case "even": + default: + ants.add(new Ant(instance, i+1)); + break; + } + + } + while(!antsAreAllDone(ants)){ + ArrayList<int[]> walkedEdges = new ArrayList<int[]>(); + //let ants do one minor round + for (Ant ant : ants) { + int[] walkedEdge = ant.makeStepInMinorRound(pheromonesOnEdge); + walkedEdges.add(walkedEdge); + } + //update pheromones after minor round + for (int[] walkedEdge : walkedEdges) { + if(walkedEdge != null){ + if(walkedEdge[0] < walkedEdge[1]){ + pheromonesOnEdge[walkedEdge[1]][walkedEdge[0]] += pheromonesStrength; + } else { + pheromonesOnEdge[walkedEdge[0]][walkedEdge[1]] += pheromonesStrength; + } + } + } + //let pheromones decay (not under 1) + for (int i = 0; i < pheromonesOnEdge.length; i++) { + for (int j = 0; j < pheromonesOnEdge[i].length; j++) { + pheromonesOnEdge[i][j] -= pheromonesDecayStrength; + if(pheromonesOnEdge[i][j]<1){ + pheromonesOnEdge[i][j] = 1; + } + } + } + } + //check if ant has discovered new best solution + for (Ant ant : ants) { + Solution antsSolution = ant.toSolution(); + + if(bestSeenSolution == null){ + System.out.println("Found new best solution "+(++newBestSolutionCount)); + bestSeenSolution = antsSolution; + } else { + try { + if(bestSeenSolution.getCost() > antsSolution.getCost()){ + System.out.println("Found new best solution "+(++newBestSolutionCount)); + bestSeenSolution = antsSolution; + } + } catch (Exception e) { + + } + } + + + } + } + + return bestSeenSolution; + } + + private boolean antsAreAllDone(ArrayList<Ant> ants){ + boolean allDone = true; + for (Ant ant : ants) { + if(!ant.done){ + allDone = false; + break; + } + } + return allDone; } //primitive greedy Approach @@ -200,7 +367,6 @@ public class Algorithms { i++; } solution.tours = convertedTours; - solution.getCost(); return solution; } @@ -209,50 +375,55 @@ public class Algorithms { Solution currentBestSolution = solution; int[] state = {2,0,0,0}; Solution possibleBetterSolution = getOtherNeighbor(state, currentBestSolution); - int newBestCount = 0; + int newBestSolutionCount = 0; long start = System.currentTimeMillis(); long end = start + this.maxRuntimeInSeconds * 1000; //tries all neighbors as possibleBetterSolution, if better solution found, change currentBestSolution and search from there //terminates when it cannot find a better solution in its neighbarhood while (possibleBetterSolution != null) { - + //stop if max execution time has exceeded if(maxRuntimeInSeconds > 0 && System.currentTimeMillis()>end){ System.out.println("terminated by time limit"); break; } - if(possibleBetterSolution.getCost() < currentBestSolution.getCost()){ - currentBestSolution = possibleBetterSolution; - int[] help = {2,0,0,0}; - state = help; - possibleBetterSolution = getOtherNeighbor(state, currentBestSolution); - System.out.println("found new best solution "+(++newBestCount)); - }else{ - //permutate state to get another neighbor - state[0]++; - if(state[0] > currentBestSolution.instance.getDimension()){ - //System.out.println("reset extracted node"); - state[0] = 2; - state[2]++; - if(state[2] > currentBestSolution.tours[state[1]].length-1){ - //System.out.println("reset position"); - state[2] = 0; - state[1]++; - if(state[1] > currentBestSolution.tours.length-1){ - //System.out.println("reset tours"); - state[1] = 0; - state[3]++; - //stop if all neighbors are worse/local optimum is reached - if(state[3] == 2){ - System.out.println("terminated by local optimum"); - break; + try { + if(possibleBetterSolution.getCost() < currentBestSolution.getCost()){ + currentBestSolution = possibleBetterSolution; + int[] help = {2,0,0,0}; + state = help; + possibleBetterSolution = getOtherNeighbor(state, currentBestSolution); + System.out.println("Found new best solution "+(++newBestSolutionCount)); + }else{ + //permutate state to get another neighbor + state[0]++; + if(state[0] > currentBestSolution.instance.getDimension()){ + //System.out.println("reset extracted node"); + state[0] = 2; + state[2]++; + if(state[2] > currentBestSolution.tours[state[1]].length-1){ + //System.out.println("reset position"); + state[2] = 0; + state[1]++; + if(state[1] > currentBestSolution.tours.length-1){ + //System.out.println("reset tours"); + state[1] = 0; + state[3]++; + //stop if all neighbors are worse/local optimum is reached + if(state[3] == 2){ + System.out.println("terminated by local optimum"); + break; + } } } - } - } - possibleBetterSolution = getOtherNeighbor(state, currentBestSolution); + } + possibleBetterSolution = getOtherNeighbor(state, currentBestSolution); + } + } catch (Exception e) { + } + } diff --git a/src/Ant.class b/src/Ant.class new file mode 100644 index 0000000000000000000000000000000000000000..962616e4582d639a480fea1dd5e70ab48cfa4588 Binary files /dev/null and b/src/Ant.class differ diff --git a/src/Ant.java b/src/Ant.java new file mode 100644 index 0000000000000000000000000000000000000000..121e4fff645051af3a953b5c8b2d21b25816585c --- /dev/null +++ b/src/Ant.java @@ -0,0 +1,140 @@ + import java.util.ArrayList; +import java.util.Arrays; + +public class Ant { + Instance instance; + Node currentNode; + ArrayList<Node> currentTour = new ArrayList<Node>(); + ArrayList<ArrayList<Node>> tours = new ArrayList<ArrayList<Node>>(); + ArrayList<Node> notVisitedNodes; + boolean done = false; + + public Ant(Instance instance){ + this.instance = instance; + notVisitedNodes = new ArrayList<Node>(Arrays.asList(instance.getNodes())); + notVisitedNodes.remove(instance.getDepot()); + currentNode = instance.getDepot(); + notVisitedNodes.remove(0); + } + + public Ant(Instance instance, int startNodeNumber){ + Node currentNode; + currentNode = instance.getDepot(); + this.instance = instance; + notVisitedNodes = new ArrayList<Node>(Arrays.asList(instance.getNodes())); + for (Node node : notVisitedNodes) { + if(node != null && node.number == (startNodeNumber%instance.getDimension())+1){ + currentNode = node; + break; + } + } + notVisitedNodes.remove(instance.getDepot()); + notVisitedNodes.remove(0); + notVisitedNodes.remove(currentNode); + this.currentNode = currentNode; + currentTour.add(currentNode); + + } + + public int[] makeStepInMinorRound(int[][] pheromonesOnEdge){ + //if ant is done with tour return null, else return edge, that she walked + if(this.done){ + return null; + } + Node nextNode = null; + + double currentProbability = 0; + ArrayList<double[]> probabilities = new ArrayList<double[]>(); + if(currentNode.depot){ + currentTour = new ArrayList<Node>(); + } else { + double distance; + double pheromones; + if(currentNode.number < instance.getDepot().number){ + distance = instance.getEdgeWeights()[instance.getDepot().number][currentNode.number]; + pheromones = pheromonesOnEdge[instance.getDepot().number][currentNode.number]; + } else { + distance = instance.getEdgeWeights()[currentNode.number][instance.getDepot().number]; + pheromones = pheromonesOnEdge[instance.getDepot().number][currentNode.number]; + } + double probability = pheromones / distance; + double[] probabilityInterval= new double[3]; + probabilityInterval[0] = currentProbability; + probabilityInterval[1] = currentProbability+probability; + probabilityInterval[2] = instance.getDepot().number; + probabilities.add(probabilityInterval); + currentProbability += probability; + } + for (Node node : notVisitedNodes) { + if(node.demand + sumOfDemands(currentTour) <= instance.getTruckCapacity()){ + double distance; + double pheromones; + if(currentNode.number < node.number){ + distance = instance.getEdgeWeights()[node.number][currentNode.number]; + pheromones = pheromonesOnEdge[node.number][currentNode.number]; + } else { + distance = instance.getEdgeWeights()[currentNode.number][node.number]; + pheromones = pheromonesOnEdge[node.number][currentNode.number]; + } + double probability = pheromones / (distance+1); + double[] probabilityInterval= new double[3]; + probabilityInterval[0] = currentProbability; + probabilityInterval[1] = currentProbability+probability; + probabilityInterval[2] = node.number; + probabilities.add(probabilityInterval); + currentProbability += probability; + } + } + double randomNumber = Math.random()*currentProbability; + int nextNodeNumber = -1; + for (double[] interval : probabilities) { + if(randomNumber >= interval[0] && randomNumber < interval[1]){ + nextNodeNumber = (int)interval[2]; + } + } + + if(nextNodeNumber == instance.getDepot().number){ + tours.add(currentTour); + nextNode = instance.getDepot(); + if(notVisitedNodes.size() == 0){ + this.done = true; + } + } else { + for (Node node : notVisitedNodes) { + if(node.number == nextNodeNumber){ + currentTour.add(node); + nextNode = node; + notVisitedNodes.remove(node); + break; + } + } + } + + + int[] walkedEdge = {currentNode.number,nextNode.number}; + currentNode = nextNode; + + return walkedEdge; + } + + private int sumOfDemands(ArrayList<Node> currentTour){ + int demand = 0; + for (Node node : currentTour) { + demand += node.demand; + } + return demand; + } + + public Solution toSolution(){ + Solution sol = new Solution(instance); + Node[][] tours = new Node[this.tours.size()][]; + int i = 0; + for (ArrayList<Node> tour : this.tours) { + tours[i] = new Node[tour.size()]; + tours[i] = tour.toArray(tours[i]); + i++; + } + sol.tours = tours; + return sol; + } +} diff --git a/src/Node.java b/src/Node.java index 1f7287b2b58880ce9d5da0e50be8e6a7063ae5ba..371ea59cdd7a746e58f77435387ef3a8cb95c13c 100644 --- a/src/Node.java +++ b/src/Node.java @@ -14,6 +14,6 @@ public class Node { public void setDepot(){this.depot = true;} public void setDemand(Integer demand){this.demand = demand;} public String toString(){ - return ""+this.number; + return ""+this.number+"("+this.demand+")"; } } diff --git a/src/Solution.class b/src/Solution.class index a6578c9dc8b3828d0f0cb5db7c7645647a5e0ffc..8c79f11ab933334fabab25d17b62d83051ee20b6 100644 Binary files a/src/Solution.class and b/src/Solution.class differ diff --git a/src/Solution.java b/src/Solution.java index 9d53c54abdc73c92a53b168bf52e69ed906b9d1e..afde66910829b003e87808cc123f6997bc2e69f6 100644 --- a/src/Solution.java +++ b/src/Solution.java @@ -1,16 +1,57 @@ import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashSet; //represents a feasible solution to a instance public class Solution { Instance instance; Node[][] tours; private int cost; + private boolean feasible = false; public Solution(Instance instance){ this.instance = instance; } - public int getCost(){ + public boolean isFeasible() throws Exception{ + ArrayList<Node> allVisitedNodes = new ArrayList<Node>(); + for (Node[] tour : this.tours) { + int tourCost = 0; + int tourDemand = 0; + Node lastNode = instance.getDepot(); + for (Node node : tour) { + if(node != null){ + tourDemand += node.demand; + allVisitedNodes.add(node); + if(lastNode.number > node.number){ + tourCost += instance.getEdgeWeights()[lastNode.number][node.number]; + } else { + tourCost += instance.getEdgeWeights()[node.number][lastNode.number]; + } + lastNode = node; + } + } + tourCost += instance.getEdgeWeights()[lastNode.number][instance.getDepot().number]; + //check if tour is in capacity limit + if(tourDemand > instance.getTruckCapacity()) { + throw new Exception("capacity problem ("+tourDemand + " greater " +instance.getTruckCapacity()+")"); + } + + } + //check if nodes are duplicates + if(allVisitedNodes.size() != new HashSet<Node>(allVisitedNodes).size()) { + throw new Exception("duplicate problem"); + } + //check if right number of nodes is in all tours + if(allVisitedNodes.size() != instance.getDimension()-1) { + throw new Exception("not all nodes problem"); + } + + return this.feasible = true; + } + + public int getCost() throws Exception{ + isFeasible(); this.cost = 0; for (Node[] tour : tours) { Node lastNode = instance.getDepot(); @@ -32,7 +73,7 @@ public class Solution { return this.cost; }; public String toString(){ - String s = "name: "+instance.getName()+ "\n" + "cost: " + cost + "\nTours: "; + String s = "name: "+instance.getName()+ "\n" + "cost: " + cost + "feasible: " + feasible + "\nTours: "; for (Node[] tour : tours) { s += "\n["; for (Node node : tour) { @@ -57,6 +98,7 @@ public class Solution { public String toSol(){ String rep = ""; + for (int i = 0; i < tours.length; i++) { rep += "Route #"+(i+1)+":"; for (Node node : tours[i]) { @@ -68,7 +110,12 @@ public class Solution { } rep += "\n"; } - rep += "Cost " + this.getCost(); + try { + rep += "Cost " + this.getCost(); + } catch (Exception e) { + rep = "not feasible: " + e.getMessage() + "\n" + rep; + } + return rep; } } \ No newline at end of file diff --git a/src/cvrp_ls.class b/src/cvrp_ls.class index 98308e98a6a7e534721ee16364b6e19e9714c6e5..5a06464d68874cdd6103905a145b635ac59db0a5 100644 Binary files a/src/cvrp_ls.class and b/src/cvrp_ls.class differ diff --git a/src/cvrp_ls.java b/src/cvrp_ls.java index 481c19969c4bc5722126298caad645b160679fda..df0ca02ef05d034169e1cda25ea2575762c9be83 100644 --- a/src/cvrp_ls.java +++ b/src/cvrp_ls.java @@ -42,15 +42,29 @@ public class cvrp_ls { } Solution optimizedSolution = chosen.generateSolution(greedySolution); - + //print results - System.out.println(("\nAfter initial greedy Approach, optimized with "+chosen.algorithmType+" with a maximum runtime of approximately "+chosen.maxRuntimeInSeconds+" seconds!").replace("-1", "unlimited")); - System.out.println("Instance name"+" & "+"Cost initial Solution"+" & "+"Cost optimized solution ("+chosen.algorithmType+")"+" & " + "Cost optimal solution (100%)"+ " \\\\"); - if(instance.getOptimalCost() > 0) - System.out.println(instance.getName()+" & "+greedySolution.getCost()+" ("+(float)greedySolution.getCost()/(float)instance.getOptimalCost()*100+"%) & "+optimizedSolution.getCost()+" ("+(float)optimizedSolution.getCost()/(float)instance.getOptimalCost()*100+"%) & "+instance.getOptimalCost() + " \\\\"); - else - System.out.println(instance.getName()+" & "+greedySolution.getCost()+" & "+optimizedSolution.getCost()+" & "+ " \\\\"); - System.out.println("\n Initial solution:\n"+greedySolution.toSol()); - System.out.println("\n Optimized solution:\n"+optimizedSolution.toSol()); + if(chosen.algorithmType.equals( "ant_colony") || chosen.algorithmType.equals("greedy")){ + System.out.println(("\nSolved with "+chosen.algorithmType+" with a maximum runtime of approximately "+chosen.maxRuntimeInSeconds+" seconds!").replace("-1", "unlimited")); + + if(chosen.algorithmType.equals("ant_colony")) + System.out.println("Ants: "+chosen.numberOfAnts+", Phermones Added: "+chosen.pheromonesStrength+", Pheromones Decayed: "+ chosen.pheromonesDecayStrength + ", Deploy Strategy: "+chosen.antStartStrategy+", Reset after Major round: "+chosen.resetPheromones); + System.out.println("Instance name"+" & "+" "+" & "+"Cost solution ("+chosen.algorithmType+")"+" & " + "Cost upper bound (100%)"+ " \\\\"); + if(instance.getOptimalCost() > 0) + System.out.println(instance.getName()+" & " + " & "+optimizedSolution.getCost()+" ("+(float)optimizedSolution.getCost()/(float)instance.getOptimalCost()*100+"%) & "+instance.getOptimalCost() + " \\\\"); + else + System.out.println(instance.getName()+" & "+greedySolution.getCost()+" & "+optimizedSolution.getCost()+" & "+ " \\\\"); + System.out.println("\n Solution:\n"+optimizedSolution.toSol()); + } else { + System.out.println(("\nAfter initial greedy Approach, optimized with "+chosen.algorithmType+" with a maximum runtime of approximately "+chosen.maxRuntimeInSeconds+" seconds!").replace("-1", "unlimited")); + System.out.println("Instance name"+" & "+"Cost initial Solution"+" & "+"Cost optimized solution ("+chosen.algorithmType+")"+" & " + "Cost upper bound (100%)"+ " \\\\"); + if(instance.getOptimalCost() > 0) + System.out.println(instance.getName()+" & "+greedySolution.getCost()+" ("+(float)greedySolution.getCost()/(float)instance.getOptimalCost()*100+"%) & "+optimizedSolution.getCost()+" ("+(float)optimizedSolution.getCost()/(float)instance.getOptimalCost()*100+"%) & "+instance.getOptimalCost() + " \\\\"); + else + System.out.println(instance.getName()+" & "+greedySolution.getCost()+" & "+optimizedSolution.getCost()+" & "+ " \\\\"); + System.out.println("\n Initial solution:\n"+greedySolution.toSol()); + System.out.println("\n Optimized solution:\n"+optimizedSolution.toSol()); + } + } }