diff --git a/src/main/java/de/ohnes/AlgorithmicComponents/Approximation/TrivialLowerBound.java b/src/main/java/de/ohnes/AlgorithmicComponents/Approximation/TrivialLowerBound.java new file mode 100644 index 0000000..2097af5 --- /dev/null +++ b/src/main/java/de/ohnes/AlgorithmicComponents/Approximation/TrivialLowerBound.java @@ -0,0 +1,20 @@ +package de.ohnes.AlgorithmicComponents.Approximation; + +import de.ohnes.util.Instance; + +public class TrivialLowerBound implements Approximation { + + @Override + public double approximate(Instance I) { + + double totalWork = 0; + + for(int i = 0; i < I.getN(); i++) { + totalWork += Math.min(I.getJob(i).getSequentialProcessingTime(), I.getJob(i).getProcessingTime(1)); + } + + return totalWork / (I.getM() + I.getL()); + + } + +} \ No newline at end of file diff --git a/src/main/java/de/ohnes/AlgorithmicComponents/Knapsack/MDKnapsack.java b/src/main/java/de/ohnes/AlgorithmicComponents/Knapsack/MDKnapsack.java index fecdbc4..959bf9d 100644 --- a/src/main/java/de/ohnes/AlgorithmicComponents/Knapsack/MDKnapsack.java +++ b/src/main/java/de/ohnes/AlgorithmicComponents/Knapsack/MDKnapsack.java @@ -1,6 +1,5 @@ package de.ohnes.AlgorithmicComponents.Knapsack; -import java.util.HashMap; import java.util.List; import de.ohnes.util.Job; @@ -24,15 +23,18 @@ public class MDKnapsack { * @param smallJobs * @param seqJobs */ - public void solve(List smallItems, List bigItems, Vector3D capacity, List shelf1, List shelf2, List smallJobs, List seqJobs) { - + public boolean solve(List smallItems, List bigItems, Vector3D capacity, List shelf1, List shelf2, List smallJobs, List seqJobs) { + List items = new java.util.ArrayList<>() {{ + addAll(smallItems); + addAll(bigItems); + }}; int b = bigItems.size(); int s = smallItems.size(); int n = s + b; //TODO: reduce 3rd dimension - Double[][][][] dp = new Double[b+1][capacity.get(0)+1][capacity.get(2)+1][capacity.get(1)+1]; - - + Double[][][][] dp = new Double[n+1][capacity.get(0)+1][capacity.get(1)+1][capacity.get(2)+1]; + + //initialization for (int x1 = 0; x1 < dp[0].length; x1++) { for (int x2 = 0; x2 < dp[0][x1].length; x2++) { @@ -41,12 +43,12 @@ public void solve(List smallItems, List bigItems } } } - + //acutal dp - // fist solve the knapsack problem for the big items - for (int i = 1; i <= bigItems.size(); i++) { - Integer[] costs = bigItems.get(i-1).getCosts(); - Vector3D[] weights = bigItems.get(i-1).getWeights(); + for (int i = 1; i <= items.size(); i++) { + boolean placed = false; + Integer[] costs = items.get(i-1).getCosts(); + Vector3D[] weights = items.get(i-1).getWeights(); for (int x1 = 0; x1 < dp[0].length; x1++) { for (int x2 = 0; x2 < dp[0][x1].length; x2++) { for (int x3 = 0; x3 < dp[0][x1][x2].length; x3++) { @@ -54,8 +56,8 @@ public void solve(List smallItems, List bigItems for (int c = 0; c < costs.length; c++) { //for the choices Vector3D w = weights[c]; int x1_ = x1 - w.get(0); - int x2_ = x2 - w.get(2); - int x3_ = x3 - w.get(1); + int x2_ = x2 - w.get(1); + int x3_ = x3 - w.get(2); if (x1_ < 0 || x2_ < 0 || x3_ < 0) { continue; } @@ -68,118 +70,38 @@ public void solve(List smallItems, List bigItems } if (minVal < Double.MAX_VALUE) { dp[i][x1][x2][x3] = minVal; + placed = true; } } } } - } - - //discard 2nd constraint, as the small items don't change it. - - Double[][][] dp2 = new Double[s+1][capacity.get(0)+1][capacity.get(2)+1]; - HashMap map = new HashMap<>(); // a map to remember the position of the best solution for the big items - //initialization - for (int x1 = 0; x1 < dp[0].length; x1++) { - for (int x2 = 0; x2 < dp[0][x1].length; x2++) { - // find the best solution for the big items - // dp2[0][x1][x2] = Arrays.stream(dp[bigItems.size()][x1][x2]).filter(d -> d != null).min(Double::compare).orElse(null); - // remember the position of best solution - for (int i = 0; i < dp[b][x1][x2].length; i++) { - if (dp[b][x1][x2][i] != null) { - String key = x1 + "," + x2; - if (map.containsKey(key)) { - if (dp[b][x1][x2][i] < dp2[0][x1][x2]) { - map.put(key, i); - dp2[0][x1][x2] = dp[b][x1][x2][i]; - } - } else { - map.put(key, i); - dp2[0][x1][x2] = dp[b][x1][x2][i]; - } - } - } + if (!placed) { + return false; } } - //acutal dp - // solve the knapsack problem for the remaining small items - for (int i = 1; i <= s; i++) { - Integer[] costs = smallItems.get(i-1).getCosts(); - Vector3D[] weights = smallItems.get(i-1).getWeights(); - for (int x1 = 0; x1 < dp2[0].length; x1++) { - for (int x2 = 0; x2 < dp2[0][x1].length; x2++) { - double minVal = Double.MAX_VALUE; - for (int c = 0; c < costs.length; c++) { //for the choices - Vector3D w = weights[c]; - int x1_ = x1 - w.get(0); - int x2_ = x2 - w.get(2); - if (x1_ < 0 || x2_ < 0) { - continue; - } - if (dp2[i-1][x1_][x2_] == null) { - continue; - } - if (dp2[i-1][x1_][x2_] + costs[c] < minVal) { - minVal = dp2[i-1][x1_][x2_] + costs[c]; - } - } - if (minVal < Double.MAX_VALUE) { - dp2[i][x1][x2] = minVal; - } - } - } - } - - Vector3D minValue = new Vector3D(0, 0, 0); double minCost = Double.MAX_VALUE; - for (int x1 = 0; x1 < dp2[0].length; x1++) { - for (int x2 = 0; x2 < dp2[0][x1].length; x2++) { - if (dp2[s][x1][x2] != null && dp2[s][x1][x2] < minCost) { - minCost = dp2[s][x1][x2]; - minValue = new Vector3D(x1, 0, x2); - } - } - } - minValue.set(1, map.get(minValue.get(0) + "," + minValue.get(2))); // set the 2nd dimension to the best solution for the big items - //reconstruction for small items - for (int i = s; i > 0; i--) { - MDKnapsackItem item = smallItems.get(i - 1); - for (KnapsackChoice choice : item.getChoices()) { - Vector3D newWeight = minValue.subtract(choice.getWeight()); - if (newWeight.get(0) < 0 || newWeight.get(1) < 0 || newWeight.get(2) < 0) { - continue; - } - if (dp2[i-1][newWeight.get(0)][newWeight.get(2)] != null) { - switch (choice.getAllotment()) { - case SMALL: - smallJobs.add(item.getJob()); - break; - case SEQUENTIAL: - seqJobs.add(item.getJob()); - break; - case SHELF1: - shelf1.add(item.getJob()); - break; - case SHELF2: - shelf2.add(item.getJob()); - break; + for (int x1 = 0; x1 < dp[0].length; x1++) { + for (int x2 = 0; x2 < dp[0][x1].length; x2++) { + for (int x3 = 0; x3 < dp[0][x1][x2].length; x3++) { + if (dp[items.size()][x1][x2][x3] != null && dp[items.size()][x1][x2][x3] < minCost) { + minCost = dp[items.size()][x1][x2][x3]; + minValue = new Vector3D(x1, x2, x3); } - minValue = newWeight; - break; //break out of loop as soon as some allotment was found. } } } - //reconstruction for big items - for (int i = b; i > 0; i--) { - MDKnapsackItem item = bigItems.get(i - 1); + //reconstruction + for (int i = items.size(); i > 0; i--) { + MDKnapsackItem item = items.get(i - 1); for (KnapsackChoice choice : item.getChoices()) { Vector3D newWeight = minValue.subtract(choice.getWeight()); if (newWeight.get(0) < 0 || newWeight.get(1) < 0 || newWeight.get(2) < 0) { continue; } - if (dp[i-1][newWeight.get(0)][newWeight.get(2)][newWeight.get(1)] != null) { + if (dp[i-1][newWeight.get(0)][newWeight.get(1)][newWeight.get(2)] != null) { switch (choice.getAllotment()) { case SMALL: smallJobs.add(item.getJob()); @@ -200,6 +122,7 @@ public void solve(List smallItems, List bigItems } } // at the end we should arrive at 0.0 - assert dp[0][minValue.get(0)][minValue.get(2)][minValue.get(1)] == 0.0; + assert dp[0][minValue.get(0)][minValue.get(1)][minValue.get(2)] == 0.0; + return true; } } diff --git a/src/main/java/de/ohnes/AlgorithmicComponents/Shelves/CpuGpuApproach.java b/src/main/java/de/ohnes/AlgorithmicComponents/Shelves/CpuGpuApproach.java index 7a4809f..bd5a046 100644 --- a/src/main/java/de/ohnes/AlgorithmicComponents/Shelves/CpuGpuApproach.java +++ b/src/main/java/de/ohnes/AlgorithmicComponents/Shelves/CpuGpuApproach.java @@ -36,8 +36,7 @@ public boolean solve(double d, double epsilon) { final int invDelta = 6; final int n = I.getN(); final int l = I.getL(); - final double v = (2.0 * invDelta) / d; //TODO: separate rounding for big tasks and small tasks - final double mu = (1.0 * n * invDelta) / d * l; + final double mu = (1.0 * n * invDelta) / d; List shelf2 = new ArrayList<>(Arrays.asList(MyMath.findBigJobs(I, d))); List smallJobs = new ArrayList<>(Arrays.asList(MyMath.findSmallJobs(I, d))); @@ -118,8 +117,10 @@ public boolean solve(double d, double epsilon) { // 2nd dimension: weight of tasks on L (less than 2l) // 3rd dimension: total work regarding the scaled and rounded instace on L (less than n/\delta) // -> optimized: (less than 2l/\delta) - Vector3D capacity = new Vector3D(I.getM(), 2* l, invDelta * 2 * l + 1); - kS.solve(smallKnapsackItems, bigKnapsackItems, capacity, shelf1, shelf2, smallJobs, sequentialJobs); + Vector3D capacity = new Vector3D(I.getM(), 2* l, invDelta * l * n); + if (!kS.solve(smallKnapsackItems, bigKnapsackItems, capacity, shelf1, shelf2, smallJobs, sequentialJobs)) { + return false; + } // calculate the work for the jobs in the shelves for the malleable machines. double Ws = 0; diff --git a/src/main/java/de/ohnes/App.java b/src/main/java/de/ohnes/App.java index 95ac05a..02c1eea 100644 --- a/src/main/java/de/ohnes/App.java +++ b/src/main/java/de/ohnes/App.java @@ -2,17 +2,15 @@ import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil.Test; import com.fasterxml.jackson.databind.ObjectMapper; +import de.ohnes.AlgorithmicComponents.Approximation.TrivialLowerBound; import de.ohnes.AlgorithmicComponents.Approximation.TwoApproximation; import de.ohnes.AlgorithmicComponents.Shelves.CpuGpuApproach; import de.ohnes.logger.MyElasticsearchClient; @@ -102,14 +100,13 @@ private static void readEnv() { */ private static TestResult runTest(Instance I) { - DualApproximationFramework dF = new DualApproximationFramework(null, new CpuGpuApproach(), new TwoApproximation(), I); + DualApproximationFramework dF = new DualApproximationFramework(null, new CpuGpuApproach(), new TrivialLowerBound(), I); long startTime = System.currentTimeMillis(); double d = dF.start(epsilon); long endTime = System.currentTimeMillis(); LOGGER.info("Ran instance with {} malleable, {} sequential machines and {} jobs in {} milliseconds.", I.getM(), I.getL(), I.getN(), (endTime - startTime)); - TestResult tr = new TestResult(); tr.setAchivedMakespan(I.getMakespan()); tr.setEstimatedOptimum(d); @@ -119,7 +116,8 @@ private static TestResult runTest(Instance I) { tr.setSeqMachines(I.getL()); tr.setMilliseconds((endTime - startTime)); tr.setInstanceID(I.getId()); - + + LOGGER.info("Result: {}", tr.toString()); return tr; } } diff --git a/src/main/java/de/ohnes/util/TestResult.java b/src/main/java/de/ohnes/util/TestResult.java index 446eb03..bdfd17a 100644 --- a/src/main/java/de/ohnes/util/TestResult.java +++ b/src/main/java/de/ohnes/util/TestResult.java @@ -18,4 +18,8 @@ public class TestResult { private double achivedMakespan; private long milliseconds; + public String toString() { + return String.format("%d, %d, %d, %d, %d, %f, %f, %d", InstanceID, jobs, machines, seqMachines, malMachines, estimatedOptimum, achivedMakespan, milliseconds); + } + }