package inport; import javafx.util.Pair; import java.io.*; import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; public class ConversionUtil { static class PairComparator implements Comparator> { public int compare(Pair p1, Pair p2) { int res = p1.getKey().compareTo(p2.getKey()); if (res != 0) { return res; } else { return p1.getValue().compareTo(p2.getValue()); } } } static private void write2DArray(FileWriter writer, String name, ArrayList>> operations) throws IOException { writer.write(name + " = \n"); boolean isFirst0 = true; for (ArrayList> m1 : operations) { if (isFirst0) { isFirst0 = false; writer.write(" [| "); } else { writer.write(" | "); } boolean isFirst1 = true; for (ArrayList m2 : m1) { if (isFirst1) { isFirst1 = false; } else { writer.write(", "); } writer.write("{"); boolean isFirst2 = true; for (Integer val : m2) { if (isFirst2) { isFirst2 = false; } else { writer.write(", "); } writer.write((val + 1) + ""); } writer.write("}"); } writer.write("\n"); } writer.write(" |];\n"); } static private void writeArray(FileWriter writer, String name, ArrayList data, Function f) throws IOException { writer.write(name + " = ["); for (int i = 0; i < data.size(); i++) { if (i != 0) { writer.write(", "); } writer.write(f.apply(data.get(i)).toString() + ""); } writer.write("];\n"); } static private void writeArray(FileWriter writer, String name, ArrayList data) throws IOException { writeArray(writer, name, data, (T val) -> val); } static private String setToString(Set s) { StringBuilder res = new StringBuilder(); res.append("{"); boolean isFirst = true; for (T t : s) { if (isFirst) { isFirst = false; } else { res.append(", "); } res.append(t.toString()); } res.append("}"); return res.toString(); } static private ArrayList integerArray(int size, int initVal) { ArrayList res = new ArrayList<>(); for (int i = 0; i < size; i++) { res.add(initVal); } return res; } static private MovingObject getExecutor(OperationTemplate t) { if (t instanceof LoadingTemplate) { return ((LoadingTemplate) t).getLoader(); } if (t instanceof MooringTemplate) { return ((MooringTemplate) t).getMoorer(); } if (t instanceof MovingTemplate) { return ((MovingTemplate) t).getMover(); } return null; } static private List getResources(OperationTemplate t) { List res = new ArrayList<>(); if (t instanceof LoadingTemplate) { res.addAll(((LoadingTemplate) t).getResources()); } if (t instanceof MooringTemplate) { res.addAll(((MooringTemplate) t).getResources()); } if (t instanceof MovingTemplate) { res.addAll(((MovingTemplate) t).getResources()); } return res; } static private boolean isCompatible(OperationTemplate t1, OperationTemplate t2) { MovingObject exec1 = getExecutor(t1); Berth place1 = t1.getStartLocation(); List resources1 = getResources(t1); MovingObject exec2 = getExecutor(t2); Berth place2 = t2.getStartLocation(); List resources2 = getResources(t2); // Пересекаемость ресурсов for (Object res2 : resources2) if (resources1.contains(res2)) return false; // Выполнитель = ресурс if (resources1.contains(exec2)) return false; // Ресурс = выполнитель if (resources2.contains(exec1)) return false; // Выполнитель = выполнитель if (exec1.equals(exec2)) { // Это не погрузка if (!(t1 instanceof LoadingTemplate) || (!(t2 instanceof LoadingTemplate))) return false; // Разные причалы if (!place1.equals(place2)) return false; Storage s1 = ((LoadingTemplate)t1).getStorage(); Storage s2 = ((LoadingTemplate)t2).getStorage(); // В одно хранилище if (s1.equals(s2)) return false; } else // На одном причале и это не перемещения if (place1.equals(place2) && (!(t1 instanceof MovingTemplate)) && (!(t2 instanceof MovingTemplate))) return false; return true; } static public void portToMiniZinc(TaskCase task, String fileName) throws IOException { try(FileWriter writer = new FileWriter(fileName, false)) { int n_intervals = (int)task.getPlanningInterval(); writer.write("n_intervals = " + n_intervals + ";\n"); writer.write("n_operations = " + task.getTemplates().size() + ";\n"); ArrayList berths = new ArrayList<>(task.getBerths()); Map, Integer> locationNumberById = new TreeMap<>(new PairComparator()); for (Berth berth : berths) { locationNumberById.put(new Pair<>(berth.getId(), false), locationNumberById.size()); locationNumberById.put(new Pair<>(berth.getId(), true), locationNumberById.size()); } writer.write("n_locations = " + locationNumberById.size() + ";\n"); BiFunction getLocNById = (Integer id, Boolean isMoored) -> locationNumberById.get(new Pair<>(id, isMoored)); ArrayList movingObjects = new ArrayList<>(); Map mObjNumberById = new TreeMap<>(); for (MovingObject obj : task.getShips()) { mObjNumberById.put(obj.getId(), movingObjects.size()); movingObjects.add(obj); } for (MovingObject obj : task.getTows()) { mObjNumberById.put(obj.getId(), movingObjects.size()); movingObjects.add(obj); } writer.write("n_moving_obj = " + movingObjects.size() + ";\n"); writer.write("\n"); Function mObjToN = (MovingObject obj) -> mObjNumberById.get(obj.getId()); ArrayList operationTemplates = new ArrayList<>(task.getTemplates()); { // Операции прибытия/отбытия в локацию. (В том числе и швартовка.) ArrayList>> arrivalOp = new ArrayList<>(); ArrayList>> departureOp = new ArrayList<>(); for (int i = 0; i < movingObjects.size(); i++) { arrivalOp.add(new ArrayList<>()); departureOp.add(new ArrayList<>()); for (int j = 0; j < locationNumberById.size(); j++) { arrivalOp.get(i).add(new ArrayList<>()); departureOp.get(i).add(new ArrayList<>()); } } for (int i = 0; i < operationTemplates.size(); i++) { if (operationTemplates.get(i) instanceof MovingTemplate) { MovingTemplate op = (MovingTemplate)operationTemplates.get(i); ArrayList movingObjN = new ArrayList<>(); for (MovingObject obj : op.getResources()) { movingObjN.add(mObjToN.apply(obj)); } movingObjN.add(mObjToN.apply(op.getMover())); for (Integer n : movingObjN) { arrivalOp .get(n).get(getLocNById.apply(op.getDestination().getId(), false)).add(i); departureOp.get(n).get(getLocNById.apply(op.getStartLocation().getId(), false)).add(i); } } else if (operationTemplates.get(i) instanceof MooringTemplate) { MooringTemplate op = (MooringTemplate)operationTemplates.get(i); ArrayList movingObjN = new ArrayList<>(); for (MovingObject obj : op.getResources()) { movingObjN.add(mObjToN.apply(obj)); } movingObjN.add(mObjToN.apply(op.getMoorer())); for (Integer n : movingObjN) { arrivalOp .get(n).get(getLocNById.apply(op.getStartLocation().getId(), !op.isDirect())).add(i); departureOp.get(n).get(getLocNById.apply(op.getStartLocation().getId(), op.isDirect())).add(i); } } } write2DArray(writer, "arrival_op", arrivalOp); write2DArray(writer, "departure_op", departureOp); } { // Начальные положения объектов. ArrayList initialStates = integerArray(movingObjects.size(), 0); for (MovingObjectState state : task.getVesselInitialState()) { initialStates.set(mObjToN.apply(state.getVessel()), getLocNById.apply(state.getLocation().getId(), false)); } writeArray(writer, "initial_m_obj_loc", initialStates, (Integer p) -> p + 1); writer.write("\n"); } { // Окна погоды. ArrayList bw_op = new ArrayList<>(); ArrayList bw_start = new ArrayList<>(); ArrayList bw_fin = new ArrayList<>(); for (int i = 0; i < operationTemplates.size(); i++) { final int id = i; operationTemplates.get(i).getTimeWindows().forEach( (Double start, Double duration) -> { bw_op.add(id + 1); bw_start.add((int)Math.ceil(start)); bw_fin.add((int)Math.floor(start + duration)); } ); } writer.write("n_bad_weather_windows = " + bw_op.size() + ";\n"); writeArray(writer, "bw_op", bw_op); writeArray(writer, "bw_start", bw_start); writeArray(writer, "bw_fin", bw_fin); writer.write("\n"); } { // Непрерывность перемещения и швартовки. ArrayList operationsDuration = integerArray(operationTemplates.size(), 0); ArrayList isMovingObj = new ArrayList<>(); for (int i = 0; i < operationTemplates.size(); i++) { if (operationTemplates.get(i) instanceof MovingTemplate) { MovingTemplate op = (MovingTemplate)operationTemplates.get(i); operationsDuration.set(i, (int)Math.ceil(op.getDuration())); isMovingObj.add(true); } else if (operationTemplates.get(i) instanceof MooringTemplate) { MooringTemplate op = (MooringTemplate) operationTemplates.get(i); operationsDuration.set(i, (int)Math.ceil(op.getDuration())); isMovingObj.add(true); } else { isMovingObj.add(false); } } writeArray(writer, "operations_duration", operationsDuration); writeArray(writer, "is_continuous_operation", isMovingObj); } { // Конечные положения объектов. ArrayList finalStates = integerArray(movingObjects.size(), 0); for (MovingObjectState state : task.getVesselEndState()) { finalStates.set(mObjToN.apply(state.getVessel()), getLocNById.apply(state.getLocation().getId(), false)); } writeArray(writer, "final_m_obj_loc", finalStates, (Integer p) -> p + 1); } { // Наличие всех ресурсов на месте. // TODO покрывается "Конфликтующими операциями". ArrayList> operationsResources = new ArrayList<>(); ArrayList operationsStartLoc = integerArray(operationTemplates.size(), 0); for (int i = 0; i < operationTemplates.size(); i++) { operationsResources.add(new TreeSet<>()); if (operationTemplates.get(i) instanceof MovingTemplate) { MovingTemplate op = (MovingTemplate)operationTemplates.get(i); Set s = new TreeSet<>(); s.add(mObjToN.apply(op.getMover()) + 1); for (MovingObject obj : op.getResources()) { s.add(mObjToN.apply(obj) + 1); } operationsResources.set(i, s); operationsStartLoc.set(i, getLocNById.apply(op.getStartLocation().getId(), false) + 1); } // TODO швартовка, погрузка. } writeArray(writer, "operations_start_loc", operationsStartLoc); writeArray(writer, "operations_resources", operationsResources, ConversionUtil::setToString); } { // Конфликтующие операции. ArrayList> conflictingPairs = new ArrayList<>(); for (int i = 0; i < operationTemplates.size(); i++) { for (int j = i + 1; j < operationTemplates.size(); j++) { if (!isCompatible(operationTemplates.get(i), operationTemplates.get(j))) { conflictingPairs.add(new Pair<>(i + 1, j + 1)); } } } writer.write("n_conflicting_op = " + conflictingPairs.size() + ";\n"); writeArray(writer, "confl_op_1", conflictingPairs, Pair::getKey); writeArray(writer, "confl_op_2", conflictingPairs, Pair::getValue); } } } static public void resolveMiniZincResults(TaskCase task, String fileName) throws IOException, ParserException { List operations = null; Integer result = null; try (FileInputStream fstream = new FileInputStream(fileName)) { BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); String line; while (((line = br.readLine()) != null)) { line = line.trim(); if (line.equals("")) { continue; } String regexpr = "^\\[((true)|(false))(,\\s((true)|(false)))*]\\z"; if (line.matches(regexpr)) { if (operations != null) { continue; } String []rawTokens = line.split("[\\s\\[\\],]"); ArrayList tokens = new ArrayList<>(); for (String str : rawTokens) { if (!str.isEmpty()) { tokens.add(str); } } final int n_intervals = (int)task.getPlanningInterval(); if (tokens.size() != (n_intervals + 2) * task.getTemplates().size()) { throw new ParserException("Invalid length of \"op_status\""); } operations = new ArrayList<>(); for (int i = 0; i < task.getTemplates().size(); i++) { int duration = 0; for (int j = 0; j < n_intervals + 2; j++) { if (tokens.get(i * (n_intervals + 2) + j).equals("true")) { duration++; } else if (duration != 0) { Operation op = new Operation(); op.setStart(j - duration - 1); op.setDuration(duration); op.setTemplate(task.getTemplates().get(i)); operations.add(op); duration = 0; } } } continue; } if (line.matches("\\d+")) { if (result != null) { continue; } result = Integer.parseInt(line); continue; } break; } if (operations == null) { throw new ParserException("No \"op_status\" in input"); } if (result == null) { throw new ParserException("No result in input"); } task.setSolution(operations); task.setSolution_result(result); } } }