diff --git a/src/constraints/conversion_2_greedy_v2.mzn b/src/constraints/conversion_2_greedy_v2.mzn index e1cfd8b082c860cbff656aff17b48ff42bc369b7..97af56a3d4544b0d25c489c1af1849acf69f45a7 100644 --- a/src/constraints/conversion_2_greedy_v2.mzn +++ b/src/constraints/conversion_2_greedy_v2.mzn @@ -348,6 +348,9 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций. array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations; + array [1..n_all_storage_sections] of set of 1..n_operations : involved_operations_as_main_stor; + array [1..n_all_storage_sections] of set of 1..n_operations : involved_operations_as_sec_stor; + array [1..n_moving_obj] of set of 1..n_all_storage_sections : sections_of_moving_obj; array [1..n_moving_obj] of bool : is_sections_of_moving_obj_empty; @@ -359,10 +362,9 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац 0..n_all_storage_sections : max_number_of_connected_sections; - array [0..n_operations, 1..(n_intervals + 1)] of var int : nominal_cargo_value; - array [0..n_sections_of_real_storage_and_bunkers, 1..(n_intervals + 1)] of var int : nominal_incoming_sum; - array [0..n_operations, 1..(n_intervals + 1)] of var int : real_cargo_value; - array [0..n_sections_of_real_storage_and_bunkers, 1..(n_intervals + 1)] of var int : total_sum; + array [0..n_operations, 0..(n_intervals + 1)] of var int : nominal_cargo_value; + array [0..n_sections_of_real_storage_and_bunkers, 0..(n_intervals + 1)] of var int : nominal_incoming_sum; + array [0..n_operations, 0..(n_intervals + 1)] of var int : real_cargo_value; % Использует ли эта операция секцию как хранилище при погрузке или как бункеровщик при бункеровке. array [0..n_sections_of_real_storage_and_bunkers, 0..n_operations] of bool : is_op_used_stor_as_secondary; @@ -377,11 +379,14 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац constraint forall (section in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( (current_partial_cargo_op[section, t] != 0) -> op_status[current_partial_cargo_op[section, t], t] ); + constraint forall (t in 1..(n_intervals + 1)) (current_partial_cargo_op[0, t] = 0); % Определение nominal_incoming_sum - номинальный объём груза, который суда вливают в хранилище. - constraint forall (section in 0..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( - nominal_incoming_sum[section, t] = sum (op in involved_operations[section]) (nominal_cargo_value[op, t]) + constraint forall (section in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( + nominal_incoming_sum[section, t] = sum (op in involved_operations_as_sec_stor[section]) (nominal_cargo_value[op, t]) ); + constraint forall (t in 0..(n_intervals + 1)) (nominal_incoming_sum[0, t] = 0); + constraint forall (section in 1..n_sections_of_real_storage_and_bunkers) (nominal_incoming_sum[section, 0] = 0); % Определение real_cargo_value array [0..n_operations] of 0..n_all_storage_sections : operations_main_stor_no_in_secondary; @@ -432,8 +437,13 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ); % Крайние значения. + constraint forall (t in 0..(n_intervals + 1)) (nominal_cargo_value[0, t] = 0); constraint forall (op in 1..n_operations) (nominal_cargo_value[op, 0] = 0); - constraint forall (t in 1..(n_intervals + 1)) (nominal_cargo_value[0, t] = 0); + + % Обнулим current_partial_cargo_op для операций перемещения. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1) where is_moving_operation[op]) ( + nominal_cargo_value[op, t] = 0 + ); % Определение real_cargo_value constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1)) ( % Целая операция. @@ -497,45 +507,31 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ); % Крайние значения. - constraint forall (t in 1..(n_intervals + 1)) (real_cargo_value[0, t] = 0); + constraint forall (t in 0..(n_intervals + 1)) (real_cargo_value[0, t] = 0); + constraint forall (op in 1..n_operations) (real_cargo_value[op, 0] = 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)) ( + + 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] + 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])) + (sum (op in involved_operations_as_sec_stor[storage]) ( real_cargo_value[op, t])) + + (sum (op in involved_operations_as_main_stor[storage]) (-real_cargo_value[op, 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)) ( + constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( debug_storage_used_volume[storage, t] = ( - debug_storage_used_volume[storage, t - 1] + + 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])) + (sum (op in involved_operations_as_sec_stor[storage]) ( real_cargo_value[op, t])) + + (sum (op in involved_operations_as_main_stor[storage]) (-real_cargo_value[op, 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); % Фиктивный объект. @@ -544,7 +540,7 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац 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] + @@ -555,7 +551,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; @@ -569,13 +565,90 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац constraint forall (no in 1..n_fixed_op, op = fixed_op[no]) ( forall (t in fixed_op_start[no]..fixed_op_end[no]) ( - (op_status[op, t]) /\ - forall (obj in fixed_op_resources[no]) ( - participation_as_resource[obj, t] = op - ) + (op_status[op, t]) + /\ (forall (obj in fixed_op_resources[no]) (participation_as_resource[obj, t] = op)) + /\ (real_cargo_value[op, t] = -fixed_op_intensity[no]) ) ); +% Оптимизация - сдвиг в начало. + % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). + array [0..n_operations, 1..n_intervals] of var bool : is_op_possible; + + constraint forall (t in 1..n_intervals) (is_op_possible[0, t] = false); % Фиктивный объект. + + % Счётчик ресурсов, которые могут быть потенциально задействованы в операции. + array [1..n_resources_counters , 1..n_intervals] of var int : possible_resources_counter; + + % Определение possible_resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + possible_resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + (participation_as_resource[obj, t] = 0) /\ + (current_moving_operation[obj, t] = 0) /\ + (m_obj_loc[obj, t] = operations_resources_start_loc[counter]) + ) + ); + + % Достаточно ли свободных ресурсов для операции. + array [0..n_operations, 1..n_intervals] of var bool : is_enough_free_resources; + + constraint forall (t in 1..n_intervals) (is_enough_free_resources[0, t] = false); % Фиктивный объект. + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_enough_free_resources[op, t] = forall (counter in counters_of_operation[op]) ( + possible_resources_counter[counter, t] >= required_counter_values[counter] + ) + ); + + % Определение is_op_possible. + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_op_possible[op, t] = ( + (bad_weather[op, t] = false) /\ % Погода не мешает. + (m_obj_loc[main_obj_of_operation[op], t] = main_obj_start_loc[op]) + /\ % Главный объект на месте. + (current_moving_operation[main_obj_of_operation[op], t] = 0) + /\ % Главный объект не участвует в операции перемещеня. + (is_enough_free_resources[op, t] = true) /\ % Достаточно свободных ресурсов на нужном месте. + (forall (conf_op in conflicting_operations[op]) (op_status[conf_op, t] = false)) + /\ % Не выполняется ни одной конфликтующей операции. + (is_moving_operation[op] -> not is_involved_in_cargo_op[main_obj_of_operation[op], t]) + /\ % Если это операция перемещения, то главный объект + % не участвует в операциях погрузки. + ((is_mooring_op[op] /\ (operations_destination[op] mod 2 = 0)) -> ( + current_moored_obj[operations_destination[op], t] = 0) + ) /\ % Если это операция пришвартовки, то в этот интервал + % причал должен быть свободным. + ((not is_moving_operation[op]) -> ( + let {1..n_all_storage_sections : m_stor = operations_main_stor[op]; + 1..n_all_storage_sections : s_stor = operations_secondary_stor[op]; + int : delta = loading_op_direction[op]; + } in + (storage_used_volume[m_stor, t] + delta >= storage_greedy_lower_limit[m_stor]) /\ + (storage_used_volume[m_stor, t] + delta <= storage_greedy_upper_limit[m_stor]) /\ + (storage_used_volume[s_stor, t] - delta >= storage_greedy_lower_limit[s_stor]) /\ + (storage_used_volume[s_stor, t] - delta <= storage_greedy_upper_limit[s_stor]) + )) /\ % Если это операция грузообработки, то она не выведет + % объём берегового хранилища и хранилища судна за + % границы дозволенного. + (((not is_moving_operation[op]) /\ (main_obj_start_loc[op] mod 2 = 1)) -> + ((current_moored_obj[twin_location[main_obj_start_loc[op]], t] = 0) \/ + (current_moored_obj[twin_location[main_obj_start_loc[op]], t] = main_obj_of_operation[op])) + ) /\ % Если это операция грузообработки без пришвартовки, + % то причал должен быть свободен в этот интервал, либо + % главный объект должен быть уже условно пришвартован. + (((bunker_of_cargo_op[op] != 0) /\ (op_status[op, t])) -> + ((m_obj_loc[bunker_of_cargo_op[op], t] = bunker_start_loc[op]) /\ + (current_moving_operation[bunker_of_cargo_op[op], t] = 0)) + ) % Бункеровщик (если есть) находится в нужной локации + % и не участвует в операциях перемещения. + ) + ); + + % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. + 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_all_storage_sections, 1..n_locations] of int : min_positive_cargo_val; % Объём максимальной положительной операции, которая может быть произведена с этой секцией в этом хранилище. Если в локации таковой нет, то это значение объёма хранилища + 1. array [1..n_all_storage_sections, 1..n_locations] of int : max_negative_cargo_val; @@ -615,15 +688,14 @@ 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", - "real_cargo_value {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(real_cargo_value), "\n\n", + "nominal_cargo_value {", show(n_intervals + 2), "} = ", show(nominal_cargo_value), "\n\n", + "nominal_incoming_sum {", show(n_intervals + 2), "} = ", show(nominal_incoming_sum), "\n\n", + "real_cargo_value {", show(n_intervals + 2), "} = ", show(real_cargo_value), "\n\n", + "current_partial_cargo_op {", show(n_intervals + 1), "} = ", show(current_partial_cargo_op), "\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", - - "total_sum {", show(n_intervals + 1), "} = ", show(total_sum), "\n\n", + "debug_storage_used_volume = ", show(debug_storage_used_volume), "\n\n", /* diff --git a/src/inport/ConversionUtils/MZnResultsResolver.java b/src/inport/ConversionUtils/MZnResultsResolver.java index bd37c597ba68233c4cfc4303f35bd7754fa60b36..9474c60e4aa75e80cfb43426d0b0dd8daf77ad0e 100644 --- a/src/inport/ConversionUtils/MZnResultsResolver.java +++ b/src/inport/ConversionUtils/MZnResultsResolver.java @@ -115,8 +115,10 @@ public class MZnResultsResolver { } ArrayList> cargoOpIntensity; - if (arrays.containsKey("cargo_op_intensity")) { + if (arrays.containsKey("cargo_op_intensity")) { // Явные нецелые операции. cargoOpIntensity = arrays.get("cargo_op_intensity"); + } else if (arrays.containsKey("real_cargo_value")) { // Жадный алгоритм. + cargoOpIntensity = arrays.get("real_cargo_value"); } else { cargoOpIntensity = new ArrayList<>(); for (int opNo = 0; opNo < opStatus.size(); opNo++) { @@ -205,7 +207,7 @@ public class MZnResultsResolver { } if (! cargoOpIntensity.get(opNo).get(t - 1).equals("0")) { - op.setIntensity(Optional.of(Integer.valueOf(cargoOpIntensity.get(opNo).get(t - 1)))); + op.setIntensity(Optional.of(Math.abs(Integer.valueOf(cargoOpIntensity.get(opNo).get(t - 1))))); } op.setFixation(true); diff --git a/src/inport/ConversionUtils/Task.java b/src/inport/ConversionUtils/Task.java index 5e9cea1a58d73ff57cff8527ed540eb285595061..e25d247ac1935ad743884b93edd4e845b311e760 100644 --- a/src/inport/ConversionUtils/Task.java +++ b/src/inport/ConversionUtils/Task.java @@ -10,7 +10,6 @@ import java.io.UncheckedIOException; import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; import static inport.ConversionUtils.MZnFormat.*; import static inport.ConversionUtils.Utils.*; @@ -1347,7 +1346,7 @@ public class Task { } } - void dataForGreediness() throws IOException { + private void dataForGreediness() throws IOException { ArrayList> connectedSections = arrayOfIntegerArrays(sectionNById.size()); ArrayList> connectedSectionsSet = arrayOfIntegerSet(sectionNById.size()); @@ -1466,6 +1465,50 @@ public class Task { } } + private void addIsOpUsedStorAsSecondary() throws IOException { + ArrayList> is_op_used_stor_as_secondary = new ArrayList<>(); + for (int i = 0; i <= nSectionsOfRealStorageAndBunkers; i++) { + is_op_used_stor_as_secondary.add(new ArrayList<>()); + for (int j = 0; j <= operationTemplates.size(); j++) { + is_op_used_stor_as_secondary.get(i).add(false); + } + } + for (int j = 0; j < operationTemplates.size(); j++) { + if (operationTemplates.get(j) instanceof LoadingTemplate) { + LoadingTemplate op = (LoadingTemplate) operationTemplates.get(j); + int section; + if (op.getBunker().isPresent()) { + section = sectionIdToN(op.getBunker().get(), op.getCargo()); + } else { + section = sectionIdToN(op.getStorage(), op.getCargo()); + } + is_op_used_stor_as_secondary.get(section + 1).set(j + 1, true); + } + } + locWrite2DArray(writer, "is_op_used_stor_as_secondary", is_op_used_stor_as_secondary, Objects::toString, true); + } + + private void addInvolvedOperations() throws IOException { + ArrayList> involved_operations_as_main_stor = arrayOfIntegerSet(sectionNById.size()); + ArrayList> involved_operations_as_sec_stor = arrayOfIntegerSet(sectionNById.size()); + for (int i = 0; i < operationTemplates.size(); i++) { + if (operationTemplates.get(i) instanceof LoadingTemplate) { + LoadingTemplate op = (LoadingTemplate) operationTemplates.get(i); + int section_1 = sectionIdToN(op.getLoader(), op.getCargo()); + int section_2; + if (op.getBunker().isPresent()) { + section_2 = sectionIdToN(op.getBunker().get(), op.getCargo()); + } else { + section_2 = sectionIdToN(op.getStorage(), op.getCargo()); + } + involved_operations_as_main_stor.get(section_1).add(i + 1); + involved_operations_as_sec_stor .get(section_2).add(i + 1); + } + } + writeArray(writer, "involved_operations_as_main_stor", involved_operations_as_main_stor, MZnFormat::setToString); + writeArray(writer, "involved_operations_as_sec_stor", involved_operations_as_sec_stor, MZnFormat::setToString); + } + void portToMiniZinc_2_greedy() { if (!task.isTypified()) { throw new ParserException("Attempt to convert untyped task as typified."); @@ -1478,6 +1521,19 @@ public class Task { } } + void portToMiniZinc_2_greedy_v2() { + if (!task.isTypified()) { + throw new ParserException("Attempt to convert untyped task as typified."); + } + try { + portToMiniZinc_2_greedy(); + addIsOpUsedStorAsSecondary(); + addInvolvedOperations(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + static public void portToMiniZinc_0(TaskCase task, String fileName) { startConversion(task, fileName, Task::portToMiniZinc_0); } @@ -1490,6 +1546,9 @@ public class Task { static public void portToMiniZincGreedy(TaskCase task, String fileName) { startConversion(task, fileName, Task::portToMiniZinc_2_greedy); } + static public void portToMiniZincGreedyV2(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_2_greedy_v2); + } static private void startConversion(TaskCase task, String fileName, Consumer conversion) { try { diff --git a/src/inport/Testing.java b/src/inport/Testing.java index 18c45b40d7c0adb1eac2fd56f036a64b7513651c..07b50ffd1c59b0b0153445f5cc5bda4161d1bb57 100644 --- a/src/inport/Testing.java +++ b/src/inport/Testing.java @@ -68,7 +68,7 @@ public class Testing { return solveTask( task, "conversion_2_greedy_v2.mzn", - Task::portToMiniZincGreedy, + Task::portToMiniZincGreedyV2, MZnResultsResolver::resolveMiniZincResults, timeLimitS); }