package inport; import javafx.util.Pair; import org.jetbrains.annotations.NotNull; import java.io.*; import java.util.*; import java.util.function.BiConsumer; import java.util.function.Function; public class ConversionUtil { static class PairComparator, U extends Comparable> 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 write2DArrayOfInt(FileWriter writer, String name, ArrayList> operations) throws IOException { locWrite2DArray(writer, name, operations, Object::toString, false); } static private void write2DArrayOfInt(FileWriter writer, String name, ArrayList> operations, boolean isNumberedFromZero) throws IOException { locWrite2DArray(writer, name, operations, Object::toString, isNumberedFromZero); } static private void write2DArrayOfSet(FileWriter writer, String name, ArrayList>> operations) throws IOException { locWrite2DArray(writer, name, operations, (ArrayList a) -> { StringBuilder s = new StringBuilder(); s.append('{'); boolean isFirst2 = true; for (Integer val : a) { if (isFirst2) { isFirst2 = false; } else { s.append(", "); } s.append(val); } s.append('}'); return s.toString(); } ); } static private > void write2DArrayOfSetAs3DArray(FileWriter writer, String name, ArrayList> operations) throws IOException { write2DArrayOfSetAs3DArray(writer, name, operations, false); } static private > void write2DArrayOfSetAs3DArray(FileWriter writer, String name, ArrayList> operations, boolean isNumberedFromZero) throws IOException { int maxSize = 0; ArrayList> sizes = new ArrayList<>(); int dim1 = operations.size(); int dim2 = 0; for (ArrayList a1 : operations) { dim2 = a1.size(); ArrayList locSizes = new ArrayList<>(); for (T a2 : a1) { maxSize = Math.max(maxSize, a2.size()); locSizes.add(a2.size()); } sizes.add(locSizes); } writer.write(name + "_max_size = " + maxSize + ";\n"); write2DArrayOfInt(writer, name + "_sizes", sizes, true); { String firstEl = Integer.toString(isNumberedFromZero ? 0 : 1); int modifier = isNumberedFromZero ? -1 : 0; writer.write(name + " = array3d(" + firstEl + ".." + (dim1 + modifier) + ", " + firstEl + ".." + (dim2 + modifier) + ", 1.." + name + "_max_size, ["); } boolean isFirst = true; for (ArrayList a1 : operations) { for (T a2 : a1) { for (Integer val : a2) { if (isFirst) { isFirst = false; } else { writer.write(", "); } writer.write(Integer.toString(val)); } for (int i = a2.size(); i < maxSize; i++) { if (isFirst) { isFirst = false; } else { writer.write(", "); } writer.write(Integer.toString(1)); } } } writer.write("]);\n"); } static private void write3dArray(FileWriter writer, String name, ArrayList>> array, Function toString) throws IOException { int dim1 = array.size(); int dim2 = (dim1 > 0) ? array.get(0).size() : 0; int dim3 = (dim2 > 0) ? array.get(0).get(0).size() : 0; writer.write(name + " = array3d(1.." + dim1 + ", 1.." + dim2 + ", 1.." + dim3 + ", "); ArrayList values = new ArrayList<>(); for (ArrayList> a2 : array) { for (ArrayList a1 : a2) { for (T val : a1) { values.add(toString.apply(val)); } } } writer.write("[" + String.join(", ", values) + "]);\n"); } static private void writeArrayOfSetAs2DArray(FileWriter writer, String name, ArrayList> operations) throws IOException { writeArrayOfSetAs2DArray(writer, name, operations, true, false); } static private void writeArrayOfSetAs2DArray(FileWriter writer, String name, ArrayList> operations, boolean addAdditionalInfo, boolean addDummyZeroElement) throws IOException { int maxSize = 0; ArrayList sizes = new ArrayList<>(); for (ArrayList s : operations) { maxSize = Math.max(maxSize, s.size()); sizes.add(s.size()); } if (addAdditionalInfo) { writer.write(name + "_max_size = " + maxSize + ";\n"); writeArray(writer, name + "_sizes", sizes); } writer.write(name + " = array2d(1.." + operations.size() + ", " + (addDummyZeroElement ? "0" : "1") + ".." + maxSize + ", ["); boolean isFirst = true; for (ArrayList s : operations) { if (addDummyZeroElement) { if (isFirst) { isFirst = false; } else { writer.write(", "); } writer.write("1"); } for (Integer val : s) { if (isFirst) { isFirst = false; } else { writer.write(", "); } writer.write(Integer.toString(val)); } for (int i = s.size(); i < maxSize; i++) { if (isFirst) { isFirst = false; } else { writer.write(", "); } writer.write("1"); } } writer.write("]);\n"); } static private void locWrite2DArray(FileWriter writer, String name, ArrayList> operations, Function toMZNFormat) throws IOException { locWrite2DArray(writer, name, operations, toMZNFormat, false); } static int boolToInt(boolean b) { return b ? 1 : 0; } static private void locWrite2DArray(FileWriter writer, String name, ArrayList> operations, Function toMZNFormat, boolean isNumberedFromZero) throws IOException { writer.write(name + " = array2d(" + (isNumberedFromZero ? 0 : 1) + ".." + (operations.size() - boolToInt(isNumberedFromZero)) + ", " + (isNumberedFromZero ? 0 : 1) + ".." + (operations.get(0).size() - boolToInt(isNumberedFromZero)) + ", ["); boolean isFirst0 = true; for (ArrayList a : operations) { for (T val : a) { if (isFirst0) { isFirst0 = false; } else { writer.write(", "); } writer.write(toMZNFormat.apply(val)); } } writer.write("]);\n"); } static private void writeArray(FileWriter writer, String name, ArrayList data, Function f, Optional dummyZeroElement) throws IOException { writer.write(name + " = array1d(" + (dummyZeroElement.isPresent() ? 0 : 1) + ".." + data.size() + ", ["); boolean isFirst = true; if (dummyZeroElement.isPresent()) { isFirst = false; writer.write(f.apply(dummyZeroElement.get()).toString()); } for (int i = 0; i < data.size(); i++) { if (isFirst) { isFirst = false; } else { 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, Optional.empty()); } static private void writeArray(FileWriter writer, String name, ArrayList data, Function f) throws IOException { writeArray(writer, name, data, f, Optional.empty()); } static private void writeArray(FileWriter writer, String name, ArrayList data, Optional dummyZeroElement) throws IOException { writeArray(writer, name, data, (T val) -> val, dummyZeroElement); } 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 String arrayToStringAsSet(ArrayList a) { return setToString(new TreeSet<>(a)); } 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 ArrayList> arrayOfIntegerArrays(int size) { ArrayList> res = new ArrayList<>(); for (int i = 0; i < size; i++) { res.add(new ArrayList<>()); } return res; } static private ArrayList> arrayOfIntegerSet(int size) { ArrayList> res = new ArrayList<>(); for (int i = 0; i < size; i++) { res.add(new TreeSet<>()); } return res; } static 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 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 class Task { private FileWriter writer = null; private final String fileName; private final TaskCase task; private final int n_intervals; private final ArrayList berths; private final Map, Integer> locationNumberById; private int getLocNById(int id, boolean isMoored) { return locationNumberById.get(new Pair<>(id, isMoored)); } private final ArrayList movingObjects; public Map getMObjNumberById() { return mObjNumberById; } private final Map mObjNumberById; private int mObjToN(MovingObject obj) { return mObjNumberById.get(obj.getId()); } private ArrayList operationTemplates; private final ArrayList storages; private final ArrayList cargoes; private final int nObjWithStorage; class StorageSectionId implements Comparable { boolean isRealStorage; // Not transport ship. Integer localN; Integer typeN; StorageSectionId(boolean isRealStorage, Integer localN, Integer typeN) { this.isRealStorage = isRealStorage; this.localN = localN; this.typeN = typeN; } @Override public int compareTo(@NotNull StorageSectionId id) { if (isRealStorage != id.isRealStorage) { return (isRealStorage ? 1 : -1); } if (! localN.equals(id.localN)) { return localN.compareTo(id.localN); } if (! typeN.equals(id.typeN)) { return typeN.compareTo(id.typeN); } return 0; } } private final Map sectionNById; private int sectionIdToN(Storage storage, Cargo cargo) { return sectionNById.get(new StorageSectionId( true, storageNById.get(storage.getId()), cargoNById.get(cargo.getId()))); } private int sectionIdToN(TransportShip transportShip, Cargo cargo) { return sectionNById.get(new StorageSectionId( false, mObjToN(transportShip), cargoNById.get(cargo.getId()))); } private final Map storageNById; private final Map cargoNById; private final Map typeToN; private ArrayList> movingOpOfObj; private ArrayList operationsDestination; private ArrayList mainObjOfOperation; private ArrayList isMooringOp; private ArrayList> objectsOfType; public ArrayList getMovingObjects() { return movingObjects; } private final int nSectionsOfRealStorageAndBunkers; private final ArrayList initialStorageVol; private final ArrayList finalStorageVol; private final ArrayList maxStorageVol; Task(TaskCase task, String fileName) { this.fileName = fileName; this.task = task; n_intervals = (int)task.getPlanningInterval(); berths = new ArrayList<>(task.getBerths()); 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()); } movingObjects = calcMovingObjects(task); mObjNumberById = new TreeMap<>(); for (int i = 0; i < movingObjects.size(); i++) { mObjNumberById.put(movingObjects.get(i).getId(), i); } operationTemplates = new ArrayList<>(task.getTemplates()); if (task.isTypified()) { operationTemplates = renumberOperations(task); } storages = new ArrayList<>(task.getStorages()); cargoes = new ArrayList<>(task.getCargoes()); cargoNById = new TreeMap<>(); for (int i = 0; i < task.getCargoes().size(); i++) { cargoNById.put(cargoes.get(i).getId(), i); } int nextStorageNo = 0; storageNById = new TreeMap<>(); sectionNById = new TreeMap<>(); for (int i = 0; i < storages.size(); i++) { // Сначала реальные хранилища. storageNById.put(storages.get(i).getId(), i); for (Pair p : storages.get(i).getStorageSections()) { sectionNById.put(new StorageSectionId(true, i, cargoNById.get(p.getKey().getId())), nextStorageNo++); } } for (MovingObject obj : movingObjects) { // Затем бункеровщики. if (obj instanceof Bunker) { for (Pair p : ((TransportShip) obj).getStorageSections()) { sectionNById.put(new StorageSectionId(false, mObjToN(obj), cargoNById.get(p.getKey().getId())), nextStorageNo++); } } } nSectionsOfRealStorageAndBunkers = sectionNById.size(); for (MovingObject obj : movingObjects) { // Дальше - все остальные. if ((obj instanceof TransportShip) && (!(obj instanceof Bunker))) { for (Pair p : ((TransportShip) obj).getStorageSections()) { sectionNById.put(new StorageSectionId(false, mObjToN(obj), cargoNById.get(p.getKey().getId())), nextStorageNo++); } } } nObjWithStorage = movingObjects.size() + storages.size(); { typeToN = new TreeMap<>(); int next = 0; for (Integer type : task.getVesselTypes().keySet()) { typeToN.put(type, next); next++; } for (Integer type : task.getBunkerTypes().keySet()) { typeToN.put(type, next); next++; } for (Integer type : task.getEquipmentsTypes().keySet()) { typeToN.put(type, next); next++; } } { objectsOfType = arrayOfIntegerSet(typeToN.size()); for (MovingObject obj : movingObjects) { if (obj.getType().isPresent()) { objectsOfType.get(typeToN.get(obj.getType().getAsInt())).add(mObjToN(obj) + 1); } } } { movingOpOfObj = arrayOfIntegerArrays(movingObjects.size()); operationsDestination = new ArrayList<>(); mainObjOfOperation = new ArrayList<>(); isMooringOp = new ArrayList<>(); initMovingObjectLocationDefinition(); } { initialStorageVol = integerArray(sectionNById.size(), 0); finalStorageVol = integerArray(sectionNById.size(), -1); BiConsumer, StorageState> f = (ArrayList a, StorageState st) -> { int val = (int)st.getCargoState(); int sectionN; if (st.getStorage() instanceof Storage) { sectionN = sectionIdToN((Storage) st.getStorage(), st.getCargo()); } else { assert st.getStorage() instanceof TransportShip; sectionN = sectionIdToN((TransportShip) st.getStorage(), st.getCargo()); } a.set(sectionN, val); }; for (StorageState st : task.getStorageInitialState()) { f.accept(initialStorageVol, st); } for (StorageState st : task.getStorageEndState()) { f.accept(finalStorageVol, st); } } { // maxStorageVol maxStorageVol = integerArray(sectionNById.size(), 0); for (MovingObject obj : movingObjects) { if (obj instanceof TransportShip) { for (Pair p : ((TransportShip) obj).getStorageSections()) { maxStorageVol.set(sectionIdToN((TransportShip) obj, p.getKey()), (int)Math.ceil(p.getValue())); } } } for (Storage storage : storages) { for (Pair p : storage.getStorageSections()) { maxStorageVol.set(sectionIdToN(storage, p.getKey()), (int)Math.ceil(p.getValue())); } } } } private ArrayList getNumbersOfResourcesTypes(OperationTemplate t) { ArrayList res = new ArrayList<>(); if (t instanceof LoadingTemplate) { res.addAll(((LoadingTemplate) t).getResourcesTypes()); } if (t instanceof MooringTemplate) { res.addAll(((MooringTemplate) t).getResourcesTypes()); } if (t instanceof MovingTemplate) { res.addAll(((MovingTemplate) t).getResourcesTypes()); } res.replaceAll(typeToN::get); return res; } /* Операции прибытия/отбытия в локацию. (В том числе и швартовка.) */ private void arrivalAndDepartureOperations() throws IOException { 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(obj)); } movingObjN.add(mObjToN(op.getMover())); for (Integer n : movingObjN) { arrivalOp .get(n).get(getLocNById(op.getDestination().getId(), false)).add(i + 1); departureOp.get(n).get(getLocNById(op.getStartLocation().getId(), false)).add(i + 1); } } 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(obj)); } movingObjN.add(mObjToN(op.getMoorer())); for (Integer n : movingObjN) { arrivalOp .get(n).get(getLocNById(op.getStartLocation().getId(), op.isDirect())).add(i + 1); departureOp.get(n).get(getLocNById(op.getStartLocation().getId(), !op.isDirect())).add(i + 1); } } } write2DArrayOfSetAs3DArray(writer, "arrival_op", arrivalOp); write2DArrayOfSetAs3DArray(writer, "departure_op", departureOp); writer.write("\n"); } /* Начальные положения объектов. */ private void initialLocations() throws IOException { ArrayList initialStates = integerArray(movingObjects.size(), 0); for (MovingObjectState state : task.getVesselInitialState()) { initialStates.set(mObjToN(state.getVessel()), getLocNById(state.getLocation().getId(), false)); } writeArray(writer, "initial_m_obj_loc", initialStates, (Integer p) -> p + 1, Optional.of(-1)); writer.write("\n"); } /* Окна погоды. */ private void weatherWindows() throws IOException { 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.floor(start)); bw_fin.add((int)Math.ceil(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"); } /* Окна погоды. Новый формат. */ private void weatherWindowsNewFormat() throws IOException { ArrayList> badWeather = new ArrayList<>(); badWeather.add(new ArrayList<>()); for (int j = 0; j <= n_intervals; j++) { badWeather.get(0).add(false); } for (int i = 0; i < operationTemplates.size(); i++) { ArrayList curLine = new ArrayList<>(); for (int j = 0; j <= n_intervals; j++) { curLine.add(false); } operationTemplates.get(i).getTimeWindows().forEach( (Double start, Double duration) -> { for (int j = (int)Math.floor(start); j < (int)Math.ceil(start + duration); j++) { curLine.set(j + 1, true); } } ); badWeather.add(curLine); } locWrite2DArray(writer, "bad_weather", badWeather, Objects::toString, true); } /* Непрерывность перемещения и швартовки. */ private void operationsContinuity() throws IOException { 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, Optional.of(1)); writeArray(writer, "is_continuous_operation", isMovingObj, Optional.of(false)); } /* Конечные положения объектов. */ private void finalLocations() throws IOException { ArrayList finalStates = integerArray(movingObjects.size(), -1); for (MovingObjectState state : task.getVesselEndState()) { finalStates.set(mObjToN(state.getVessel()), getLocNById(state.getLocation().getId(), false)); } writeArray(writer, "final_m_obj_loc", finalStates, (Integer p) -> p + 1, Optional.of(-1)); } /* Наличие всех ресурсов на месте, в том числе и самого корабля. */ private void presenceOfResourcesInLocation() throws IOException { ArrayList> operationsResources = new ArrayList<>(); ArrayList> operationsResourcesStartLoc = new ArrayList<>(); BiConsumer addResource = (MovingObject r, Integer stLoc) -> { operationsResources.get(operationsResources.size() - 1).add(mObjToN(r) + 1); operationsResourcesStartLoc.get(operationsResourcesStartLoc.size() - 1).add(stLoc + 1); }; for (OperationTemplate operationTemplate : operationTemplates) { operationsResources.add(new ArrayList<>()); operationsResourcesStartLoc.add(new ArrayList<>()); if (operationTemplate instanceof MovingTemplate) { // Перемещение. MovingTemplate op = (MovingTemplate) operationTemplate; addResource.accept(op.getMover(), getLocNById(op.getStartLocation().getId(), false)); for (MovingObject obj : op.getResources()) { addResource.accept(obj, getLocNById(op.getStartLocation().getId(), false)); } } else if (operationTemplate instanceof MooringTemplate) { // Швартовка. MooringTemplate op = (MooringTemplate) operationTemplate; addResource.accept(op.getMoorer(), getLocNById(op.getStartLocation().getId(), !op.isDirect())); for (MovingObject obj : op.getResources()) { addResource.accept(obj, getLocNById(op.getStartLocation().getId(), false)); } } else if (operationTemplate instanceof LoadingTemplate) { // Погрузка. LoadingTemplate op = (LoadingTemplate) operationTemplate; addResource.accept(op.getLoader(), getLocNById(op.getStartLocation().getId(), op.getWithMooring())); for (MovingObject obj : op.getResources()) { addResource.accept(obj, getLocNById(op.getStartLocation().getId(), false)); } } } writeArrayOfSetAs2DArray(writer, "operations_resources", operationsResources); writeArrayOfSetAs2DArray(writer, "operations_resources_start_loc", operationsResourcesStartLoc, false, false); writer.write("\n"); } /* Конфликтующие операции. */ private void conflictingOperations() throws IOException { 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); writer.write("\n"); } /* Ограничения на вместимость. */ private void maxStorageVolume() throws IOException { writeArray(writer, "max_storage_vol", maxStorageVol, Optional.of(0)); writer.write("\n"); } /* Граничные состояния хранилищ. */ private void boundaryStorageStates() throws IOException { writeArray(writer, "initial_storage_vol", initialStorageVol, Optional.of(0)); writeArray(writer, "final_storage_vol", finalStorageVol, Optional.of(-1)); } /* Потоки грузов. */ private void cargoFlows() throws IOException { ArrayList> cargoFlows = new ArrayList<>(); for (int i = 0; i <= sectionNById.size(); i++) { cargoFlows.add(integerArray(n_intervals + 2, 0)); } for (CargoFlow flow : task.getCargoFlows()) { int storageN = sectionIdToN(flow.getStorage(), flow.getCargo()); for (int i = 1; i < n_intervals + 2; i++) { cargoFlows.get(storageN + 1).set(i, (int)flow.getCurrentValue(i - 0.1)); } } write2DArrayOfInt(writer,"cargo_flows", cargoFlows, true); } /* Грузовые операции со всеми хранилищами. */ private void cargoOperations() throws IOException { ArrayList> involvedOperations = new ArrayList<>(); ArrayList loadingOpDelta = new ArrayList<>(); ArrayList loading_op_local_direction = new ArrayList<>(); ArrayList loadingOpN = new ArrayList<>(); ArrayList loading_op_delta_of_main_obj = new ArrayList<>(); ArrayList loading_op_abs_delta = new ArrayList<>(); ArrayList loading_op_direction = new ArrayList<>(); ArrayList operations_main_stor = new ArrayList<>(); ArrayList operations_secondary_stor = new ArrayList<>(); ArrayList operations_cargo_t = new ArrayList<>(); ArrayList bunker_of_cargo_op = new ArrayList<>(); for (int i = 0; i < sectionNById.size(); i++) { involvedOperations.add(new ArrayList<>()); } for (int i = 0; i < operationTemplates.size(); i++) { if (operationTemplates.get(i) instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate) operationTemplates.get(i); int shipN = mObjToN(op.getLoader()); int cargoN = cargoNById.get(op.getCargo().getId()); int storageN; if (op.getBunker().isPresent()) { storageN = sectionIdToN(op.getBunker().get(), op.getCargo()); } else { storageN = sectionIdToN(op.getStorage(), op.getCargo()); } int shipStorageN = sectionIdToN(op.getLoader(), op.getCargo()); loadingOpDelta.add(-(int)op.getIntensity()); loading_op_local_direction.add(-(int)op.getIntensity() > 0 ? 1 : -1); loadingOpN.add(i); involvedOperations.get(storageN).add(loadingOpDelta.size()); loadingOpDelta.add((int)op.getIntensity()); loading_op_local_direction.add( (int)op.getIntensity() > 0 ? 1 : -1); loadingOpN.add(i); involvedOperations.get(shipStorageN).add(loadingOpDelta.size()); loading_op_delta_of_main_obj.add((int)op.getIntensity()); loading_op_abs_delta.add(Math.abs((int)op.getIntensity())); loading_op_direction.add((int)op.getIntensity() > 0 ? 1 : -1); operations_main_stor.add(shipStorageN + 1); operations_secondary_stor.add(storageN + 1); operations_cargo_t.add(cargoN + 1); bunker_of_cargo_op.add(op.getBunker().isPresent() ? mObjToN(op.getBunker().get()) + 1 : 0); } else { loading_op_delta_of_main_obj.add(0); loading_op_abs_delta.add(0); loading_op_direction.add(1); operations_main_stor.add(1); operations_secondary_stor.add(1); operations_cargo_t.add(1); bunker_of_cargo_op.add(0); } } ArrayList> sections_of_moving_obj = arrayOfIntegerArrays(movingObjects.size()); for (int i = 0; i < movingObjects.size(); i++) { if (movingObjects.get(i) instanceof TransportShip) { TransportShip ship = ((TransportShip) movingObjects.get(i)); for (Pair p : ship.getStorageSections()) { sections_of_moving_obj.get(i).add(sectionIdToN(ship, p.getKey()) + 1); } } } ArrayList is_sections_of_moving_obj_empty = new ArrayList<>(); for (ArrayList sections : sections_of_moving_obj) { is_sections_of_moving_obj_empty.add(sections.isEmpty()); } writer.write("n_loading_op = " + loadingOpDelta.size() + ";\n"); writeArray(writer, "involved_operations", involvedOperations, ConversionUtil::arrayToStringAsSet); writeArray(writer, "loading_op_delta", loadingOpDelta); writeArray(writer, "loading_op_local_direction", loading_op_local_direction); writeArray(writer, "loading_op_n", loadingOpN, (Integer i) -> i + 1); writeArray(writer, "loading_op_delta_of_main_obj", loading_op_delta_of_main_obj, Optional.of(0)); writeArray(writer, "loading_op_abs_delta", loading_op_abs_delta, Optional.of(0)); writeArray(writer, "loading_op_direction", loading_op_direction, Optional.of(1)); writeArray(writer, "operations_main_stor", operations_main_stor, Optional.of(1)); writeArray(writer, "operations_secondary_stor", operations_secondary_stor, Optional.of(1)); writeArray(writer, "operations_cargo_t", operations_cargo_t, Optional.of(1)); writeArray(writer, "bunker_of_cargo_op", bunker_of_cargo_op, Optional.of(0)); writeArray(writer, "sections_of_moving_obj", sections_of_moving_obj, ConversionUtil::arrayToStringAsSet); writeArray(writer, "is_sections_of_moving_obj_empty", is_sections_of_moving_obj_empty); writer.write("\n"); } /* Ограничение на необходимость полезной операции между движениями к одному пункту назначения. */ private void constraintOnUsefulOperationBetweenMovements_0() throws IOException { ArrayList> objUsefulOperations = new ArrayList<>(); ArrayList> movingOpOfObj = new ArrayList<>(); BiConsumer addUsOp = (MovingObject obj, Integer op) -> objUsefulOperations.get(mObjToN(obj)).add(op + 1); BiConsumer addMovingOp = (MovingObject obj, Integer op) -> movingOpOfObj.get(mObjToN(obj)).add(op + 1); for (int i = 0; i < movingObjects.size(); i++) { movingOpOfObj.add(new ArrayList<>()); objUsefulOperations.add(new ArrayList<>()); } for (int i = 0; i < operationTemplates.size(); i++) { OperationTemplate t = operationTemplates.get(i); if (t instanceof MovingTemplate) { MovingTemplate op = (MovingTemplate)t; addMovingOp.accept(op.getMover(), i); for (MovingObject obj : op.getResources()) { addUsOp.accept(obj, i); addMovingOp.accept(obj, i); } } else if (t instanceof MooringTemplate) { MooringTemplate op = (MooringTemplate)t; addMovingOp.accept(op.getMoorer(), i); for (MovingObject obj : op.getResources()) { addUsOp.accept(obj, i); addMovingOp.accept(obj, i); } if (!op.isDirect()) { // Отшвартовка. addUsOp.accept(op.getMoorer(), i); } } else if (t instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate)t; addUsOp.accept(op.getLoader(), i); } } writeArrayOfSetAs2DArray(writer, "obj_useful_operations", objUsefulOperations); writeArrayOfSetAs2DArray(writer, "moving_op_of_obj", movingOpOfObj); writer.write("\n"); } private void constraintOnUsefulOperationBetweenMovements_1() throws IOException { ArrayList> objUsefulOperations = new ArrayList<>(); BiConsumer addUsOp = (MovingObject obj, Integer op) -> objUsefulOperations.get(mObjToN(obj)).add(op + 1); for (int i = 0; i < movingObjects.size(); i++) { objUsefulOperations.add(new ArrayList<>()); } for (int i = 0; i < operationTemplates.size(); i++) { OperationTemplate t = operationTemplates.get(i); if (t instanceof MovingTemplate) { MovingTemplate op = (MovingTemplate)t; for (MovingObject obj : op.getResources()) { addUsOp.accept(obj, i); } } else if (t instanceof MooringTemplate) { MooringTemplate op = (MooringTemplate)t; for (MovingObject obj : op.getResources()) { addUsOp.accept(obj, i); } if (!op.isDirect()) { // Отшвартовка. addUsOp.accept(op.getMoorer(), i); } } else if (t instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate)t; addUsOp.accept(op.getLoader(), i); } } writeArrayOfSetAs2DArray(writer, "obj_useful_operations", objUsefulOperations); writer.write("\n"); } private void initMovingObjectLocationDefinition() { BiConsumer addMovingOp = (MovingObject obj, Integer op) -> movingOpOfObj.get(mObjToN(obj)).add(op + 1); for (int i = 0; i < operationTemplates.size(); i++) { OperationTemplate t = operationTemplates.get(i); mainObjOfOperation.add(mObjToN(getExecutor(t))); isMooringOp.add(t instanceof MooringTemplate); if ((t instanceof MovingTemplate) || (t instanceof MooringTemplate)) { addMovingOp.accept(getExecutor(t), i); if (!task.isTypified()) { for (MovingObject obj : getResources(t)) { addMovingOp.accept(obj, i); } } else { for (Integer typeId : new TreeSet<>(getNumbersOfResourcesTypes(t))) { for (Integer objId : objectsOfType.get(typeId)) { movingOpOfObj.get(objId - 1).add(i + 1); } } } } if (t instanceof MovingTemplate) { MovingTemplate op = (MovingTemplate)t; operationsDestination.add(getLocNById(op.getDestination().getId(), false)); } else if (t instanceof MooringTemplate) { MooringTemplate op = (MooringTemplate)t; operationsDestination.add(getLocNById(op.getStartLocation().getId(), op.isDirect())); } else { operationsDestination.add(getLocNById(t.getStartLocation().getId(), false)); } } } private void movingObjectLocationDefinition(boolean isV1) throws IOException { writeArray(writer, "is_mooring_op", isMooringOp, Optional.of(false)); writeArray(writer, "operations_destination", operationsDestination, (Integer val) -> val + 1, Optional.of(-1)); writer.write("\n"); } private void cargoOpUsingObj() throws IOException { ArrayList> relatedCargoOp = new ArrayList<>(); for (int i = 0; i < movingObjects.size(); i++) { relatedCargoOp.add(new TreeSet<>()); } for (int i = 0; i < operationTemplates.size(); i++) { if (operationTemplates.get(i) instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate) operationTemplates.get(i); relatedCargoOp.get(mObjToN(op.getLoader())).add(i + 1); if (op.getBunker().isPresent()) { relatedCargoOp.get(mObjToN(op.getBunker().get())).add(i + 1); } } } writeArray(writer, "related_cargo_op", relatedCargoOp, ConversionUtil::setToString, Optional.of(new TreeSet<>())); } private void unmooringOpUsingObj() throws IOException { ArrayList> relatedUnmooringOp = new ArrayList<>(); for (int i = 0; i < movingObjects.size(); i++) { relatedUnmooringOp.add(new TreeSet<>()); } for (int i = 0; i < operationTemplates.size(); i++) { if (operationTemplates.get(i) instanceof MooringTemplate) { MooringTemplate op = (MooringTemplate) operationTemplates.get(i); if (! op.isDirect()) { relatedUnmooringOp.get(mObjToN(op.getMoorer())).add(i + 1); } } } writeArray(writer, "related_unmooring_op", relatedUnmooringOp, ConversionUtil::setToString, Optional.of(new TreeSet<>())); } // related_unmooring_op private void addOpWithNominallyMooring() throws IOException { ArrayList>> opWithNominallyMooring = new ArrayList<>(); for (int loc = 0; loc <= locationNumberById.size(); loc++) { opWithNominallyMooring.add(new ArrayList<>()); for (int obj = 0; obj <= movingObjects.size(); obj++) { opWithNominallyMooring.get(loc).add(new TreeSet<>()); } } for (int i = 0; i < operationTemplates.size(); i++) { OperationTemplate t = operationTemplates.get(i); if ((t instanceof MooringTemplate) || ((t instanceof LoadingTemplate) && (! ((LoadingTemplate)t).getWithMooring()))) { opWithNominallyMooring.get(getLocNById(t.getStartLocation().getId(), true) + 1) .get(mObjToN(getExecutor(t)) + 1) .add(i + 1); } } write2DArrayOfSetAs3DArray(writer, "op_with_nominally_mooring", opWithNominallyMooring, true); } void portToMiniZinc_0() throws IOException { if (task.isTypified()) { throw new ParserException("Attempt to convert typified task as untyped."); } try { writer = new FileWriter(fileName, false); writer.write("n_intervals = " + n_intervals + ";\n"); writer.write("n_operations = " + task.getTemplates().size() + ";\n"); writer.write("n_locations = " + locationNumberById.size() + ";\n"); writer.write("n_moving_obj = " + movingObjects.size() + ";\n"); writer.write("\n"); arrivalAndDepartureOperations(); initialLocations(); weatherWindows(); operationsContinuity(); finalLocations(); presenceOfResourcesInLocation(); conflictingOperations(); writer.write("n_obj_with_storage = " + nObjWithStorage + ";\n"); writer.write("n_cargo_types = " + cargoes.size() + ";\n"); maxStorageVolume(); boundaryStorageStates(); cargoFlows(); cargoOperations(); constraintOnUsefulOperationBetweenMovements_0(); } finally { if (writer != null) { writer.close(); } } } void portToMiniZinc_1() throws IOException { if (task.isTypified()) { throw new ParserException("Attempt to convert typified task as untyped."); } try { writer = new FileWriter(fileName, false); writer.write("n_intervals = " + n_intervals + ";\n"); writer.write("n_operations = " + task.getTemplates().size() + ";\n"); writer.write("n_locations = " + locationNumberById.size() + ";\n"); writer.write("n_moving_obj = " + movingObjects.size() + ";\n"); writer.write("\n"); movingObjectLocationDefinition(true); initialLocations(); weatherWindows(); operationsContinuity(); finalLocations(); presenceOfResourcesInLocation(); conflictingOperations(); writer.write("n_obj_with_storage = " + nObjWithStorage + ";\n"); writer.write("n_cargo_types = " + cargoes.size() + ";\n"); maxStorageVolume(); boundaryStorageStates(); cargoFlows(); cargoOperations(); // constraintOnUsefulOperationBetweenMovements_1(); } finally { if (writer != null) { writer.close(); } } } public static ArrayList calcMovingObjects(TaskCase taskCase) { ArrayList movingObjects = new ArrayList<>(); movingObjects.addAll(taskCase.getShips()); movingObjects.addAll(taskCase.getBunkers()); movingObjects.addAll(taskCase.getTows()); movingObjects.addAll(taskCase.getEquipments()); return movingObjects; } /* Каждую операцию лишает типизации по главному действующему лицу. */ public static ArrayList renumberOperations(TaskCase task) { TreeMap> shipsByType = new TreeMap<>(); for (Integer type : task.getVesselTypes().keySet()) { shipsByType.put(type, new ArrayList<>()); } for (Integer type : task.getBunkerTypes().keySet()) { shipsByType.put(type, new ArrayList<>()); } for (Integer type : task.getEquipmentsTypes().keySet()) { shipsByType.put(type, new ArrayList<>()); } for (MovingObject obj : calcMovingObjects(task)) { if (obj.getType().isPresent()) { shipsByType.get(obj.getType().getAsInt()).add(obj); } } ArrayList result = new ArrayList<>(); for (OperationTemplate op : task.getTemplates()) { if (op instanceof LoadingTemplate) { LoadingTemplate t = (LoadingTemplate)op; if (t.getLoaderType().isPresent()) { for (MovingObject obj : shipsByType.get(t.getLoaderType().getAsInt())) { assert(obj instanceof TransportShip); if (t.getBunkerType().isPresent()) { for (MovingObject bunker : shipsByType.get(t.getBunkerType().getAsInt())) { assert(obj instanceof Bunker); result.add(new LoadingTemplate( (TransportShip)obj, t.getStartLocation(), t.getStorage(), t.getCargo(), Optional.of((Bunker)bunker), t.getResourcesTypes(), t.getWithMooring(), t.getIntensity(), t.getId() )); } } else { result.add(new LoadingTemplate( (TransportShip)obj, t.getStartLocation(), t.getStorage(), t.getCargo(), Optional.empty(), t.getResourcesTypes(), t.getWithMooring(), t.getIntensity(), t.getId() )); } } } } if (op instanceof MooringTemplate) { MooringTemplate t = (MooringTemplate)op; if (t.getMoorerType().isPresent()) { for (MovingObject obj : shipsByType.get(t.getMoorerType().getAsInt())) { assert(obj instanceof TransportShip); result.add(new MooringTemplate((TransportShip)obj, t.getStartLocation(), t.getResourcesTypes(), t.getDuration(), t.isDirect(), t.getId())); } } } if (op instanceof MovingTemplate) { MovingTemplate t = (MovingTemplate)op; if (t.getMoverType().isPresent()) { for (MovingObject obj : shipsByType.get(t.getMoverType().getAsInt())) { result.add(new MovingTemplate(obj, t.getStartLocation(), t.getDestination(), t.getResourcesTypes(), t.getDuration(), t.getId())); } } } } return result; } private void conflictingOperationsOnStorageAndOnTypeOnMainObject() throws IOException { ArrayList> conflictingOperationsG = new ArrayList<>(); for (int i = 0; i < operationTemplates.size(); i++) { conflictingOperationsG.add(new TreeSet<>()); for (int j = 0; j < operationTemplates.size(); j++) { if (i == j) { continue; } if ((operationTemplates.get(i) instanceof LoadingTemplate) && (operationTemplates.get(j) instanceof LoadingTemplate)) { LoadingTemplate op1 = (LoadingTemplate) operationTemplates.get(i); LoadingTemplate op2 = (LoadingTemplate) operationTemplates.get(j); if ((op1.getStorage() == op2.getStorage()) && (op1.getStartLocation() == op2.getStartLocation()) && (op1.getLoader() == op2.getLoader())) { conflictingOperationsG.get(i).add(j + 1); } } { // Взаимоисключение операций погрузки без швартовки на одном причале с разными субъектами. // + операций бункеровки без швартовки на одном причалое // TODO переделать if ((operationTemplates.get(i) instanceof LoadingTemplate) && (operationTemplates.get(j) instanceof LoadingTemplate)) { LoadingTemplate op1 = (LoadingTemplate) operationTemplates.get(i); LoadingTemplate op2 = (LoadingTemplate) operationTemplates.get(j); if ((! op1.getWithMooring()) && (! op2.getWithMooring()) && (op1.getStartLocation() == op2.getStartLocation()) && (op1.getBunker().isPresent()) && (op2.getBunker().isPresent())) { conflictingOperationsG.get(i).add(j + 1); } } } { // Взаимоисключение операций перемещения и грузообработки с общим деятелем. // TODO вынести в отдельный constraint OperationTemplate t1 = operationTemplates.get(i); OperationTemplate t2 = operationTemplates.get(j); if (t1 instanceof LoadingTemplate) { OperationTemplate t3 = t1; t1 = t2; t2 = t3; } if (((t1 instanceof MovingTemplate) || (t1 instanceof MooringTemplate)) && (t2 instanceof LoadingTemplate)) { if (getExecutor(t1) == getExecutor(t2)) { conflictingOperationsG.get(i).add(j + 1); } } } { // Взаимоисключение всех возможных пар операций перемещения с одним деятелем и пунктом отправления. if ((operationTemplates.get(i) instanceof MovingTemplate) && (operationTemplates.get(j) instanceof MovingTemplate)) { MovingTemplate op1 = (MovingTemplate) operationTemplates.get(i); MovingTemplate op2 = (MovingTemplate) operationTemplates.get(j); if ((op1.getMover() == op2.getMover()) && (op1.getStartLocation() == op2.getStartLocation())) { conflictingOperationsG.get(i).add(j + 1); } } } } } writeArray(writer, "conflicting_operations", conflictingOperationsG, ConversionUtil::setToString, Optional.of(new TreeSet<>())); } public ArrayList> getIsFixedArray() { Map, Integer> opNoByOpIdAndExecutorNo = new TreeMap<>(new PairComparator<>()); for (int i = 0; i < operationTemplates.size(); i++) { OperationTemplate op = operationTemplates.get(i); opNoByOpIdAndExecutorNo.put(new Pair<>(op.getId(), getExecutor(op).getId()), i); } ArrayList> isFixed = new ArrayList<>(); for (int i = 0; i <= operationTemplates.size(); i++) { isFixed.add(new ArrayList<>()); for (int j = 0; j <= n_intervals; j++) { isFixed.get(i).add(false); } } for (Operation op : task.getFixedOperations()) { if (op.getFixation()) { int operation = opNoByOpIdAndExecutorNo.get(new Pair<>(op.getTemplate().getId(), op.getExecutor().getId())); for (int i = (int)Math.floor(op.getStart()); i < (int)Math.ceil(op.getDuration() + op.getStart()); i++) { isFixed.get(operation + 1).set(i + 1, true); } } } return isFixed; } private void fixedOperations() throws IOException { ArrayList fixedOp = new ArrayList<>(); ArrayList> fixedOpResources = new ArrayList<>(); ArrayList fixedOpStart = new ArrayList<>(); ArrayList fixedOpEnd = new ArrayList<>(); ArrayList fixedOpIntensity = new ArrayList<>(); ArrayList>> is_fixed_op_planned_in_future = new ArrayList<>(); class OperationData implements Comparable { private int opId, executorId; private OptionalInt bunkerId; OperationData(int opId, int executorId, OptionalInt bunkerId) { this.opId = opId; this.executorId = executorId; this.bunkerId = bunkerId; } @Override public int compareTo(@NotNull OperationData o) { if (opId != o.opId) { return Integer.compare(opId, o.opId); } if (executorId != o.executorId) { return Integer.compare(executorId, o.executorId); } if (! bunkerId.isPresent()) { return (! o.bunkerId.isPresent()) ? 0 : -1; } if (! o.bunkerId.isPresent()) { return 1; } return Integer.compare(bunkerId.getAsInt(), o.bunkerId.getAsInt()); } }; Map opNoByOpData = new TreeMap<>(); for (int i = 0; i < operationTemplates.size(); i++) { OperationTemplate op = operationTemplates.get(i); OptionalInt bunkerId = OptionalInt.empty(); if ((op instanceof LoadingTemplate) && (((LoadingTemplate)op).getBunker().isPresent())) { bunkerId = OptionalInt.of(((LoadingTemplate)op).getBunker().get().getId()); } opNoByOpData.put(new OperationData(op.getId(), getExecutor(op).getId(), bunkerId), i); } ArrayList> is_obj_involved_in_fixed_op = new ArrayList<>(); for (int i = 0; i <= movingObjects.size(); i++) { is_obj_involved_in_fixed_op.add(new ArrayList<>()); for (int j = 0; j < n_intervals + 2; j++) { is_obj_involved_in_fixed_op.get(i).add(false); } } for (int i = 0; i < movingObjects.size(); i++) { is_fixed_op_planned_in_future.add(new ArrayList<>()); for (int j = 0; j < locationNumberById.size(); j++) { is_fixed_op_planned_in_future.get(i).add(new ArrayList<>()); for (int k = 0; k < n_intervals; k++) { is_fixed_op_planned_in_future.get(i).get(j).add(false); } } } for (Operation op : task.getFixedOperations()) { if (op.getFixation()) { OptionalInt bunkerId = op.getBunker().map(b -> OptionalInt.of(b.getId())).orElse(OptionalInt.empty()); int opNo = opNoByOpData.get(new OperationData(op.getTemplate().getId(), op.getExecutor().getId(), bunkerId)); int start = (int)Math.floor(op.getStart()); int end = (int)Math.ceil(op.getDuration() + op.getStart()); { ArrayList involvedMovingObj = new ArrayList<>(); involvedMovingObj.add(mObjToN(op.getExecutor())); if (op.getBunker().isPresent()) { involvedMovingObj.add(mObjToN(op.getBunker().get())); } for (MovingObject obj : op.getResources()) { involvedMovingObj.add(mObjToN(obj)); } for (int t = start; t < end; t++) { for (Integer obj : involvedMovingObj) { is_obj_involved_in_fixed_op.get(obj + 1).set(t + 1, true); } } } int loc = getLocNById(op.getTemplate().getStartLocation().getId(), false); int executor = mObjToN(op.getExecutor()); for (int i = 0; i < end; i++) { is_fixed_op_planned_in_future.get(executor).get(loc).set(i, true); } fixedOp.add(opNo + 1); TreeSet resources = new TreeSet<>(); for (MovingObject obj : op.getResources()) { resources.add(mObjToN(obj)); } fixedOpResources.add(resources); fixedOpStart.add(start + 1); fixedOpEnd.add(end); fixedOpIntensity.add((int)Math.ceil(op.getIntensity().orElse(0))); } } writer.write("n_fixed_op = " + fixedOp.size() + ";\n"); writeArray(writer, "fixed_op", fixedOp); writeArray(writer, "fixed_op_resources", fixedOpResources, ConversionUtil::setToString); writeArray(writer, "fixed_op_start", fixedOpStart); writeArray(writer, "fixed_op_end", fixedOpEnd); writeArray(writer, "fixed_op_intensity", fixedOpIntensity); locWrite2DArray(writer, "is_fixed", getIsFixedArray(), Objects::toString, true); locWrite2DArray(writer, "is_obj_involved_in_fixed_op", is_obj_involved_in_fixed_op, Objects::toString, true); write3dArray(writer, "is_fixed_op_planned_in_future", is_fixed_op_planned_in_future, Objects::toString); } void defDataForCurMovingOp() throws IOException { ArrayList isMovingOp = new ArrayList<>(); for (OperationTemplate op : operationTemplates) { isMovingOp.add((op instanceof MovingTemplate) || (op instanceof MooringTemplate)); } writeArray(writer, "is_moving_operation", isMovingOp, Optional.of(false)); writer.write("\n"); writeArray(writer, "main_obj_of_operation", mainObjOfOperation, (Integer val) -> val + 1, Optional.of(-1)); ArrayList> locMovingOpOfObj = new ArrayList<>(); locMovingOpOfObj.add(new ArrayList<>()); for (int i = 0; i <= operationTemplates.size(); i++) { locMovingOpOfObj.get(0).add(false); } for (ArrayList operations : movingOpOfObj) { ArrayList lOperations = new ArrayList<>(); lOperations.add(false); for (int i = 0; i < operationTemplates.size(); i++) { lOperations.add(false); } for (Integer op : operations) { lOperations.set(op, true); } locMovingOpOfObj.add(lOperations); } locWrite2DArray(writer, "moving_op_of_obj", locMovingOpOfObj, Objects::toString, true); } private void typifiedResourcesDefinition() throws IOException { { // objects_of_type и operations_that_used_obj_as_resource writer.write("n_resources_types = " + typeToN.size() + ";\n"); writeArray(writer, "objects_of_type", objectsOfType, ConversionUtil::setToString); ArrayList> res = arrayOfIntegerSet(movingObjects.size()); for (int i = 0; i < operationTemplates.size(); i++) { for (Integer typeNo : getNumbersOfResourcesTypes(operationTemplates.get(i))) { for (int obj : objectsOfType.get(typeNo)) { res.get(obj - 1).add(i + 1); } } } writeArray(writer, "operations_that_used_obj_as_resource", res, ConversionUtil::setToString, Optional.of(new TreeSet<>())); writer.write("\n"); } { // counters, operations_resources_start_loc ArrayList counterType = new ArrayList<>(); ArrayList operationOfCounter = new ArrayList<>(); ArrayList requiredCounterValues = new ArrayList<>(); ArrayList> countersOfOperation = arrayOfIntegerSet(operationTemplates.size()); ArrayList operationsResourcesStartLoc = new ArrayList<>(); for (int i = 0; i < operationTemplates.size(); i++) { Map numberOfTypes = new TreeMap<>(); for (int type : getNumbersOfResourcesTypes(operationTemplates.get(i))) { if (!numberOfTypes.containsKey(type)) { numberOfTypes.put(type, 1); } else { numberOfTypes.put(type, numberOfTypes.get(type) + 1); } } for (Map.Entry p : numberOfTypes.entrySet()) { counterType.add(p.getKey()); operationOfCounter.add(i); requiredCounterValues.add(p.getValue()); countersOfOperation.get(i).add(counterType.size()); operationsResourcesStartLoc.add(locationNumberById.get(new Pair<>(operationTemplates.get(i).getStartLocation().getId(), false))); } } writer.write("n_resources_counters = " + counterType.size() + ";\n"); writeArray(writer, "counter_type", counterType, (Integer val) -> val + 1); writeArray(writer, "operation_of_counter", operationOfCounter, (Integer val) -> val + 1); writeArray(writer, "required_counter_values", requiredCounterValues); writeArray(writer, "operations_resources_start_loc", operationsResourcesStartLoc, (Integer val) -> val + 1); writeArray(writer, "counters_of_operation", countersOfOperation, ConversionUtil::setToString, Optional.of(new TreeSet<>())); } } void requiredLocationsOnOpStart() throws IOException { ArrayList mainObjStartLoc = new ArrayList<>(); ArrayList bunkerStartLoc = new ArrayList<>(); for (OperationTemplate op : operationTemplates) { boolean isMoored = false; if ((op instanceof LoadingTemplate) && (((LoadingTemplate) op).getWithMooring())) { isMoored = true; } if ((op instanceof MooringTemplate) && (!((MooringTemplate)op).isDirect())) { isMoored = true; } mainObjStartLoc.add(getLocNById(op.getStartLocation().getId(), isMoored)); bunkerStartLoc.add(getLocNById(op.getStartLocation().getId(), false)); } writeArray(writer, "main_obj_start_loc", mainObjStartLoc, (Integer val) -> val + 1, Optional.of(-1)); writeArray(writer, "bunker_start_loc", bunkerStartLoc, (Integer val) -> val + 1, Optional.of(-1)); } void dataForOptimization3() throws IOException { ArrayList> min_positive_cargo_val = arrayOfIntegerArrays(sectionNById.size()); ArrayList> max_negative_cargo_val = arrayOfIntegerArrays(sectionNById.size()); ArrayList> can_obj_leave_loc_only_alone = new ArrayList<>(); for (int i = 0; i < sectionNById.size(); i++) { for (int j = 0; j < locationNumberById.size(); j++) { min_positive_cargo_val.get(i).add(maxStorageVol.get(i) + 1); max_negative_cargo_val.get(i).add(-maxStorageVol.get(i) - 1); } } for (int i = 0; i < movingObjects.size(); i++) { can_obj_leave_loc_only_alone.add(new ArrayList<>()); for (int j = 0; j < locationNumberById.size(); j++) { can_obj_leave_loc_only_alone.get(i).add((j + 1) % 2 == 1); } } for (OperationTemplate t : operationTemplates) { if (t instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate) t; int val = (int) op.getIntensity(); int loc = getLocNById(op.getStartLocation().getId(), false) ; ArrayList> sections = new ArrayList<>(); sections.add(new Pair<>(sectionIdToN(op.getLoader(), op.getCargo()), val)); if (op.getBunker().isPresent()) { sections.add(new Pair<>(sectionIdToN(op.getBunker().get(), op.getCargo()), -val)); } else { sections.add(new Pair<>(sectionIdToN(op.getStorage(), op.getCargo()), -val)); } for (Pair p : sections) { if (p.getValue() > 0) { min_positive_cargo_val.get(p.getKey()).set(loc, Math.min(p.getValue(), min_positive_cargo_val.get(p.getKey()).get(loc))); } else { max_negative_cargo_val.get(p.getKey()).set(loc, Math.max(p.getValue(), max_negative_cargo_val.get(p.getKey()).get(loc))); } } } else if (t instanceof MovingTemplate) { int loc = getLocNById(t.getStartLocation().getId(), false); int obj = mObjToN(getExecutor(t)); if (! ((MovingTemplate) t).getResourcesTypes().isEmpty()) { can_obj_leave_loc_only_alone.get(obj).set(loc, false); } } } write2DArrayOfInt(writer, "min_positive_cargo_val", min_positive_cargo_val, false); write2DArrayOfInt(writer, "max_negative_cargo_val", max_negative_cargo_val, false); locWrite2DArray(writer, "can_obj_leave_loc_only_alone", can_obj_leave_loc_only_alone, Objects::toString); writer.write("\n"); } /* С типизацией. */ void portToMiniZinc_2() throws IOException { if (!task.isTypified()) { throw new ParserException("Attempt to convert untyped task as typified."); } try { writer = new FileWriter(fileName, false); writer.write("n_intervals = " + n_intervals + ";\n"); writer.write("n_operations = " + operationTemplates.size() + ";\n"); writer.write("n_locations = " + locationNumberById.size() + ";\n"); writer.write("n_moving_obj = " + movingObjects.size() + ";\n"); writer.write("\n"); movingObjectLocationDefinition(false); initialLocations(); finalLocations(); defDataForCurMovingOp(); weatherWindowsNewFormat(); conflictingOperationsOnStorageAndOnTypeOnMainObject(); requiredLocationsOnOpStart(); operationsContinuity(); typifiedResourcesDefinition(); cargoOpUsingObj(); unmooringOpUsingObj(); addOpWithNominallyMooring(); writer.write("n_all_storage_sections = " + sectionNById.size() + ";\n"); writer.write("n_cargo_types = " + cargoes.size() + ";\n"); maxStorageVolume(); boundaryStorageStates(); cargoFlows(); cargoOperations(); dataForOptimization3(); fixedOperations(); } finally { if (writer != null) { writer.close(); } } } void dataForGreediness() throws IOException { ArrayList> connectedSections = arrayOfIntegerArrays(sectionNById.size()); ArrayList> connectedSectionsSet = arrayOfIntegerSet(sectionNById.size()); for (OperationTemplate t : operationTemplates) { if (t instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate) t; int section1 = sectionIdToN(op.getLoader(), op.getCargo()); int section2; if (op.getBunker().isPresent()) { section2 = sectionIdToN(op.getBunker().get(), op.getCargo()); } else { section2 = sectionIdToN(op.getStorage(), op.getCargo()); } connectedSectionsSet.get(section2).add(section1); } } ArrayList> positionsOfConnectedSections = arrayOfIntegerArrays(sectionNById.size()); for (int i = 0; i < sectionNById.size(); i++) { positionsOfConnectedSections.set(i, integerArray(sectionNById.size(), 0)); } for (int i = 0; i < sectionNById.size(); i++) { connectedSections.set(i, new ArrayList<>(connectedSectionsSet.get(i))); for (int j = 0; j < connectedSections.get(i).size(); j++) { positionsOfConnectedSections.get(connectedSections.get(i).get(j)).set(i, j); } } ArrayList operationsMainStorNoInSecondary = new ArrayList<>(); ArrayList operationsSecondaryStorNoInMain = new ArrayList<>(); for (OperationTemplate t : operationTemplates) { if (t instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate) t; int section1 = sectionIdToN(op.getLoader(), op.getCargo()); int section2; if (op.getBunker().isPresent()) { section2 = sectionIdToN(op.getBunker().get(), op.getCargo()); } else { section2 = sectionIdToN(op.getStorage(), op.getCargo()); } operationsMainStorNoInSecondary.add(positionsOfConnectedSections.get(section1).get(section2)); operationsSecondaryStorNoInMain.add(positionsOfConnectedSections.get(section2).get(section1)); } else { operationsMainStorNoInSecondary.add(-1); operationsSecondaryStorNoInMain.add(-1); } } int max_number_of_connected_sections = 0; ArrayList number_of_connected_sections = new ArrayList<>(); for (int i = 0; i < nSectionsOfRealStorageAndBunkers; i++) { number_of_connected_sections.add(connectedSections.get(i).size()); max_number_of_connected_sections = Math.max(max_number_of_connected_sections, connectedSections.get(i).size()); } writer.write("n_sections_of_real_storage_and_bunkers = " + nSectionsOfRealStorageAndBunkers + ";\n"); writer.write("max_number_of_connected_sections = " + max_number_of_connected_sections + ";\n"); writeArray(writer, "number_of_connected_sections", number_of_connected_sections, Optional.of(0)); writeArray(writer, "operations_main_stor_no_in_secondary", operationsMainStorNoInSecondary, (Integer i) -> i + 1, Optional.of(-1)); writeArray(writer, "operations_secondary_stor_no_in_main", operationsSecondaryStorNoInMain, (Integer i) -> i + 1, Optional.of(-1)); ArrayList>> connected_op_to_pair_of_sections = new ArrayList<>(); for (int i = 0; i <= nSectionsOfRealStorageAndBunkers; i++) { connected_op_to_pair_of_sections.add(new ArrayList<>()); for (int j = 0; j <= max_number_of_connected_sections; j++) { connected_op_to_pair_of_sections.get(i).add(new ArrayList<>()); } } for (int i = 0; i < operationTemplates.size(); i++) { if (operationTemplates.get(i) instanceof LoadingTemplate) { LoadingTemplate op = (LoadingTemplate) operationTemplates.get(i); int section1 = sectionIdToN(op.getLoader(), op.getCargo()); int section2; if (op.getBunker().isPresent()) { section2 = sectionIdToN(op.getBunker().get(), op.getCargo()); } else { section2 = sectionIdToN(op.getStorage(), op.getCargo()); } connected_op_to_pair_of_sections.get(section2 + 1).get(operationsMainStorNoInSecondary.get(i) + 1).add(i + 1); } } locWrite2DArray(writer, "connected_op_to_pair_of_sections", connected_op_to_pair_of_sections, ConversionUtil::arrayToStringAsSet, true); { ArrayList storage_greedy_upper_limit = new ArrayList<>(maxStorageVol); ArrayList storage_greedy_lower_limit = integerArray(sectionNById.size(), 0); for (int i = 0; i < sectionNById.size(); i++) { if (finalStorageVol.get(i) >= 0) { if (finalStorageVol.get(i) <= initialStorageVol.get(i)) { storage_greedy_lower_limit.set(i, finalStorageVol.get(i)); } else { storage_greedy_upper_limit.set(i, Math.min(storage_greedy_upper_limit.get(i), finalStorageVol.get(i))); } } } writeArray(writer, "storage_greedy_upper_limit", storage_greedy_upper_limit, Optional.of(0)); writeArray(writer, "storage_greedy_lower_limit", storage_greedy_lower_limit, Optional.of(0)); } { ArrayList> all_used_positions_in_real_cargo_value = arrayOfIntegerArrays(sectionNById.size()); for (int i = 0; i < sectionNById.size(); i++) { for (int j = 0; j < connectedSections.get(i).size(); j++) { all_used_positions_in_real_cargo_value.get(connectedSections.get(i).get(j)).add(i + 1); } } locWrite2DArray(writer, "positions_of_connected_sections", positionsOfConnectedSections, (Integer i) -> Integer.toString(i + 1), false); writeArray(writer, "all_used_positions_in_real_cargo_value", all_used_positions_in_real_cargo_value, ConversionUtil::arrayToStringAsSet, Optional.of(new ArrayList<>())); } } void portToMiniZinc_2_greedy() throws IOException { if (!task.isTypified()) { throw new ParserException("Attempt to convert untyped task as typified."); } try { writer = new FileWriter(fileName, false); writer.write("n_intervals = " + n_intervals + ";\n"); writer.write("n_operations = " + operationTemplates.size() + ";\n"); writer.write("n_locations = " + locationNumberById.size() + ";\n"); writer.write("n_moving_obj = " + movingObjects.size() + ";\n"); writer.write("\n"); movingObjectLocationDefinition(false); initialLocations(); finalLocations(); defDataForCurMovingOp(); weatherWindowsNewFormat(); conflictingOperationsOnStorageAndOnTypeOnMainObject(); requiredLocationsOnOpStart(); operationsContinuity(); typifiedResourcesDefinition(); cargoOpUsingObj(); addOpWithNominallyMooring(); writer.write("n_all_storage_sections = " + sectionNById.size() + ";\n"); writer.write("n_cargo_types = " + cargoes.size() + ";\n"); maxStorageVolume(); boundaryStorageStates(); cargoFlows(); cargoOperations(); fixedOperations(); dataForGreediness(); } finally { if (writer != null) { writer.close(); } } } } static public void portToMiniZinc_0(TaskCase task, String fileName) throws IOException { Task taskData = new Task(task, fileName); taskData.portToMiniZinc_0(); } static public void portToMiniZinc_1(TaskCase task, String fileName) { try { Task taskData = new Task(task, fileName); taskData.portToMiniZinc_1(); } catch (IOException e) { throw new UncheckedIOException(e); } } static public void portToMiniZinc_2(TaskCase task, String fileName) { try { Task taskData = new Task(task, fileName); taskData.portToMiniZinc_2(); } catch (IOException e) { throw new UncheckedIOException(e); } } static public void portToMiniZincGreedy(TaskCase task, String fileName) { try { Task taskData = new Task(task, fileName); taskData.portToMiniZinc_2_greedy(); } catch (IOException e) { throw new UncheckedIOException(e); } } public static void resolveMiniZincResults(TaskCase taskCase, String fileName) { ArrayList operations = null; Integer result = null; try (FileInputStream fstream = new FileInputStream(fileName)) { BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); String line; Map>> arrays = new TreeMap<>(); while (((line = br.readLine()) != null)) { line = line.trim(); if (line.equals("")) { continue; } int pos = 0; while ((pos < line.length()) && (line.charAt(pos) != ' ')) { pos++; } String name = line.substring(0, pos); if (name.equals("=====UNSATISFIABLE=====")) { result = -1; break; } if (name.equals("----------")) { 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"); } for (String keyArray : Arrays.asList("op_status", "participation_as_resource")) { if (! arrays.containsKey(keyArray)) { if (result == -1) { operations = new ArrayList<>(); } else { throw new ParserException("No \"" + keyArray + "\" in input"); } } } if (result != -1) { Task task = new Task(taskCase, ""); operations = new ArrayList<>(); ArrayList> opStatus = arrays.get("op_status"); ArrayList templates = new ArrayList<>(taskCase.getTemplates()); if (taskCase.isTypified()) { templates = Task.renumberOperations(taskCase); } ArrayList> cargoOpIntensity; if (arrays.containsKey("cargo_op_intensity")) { cargoOpIntensity = arrays.get("cargo_op_intensity"); } else { cargoOpIntensity = new ArrayList<>(); for (int opNo = 0; opNo < opStatus.size(); opNo++) { cargoOpIntensity.add(new ArrayList<>()); for (String val : opStatus.get(opNo)) { if (val.equals("true") && (templates.get(opNo - 1) instanceof LoadingTemplate)) { LoadingTemplate op = (LoadingTemplate)templates.get(opNo - 1); cargoOpIntensity.get(opNo).add(Integer.toString((int)Math.ceil(Math.abs(op.getIntensity())))); } else { cargoOpIntensity.get(opNo).add("0"); } } } } Map operationById = new TreeMap<>(); for (OperationTemplate operation : taskCase.getTemplates()) { operationById.put(operation.getId(), operation); } Map objByNo = new TreeMap<>(); ArrayList> isFixed; for (MovingObject obj : task.getMovingObjects()) { objByNo.put(task.getMObjNumberById().get(obj.getId()), obj); } isFixed = task.getIsFixedArray(); Set oldSolution = new TreeSet<>(); for (Operation op : taskCase.getFixedOperations()) { if (op.getFixation()) { oldSolution.add(op.toString()); } } for (int opNo = 1; opNo < opStatus.size(); opNo++) { int duration = 0; int t = 1; boolean lastFixation = false; while (t < opStatus.get(opNo).size()) { boolean isOpLogicallyInterrupted = false; if (opStatus.get(opNo).get(t).equals("true") && (lastFixation != isFixed.get(opNo).get(t)) && (duration != 0)) { // У операции изменилась фиксация. isOpLogicallyInterrupted = true; } if (opStatus.get(opNo).get(t).equals("false") && (duration != 0)) { // Операция просто закончилась. isOpLogicallyInterrupted = true; } if ((! cargoOpIntensity.get(opNo).get(t - 1).equals(cargoOpIntensity.get(opNo).get(t))) && (duration != 0)) { // Изменилась интенсивность погрузки. isOpLogicallyInterrupted = true; } if (isOpLogicallyInterrupted) { // Добавляем новую операцию. Operation op = new Operation(); op.setStart(t - duration - 1); op.setDuration(duration); op.setTemplate(operationById.get(templates.get(opNo - 1).getId())); if (taskCase.isTypified()) { op.setExecutor(ConversionUtil.getExecutor(templates.get(opNo - 1))); ArrayList resources = new ArrayList<>(); // TODO ускорить. ArrayList> opOfResource = arrays.get("participation_as_resource"); for (int obj = 1; obj < opOfResource.size(); obj++) { if (opOfResource.get(obj).get(t - 1).equals(Integer.toString(opNo))) { resources.add(objByNo.get(obj - 1)); } } op.setResources(resources); } { // Установка бункеровщика. OperationTemplate template = templates.get(opNo - 1); if (template instanceof LoadingTemplate) { LoadingTemplate operation = (LoadingTemplate)template; if (operation.getBunker().isPresent()) { op.setBunker(operation.getBunker()); } } } if (! cargoOpIntensity.get(opNo).get(t - 1).equals("0")) { op.setIntensity(Optional.of(Integer.valueOf(cargoOpIntensity.get(opNo).get(t - 1)))); } op.setFixation(true); if (! oldSolution.contains(op.toString())) { op.setFixation(false); } operations.add(op); duration = 0; } if (opStatus.get(opNo).get(t).equals("true") && (lastFixation != isFixed.get(opNo).get(t))) { // Остаёмся на месте. lastFixation = isFixed.get(opNo).get(t); continue; } if (opStatus.get(opNo).get(t).equals("true")) { duration++; } else { duration = 0; } if ((0 <= t) && (t < isFixed.get(opNo).size())) { lastFixation = isFixed.get(opNo).get(t); } t++; } } } taskCase.setSolution(operations); taskCase.setSolution_result(result); } catch (IOException e) { throw new UncheckedIOException(e); } } }