From aee5e99352179dfcf4eb2c244cd4564303aeed3f 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: Thu, 4 Jul 2019 16:36:11 +0300 Subject: [PATCH] Refactoring. --- src/constraints/conversion_2_greedy.mzn | 8 + src/constraints/conversion_2_greedy_v2.mzn | 210 +- src/inport/ConversionUtil.java | 2159 ----------------- src/inport/ConversionUtils/MZnFormat.java | 274 +++ .../ConversionUtils/MZnResultsResolver.java | 241 ++ .../ParserException.java | 2 +- src/inport/ConversionUtils/Task.java | 1510 ++++++++++++ src/inport/ConversionUtils/Utils.java | 112 + src/inport/Main.java | 18 +- src/inport/Operation.java | 6 +- src/inport/Testing.java | 32 +- tests/requiring_optimization/Case_SPB.tipp | 10 +- 12 files changed, 2283 insertions(+), 2299 deletions(-) delete mode 100644 src/inport/ConversionUtil.java create mode 100644 src/inport/ConversionUtils/MZnFormat.java create mode 100644 src/inport/ConversionUtils/MZnResultsResolver.java rename src/inport/{ => ConversionUtils}/ParserException.java (79%) create mode 100644 src/inport/ConversionUtils/Task.java create mode 100644 src/inport/ConversionUtils/Utils.java diff --git a/src/constraints/conversion_2_greedy.mzn b/src/constraints/conversion_2_greedy.mzn index bbb1006..13da1ab 100644 --- a/src/constraints/conversion_2_greedy.mzn +++ b/src/constraints/conversion_2_greedy.mzn @@ -218,6 +218,9 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац % Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. array [0..n_moving_obj] of set of 0..n_operations : related_cargo_op; + % Операции отшвартовки, которые используют объект в качестве главного. + array [0..n_moving_obj] of set of 1..n_operations : related_unmooring_op; + % Определение 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] = ( @@ -698,6 +701,11 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ); */ +% Для оптимизаций. + 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; + + array [1..n_moving_obj, 1..n_locations] of bool : can_obj_leave_loc_only_alone; array [1..n_moving_obj, 1..n_locations, 1..n_intervals] of bool : is_fixed_op_planned_in_future; % Критерий оптимизации diff --git a/src/constraints/conversion_2_greedy_v2.mzn b/src/constraints/conversion_2_greedy_v2.mzn index 67c6e1d..e1cfd8b 100644 --- a/src/constraints/conversion_2_greedy_v2.mzn +++ b/src/constraints/conversion_2_greedy_v2.mzn @@ -218,6 +218,9 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац % Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. array [0..n_moving_obj] of set of 0..n_operations : related_cargo_op; + % Операции отшвартовки, которые используют объект в качестве главного. + array [0..n_moving_obj] of set of 1..n_operations : related_unmooring_op; + % Определение 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] = ( @@ -356,11 +359,30 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац 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; + 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_sections_of_real_storage_and_bunkers, 0..n_operations] of bool : is_op_used_stor_as_secondary; + + array [0..n_sections_of_real_storage_and_bunkers, 1..(n_intervals + 1)] of var 0..n_operations : current_partial_cargo_op; + % Определение current_partial_cargo_op + % current_partial_cargo_op только из множества допустимых операций. + 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) -> (is_op_used_stor_as_secondary[section, current_partial_cargo_op[section, t]]) + ); + % current_partial_cargo_op активна. + 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] + ); + + % Определение 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]) + ); + % Определение 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; @@ -377,7 +399,7 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац where pos != 0) ( let {var int : total_vol = storage_used_volume[section_1, t - 1] + loading_op_delta_of_main_obj[op];} in (op_status[op, t] /\ total_vol > storage_greedy_upper_limit[section_1]) -> ( - nominal_cargo_value[section_2, pos, t] = -(loading_op_delta_of_main_obj[op] - (total_vol - storage_greedy_upper_limit[section_1])) + nominal_cargo_value[op, t] = -(loading_op_delta_of_main_obj[op] - (total_vol - storage_greedy_upper_limit[section_1])) ) ); constraint forall (op in 1..n_operations, @@ -388,7 +410,7 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац where pos != 0) ( let {var int : total_vol = storage_used_volume[section_1, t - 1] + loading_op_delta_of_main_obj[op];} in (op_status[op, t] /\ total_vol < storage_greedy_lower_limit[section_1]) -> ( - nominal_cargo_value[section_2, pos, t] = -(loading_op_delta_of_main_obj[op] - (total_vol - storage_greedy_lower_limit[section_1])) + nominal_cargo_value[op, t] = -(loading_op_delta_of_main_obj[op] - (total_vol - storage_greedy_lower_limit[section_1])) ) ); constraint forall (op in 1..n_operations, @@ -400,134 +422,87 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац let {var int : total_vol = storage_used_volume[section_1, t - 1] + loading_op_delta_of_main_obj[op];} in (op_status[op, t] /\ (total_vol >= storage_greedy_lower_limit[section_1]) /\ (total_vol <= storage_greedy_upper_limit[section_1])) -> ( - nominal_cargo_value[section_2, pos, t] = -loading_op_delta_of_main_obj[op] + nominal_cargo_value[op, t] = -loading_op_delta_of_main_obj[op] ) ); - % Если нет активной операции, влияющей на эту пару секций, то 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) + % Если опреация не активна, то nominal_cargo_value = 0. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1)) ( + (not op_status[op, t]) -> (nominal_cargo_value[op, 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 - ); + 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); - % Определение cargo_overflow_remains. - % array [0..n_sections_of_real_storage_and_bunkers, 1..(n_intervals + 1)] of var int : total_sum; - constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( - total_sum[section, t] = sum (i in 1..number_of_connected_sections[section]) (nominal_cargo_value[section, i, t]) + % Определение real_cargo_value + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1)) ( % Целая операция. + (current_partial_cargo_op[operations_secondary_stor[op], t] != op) -> + (real_cargo_value[op, t] = nominal_cargo_value[op, t]) ); - constraint forall (t in 1..(n_intervals + 1)) (total_sum[0, t] = 0); - - % Переполнение. - constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( - (total_sum[section, t] + storage_used_volume[section, t - 1] > storage_greedy_upper_limit[section]) - -> - (cargo_overflow_remains[section, number_of_connected_sections[section] + 1, t] = - total_sum[section, t] + storage_used_volume[section, t - 1] - storage_greedy_upper_limit[section] + % Нецелая операция. + % Переполнение за нижнюю границу. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1), + section = operations_secondary_stor[op]) ( % Нецелая операция. + ( (current_partial_cargo_op[section, t] == op) + /\ (nominal_cargo_value[op, t] < 0) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] < storage_greedy_lower_limit[section]) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] + - nominal_cargo_value[op, t] >= storage_greedy_lower_limit[section]) + ) -> ( + real_cargo_value[op, t] = storage_greedy_lower_limit[section] - ( + nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] - nominal_cargo_value[op, t]) ) ); - constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( - (total_sum[section, t] + storage_used_volume[section, t - 1] < storage_greedy_lower_limit[section]) - -> - (cargo_overflow_remains[section, number_of_connected_sections[section] + 1, t] = - total_sum[section, t] + storage_used_volume[section, t - 1] - storage_greedy_lower_limit[section] + % Переполнение за верхнюю границу. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1), + section = operations_secondary_stor[op]) ( % Нецелая операция. + ( (current_partial_cargo_op[section, t] == op) + /\ (nominal_cargo_value[op, t] > 0) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] > storage_greedy_upper_limit[section]) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] + - nominal_cargo_value[op, t] <= storage_greedy_upper_limit[section]) + ) -> ( + real_cargo_value[op, t] = storage_greedy_upper_limit[section] - ( + nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] - nominal_cargo_value[op, t]) ) ); - constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( - let {var int : total = total_sum[section, t] + storage_used_volume[section, t - 1]} in - ((storage_greedy_lower_limit[section] <= total) /\ (total <= storage_greedy_upper_limit[section])) - -> - (cargo_overflow_remains[section, number_of_connected_sections[section] + 1, t] = 0) + % Переполнения нет. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1), + section = operations_secondary_stor[op]) ( % Нецелая операция. + ( (current_partial_cargo_op[section, t] == op) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] <= storage_greedy_upper_limit[section]) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] >= storage_greedy_lower_limit[section]) + ) -> (real_cargo_value[op, t] = nominal_cargo_value[op, 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] = - cargo_overflow_remains[section, i + 1, t] - - nominal_cargo_value[section, i, t] - ) + % Неустранимое переполнение за нижнюю границу. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1), + section = operations_secondary_stor[op]) ( % Нецелая операция. + ( (current_partial_cargo_op[section, t] == op) + /\ (nominal_cargo_value[op, t] <= 0) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] < storage_greedy_lower_limit[section]) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] + - nominal_cargo_value[op, t] < storage_greedy_lower_limit[section]) + ) -> (real_cargo_value[op, t] = 0) ); - - % Иначе оно полностью перекрыло переполнение. - 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 (op in 1..n_operations, t in 1..(n_intervals + 1), + section = operations_secondary_stor[op]) ( % Нецелая операция. + ( (current_partial_cargo_op[section, t] == op) + /\ (nominal_cargo_value[op, t] >= 0) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] > storage_greedy_upper_limit[section]) + /\ (nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] + - nominal_cargo_value[op, t] > storage_greedy_upper_limit[section]) + ) -> (real_cargo_value[op, 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 - ); + constraint forall (t in 1..(n_intervals + 1)) (real_cargo_value[0, 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] + @@ -544,7 +519,6 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ) ); -/* 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] + @@ -570,7 +544,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] + @@ -581,7 +555,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; @@ -602,6 +576,11 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац ) ); +% Для оптимизаций. + 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; + + array [1..n_moving_obj, 1..n_locations] of bool : can_obj_leave_loc_only_alone; array [1..n_moving_obj, 1..n_locations, 1..n_intervals] of bool : is_fixed_op_planned_in_future; % Критерий оптимизации @@ -637,7 +616,6 @@ 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", diff --git a/src/inport/ConversionUtil.java b/src/inport/ConversionUtil.java deleted file mode 100644 index 7619e95..0000000 --- a/src/inport/ConversionUtil.java +++ /dev/null @@ -1,2159 +0,0 @@ -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); - } - } -} diff --git a/src/inport/ConversionUtils/MZnFormat.java b/src/inport/ConversionUtils/MZnFormat.java new file mode 100644 index 0000000..5d3398e --- /dev/null +++ b/src/inport/ConversionUtils/MZnFormat.java @@ -0,0 +1,274 @@ +package inport.ConversionUtils; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.*; +import java.util.function.Function; + +public class MZnFormat { + + static public void write2DArrayOfInt(FileWriter writer, + String name, + ArrayList> operations) throws IOException { + locWrite2DArray(writer, name, operations, Object::toString, false); + } + + static public void write2DArrayOfInt(FileWriter writer, + String name, + ArrayList> operations, + boolean isNumberedFromZero) throws IOException { + locWrite2DArray(writer, name, operations, Object::toString, isNumberedFromZero); + } + + static public 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 public void locWrite2DArray(FileWriter writer, + String name, + ArrayList> operations, + Function toMZNFormat) throws IOException { + locWrite2DArray(writer, name, operations, toMZNFormat, false); + } + + static public int boolToInt(boolean b) { + return b ? 1 : 0; + } + + static public 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 public > void write2DArrayOfSetAs3DArray(FileWriter writer, + String name, + ArrayList> operations) throws IOException { + write2DArrayOfSetAs3DArray(writer, name, operations, false); + } + + static public > 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 public 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 public void writeArrayOfSetAs2DArray(FileWriter writer, + String name, + ArrayList> operations) throws IOException { + writeArrayOfSetAs2DArray(writer, name, operations, true, false); + } + + static public 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 public 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 public void writeArray(FileWriter writer, String name, ArrayList data) throws IOException { + writeArray(writer, name, data, (T val) -> val, Optional.empty()); + } + + static public void writeArray(FileWriter writer, + String name, + ArrayList data, + Function f) throws IOException { + writeArray(writer, name, data, f, Optional.empty()); + } + + static public void writeArray(FileWriter writer, + String name, + ArrayList data, + Optional dummyZeroElement) throws IOException { + writeArray(writer, name, data, (T val) -> val, dummyZeroElement); + } + + static public 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 public String arrayToStringAsSet(ArrayList a) { + return setToString(new TreeSet<>(a)); + } +} diff --git a/src/inport/ConversionUtils/MZnResultsResolver.java b/src/inport/ConversionUtils/MZnResultsResolver.java new file mode 100644 index 0000000..bd37c59 --- /dev/null +++ b/src/inport/ConversionUtils/MZnResultsResolver.java @@ -0,0 +1,241 @@ +package inport.ConversionUtils; + +import inport.*; + +import java.io.*; +import java.util.*; + +public class MZnResultsResolver { + 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(Utils.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); + } + } +} diff --git a/src/inport/ParserException.java b/src/inport/ConversionUtils/ParserException.java similarity index 79% rename from src/inport/ParserException.java rename to src/inport/ConversionUtils/ParserException.java index 87a8f36..f74c4e1 100644 --- a/src/inport/ParserException.java +++ b/src/inport/ConversionUtils/ParserException.java @@ -1,4 +1,4 @@ -package inport; +package inport.ConversionUtils; public class ParserException extends RuntimeException { ParserException(String mess) { diff --git a/src/inport/ConversionUtils/Task.java b/src/inport/ConversionUtils/Task.java new file mode 100644 index 0000000..5e9cea1 --- /dev/null +++ b/src/inport/ConversionUtils/Task.java @@ -0,0 +1,1510 @@ +package inport.ConversionUtils; + +import inport.*; +import javafx.util.Pair; +import org.jetbrains.annotations.NotNull; + +import java.io.FileWriter; +import java.io.IOException; +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.*; + +public 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; + + public 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 (OperationTemplate operationTemplate : operationTemplates) { + ArrayList curLine = new ArrayList<>(); + for (int j = 0; j <= n_intervals; j++) { + curLine.add(false); + } + + operationTemplate.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 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, MZnFormat::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, MZnFormat::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, MZnFormat::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, MZnFormat::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() { + if (task.isTypified()) { + throw new ParserException("Attempt to convert typified task as untyped."); + } + try { + 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(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + void portToMiniZinc_1() { + if (task.isTypified()) { + throw new ParserException("Attempt to convert typified task as untyped."); + } + try { + 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(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + 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, MZnFormat::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, MZnFormat::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, MZnFormat::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, MZnFormat::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, MZnFormat::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() { + if (!task.isTypified()) { + throw new ParserException("Attempt to convert untyped task as typified."); + } + try { + 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(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + 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, MZnFormat::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, MZnFormat::arrayToStringAsSet, Optional.of(new ArrayList<>())); + } + } + + void portToMiniZinc_2_greedy() { + if (!task.isTypified()) { + throw new ParserException("Attempt to convert untyped task as typified."); + } + try { + portToMiniZinc_2(); + dataForGreediness(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + static public void portToMiniZinc_0(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_0); + } + static public void portToMiniZinc_1(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_1); + } + static public void portToMiniZinc_2(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_2); + } + static public void portToMiniZincGreedy(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_2_greedy); + } + + static private void startConversion(TaskCase task, String fileName, Consumer conversion) { + try { + Task taskData = new Task(task, fileName); + try { + taskData.writer = new FileWriter(fileName, false); + conversion.accept(taskData); + } finally { + if (taskData.writer != null) { + taskData.writer.close(); + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} + diff --git a/src/inport/ConversionUtils/Utils.java b/src/inport/ConversionUtils/Utils.java new file mode 100644 index 0000000..943f61e --- /dev/null +++ b/src/inport/ConversionUtils/Utils.java @@ -0,0 +1,112 @@ +package inport.ConversionUtils; + +import inport.*; +import javafx.util.Pair; + +import java.util.*; + +public class Utils { + 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 public ArrayList integerArray(int size, int initVal) { + ArrayList res = new ArrayList<>(); + for (int i = 0; i < size; i++) { + res.add(initVal); + } + return res; + } + + static public ArrayList> arrayOfIntegerArrays(int size) { + ArrayList> res = new ArrayList<>(); + for (int i = 0; i < size; i++) { + res.add(new ArrayList<>()); + } + return res; + } + + static public ArrayList> arrayOfIntegerSet(int size) { + ArrayList> res = new ArrayList<>(); + for (int i = 0; i < size; i++) { + res.add(new TreeSet<>()); + } + return res; + } + + static public 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 public 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 public 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; + } +} diff --git a/src/inport/Main.java b/src/inport/Main.java index d3c30f3..dc13d80 100644 --- a/src/inport/Main.java +++ b/src/inport/Main.java @@ -8,7 +8,9 @@ import java.util.function.BiFunction; import static inport.Testing.*; -import inport.ConversionUtil.*; +import inport.ConversionUtils.MZnResultsResolver; +import inport.ConversionUtils.ParserException; +import inport.ConversionUtils.Task; public class Main { @@ -85,8 +87,8 @@ public class Main { error = solveTask( task, constraintName, - ConversionUtil::portToMiniZinc_2, - ConversionUtil::resolveMiniZincResults, + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, DEFAULT_TIME_LIMIT_S); } @@ -106,7 +108,7 @@ public class Main { TaskCase task = new TaskCase(); try { task.deserialize(input); - ConversionUtil.portToMiniZinc_0(task, output); + Task.portToMiniZinc_0(task, output); } catch (IOException ex) { System.out.println(ex.getMessage()); } @@ -118,7 +120,7 @@ public class Main { TaskCase task = new TaskCase(); try { task.deserialize(input); - ConversionUtil.portToMiniZinc_1(task, output); + Task.portToMiniZinc_1(task, output); } catch (IOException ex) { System.out.println(ex.getMessage()); } @@ -133,7 +135,7 @@ public class Main { TaskCase task = new TaskCase(); task.deserialize(input); - ConversionUtil.resolveMiniZincResults(task, fileWIthResult); + MZnResultsResolver.resolveMiniZincResults(task, fileWIthResult); task.serialize(output); } catch (IOException | ParserException ex) { @@ -153,6 +155,10 @@ public class Main { debug(Testing::solveTaskWithGreedyConstraints, DEFAULT_TIME_LIMIT_S); break; } + case "debug greedy v2" : { + debug(Testing::solveTaskWithGreedyConstraintsV2, DEFAULT_TIME_LIMIT_S); + break; + } case "debug read-write" : { debugReadWrite(); break; diff --git a/src/inport/Operation.java b/src/inport/Operation.java index a98c22a..a1615a4 100644 --- a/src/inport/Operation.java +++ b/src/inport/Operation.java @@ -4,6 +4,8 @@ */ package inport; +import inport.ConversionUtils.Utils; + import java.util.*; /** @@ -118,10 +120,10 @@ public class Operation { @Override public String toString() { if (executor == null) { - executor = ConversionUtil.getExecutor(template); + executor = Utils.getExecutor(template); } if (resources == null) { - resources = ConversionUtil.getResources(template); + resources = Utils.getResources(template); } StringBuilder sb = new StringBuilder(); sb.append(template.getId()).append("; "); diff --git a/src/inport/Testing.java b/src/inport/Testing.java index f8a72ab..18c45b4 100644 --- a/src/inport/Testing.java +++ b/src/inport/Testing.java @@ -1,5 +1,8 @@ package inport; +import inport.ConversionUtils.MZnResultsResolver; +import inport.ConversionUtils.ParserException; +import inport.ConversionUtils.Task; import javafx.util.Pair; import java.io.*; @@ -29,8 +32,8 @@ public class Testing { return solveTask( task, "conversion_1.mzn", - ConversionUtil::portToMiniZinc_1, - ConversionUtil::resolveMiniZincResults, + Task::portToMiniZinc_1, + MZnResultsResolver::resolveMiniZincResults, timeLimitS); } @@ -38,8 +41,8 @@ public class Testing { return solveTask( task, "conversion_2.mzn", - ConversionUtil::portToMiniZinc_2, - ConversionUtil::resolveMiniZincResults, + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, timeLimitS); } @@ -47,8 +50,8 @@ public class Testing { return solveTask( task, "conversion_2_with_partial_cargo_operations.mzn", - ConversionUtil::portToMiniZinc_2, - ConversionUtil::resolveMiniZincResults, + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, timeLimitS); } @@ -56,8 +59,17 @@ public class Testing { return solveTask( task, "conversion_2_greedy.mzn", - ConversionUtil::portToMiniZincGreedy, - ConversionUtil::resolveMiniZincResults, + Task::portToMiniZincGreedy, + MZnResultsResolver::resolveMiniZincResults, + timeLimitS); + } + + public static String solveTaskWithGreedyConstraintsV2(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2_greedy_v2.mzn", + Task::portToMiniZincGreedy, + MZnResultsResolver::resolveMiniZincResults, timeLimitS); } @@ -65,8 +77,8 @@ public class Testing { return solveTask( task, "conversion_2.0.mzn", - ConversionUtil::portToMiniZinc_2, - ConversionUtil::resolveMiniZincResults, + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, "temp_data_2", timeLimitS); } diff --git a/tests/requiring_optimization/Case_SPB.tipp b/tests/requiring_optimization/Case_SPB.tipp index 251a4d8..3abeacf 100644 --- a/tests/requiring_optimization/Case_SPB.tipp +++ b/tests/requiring_optimization/Case_SPB.tipp @@ -223,10 +223,10 @@ Initial Vessel State 38; 6 /* Бункеровщики. -11; 4 -12; 4 -13; 5 -14; 5 +11; 1 +12; 1 +13; 2 +14; 2 /* Буксиры. 21; 3 @@ -292,7 +292,7 @@ Final Storage State 10002; 38; 4500 Task Properties -20.0; 0 +16.0; 0 Solution -- GitLab