diff --git a/src/constraints/conversion_2.mzn b/src/constraints/conversion_2.mzn index 8d323493d1f394ec2c0460bbf5d4ec0c319fdc80..d6be3a5be3291f6226e50158bd3ce68c73544374 100644 --- a/src/constraints/conversion_2.mzn +++ b/src/constraints/conversion_2.mzn @@ -27,7 +27,6 @@ array [1..n_moving_obj, 0..moving_op_of_obj_max_size] of 1..n_operations : movin op_status[op, t] -> ((current_moving_operation[obj, t] != 0) /\ (moving_op_of_obj[obj, current_moving_operation[obj, t]] = op)) ); - % Если операция, затрагивающая данный объект в качестве ресурса % TODO упростить в conversion_1 % Связь current_moving_operation c op_status. @@ -102,7 +101,7 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац (current_moving_operation[obj, t - 1] != 0) /\ ((obj != main_obj_of_operation[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) /\ - (is_mooring_op[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) + ( is_mooring_op[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) ) ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) ); @@ -163,6 +162,7 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац ) ); +/* TODO разобраться и удалить лишнее. % { Если объект участвует как ресурс в операции перемещения (не швартовки), то это согласованно с current_moving_operation, % иначе (как ресурс в погрузке или швартове) - он должен стоять на месте. } constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( @@ -181,6 +181,18 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац ) -> current_moving_operation[obj, t] = 0) ) ); +*/ + + % Если объект участвует как ресурс в операции перемещения, то это согласованно с current_moving_operation. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) -> ( + (is_moving_operation[participation_as_resource[obj, t]]) -> ( + (current_moving_operation[obj, t] != 0) + /\ + (participation_as_resource[obj, t] = moving_op_of_obj[obj, current_moving_operation[obj, t]]) + ) + ) + ); % { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( @@ -262,23 +274,17 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац ); % Конфликтующие операции. - int : n_conflicting_op; + array [1..n_operations] of set of 1..n_operations : conflicting_operations; - array [1..n_conflicting_op] of 1..n_operations : confl_op_1; - array [1..n_conflicting_op] of 1..n_operations : confl_op_2; - - constraint forall (t in 0..(n_intervals + 1), i in 1..n_conflicting_op) ( - op_status[confl_op_1[i], t] -> not op_status[confl_op_2[i], t] - ); + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1), conf_op in conflicting_operations[op]) ( + op_status[op, t] -> not op_status[conf_op, t] + ); % Окна непогоды. - int : n_bad_weather_windows; - array [1..n_bad_weather_windows] of 1..n_operations : bw_op; - array [1..n_bad_weather_windows] of 0..(n_intervals + 1) : bw_start; - array [1..n_bad_weather_windows] of 0..(n_intervals + 1) : bw_fin; % Включительно. + array [1..n_operations, 1..n_intervals] of bool : bad_weather; - constraint forall (i in 1..n_bad_weather_windows, t in bw_start[i]..bw_fin[i]) ( - op_status[bw_op[i], t] == false + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + bad_weather[op, t] -> (op_status[op, t] = false) ); % Грузообработка. @@ -335,6 +341,76 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац ) ); +% Оптимизация - сдвиг в начало. + % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). + array [1..n_operations, 1..n_intervals] of var bool : is_op_possible; + + % Счётчик ресурсов, которые могут быть потенциально задействованы в операции. + 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 [1..n_operations, 1..n_intervals] of var bool : is_enough_free_resources; + + 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] + ) + ); + + % Участвует ли данный объект в операции грузообработки в качестве главного. + array [1..n_moving_obj, 1..n_intervals] of var bool : is_obj_involved_in_cargo_op; + + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + is_obj_involved_in_cargo_op[obj, t] = ( + ((participation_as_resource[obj, t] != 0) /\ (current_moving_operation[obj, t] = 1)) % В качестве ресурса. + \/ + exists (op in 1..n_operations where main_obj_of_operation[op] = obj) ( % В качестве главного объекта. + op_status[op, t] + ) + ) + ); + + array [1..n_operations, 1..n_intervals] of var bool : debug_1; + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + debug_1[op, t] = + (m_obj_loc[main_obj_of_operation[op], t] = main_obj_start_loc[op]) % Главный объект на месте. + ); + + % Определение 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[op, t] = false)) + /\ % Не выполняется ни одной конфликтующей операции. + (is_moving_operation[op] -> not is_obj_involved_in_cargo_op[main_obj_of_operation[op], t]) + /\ % Если это операция перемещения, то главный объект + % не участвует в операциях погрузки. + ((is_mooring_op[op] /\ (operations_destination[op] mod 2 = 0)) -> ( + obj_in_loc_counter[operations_destination[op], t] = 0) + ) % Если это операция пришвартовки, то в этот интервал + % причал должен быть свободным. + ) + ); + + % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. + constraint forall (op in 1..n_operations, t in 2..n_intervals) ( + op_start[op, t] -> not is_op_possible[op, t - 1] + ); + % Критерий оптимизации array [0..(n_intervals + 1)] of var bool : is_not_terminated; constraint (is_not_terminated[0] == false /\ is_not_terminated[n_intervals + 1] == false); @@ -366,4 +442,11 @@ output [show(sum(is_not_terminated)), "\n", "real_current_moving_operation = ", show(current_moving_operation), "\n\n", "moving_op_of_obj {", show(moving_op_of_obj_max_size + 1), "}= ", show(moving_op_of_obj), "\n\n", +/* + "is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n", + "debug_1 {", show(n_intervals), "} = ", show(debug_1), "\n\n", + "is_enough_free_resources {", show(n_intervals), "} = ", show(is_enough_free_resources), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "possible_resources_counter {", show(n_intervals), "} = ", show(possible_resources_counter), "\n\n", +*/ ""]; diff --git a/src/inport/ConversionUtil.java b/src/inport/ConversionUtil.java index 9caf1d6eaf86fd1deb2d56110e34c162c6396307..bcb9a930d080a047c9232a7c621e9b95dde2843b 100644 --- a/src/inport/ConversionUtil.java +++ b/src/inport/ConversionUtil.java @@ -510,6 +510,28 @@ public class ConversionUtil { writer.write("\n"); } + /* Окна погоды. Новый формат. */ + private void weatherWindowsNewFormat() throws IOException { + ArrayList> badWeather = new ArrayList<>(); + + 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, true); + } + } + ); + badWeather.add(curLine); + } + locWrite2DArray(writer, "bad_weather", badWeather, Objects::toString); + } + /* Непрерывность перемещения и швартовки. */ private void operationsContinuity() throws IOException { ArrayList operationsDuration = integerArray(operationTemplates.size(), 0); @@ -994,18 +1016,21 @@ public class ConversionUtil { } private void conflictingOperationsOnStorageAndOnTypeOnMainObject() throws IOException { - ArrayList> conflictingPairs = new ArrayList<>(); + ArrayList> conflictingOperationsG = new ArrayList<>(); for (int i = 0; i < operationTemplates.size(); i++) { - for (int j = i + 1; j < operationTemplates.size(); j++) { + 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.getLoader() == op2.getLoader()) && - (op1.getStorage() == op2.getStorage()) && + if ((op1.getStorage() == op2.getStorage()) && (op1.getStartLocation() == op2.getStartLocation())) { - conflictingPairs.add(new Pair<>(i + 1, j + 1)); + conflictingOperationsG.get(i).add(j + 1); } } { // Взаимоисключение операций перемещения и грузообработки с общим деятелем. @@ -1020,7 +1045,7 @@ public class ConversionUtil { if (((t1 instanceof MovingTemplate) || (t1 instanceof MooringTemplate)) && (t2 instanceof LoadingTemplate)) { if (getExecutor(t1) == getExecutor(t2)) { - conflictingPairs.add(new Pair<>(i + 1, j + 1)); + conflictingOperationsG.get(i).add(j + 1); } } } @@ -1032,16 +1057,13 @@ public class ConversionUtil { MooringTemplate op2 = (MooringTemplate) operationTemplates.get(j); if (op1.getStartLocation() == op2.getStartLocation()) { - conflictingPairs.add(new Pair<>(i + 1, j + 1)); + conflictingOperationsG.get(i).add(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"); + writeArray(writer, "conflicting_operations", conflictingOperationsG, ConversionUtil::setToString); } private void typifiedResourcesDefinition() throws IOException { @@ -1131,7 +1153,7 @@ public class ConversionUtil { movingObjectLocationDefinition(); initialLocations(); finalLocations(); - weatherWindows(); + weatherWindowsNewFormat(); conflictingOperationsOnStorageAndOnTypeOnMainObject(); operationsContinuity();