diff --git a/src/inport/ConversionUtils/MZnResultsResolver.java b/src/inport/ConversionUtils/MZnResultsResolver.java index 9474c60e4aa75e80cfb43426d0b0dd8daf77ad0e..2d0e7d7901d2e632759e5cfdeb6b3b9ec79a5092 100644 --- a/src/inport/ConversionUtils/MZnResultsResolver.java +++ b/src/inport/ConversionUtils/MZnResultsResolver.java @@ -6,6 +6,86 @@ import java.io.*; import java.util.*; public class MZnResultsResolver { + private static int resolveDimension(String str) { + str = str.trim(); + if (str.equals("{}")) { + return 0; + } + int pos = str.indexOf(".."); + int lim1 = Integer.parseInt(str.substring(0, pos)); + int lim2 = Integer.parseInt(str.substring(pos + 2, str.length())); + return lim2 - lim1 + 1; + } + + private static void parseArray(Map>> arrays, int pos, String line, TaskCase taskCase, String name) { + int index = line.indexOf("array", pos); + + if (index >= pos) { // Из flatzinc-а. + if (line.charAt(index + "array".length()) == '2') { + String[] values = line.substring(line.indexOf('[') + 1, line.indexOf(']')).split(","); + + String[] items = line.substring(line.indexOf('(', pos) + 1, line.indexOf('[')).split(","); + int dim1 = resolveDimension(items[0]); + int dim2 = resolveDimension(items[1]); + + ArrayList> res = new ArrayList<>(); + + for (int i = 0; i < dim1; i++) { + res.add(new ArrayList<>()); + for (int j = 0; j < dim2; j++) { + res.get(i).add(values[i * dim2 + j].trim()); + } + } + arrays.put(name, res); + } + } else { // Из minizinc-а + while ((pos < line.length()) && (line.charAt(pos) != '[') && (line.charAt(pos) != '{')) { + pos++; + } + int arrayFirstDim = ((int) taskCase.getPlanningInterval()) + 2; + + if (line.charAt(pos) == '{') { + pos++; + int nextPos = pos; + while (line.charAt(nextPos) != '}') { + nextPos++; + } + String[] dimensions = line.substring(pos, nextPos).trim().split(" "); + if (dimensions.length > 0) { + arrayFirstDim = Integer.valueOf(dimensions[0].trim()); + } + pos = nextPos + 1; + while (line.charAt(pos) != '[') { + pos++; + } + } + + int pos2 = pos; + while ((pos2 < line.length()) && (line.charAt(pos2) != ']')) { + pos2++; + } + String values = line.substring(pos + 1, pos2); + ArrayList elements = new ArrayList<>(); + + for (String val : values.split(",")) { + elements.add(val.trim()); + } + + if ((arrayFirstDim != 0) && (elements.size() % arrayFirstDim == 0)) { + ArrayList> res = new ArrayList<>(); + + for (int i = 0; i < elements.size(); i += arrayFirstDim) { + ArrayList subRes = new ArrayList<>(); + for (int j = 0; j < arrayFirstDim; j++) { + subRes.add(elements.get(i + j)); + } + res.add(subRes); + } + arrays.put(name, res); + } + } + } + public static void resolveMiniZincResults(TaskCase taskCase, String fileName) { ArrayList operations = null; Integer result = null; @@ -36,66 +116,14 @@ public class MZnResultsResolver { break; } if (name.matches("\\d+")) { - if (result != null) { - continue; - } - result = Integer.parseInt(name); continue; } - - while ((pos < line.length()) && (line.charAt(pos) != '[') && (line.charAt(pos) != '{')) { - pos++; - } - int arrayFirstDim = ((int) taskCase.getPlanningInterval()) + 2; - - if (line.charAt(pos) == '{') { - pos++; - int nextPos = pos; - while (line.charAt(nextPos) != '}') { - nextPos++; - } - String []dimensions = line.substring(pos, nextPos).trim().split(" "); - if (dimensions.length > 0) { - arrayFirstDim = Integer.valueOf(dimensions[0].trim()); - } - pos = nextPos + 1; - while (line.charAt(pos) != '[') { - pos++; - } - } - - int pos2 = pos; - while ((pos2 < line.length()) && (line.charAt(pos2) != ']')) { - pos2++; - } - String values = line.substring(pos + 1, pos2); - ArrayList elements = new ArrayList<>(); - - for (String val : values.split(",")) { - elements.add(val.trim()); - } - - if ((arrayFirstDim != 0) && (elements.size() % arrayFirstDim == 0)) { - ArrayList> res = new ArrayList<>(); - - for (int i = 0; i < elements.size(); i += arrayFirstDim) { - ArrayList subRes = new ArrayList<>(); - for (int j = 0; j < arrayFirstDim; j++) { - subRes.add(elements.get(i + j)); - } - res.add(subRes); - } - arrays.put(name, res); - } - } - - if (result == null) { - throw new ParserException("No result in input"); + parseArray(arrays, pos, line, taskCase, name); } for (String keyArray : Arrays.asList("op_status", "participation_as_resource")) { if (! arrays.containsKey(keyArray)) { - if (result == -1) { + if ((result != null) && (result == -1)) { operations = new ArrayList<>(); } else { throw new ParserException("No \"" + keyArray + "\" in input"); @@ -103,6 +131,19 @@ public class MZnResultsResolver { } } + if (result == null) { + ArrayList> opStatus = arrays.get("op_status"); + result = 0; + + for (ArrayList a : opStatus) { + for (int i = 0; i < a.size(); i++) { + if (a.get(i).trim().equals("true")) { + result = Math.max(result, i); + } + } + } + } + if (result != -1) { Task task = new Task(taskCase, ""); diff --git a/src/inport/ConversionUtils/Solver.java b/src/inport/ConversionUtils/Solver.java new file mode 100644 index 0000000000000000000000000000000000000000..248a2892397c49053cd91a7e475bb1b93adfc645 --- /dev/null +++ b/src/inport/ConversionUtils/Solver.java @@ -0,0 +1,200 @@ +package inport.ConversionUtils; + +import inport.Main; +import inport.TaskCase; + +import java.io.*; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +public class Solver { + private final Lock lock = new ReentrantLock(); + private final Condition condition = lock.newCondition(); + private Boolean isDestroyed; + + private TaskCase task; + private final String constraintName; + private final BiConsumer converterToMinizincFormat; + private final BiConsumer interpreter; + private String tempDir = "temp_data"; + private int timeLimitS; + private String flatZincSolver = ""; + + public void setTask(TaskCase task) { + this.task = task; + } + public void setTempDir(String tempDir) { + this.tempDir = tempDir; + } + public void setTimeLimitS(int timeLimitS) { + this.timeLimitS = timeLimitS; + } + public void setFlatZincSolver(String flatZincSolver) { + this.flatZincSolver = flatZincSolver; + } + + public String getFlatZincSolver() { + return flatZincSolver; + } + + public Solver(String constraintName, + BiConsumer converterToMinizincFormat, + BiConsumer interpreter) { + this.constraintName = constraintName; + this.converterToMinizincFormat = converterToMinizincFormat; + this.interpreter = interpreter; + } + + public String solve() { + File directory = new File(tempDir); + if (!directory.exists()) { + directory.mkdir(); + } + + tempDir = tempDir + "/"; + String minizincData = tempDir + "minizinc_data.dzn"; + String solverResults = tempDir + "solver_results.txt"; + String constraints = tempDir + "constraints.mzn"; + String flatZincConstraints = tempDir + "model.fzn"; + + try { + try (FileWriter res = new FileWriter(constraints)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream("/constraints/" + constraintName))); + String line; + while ((line = reader.readLine()) != null) { + res.write(line + "\n"); + } + } + converterToMinizincFormat.accept(task, minizincData); + + ProcessBuilder pb; + boolean isResultsInOutput; + + if (flatZincSolver.isEmpty()) { + pb = new ProcessBuilder("minizinc", + "--solver", "Chuffed", + constraints, minizincData, + "-o", solverResults); + isResultsInOutput = false; + } else { + isResultsInOutput = true; + { + ProcessBuilder lPB = new ProcessBuilder("mzn2fzn", + "-o", flatZincConstraints, + constraints, + minizincData); + Process process = lPB.start(); + process.waitFor(); + + BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); + String output = br.lines().collect(Collectors.joining("\n")); + + if (output.trim().equals("=====UNSATISFIABLE=====")) { + task.setSolution(new ArrayList<>()); + task.setSolution_result(-1); + return ""; + } + } + pb = new ProcessBuilder("external_tools/or-tools_flatzinc_Ubuntu-18.04-64bit_v7.2.6977/bin/fzn-or-tools", + flatZincConstraints); + + } + + lock.lock(); + isDestroyed = false; + lock.unlock(); + + final Process process = pb.start(); + + Thread killer = new Thread(() -> { + lock.lock(); + long start = System.currentTimeMillis(); + try { + while (process.isAlive()) { + long currentTimeMillis = System.currentTimeMillis(); + + if (currentTimeMillis - start > timeLimitS * 1000) { + process.destroyForcibly(); + isDestroyed = true; + break; + } + condition.await(timeLimitS * 1000 - (currentTimeMillis - start), TimeUnit.MILLISECONDS); + } + } catch (InterruptedException ex) { + isDestroyed = true; + process.destroyForcibly(); + } finally { + lock.unlock(); + } + }); + + killer.start(); + int exitCode = process.waitFor(); + + lock.lock(); + try { + condition.signal(); + } finally { + lock.unlock(); + } + killer.join(); + assert exitCode == 0; + + lock.lock(); + try { + if (isDestroyed) { + return "Time limit exceeded."; + } + }finally { + lock.unlock(); + } + + if (isResultsInOutput) { + try (FileWriter res = new FileWriter(solverResults)) { + BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); + res.write(br.lines().collect(Collectors.joining("\n"))); + } + interpreter.accept(task, solverResults); + } else { + + BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); + String output = br.lines().collect(Collectors.joining("\n")); + +// BufferedReader br2 = new BufferedReader(new InputStreamReader(process.getErrorStream())); +// String errors = br.lines().collect(Collectors.joining("\n")); + +// System.out.println("output : " + output); +// System.out.println("errors : " + errors); + + if (output.trim().equals("=====UNSATISFIABLE=====")) { + task.setSolution(new ArrayList<>()); + task.setSolution_result(-1); + } else { + interpreter.accept(task, solverResults); + } + } + } catch (UncheckedIOException | IOException | InterruptedException | ParserException ex) { + return ex.getMessage(); + } finally { +// removeDirectory(directory); + } + return ""; + } + + private static void removeDirectory(File dir) { + if (dir.isDirectory()) { + File[] files = dir.listFiles(); + if (files != null && files.length > 0) { + for (File aFile : files) { + removeDirectory(aFile); + } + } + } + dir.delete(); + } +} diff --git a/src/inport/Testing.java b/src/inport/Testing.java index c130724023eb86ecb419ffe8fee0e357a483626a..24bc35841483b269a5d913ed66d59dfa29399289 100644 --- a/src/inport/Testing.java +++ b/src/inport/Testing.java @@ -1,205 +1,42 @@ package inport; -import inport.ConversionUtils.MZnResultsResolver; -import inport.ConversionUtils.ParserException; -import inport.ConversionUtils.Task; -import inport.ConversionUtils.Pair; +import inport.ConversionUtils.*; import java.io.*; import java.util.ArrayList; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.stream.Collectors; public class Testing { - private static void removeDirectory(File dir) { - if (dir.isDirectory()) { - File[] files = dir.listFiles(); - if (files != null && files.length > 0) { - for (File aFile : files) { - removeDirectory(aFile); - } - } - } - dir.delete(); - } - - public static String solveTask_1(TaskCase task, int timeLimitS) { - return solveTask( - task, - "conversion_1.mzn", + public static Solver getTask_1_Solver() { + return new Solver("conversion_1.mzn", Task::portToMiniZinc_1, - MZnResultsResolver::resolveMiniZincResults, - timeLimitS); + MZnResultsResolver::resolveMiniZincResults); } - public static String solveTask_2(TaskCase task, int timeLimitS) { - return solveTask( - task, - "conversion_2.mzn", + public static Solver getTask_2_Solver() { + return new Solver("conversion_2.mzn", Task::portToMiniZinc_2, - MZnResultsResolver::resolveMiniZincResults, - timeLimitS); + MZnResultsResolver::resolveMiniZincResults); } - public static String solveTaskWithPartialCargoOp(TaskCase task, int timeLimitS) { - return solveTask( - task, - "conversion_2_with_partial_cargo_operations.mzn", + public static Solver getTaskWithPartialCargoOp_Solver() { + return new Solver("conversion_2_with_partial_cargo_operations.mzn", Task::portToMiniZinc_2, - MZnResultsResolver::resolveMiniZincResults, - timeLimitS); + MZnResultsResolver::resolveMiniZincResults); } - public static String solveTaskWithGreedyConstraints(TaskCase task, int timeLimitS) { - return solveTask( - task, - "conversion_2_greedy.mzn", + public static Solver getTaskWithGreedyConstraints_Solver() { + return new Solver("conversion_2_greedy.mzn", Task::portToMiniZincGreedy, - MZnResultsResolver::resolveMiniZincResults, - timeLimitS); + MZnResultsResolver::resolveMiniZincResults); } - public static String solveTaskWithGreedyConstraintsV2(TaskCase task, int timeLimitS) { - return solveTask( - task, - "conversion_2_greedy_v2.mzn", + public static Solver getTaskWithGreedyConstraintsV2_Solver() { + return new Solver("conversion_2_greedy_v2.mzn", Task::portToMiniZincGreedyV2, - MZnResultsResolver::resolveMiniZincResults, - timeLimitS); - } - - public static String solveTask_2_0(TaskCase task, int timeLimitS) { - return solveTask( - task, - "conversion_2.0.mzn", - Task::portToMiniZinc_2, - MZnResultsResolver::resolveMiniZincResults, - "temp_data_2", - timeLimitS); - } - - public static String solveTask(TaskCase task, - String constraintName, - BiConsumer converterToMinizincFormat, - BiConsumer interpreter, - int timeLimitS) { - return solveTask(task, constraintName, converterToMinizincFormat, interpreter, "temp_data", timeLimitS); - } - - private final static Lock lock = new ReentrantLock(); - private final static Condition condition = lock.newCondition(); - private static Boolean isDestroyed; - - /* Возвращает описание ошибки, если ошибки не было, то пустую строку. */ - public static String solveTask(TaskCase task, - String constraintName, - BiConsumer converterToMinizincFormat, - BiConsumer interpreter, - String tempDir, - final int timeLimitS) { - File directory = new File(tempDir); - if (!directory.exists()) { - directory.mkdir(); - } - - tempDir = tempDir + "/"; - String minizincData = tempDir + "minizinc_data.dzn"; - String solverResults = tempDir + "solver_results.txt"; - String constraints = tempDir + "constraints.mzn"; - - try { - try (FileWriter res = new FileWriter(constraints)) { - BufferedReader reader = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream("/constraints/" + constraintName))); - String line; - while ((line = reader.readLine()) != null) { - res.write(line + "\n"); - } - } - converterToMinizincFormat.accept(task, minizincData); - - ProcessBuilder pb = new ProcessBuilder("minizinc", - "--solver", "Chuffed", - constraints, minizincData, - "-o", solverResults); - - lock.lock(); - isDestroyed = false; - lock.unlock(); - - final Process process = pb.start(); - - Thread killer = new Thread(() -> { - lock.lock(); - long start = System.currentTimeMillis(); - try { - while (process.isAlive()) { - long currentTimeMillis = System.currentTimeMillis(); - - if (currentTimeMillis - start > timeLimitS * 1000) { - process.destroyForcibly(); - isDestroyed = true; - break; - } - condition.await(timeLimitS * 1000 - (currentTimeMillis - start), TimeUnit.MILLISECONDS); - } - } catch (InterruptedException ex) { - isDestroyed = true; - process.destroyForcibly(); - } finally { - lock.unlock(); - } - }); - - killer.start(); - int exitCode = process.waitFor(); - - lock.lock(); - try { - condition.signal(); - } finally { - lock.unlock(); - } - killer.join(); - assert exitCode == 0; - - lock.lock(); - try { - if (isDestroyed) { - return "Time limit exceeded."; - } - }finally { - lock.unlock(); - } - - BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); - String output = br.lines().collect(Collectors.joining("\n")); - -// BufferedReader br2 = new BufferedReader(new InputStreamReader(process.getErrorStream())); -// String errors = br.lines().collect(Collectors.joining("\n")); - -// System.out.println("output : " + output); -// System.out.println("errors : " + errors); - - if (output.trim().equals("=====UNSATISFIABLE=====")) { - task.setSolution(new ArrayList<>()); - task.setSolution_result(-1); - } else { - interpreter.accept(task, solverResults); - } - } catch (UncheckedIOException | IOException | InterruptedException | ParserException ex) { - return ex.getMessage(); - } finally { -// removeDirectory(directory); - } - return ""; + MZnResultsResolver::resolveMiniZincResults); } - private static String testCase(String file, BiFunction solver, int timeLimitS) { + private static String testCase(String file, Solver solver) { TaskCase task = new TaskCase(); try { task.deserialize(file); @@ -207,7 +44,8 @@ public class Testing { return "Error : " + e.getMessage(); } double expected_result = task.getSolution_result(); - String error = solver.apply(task, timeLimitS); + solver.setTask(task); + String error = solver.solve(); double result = task.getSolution_result(); if (!error.isEmpty()) { return "Error : " + error; @@ -218,10 +56,12 @@ public class Testing { return "OK"; } - public static void testGroup(String group, BiFunction solver, int timeLimitS) { + public static void testGroup(String group, Solver solver, int timeLimitS) { File testDir = new File("tests/" + group + "/"); System.out.println(testDir.toString() + " :"); + solver.setTimeLimitS(timeLimitS); + int nPassedTests = 0; for (File file : testDir.listFiles()) { @@ -229,7 +69,7 @@ public class Testing { long start = System.currentTimeMillis(); - String res = testCase(testDir.toString() + "/" + file.getName(), solver, timeLimitS); + String res = testCase(testDir.toString() + "/" + file.getName(), solver); long finish = System.currentTimeMillis(); System.out.println(" " + res + ", " + (finish - start) / 1000.0 + " s"); @@ -240,15 +80,8 @@ public class Testing { System.out.println("Passed tests : " + nPassedTests + "/" + testDir.listFiles().length); } - public static void test_1(int timeLimitS) { - testGroup("without_typing", Testing::solveTask_1, timeLimitS); - } - - static void test_2(int timeLimitS) { - testGroup("with_typing", Testing::solveTask_2, timeLimitS); - } public static void testWithPartialOp(int timeLimitS) { - testGroup("with_typing", Testing::solveTaskWithPartialCargoOp, timeLimitS); + testGroup("with_typing", getTaskWithPartialCargoOp_Solver(), timeLimitS); } static void testingWithDiffParameters(String test, @@ -307,10 +140,13 @@ public class Testing { operation.setIntensity(operation.getIntensity().map(v -> (int)(v * m))); } -// taskCase.serialize(directory + "/" + mult + " " + i + ".tipp"); - long start = System.currentTimeMillis(); - String result = solveTaskWithPartialCargoOp(taskCase, timeLimitS); + + Solver s = getTaskWithPartialCargoOp_Solver(); + s.setTimeLimitS(timeLimitS); + s.setTempDir("temp_data"); + + String result = s.solve(); long finish = System.currentTimeMillis(); if (result.isEmpty()) {