diff --git a/src/constraints/conversion_2_greedy.mzn b/src/constraints/conversion_2_greedy.mzn index 6b81e800933c62c7ba78c2dfcd56259792afb7e8..bec3fdd569b7653f1a0e7540ca4d3292262ef59f 100644 --- a/src/constraints/conversion_2_greedy.mzn +++ b/src/constraints/conversion_2_greedy.mzn @@ -221,7 +221,6 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац % Определение is_involved_in_cargo_op. constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( is_involved_in_cargo_op[obj, t] = ( - % (exists (op in 1..n_operations where (not is_moving_operation[op]) /\ (main_obj_of_operation[op] = obj)) ( (exists (op in related_cargo_op[obj]) (op_status[op, t])) \/ ((participation_as_resource[obj, t] != 0) /\ (not is_moving_operation[participation_as_resource[obj, t]])) @@ -347,6 +346,206 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations; + + array [0..n_all_storage_sections] of int : storage_greedy_upper_limit; + array [0..n_all_storage_sections] of int : storage_greedy_lower_limit; + + 0..n_all_storage_sections : n_sections_of_real_storage_and_bunkers; + array [0..n_sections_of_real_storage_and_bunkers] of 0..n_all_storage_sections : number_of_connected_sections; + + 0..n_all_storage_sections : max_number_of_connected_sections; + + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections, 1..(n_intervals + 1)] of var int : nominal_cargo_value; + array [0..n_sections_of_real_storage_and_bunkers, 0..(max_number_of_connected_sections + 1), 1..(n_intervals + 1)] of var int : cargo_overflow_remains; + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections, 1..(n_intervals + 1)] of var int : real_cargo_value; + + % Определение real_cargo_value + array [0..n_operations] of 0..n_all_storage_sections : operations_main_stor_no_in_secondary; + array [0..n_operations] of 0..n_all_storage_sections : operations_secondary_stor_no_in_main; + + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections] of set of 1..n_operations : connected_op_to_pair_of_sections; + + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections, 1..(n_intervals + 1)] of var int : debug_1; + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1) where operations_main_stor_no_in_secondary[op] != 0) ( + op_status[op, t] -> ( + debug_1[operations_secondary_stor[op], operations_main_stor_no_in_secondary[op], t] = + min(storage_greedy_upper_limit[operations_main_stor[op]] - storage_used_volume[operations_main_stor[op], t - 1], + loading_op_delta_of_main_obj[op]) + ) + ); + + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + section_2 in 1..number_of_connected_sections[section_1], + t in 1..(n_intervals + 1)) ( + (forall (op in connected_op_to_pair_of_sections[section_1, section_2]) (not op_status[op, t])) + -> + (debug_1[section_1, section_2, t] = 0) + ); + + + + + % Определение nominal_cargo_value + % Операция грузообработки активна -> нужные номинальные значения согласованы с ней. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1) where operations_main_stor_no_in_secondary[op] != 0) ( + op_status[op, t] -> ( + nominal_cargo_value[operations_secondary_stor[op], operations_main_stor_no_in_secondary[op], t] = + -max( + min(storage_greedy_upper_limit[operations_main_stor[op]] - storage_used_volume[operations_main_stor[op], t - 1], + loading_op_delta_of_main_obj[op]), + storage_greedy_lower_limit[operations_main_stor[op]] - storage_used_volume[operations_main_stor[op], t - 1]) + ) + ); + + % Если нет активной операции, влияющей на эту пару секций, то nominal_cargo_value = 0. + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + section_2 in 1..number_of_connected_sections[section_1], + t in 1..(n_intervals + 1)) ( + (forall (op in connected_op_to_pair_of_sections[section_1, section_2]) (not op_status[op, t])) + -> + (nominal_cargo_value[section_1, section_2, t] = 0) + ); + + % Крайние значения. + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + section_2 in (number_of_connected_sections[section_1] + 1)..max_number_of_connected_sections, + t in 1..(n_intervals + 1)) ( + nominal_cargo_value[section_1, section_2, t] = 0 + ); + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + t in 1..(n_intervals + 1)) ( + nominal_cargo_value[section_1, 0, t] = 0 + ); + constraint forall (section_2 in 0..max_number_of_connected_sections, + t in 1..(n_intervals + 1)) ( + nominal_cargo_value[0, section_2, t] = 0 + ); + + % Определение cargo_overflow_remains. + % Переполнение. + constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( + let {var int : delta = sum (i in 1..number_of_connected_sections[section]) (nominal_cargo_value[section, i, t]); + var int : real_delta = min(max(delta, + storage_greedy_lower_limit[section] - storage_used_volume[section, t - 1]), + storage_greedy_upper_limit[section] - storage_used_volume[section, t - 1]); + } in ( + cargo_overflow_remains[section, number_of_connected_sections[section] + 1, t] = (delta - real_delta) + ) + ); + + % Избавляемся от лишнего. + % Если остаток переполнения и номналное значение одного знака, то полностью отменяем это номинальное значение. + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in 1..number_of_connected_sections[section]) ( + ((((cargo_overflow_remains[section, i + 1, t] < 0) /\ (nominal_cargo_value[section, i, t] < 0)) + \/ + ((cargo_overflow_remains[section, i + 1, t] > 0) /\ (nominal_cargo_value[section, i, t] > 0)) + ) /\ (abs(cargo_overflow_remains[section, i + 1, t]) >= abs(nominal_cargo_value[section, i, t])) + ) -> ( + cargo_overflow_remains[section, i, t] = + cargo_overflow_remains[section, i + 1, t] - + nominal_cargo_value[section, i, t] + ) + ); + + % Иначе оно полностью перекрыло переполнение. + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in 1..number_of_connected_sections[section]) ( + (((cargo_overflow_remains[section, i + 1, t] <= 0) /\ (nominal_cargo_value[section, i, t] >= 0)) + \/ + ((cargo_overflow_remains[section, i + 1, t] >= 0) /\ (nominal_cargo_value[section, i, t] <= 0)) + \/ + (abs(cargo_overflow_remains[section, i + 1, t]) < abs(nominal_cargo_value[section, i, t])) + ) -> ( + cargo_overflow_remains[section, i, t] = 0 + ) + ); + + % Крайние значения. + constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( + cargo_overflow_remains[section, 0, t] = 0 + ); + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in (number_of_connected_sections[section] + 2)..max_number_of_connected_sections) ( + cargo_overflow_remains[section, i, t] = 0 + ); + constraint forall (section_2 in 0..(max_number_of_connected_sections + 1), + t in 1..(n_intervals + 1)) ( + cargo_overflow_remains[0, section_2, t] = 0 + ); + + % Определение real_cargo_value + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in 1..number_of_connected_sections[section]) ( + real_cargo_value[section, i, t] = nominal_cargo_value[section, i, t] + - cargo_overflow_remains[section, i + 1, t] + + cargo_overflow_remains[section, i, t] + ); + % Крайние значения. + constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( + real_cargo_value[section, 0, t] = 0 + ); + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in (number_of_connected_sections[section] + 1)..max_number_of_connected_sections) ( + real_cargo_value[section, i, t] = 0 + ); + constraint forall (section_2 in 0..max_number_of_connected_sections, + t in 1..(n_intervals + 1)) ( + real_cargo_value[0, section_2, t] = 0 + ); + + array [0..n_all_storage_sections] of set of 1..n_all_storage_sections : all_used_positions_in_real_cargo_value; + array [1..n_all_storage_sections, 1..n_all_storage_sections] of 0..max_number_of_connected_sections : positions_of_connected_sections; + + + constraint forall (storage in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in 1..number_of_connected_sections[storage]) (real_cargo_value[storage, i, t])) + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); + constraint forall (storage in (n_sections_of_real_storage_and_bunkers + 1)..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); + +/* + constraint forall (storage in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( + debug_storage_used_volume[storage, t] = ( + debug_storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in 1..number_of_connected_sections[storage]) (real_cargo_value[storage, i, t])) + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); + + constraint forall (storage in (n_sections_of_real_storage_and_bunkers + 1)..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + debug_storage_used_volume[storage, t] = ( + debug_storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); +*/ + + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of var int : debug_storage_used_volume; + constraint forall (t in 0..(n_intervals + 1)) (debug_storage_used_volume[0, t] = 0); % Фиктивный объект. + + constraint forall (storage in 1..n_all_storage_sections) ( % Initial values. + debug_storage_used_volume[storage, 0] = initial_storage_vol[storage] + ); + +/* constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( storage_used_volume[storage, t] = ( storage_used_volume[storage, t - 1] + @@ -357,7 +556,7 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ) ) ); - +*/ % Фиксированные операции. int : n_fixed_op; array [1..n_fixed_op] of 1..n_operations : fixed_op; @@ -376,7 +575,7 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ) ) ); - +/* % Оптимизация - сдвиг в начало. % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). array [0..n_operations, 1..n_intervals] of var bool : is_op_possible; @@ -454,7 +653,7 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац constraint forall (op in 1..n_operations, t in 2..n_intervals) ( (op_start[op, t] /\ (not is_fixed[op, t])) -> not is_op_possible[op, t - 1] ); - +*/ % Критерий оптимизации array [1..(n_intervals + 1)] of var bool : is_not_terminated; % В конце всё остановится. @@ -487,6 +686,15 @@ output [show(sum(is_not_terminated)), "\n", "current_moored_obj = ", show(current_moored_obj), "\n\n", + "nominal_cargo_value {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(nominal_cargo_value), "\n\n", + "cargo_overflow_remains {", show(max_number_of_connected_sections + 2), " ", show(n_intervals + 1), "} = ", show(cargo_overflow_remains), "\n\n", + "real_cargo_value {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(real_cargo_value), "\n\n", + + "debug_1 {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(debug_1), "\n\n", + + + "debug_storage_used_volume = ", show(debug_storage_used_volume), "\n\n", + /* "is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n", "debug_1 {", show(n_intervals), "} = ", show(debug_1), "\n\n", diff --git a/src/inport/ConversionUtil.java b/src/inport/ConversionUtil.java index 666b5029089752985d736a3e1955dbb6dbd7d83c..4af060a6842010a51f5fb02d620b4e5b26e89b3f 100644 --- a/src/inport/ConversionUtil.java +++ b/src/inport/ConversionUtil.java @@ -416,6 +416,19 @@ public class ConversionUtil { } 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; @@ -432,6 +445,12 @@ public class ConversionUtil { 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; @@ -471,22 +490,28 @@ public class ConversionUtil { storageNById = new TreeMap<>(); sectionNById = new TreeMap<>(); - for (int i = 0; i < storages.size(); i++) { + 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 TransportShip) { + 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++); } } } - 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++); + 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++); + } } } @@ -524,6 +549,48 @@ public class ConversionUtil { 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) { @@ -736,26 +803,6 @@ public class ConversionUtil { /* Ограничения на вместимость. */ private void maxStorageVolume() throws IOException { - ArrayList maxStorageVol = integerArray(sectionNById.size(), 0); - - for (MovingObject obj : movingObjects) { - if (obj instanceof TransportShip) { - for (Pair p : ((TransportShip) obj).getStorageSections()) { - maxStorageVol.set(sectionNById.get(new StorageSectionId(false, - mObjToN(obj), - cargoNById.get(p.getKey().getId()))), - (int)Math.ceil(p.getValue())); - } - } - } - for (Storage storage : storages) { - for (Pair p : storage.getStorageSections()) { - maxStorageVol.set(sectionNById.get(new StorageSectionId(true, - storageNById.get(storage.getId()), - cargoNById.get(p.getKey().getId()))), - (int)Math.ceil(p.getValue())); - } - } writeArray(writer, "max_storage_vol", maxStorageVol, Optional.of(0)); writer.write("\n"); @@ -763,38 +810,6 @@ public class ConversionUtil { /* Граничные состояния хранилищ. */ private void boundaryStorageStates() throws IOException { - // TODO выделить отдельно общий код. - ArrayList initialStorageVol = integerArray(sectionNById.size(), 0); - ArrayList finalStorageVol = integerArray(sectionNById.size(), -1); - - BiConsumer, StorageState> f = (ArrayList a, StorageState st) -> { - int cargoN = cargoNById.get(st.getCargo().getId()); - int val = (int)st.getCargoState(); - - boolean isRealStorage; - int localN; - - if (st.getStorage() instanceof Storage) { - Storage storage = (Storage) st.getStorage(); - isRealStorage = true; - localN = storageNById.get(storage.getId()); - } else { - assert st.getStorage() instanceof TransportShip; - isRealStorage = false; - TransportShip ship = (TransportShip) st.getStorage(); - localN = mObjToN(ship); - } - - int sectionN = sectionNById.get(new StorageSectionId(isRealStorage, localN, cargoN)); - a.set(sectionN, val); - }; - - for (StorageState st : task.getStorageInitialState()) { - f.accept(initialStorageVol, st); - } - for (StorageState st : task.getStorageEndState()) { - f.accept(finalStorageVol, st); - } writeArray(writer, "initial_storage_vol", initialStorageVol, Optional.of(0)); writeArray(writer, "final_storage_vol", finalStorageVol, Optional.of(-1)); } @@ -806,9 +821,7 @@ public class ConversionUtil { cargoFlows.add(integerArray(n_intervals + 2, 0)); } for (CargoFlow flow : task.getCargoFlows()) { - int storageN = sectionNById.get(new StorageSectionId(true, - storageNById.get(flow.getStorage().getId()), - cargoNById.get(flow.getCargo().getId()))); + 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)); } @@ -847,12 +860,12 @@ public class ConversionUtil { int storageN; if (op.getBunker().isPresent()) { - storageN = sectionNById.get(new StorageSectionId(false, mObjToN(op.getBunker().get()), cargoN)); + storageN = sectionIdToN(op.getBunker().get(), op.getCargo()); } else { - storageN = sectionNById.get(new StorageSectionId(true, storageNById.get(op.getStorage().getId()), cargoN)); + storageN = sectionIdToN(op.getStorage(), op.getCargo()); } - int shipStorageN = sectionNById.get(new StorageSectionId(false, shipN, cargoN)); + int shipStorageN = sectionIdToN(op.getLoader(), op.getCargo()); loadingOpDelta.add(-(int)op.getIntensity()); loading_op_local_direction.add(-(int)op.getIntensity() > 0 ? 1 : -1); @@ -868,7 +881,7 @@ public class ConversionUtil { loading_op_abs_delta.add(Math.abs((int)op.getIntensity())); loading_op_direction.add((int)op.getIntensity() > 0 ? 1 : -1); - operations_main_stor.add(shipN + 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); @@ -1536,6 +1549,183 @@ public class ConversionUtil { } } } + + 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); + } + } + +// System.out.print("#######\n"); +// for (int i = 0; i < sectionNById.size(); i++) { +// for (Integer val : positionsOfConnectedSections.get(i)) { +// System.out.print(val + " "); +// } +// System.out.print("\n"); +// } +// System.out.print("---\n"); + + 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 { @@ -1561,6 +1751,15 @@ public class ConversionUtil { } } + 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; @@ -1609,7 +1808,10 @@ public class ConversionUtil { while (line.charAt(nextPos) != '}') { nextPos++; } - arrayFirstDim = Integer.valueOf(line.substring(pos, nextPos).trim()); + 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++; diff --git a/src/inport/Main.java b/src/inport/Main.java index 6843a80e4ddd1d3d97a5e269dca27b6bd42b52fc..d3c30f38fc8a8be8075f33d3657370f70fd5d858 100644 --- a/src/inport/Main.java +++ b/src/inport/Main.java @@ -149,6 +149,10 @@ public class Main { debug(Testing::solveTaskWithPartialCargoOp, DEFAULT_TIME_LIMIT_S); break; } + case "debug greedy" : { + debug(Testing::solveTaskWithGreedyConstraints, DEFAULT_TIME_LIMIT_S); + break; + } case "debug read-write" : { debugReadWrite(); break; @@ -289,6 +293,7 @@ public class Main { } int arrayFirstDim = ((int) task.getPlanningInterval()) + 2; + int arraySecondDim = 0; if (line.charAt(pos) == '{') { pos++; @@ -296,7 +301,14 @@ public class Main { while (line.charAt(nextPos) != '}') { nextPos++; } - arrayFirstDim = Integer.valueOf(line.substring(pos, nextPos).trim()); + String []dimensions = line.substring(pos, nextPos).trim().split(" "); + if (dimensions.length > 0) { + arrayFirstDim = Integer.valueOf(dimensions[0].trim()); + } + if (dimensions.length > 1) { + arraySecondDim = Integer.valueOf(dimensions[1].trim()); + } + pos = nextPos + 1; while (line.charAt(pos) != '[') { pos++; @@ -330,7 +342,7 @@ public class Main { maxLength = Math.max(maxLength, val.length()); } - if ((arrayFirstDim != 0) && (elements.size() % arrayFirstDim == 0)) { + if ((arrayFirstDim != 0) && (elements.size() % arrayFirstDim == 0) && ((arraySecondDim == 0) || (elements.size() % (arrayFirstDim * arraySecondDim) != 0))) { writer.write(name + " :\n"); for (int i = 0; i < elements.size(); i += arrayFirstDim) { writer.write(" "); @@ -344,6 +356,23 @@ public class Main { writer.write("\n"); } writer.write("\n"); + } else if ((arrayFirstDim != 0) && (arraySecondDim != 0) && (elements.size() % (arrayFirstDim * arraySecondDim) == 0)) { + writer.write(name + " :\n"); + for (int i = 0; i < elements.size(); i += arrayFirstDim * arraySecondDim) { + for (int j = 0; j < arrayFirstDim; j++) { + writer.write(" "); + for (int k = 0; k < arraySecondDim; k++) { + String val = elements.get(i + j * arraySecondDim + k); + for (int l = val.length(); l < maxLength; l++) { + writer.write(" "); + } + writer.write(val + " "); + } + writer.write("\n"); + } + writer.write("\n"); + } + writer.write("\n"); } } diff --git a/src/inport/Testing.java b/src/inport/Testing.java index a2a2b4f16be0e872c873e038c415572e5a7668c4..f8a72ab87d6879592004af2ec475b9f825183688 100644 --- a/src/inport/Testing.java +++ b/src/inport/Testing.java @@ -52,6 +52,15 @@ public class Testing { timeLimitS); } + public static String solveTaskWithGreedyConstraints(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2_greedy.mzn", + ConversionUtil::portToMiniZincGreedy, + ConversionUtil::resolveMiniZincResults, + timeLimitS); + } + public static String solveTask_2_0(TaskCase task, int timeLimitS) { return solveTask( task, diff --git a/tests/requiring_optimization/Case_SPB.tipp b/tests/requiring_optimization/Case_SPB.tipp index aa4456d0bf6fe9705b85a88acca356a75948969c..f708d31b5c10d389a7a1bcec2fcae7f0fcbb6820 100644 --- a/tests/requiring_optimization/Case_SPB.tipp +++ b/tests/requiring_optimization/Case_SPB.tipp @@ -292,7 +292,7 @@ Final Storage State 10002; 38; 4500 Task Properties -100.0; 0 +20.0; 0 Solution diff --git "a/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" "b/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" index 13dac3982343770318491436e05bb0b0ee136095..996dc24e16333c2d788863e1f369cd8fd3ee5225 100644 Binary files "a/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" and "b/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" differ