From e43ed078f08fa0f1ccd07133c25779001f6edc01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=81=D0=B5=D0=BB=D1=91=D0=B2=20=D0=92=D0=BB?= =?UTF-8?q?=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 12 Nov 2018 23:52:09 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B2=D0=B8?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=20=D0=BF=D0=BE=D1=80?= =?UTF-8?q?=D1=82=D1=83=20=D0=B1=D0=B5=D0=B7=20=D1=88=D0=B2=D0=B0=D1=80?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/inport/ConversionUtil.java | 91 ++++++++++++++++++++++++++++++-- test/conversion_0.mzn | 95 ++++++++++++++++++++++++++-------- 2 files changed, 160 insertions(+), 26 deletions(-) diff --git a/src/inport/ConversionUtil.java b/src/inport/ConversionUtil.java index bee75a7..1b11bd0 100644 --- a/src/inport/ConversionUtil.java +++ b/src/inport/ConversionUtil.java @@ -94,6 +94,75 @@ public class ConversionUtil { return res; } + static private MovingObject getExecutor(OperationTemplate t) { + if (t instanceof LoadingTemplate) { + return ((LoadingTemplate) t).getLoader(); + } + if (t instanceof MooringTemplate) { + return ((MooringTemplate) t).getMoorer(); + } + if (t instanceof MovingTemplate) { + return ((MovingTemplate) t).getMover(); + } + return null; + } + + static private List getResources(OperationTemplate t) { + List res = new ArrayList<>(); + if (t instanceof LoadingTemplate) { + res.addAll(((LoadingTemplate) t).getResources()); + } + if (t instanceof MooringTemplate) { + res.addAll(((MooringTemplate) t).getResources()); + } + if (t instanceof MovingTemplate) { + res.addAll(((MovingTemplate) t).getResources()); + } + return res; + } + + static private boolean isCompatible(OperationTemplate t1, OperationTemplate t2) { + MovingObject exec1 = getExecutor(t1); + Berth place1 = t1.getStartLocation(); + List resources1 = getResources(t1); + + MovingObject exec2 = getExecutor(t2); + Berth place2 = t2.getStartLocation(); + List resources2 = getResources(t2); + // Пересекаемость ресурсов + for (Object res2 : resources2) + if (resources1.contains(res2)) + return false; + // Выполнитель = ресурс + if (resources1.contains(exec2)) + return false; + // Ресурс = выполнитель + if (resources2.contains(exec1)) + return false; + + // Выполнитель = выполнитель + if (exec1.equals(exec2)) + { + // Это не погрузка + if (!(t1 instanceof LoadingTemplate) || (!(t2 instanceof LoadingTemplate))) + return false; + // Разные причалы + if (!place1.equals(place2)) + return false; + Storage s1 = ((LoadingTemplate)t1).getStorage(); + Storage s2 = ((LoadingTemplate)t2).getStorage(); + // В одно хранилище + if (s1.equals(s2)) + return false; + } + else + // На одном причале и это не перемещения + if (place1.equals(place2) && (!(t1 instanceof MovingTemplate)) && (!(t2 instanceof MovingTemplate))) + return false; + + return true; + } + static public void portToMiniZinc(TaskCase task, String fileName) throws IOException { try(FileWriter writer = new FileWriter(fileName, false)) { int n_intervals = (int)task.getPlanningInterval(); @@ -159,9 +228,9 @@ public class ConversionUtil { { // Начальные положения объектов. ArrayList initialStates = integerArray(movingObjects.size(), 0); for (MovingObjectState state : task.getVesselInitialState()) { - initialStates.set(mObjToN.apply(state.getVessel()), locationNumberById.get(new Pair<>(state.getLocation().getId(), false)) + 1); + initialStates.set(mObjToN.apply(state.getVessel()), locationNumberById.get(new Pair<>(state.getLocation().getId(), false))); } - writeArray(writer, "initial_m_obj_loc", initialStates); + writeArray(writer, "initial_m_obj_loc", initialStates, (Integer p) -> p + 1); } // TODO окна погоды. @@ -188,7 +257,7 @@ public class ConversionUtil { for (MovingObjectState state : task.getVesselEndState()) { finalStates.set(mObjToN.apply(state.getVessel()), locationNumberById.get(new Pair<>(state.getLocation().getId(), false))); } - writeArray(writer, "final_m_obj_loc", finalStates); + writeArray(writer, "final_m_obj_loc", finalStates, (Integer p) -> p + 1); } { // Наличие всех ресурсов на месте. ArrayList> operationsResources = new ArrayList<>(); @@ -204,14 +273,26 @@ public class ConversionUtil { s.add(mObjToN.apply(obj) + 1); } operationsResources.set(i, s); - operationsStartLoc.set(i, locationNumberById.get(new Pair<>(op.getStartLocation().getId(), false))); + operationsStartLoc.set(i, locationNumberById.get(new Pair<>(op.getStartLocation().getId(), false)) + 1); } // TODO швартовка, погрузка. } writeArray(writer, "operations_start_loc", operationsStartLoc); writeArray(writer, "operations_resources", operationsResources, ConversionUtil::setToString); } - + { // Конфликтующие операции. + ArrayList> conflictingPairs = new ArrayList<>(); + for (int i = 0; i < operationTemplates.size(); i++) { + for (int j = i + 1; j < operationTemplates.size(); j++) { + if (!isCompatible(operationTemplates.get(i), operationTemplates.get(j))) { + conflictingPairs.add(new Pair<>(i + 1, j + 1)); + } + } + } + writer.write("n_conflicting_op = " + conflictingPairs.size() + ";\n"); + writeArray(writer, "confl_op_1", conflictingPairs, Pair::getKey); + writeArray(writer, "confl_op_2", conflictingPairs, Pair::getValue); + } } } } diff --git a/test/conversion_0.mzn b/test/conversion_0.mzn index cc2a8d5..cd523c8 100644 --- a/test/conversion_0.mzn +++ b/test/conversion_0.mzn @@ -16,11 +16,11 @@ array [1..n_moving_obj, 1..n_locations] of set of 1..n_operations : arrival_op; array [1..n_moving_obj, 1..n_locations] of set of 1..n_operations : departure_op; % Определение m_obj_loc. -constraint forall (i in 1..n_moving_obj, j in 1..(n_intervals + 1)) - ((m_obj_loc[i, j] != 0) -> ( - (m_obj_loc[i, j] == m_obj_loc[i, j - 1] /\ (forall (k in departure_op[i, m_obj_loc[i, j]]) (op_status[k, j - 1] == 0))) +constraint forall (obj in 1..n_moving_obj, j in 1..(n_intervals + 1)) + ((m_obj_loc[obj, j] != 0) -> ( + (m_obj_loc[obj, j] == m_obj_loc[obj, j - 1] /\ (forall (k in departure_op[obj, m_obj_loc[obj, j]]) (op_status[k, j - 1] == 0))) \/ - (not (forall (k in arrival_op[i, m_obj_loc[i, j]]) (op_fin[i, j - 1] == 0))) + (not (forall (k in arrival_op[obj, m_obj_loc[obj, j]]) (op_fin[k, j - 1] == 0))) )); % Начальное состояние. @@ -37,34 +37,56 @@ constraint forall (i in 1..n_moving_obj) ( constraint forall (i in 1..n_operations, j in {0, n_intervals + 1}) (op_status[i, j] == 0); % Краевые значения. % Определение op_start и op_fin. -constraint forall (i in 1..n_operations) (op_start[i, 0] == 0 /\ op_fin[i, n_intervals + 1] == 0); -constraint forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] = op_status[i, j] /\ not op_status[i, j - 1]); -constraint forall (i in 1..n_operations, j in 1..n_intervals ) (op_fin [i, j] = op_status[i, j] /\ not op_status[i, j + 1]); +constraint forall (op in 1..n_operations, j in {0, n_intervals + 1}) + (op_start[op, j] == 0 /\ op_fin[op, j] == 0); +constraint forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] = (op_status[i, j] /\ not op_status[i, j - 1])); +constraint forall (i in 1..n_operations, j in 1..n_intervals ) (op_fin [i, j] = (op_status[i, j] /\ not op_status[i, j + 1])); % Непрерывность перемещения. array [1..n_operations] of var int : operations_duration; array [1..n_operations] of var bool : is_moving_operation; +% TODO +%constraint forall (i in 1..n_operations) ( +% if (is_moving_operation[i]) then ( +% forall (j in 1..n_intervals) ( +% let {var int : len = operations_duration[i]} in +% if (j + len > n_intervals + 1) then +% op_start[i, j] == 0 +% else ( +% (op_start[i, j] == 1) -> ( +% (forall (k in 1..(len - 1)) +% (op_status[i, j + k] == 1) +% ) /\ +% (op_status[i, j + len] == 0) +% ) +% ) +% endif +% ) +% ) else true +% endif +%); + + constraint forall (i in 1..n_operations) ( if (is_moving_operation[i]) then ( - forall (j in 1..n_intervals) ( - if (j + operations_duration[i] > n_intervals + 1) then - op_start[i, j] = 0 - else ( - (op_start[i, j] == 1) -> ( - (forall (k in 1..(operations_duration[i] - 1)) - (op_status[i, j + k] == 1) - ) /\ - (op_status[i, j + operations_duration[i]] == 0) - ) + let {var int : len = operations_duration[i]} in + (forall (j in 1..(n_intervals - len + 1)) ( + (op_start[i, j] == 1) -> ( + (forall (k in 1..(len - 1)) + (op_status[i, j + k] == 1) + ) /\ + (op_status[i, j + len] == 0) ) - endif + )) /\ + (forall (j in (n_intervals - len + 2)..(n_intervals + 1)) + (op_start[i, j] == 0) ) ) else true endif ); -% Наличие всех ресурсов на месте. +% Наличие всех ресурсов на месте во время начала операции перемещения. array [1..n_operations] of set of 1..n_moving_obj : operations_resources; array [1..n_operations] of 0..n_locations : operations_start_loc; @@ -74,6 +96,37 @@ constraint forall (op in 1..n_operations, j in 1..n_intervals) ( ) ); -solve satisfy; +% Конфликтующие операции. +int : n_conflicting_op; + +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]) + /\ + (op_status[confl_op_2[i], t] -> not op_status[confl_op_1[i], t]) +); + +% Критерий оптимизации +array [0..(n_intervals + 1)] of var bool : is_not_terminated; +constraint (is_not_terminated[0] == 0 /\ is_not_terminated[n_intervals + 1] == 0); +constraint forall (t in 1..n_intervals) ( + is_not_terminated[t] == ( + (not (forall (op in 1..n_operations) (op_status[op, t] == 0))) + \/ + is_not_terminated[t + 1] + ) +); + +solve minimize sum(is_not_terminated); -output ["op_status = ", show(op_status), "\n"]; +output ["res = ", show(sum(is_not_terminated)), "\n\n", + "op_status = ", show(op_status), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "op_fin = ", show(op_fin), "\n\n", + "op_start = ", show(op_start), "\n\n", + "arrival_op = ", show(arrival_op), "\n\n", + "departure_op = ", show(departure_op), "\n\n", + "is_not_terminated = ", show(is_not_terminated), "\n\n" + ]; -- GitLab