diff --git a/Make.bat b/Make.bat new file mode 100644 index 0000000000000000000000000000000000000000..1ea9f8fd3ad3a144e0a935256260ffd08457c211 --- /dev/null +++ b/Make.bat @@ -0,0 +1,5 @@ +set out_dir=temp +if not exist %out_dir% mkdir %out_dir% +javac -d %out_dir% -encoding UTF-8 -classpath annotations-java8.jar src/inport/*.java src/inport/ConversionUtils/*.java +jar cfe Conversion.jar inport.Main -C %out_dir% inport -C src constraints +rmdir /s /q %out_dir% diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b4e01dd5e9d96f54d28b82fee4a2510355609971 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +out_dir = temp + +Conversion.jar: src/inport/*.java src/constraints/*.mzn manifest.txt + mkdir -p $(out_dir) + javac -d $(out_dir) -encoding UTF-8 -classpath annotations-java8.jar src/inport/*.java + cd $(out_dir) && jar -cvfm ../Conversion.jar ../manifest.txt inport/* ../src/constraints/../constraints/* diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ab719df8586473ed84fe5c77c911de1422201a7d --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Внутрипортовое планирование + +Описание сведения к minizinc-у можно найти в "Планирование портовых операций.docx". + +### Сборка + +Для создания jar-архива необходимо запустить ++ Make.bat - для Windows. ++ Makefile - для Linux. + +### Запуск + +`java -jar Conversion.jar solve example.tipp [conversion_type]`
+где + ++ example.tipp - файл с исходными данными, в него же будет дописан результат. ++ conversion_type - тип сведения, может быть + - "Without splitting" - операции грузообработки всегда выполняются полностью, ограничения из constraints/conversion_2.mzn. Вариант по умолчанию. + - "With splitting" - интенсивность операции может изменятся от 1 до её максимального значения, ограничения из constraints/conversion_2_with_partial_cargo_operations.mzn. + - "Greedy v2" - "жадный алгоритм", ограничения из conversion_2_greedy_v2.mzn. + +### Тестирование + +Проверенные тесты находятся в tests/with_typing . Их последовательный запуск:
+`java -jar Conversion.jar testing [conversion_type]`
где ++ conversion_type - тип сведения, тот же что и при запуске. + + + diff --git a/annotations-java8.jar b/annotations-java8.jar new file mode 100644 index 0000000000000000000000000000000000000000..25774366a0bdcf9d53b70bc32e3fb174c895d2b6 Binary files /dev/null and b/annotations-java8.jar differ diff --git a/src/constraints/conversion_1.mzn b/src/constraints/conversion_1.mzn index 6fb0e7b091d28206cad330d9e6593ab859088d9b..64f2f6c288ef39c61c8dd610300d51c9c55237c8 100644 --- a/src/constraints/conversion_1.mzn +++ b/src/constraints/conversion_1.mzn @@ -279,7 +279,7 @@ constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( % Само о solve minimize sum(is_not_terminated); output [show(sum(is_not_terminated)), "\n", - show(op_status), "\n\n", + "op_status = ", show(op_status), "\n\n", "m_obj_loc = ", show(m_obj_loc), "\n\n", "op_fin = ", show(op_fin), "\n\n", "op_start = ", show(op_start), "\n\n", diff --git a/src/constraints/conversion_2.mzn b/src/constraints/conversion_2.mzn new file mode 100644 index 0000000000000000000000000000000000000000..feca09a5b641637a7e8d436af1d814d2f1ff93af --- /dev/null +++ b/src/constraints/conversion_2.mzn @@ -0,0 +1,611 @@ +include "globals.mzn"; + +int : n_intervals; +int : n_operations; +int : n_locations; +int : n_moving_obj; + +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_status; +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_start; + +constraint forall (t in 0..(n_intervals + 1)) (op_status[0, t] = false); % Фиктивная операция. +constraint forall (t in 0..(n_intervals + 1)) ( op_start[0, t] = false); % Фиктивная операция. + +array [0..n_moving_obj, 0..n_operations] of bool : moving_op_of_obj; + +% Определение current_moving_operation. + % Текущая операция операция перемещения, в которой задействован данный объект. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : current_moving_operation; + + constraint forall (t in 0..(n_intervals + 1)) (current_moving_operation[0, t] = 0); % Фиктивный объект. + + % Крайние значения. + constraint forall (obj in 1..n_moving_obj, t in {0, n_intervals + 1}) ( + current_moving_operation[obj, t] = 0 + ); + + % Текущая операция лежит в множестве тех, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> moving_op_of_obj[obj, current_moving_operation[obj, t]] + ); + % Если операция, затрагивающая данный объект в качестве главного, выполняется - то именно она текущая операция перемещения для этого объекта. + constraint forall (op in 1..n_operations, t in 1..n_intervals where is_moving_operation[op]) ( + op_status[op, t] -> (current_moving_operation[main_obj_of_operation[op], t] = op) + ); + % Связь current_moving_operation c op_status. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> (op_status[current_moving_operation[obj, t], t]) + ); + +% Определение current_moored_obj. + % Объект, пришвартованный к данной локации. + array [0..n_locations, 0..(n_intervals + 1)] of var 0..n_moving_obj : current_moored_obj; + + constraint forall (t in 0..(n_intervals + 1)) (current_moored_obj[0, t] = 0); % Фиктивная локация. + + % Фиксирование неиспользуемых значений. + constraint forall (loc in 1..n_locations, t in 0..(n_intervals + 1) where loc mod 2 = 1) ( + current_moored_obj[loc, t] = 0 + ); + + % Крайние значения. + constraint forall (loc in 1..n_locations, t in {0, n_intervals + 1}) ( + current_moored_obj[loc, t] = 0 + ); + + % Операции с условной швартовкой. + int : op_with_nominally_mooring_max_size; + array [0..n_locations, 0..n_moving_obj] of 0..op_with_nominally_mooring_max_size : op_with_nominally_mooring_sizes; + array [0..n_locations, 0..n_moving_obj, 1..op_with_nominally_mooring_max_size] of 1..n_operations : op_with_nominally_mooring; + + % current_moored_obj соответствуе какому-либо реально пришвартованному объекту. + constraint forall (loc in 1..n_locations, t in 1..n_intervals, obj = current_moored_obj[loc, t] + where loc mod 2 = 0) ( + (obj != 0) -> ((m_obj_loc[obj, t] = loc) \/ + (exists (op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]]) + (op_status[op, t])) + ) + ); + + % Если объект пришвартован или швартуется, то current_moored_obj об это знает. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals, loc = m_obj_loc[obj, t]) ( + (loc mod 2 = 0) -> (current_moored_obj[loc, t] = obj) + ); + + % Если выполняется операция, где судно условно пришвартовано, то current_moored_obj знает об этом. + constraint forall (loc in 1..n_locations, + obj in 1..n_moving_obj, + op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]], + t in 1..n_intervals) ( + op_status[op, t] -> (current_moored_obj[loc, t] = obj) + ); + +array [1..n_locations] of 0..n_locations : twin_location = [i - 1 + (i mod 2) * 2 | i in 1..n_locations]; +array [1..n_locations] of 1..n_locations : main_location = [i - ((i + 1) mod 2)| i in 1..n_locations]; + +array [0..n_operations] of 0..n_locations : operations_destination; % Локация в которой окажется объект после завершения операции. + +% Определение m_obj_loc. + % Местоположение объекта или пункт назначения (если объект движется) перед началом определённого интервала. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_locations : m_obj_loc; + + constraint forall (t in 0..(n_intervals + 1)) (m_obj_loc[0, t] = 0); % Фиктивный объект. + + % Главный объект (субъект) операции. + array [0..n_operations] of 0..n_moving_obj : main_obj_of_operation; + + % Является ли операция швартовкой/отшвартовкой. + array [0..n_operations] of bool : is_mooring_op; + + % За фиктивный нулевой интервал объект не успевает ничего сделать с начальным положением. + constraint forall (obj in 1..n_moving_obj) ( + m_obj_loc[obj, 1] = m_obj_loc[obj, 0] + ); + + % Направление движения/местоположение объекта может измениться только если перед этим началась операция перемещения, и он не вспомогательный при операции швартовки. + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] != current_moving_operation[obj, t - 2]) /\ + (current_moving_operation[obj, t - 1] != 0) /\ + ((obj = main_obj_of_operation[current_moving_operation[obj, t - 1]]) + \/ + (not is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = operations_destination[current_moving_operation[obj, t - 1]]) + ); + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] = current_moving_operation[obj, t - 2]) \/ + (current_moving_operation[obj, t - 1] = 0) \/ + ((obj != main_obj_of_operation[current_moving_operation[obj, t - 1]]) + /\ + ( is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) + ); + +% Начальное состояние. + array [0..n_moving_obj] of 0..n_locations : initial_m_obj_loc; + constraint forall (i in 1..n_moving_obj) (m_obj_loc[i, 0] = initial_m_obj_loc[i]); + +% Конечное состояние. + array [0..n_moving_obj] of 0..n_locations : final_m_obj_loc; + constraint forall (i in 1..n_moving_obj) ( + (final_m_obj_loc[i] != 0) -> + (m_obj_loc[i, n_intervals + 1] = final_m_obj_loc[i]) + ); + +% Определение op_status, op_start. + constraint forall (i in 1..n_operations, j in {0, n_intervals + 1}) (op_status[i, j] == 0); % Краевые значения. + + constraint forall (op in 1..n_operations, j in {0, n_intervals + 1}) (op_start[op, j] = false); + constraint forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] = (op_status[i, j] /\ not op_status[i, j - 1])); + +% Связь ресурсов с операцией и основным объектом. + % Операции, которые могут задействовать данный объект как ресурс. + array [0..n_moving_obj] of set of 1..n_operations : operations_that_used_obj_as_resource; + + % Является ли данная операция операцией перемещения. + array [0..n_operations] of bool : is_moving_operation; + + % Операция, в которой участвует данный объект как ресурс. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : participation_as_resource; + + constraint forall (t in 0..(n_intervals + 1)) (participation_as_resource[0, t] = 0); % Фиктивный объект. + + % Граничные значения. + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, 0] = 0); + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, n_intervals + 1] = 0); + + % Только те операции, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) + -> participation_as_resource[obj, t] in operations_that_used_obj_as_resource[obj] + ); + + % Связь с текущими операциями перемещения. + % Если объект задействован в операции перемещения, которая использует его как ресурс, + % то participation_as_resource должен указывать на эту операцию. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] in operations_that_used_obj_as_resource[obj]) + -> + (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + % Если объект участвует как ресурс в операции перемещения, то это согласованно с current_moving_operation. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + ((participation_as_resource[obj, t] != 0) /\ + (is_moving_operation[participation_as_resource[obj, t]]) + ) -> (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + + % { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) -> op_status[participation_as_resource[obj, t], t] + ); + + % От начала операции и до конца её ресурсы не могут измениться (в том числе и для погрузки). + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals - 1)) ( + ((participation_as_resource[obj, t] != 0) /\ + (op_status[participation_as_resource[obj, t], t + 1]) + ) -> (participation_as_resource[obj, t + 1] = participation_as_resource[obj, t]) + ); + + int : n_resources_types; % Количество различных типов ресурсов. + array [1..n_resources_types] of set of 1..n_moving_obj : objects_of_type; % Все объекты конкретного типа. + + int : n_resources_counters; % Количество счётчиков ресурсов. + % Счётчик ресурсов. + array [1..n_resources_counters , 1..n_intervals] of var int : resources_counter; + array [1..n_resources_counters] of 1..n_resources_types : counter_type; % Типы ресурсов, за которыми следят счётчики. + array [1..n_resources_counters] of 1..n_operations : operation_of_counter; % Операция, которой принадлежит данный счётчик. + array [1..n_resources_counters] of int : required_counter_values; % Необходимые значения на счётчиках ресурсов для выполнения операции. + array [0..n_operations] of set of 1..n_resources_counters : counters_of_operation; % Счётчики, которые относятся к данной операции. + + % Участие всех необходимых ресурсов в операции. + constraint forall (t in 1..n_intervals, op in 1..n_operations, counter in counters_of_operation[op]) ( + op_status[op, t] -> (resources_counter[counter, t] = required_counter_values[counter]) + ); + + % Определение resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + participation_as_resource[obj, t] = operation_of_counter[counter] + ) + ); + +% Участие объекта в операциях грузообработки. + array [0..n_moving_obj, 0..n_intervals] of var bool : is_involved_in_cargo_op; + + constraint forall (t in 1..n_intervals) (is_involved_in_cargo_op[0, t] = false); % Фиктивный объект. + constraint forall (obj in 1..n_moving_obj) (is_involved_in_cargo_op[obj, 0] = false); + + % Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. + 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] = ( + (exists (op in related_cargo_op[obj]) (op_status[op, t])) + \/ + ((participation_as_resource[obj, t] != 0) /\ (not is_moving_operation[participation_as_resource[obj, t]])) + ) + ); + % Операции перемещения исключают операции грузообработки и наоборот. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + is_involved_in_cargo_op[obj, t] -> (current_moving_operation[obj, t] = 0) + ); + +% Наличие всех объектов на месте во время начала операции перемещения + готовность к началу. + % Требуемое положение конкретных типов объектов в момент начала операций. + array [1..n_resources_counters] of 1..n_locations : operations_resources_start_loc; + + % Наличие на месте всех ресурсов. + constraint forall ( + op in 1..n_operations, + t in 1..n_intervals, + counter in counters_of_operation[op], + obj in objects_of_type[counter_type[counter]]) ( + ((participation_as_resource[obj, t] = op) /\ (op_start[op, t]) + ) -> (m_obj_loc[obj, t] == operations_resources_start_loc[counter]) + ); + + % Требуемое положение главного объекта в момент начала операций. + array [0..n_operations] of 0..n_locations : main_obj_start_loc; + % Требуемое положение бункеровщика в момент начала операции. + array [0..n_operations] of 0..n_locations : bunker_start_loc; + + % Бункеровщик, участвующий в операции погрузки (0, если такогого нет или это не погрузка). + array [0..n_operations] of 0..n_moving_obj : bunker_of_cargo_op; + + % Наличие главных объектов на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = main_obj_of_operation[op]) ( + op_start[op, t] -> (m_obj_loc[obj, t] == main_obj_start_loc[op]) + ); + + % Наличие бункеровщиков на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = bunker_of_cargo_op[op] where obj != 0) ( + op_start[op, t] -> (m_obj_loc[obj, t] == bunker_start_loc[op]) + ); + +% Непрерывность перемещения и швартовки. + array [0..n_operations] of int : operations_duration; + array [0..n_operations] of bool : is_continuous_operation; + + constraint forall (i in 1..n_operations, len = operations_duration[i] where is_continuous_operation[i]) ( + (forall (j in 1..(n_intervals - len + 1)) ( + (op_start[i, j] == 1) -> ( + (forall (k in 1..(len - 1)) (op_status[i, j + k])) + /\ + (not op_status[i, j + len]) + ) + )) /\ + (forall (j in (n_intervals - len + 2)..(n_intervals + 1)) (op_start[i, j] == false)) + ); + +% Конфликтующие операции. + array [0..n_operations] of set of 1..n_operations : conflicting_operations; + + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1), conf_op in conflicting_operations[op]) ( + op_status[op, t] -> not op_status[conf_op, t] + ); + +% Окна непогоды. + array [0..n_operations, 0..n_intervals] of bool : bad_weather; + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + bad_weather[op, t] -> (op_status[op, t] = false) + ); + +% Грузообработка. + int : n_cargo_types; + int : n_all_storage_sections; + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of var int : storage_used_volume; + + constraint forall (t in 0..(n_intervals + 1)) (storage_used_volume[0, t] = 0); % Фиктивный объект. + + % Ограничения на вместимость. + array [0..n_all_storage_sections] of int : max_storage_vol; + % Максимальный объём. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + (storage_used_volume[storage, t]) <= max_storage_vol[storage] + ); + % Неотрицательность объёма. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + 0 <= storage_used_volume[storage, t] + ); + + % Ограничения на граничные значения. + array [0..n_all_storage_sections] of int : initial_storage_vol; + array [0..n_all_storage_sections] of int : final_storage_vol; + + constraint forall (storage in 1..n_all_storage_sections) ( % Initial values. + storage_used_volume[storage, 0] = initial_storage_vol[storage] + ); + + constraint forall (storage in 1..n_all_storage_sections % Final values. + where final_storage_vol[storage] >= 0) ( + storage_used_volume[storage, n_intervals + 1] = final_storage_vol[storage] + ); + + % Изменение грузов в хранилищах. + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of int : cargo_flows; + + int : n_loading_op; + + array [0..n_operations] of int : loading_op_delta_of_main_obj; + array [0..n_operations] of int : loading_op_abs_delta; + array [0..n_operations] of {1, -1} : loading_op_direction; + + array [0..n_operations] of 1..n_all_storage_sections : operations_main_stor; + array [0..n_operations] of 1..n_all_storage_sections : operations_secondary_stor; + array [0..n_operations] of 1..n_cargo_types : operations_cargo_t; + + array [1..n_loading_op] of int : loading_op_delta; + array [1..n_loading_op] of {1, -1} : loading_op_local_direction; + array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций. + + array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations; + array [1..n_moving_obj] of set of 1..n_all_storage_sections : sections_of_moving_obj; + array [1..n_moving_obj] of bool : is_sections_of_moving_obj_empty; + + constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + sum (inv_op in involved_operations[storage]) ( + loading_op_delta[inv_op] * + op_status[loading_op_n[inv_op], t] + ) + ) + ); + +% Фиксированные операции. + int : n_fixed_op; + array [1..n_fixed_op] of 1..n_operations : fixed_op; + array [1..n_fixed_op] of set of 1..n_moving_obj : fixed_op_resources; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_start; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_end; % Включительно. + array [1..n_fixed_op] of int : fixed_op_intensity; + + array [0..n_operations, 0..n_intervals] of bool : is_fixed; + array [0..n_moving_obj, 0..(n_intervals + 1)] of bool : is_obj_involved_in_fixed_op; + + constraint forall (no in 1..n_fixed_op, op = fixed_op[no]) ( + forall (t in fixed_op_start[no]..fixed_op_end[no]) ( + (op_status[op, t]) /\ + forall (obj in fixed_op_resources[no]) ( + participation_as_resource[obj, t] = op + ) + ) + ); + +% Оптимизация - сдвиг в начало. + % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). + array [0..n_operations, 1..n_intervals] of var bool : is_op_possible; + + constraint forall (t in 1..n_intervals) (is_op_possible[0, t] = false); % Фиктивный объект. + + % Счётчик ресурсов, которые могут быть потенциально задействованы в операции. + array [1..n_resources_counters , 1..n_intervals] of var int : possible_resources_counter; + + % Определение possible_resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + possible_resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + (participation_as_resource[obj, t] = 0) /\ + (current_moving_operation[obj, t] = 0) /\ + (m_obj_loc[obj, t] = operations_resources_start_loc[counter]) + ) + ); + + % Достаточно ли свободных ресурсов для операции. + array [0..n_operations, 1..n_intervals] of var bool : is_enough_free_resources; + + constraint forall (t in 1..n_intervals) (is_enough_free_resources[0, t] = false); % Фиктивный объект. + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_enough_free_resources[op, t] = forall (counter in counters_of_operation[op]) ( + possible_resources_counter[counter, t] >= required_counter_values[counter] + ) + ); + + % Определение is_op_possible. + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_op_possible[op, t] = ( + (bad_weather[op, t] = false) /\ % Погода не мешает. + (m_obj_loc[main_obj_of_operation[op], t] = main_obj_start_loc[op]) + /\ % Главный объект на месте. + (current_moving_operation[main_obj_of_operation[op], t] = 0) + /\ % Главный объект не участвует в операции перемещеня. + (is_enough_free_resources[op, t] = true) /\ % Достаточно свободных ресурсов на нужном месте. + (forall (conf_op in conflicting_operations[op]) (op_status[conf_op, t] = false)) + /\ % Не выполняется ни одной конфликтующей операции. + (is_moving_operation[op] -> not is_involved_in_cargo_op[main_obj_of_operation[op], t]) + /\ % Если это операция перемещения, то главный объект + % не участвует в операциях погрузки. + ((is_mooring_op[op] /\ (operations_destination[op] mod 2 = 0)) -> ( + current_moored_obj[operations_destination[op], t] = 0) + ) /\ % Если это операция пришвартовки, то в этот интервал + % причал должен быть свободным. + ((not is_moving_operation[op]) -> ( + let {1..n_all_storage_sections : m_stor = operations_main_stor[op]; + 1..n_all_storage_sections : s_stor = operations_secondary_stor[op]; + int : delta = loading_op_delta_of_main_obj[op]; + } in + (storage_used_volume[m_stor, t] + delta >= 0) /\ + (storage_used_volume[m_stor, t] + delta <= max_storage_vol[m_stor]) /\ + (storage_used_volume[s_stor, t] - delta >= 0) /\ + (storage_used_volume[s_stor, t] - delta <= max_storage_vol[s_stor]) + )) /\ % Если это операция грузообработки, то она не выведет + % объём берегового хранилища и хранилища судна за + % границы дозволенного. + (((not is_moving_operation[op]) /\ (main_obj_start_loc[op] mod 2 = 1)) -> + ((current_moored_obj[twin_location[main_obj_start_loc[op]], t] = 0) \/ + (current_moored_obj[twin_location[main_obj_start_loc[op]], t] = main_obj_of_operation[op])) + ) /\ % Если это операция грузообработки без пришвартовки, + % то причал должен быть свободен в этот интервал, либо + % главный объект должен быть уже условно пришвартован. + (((bunker_of_cargo_op[op] != 0) /\ (op_status[op, t])) -> + ((m_obj_loc[bunker_of_cargo_op[op], t] = bunker_start_loc[op]) /\ + (current_moving_operation[bunker_of_cargo_op[op], t] = 0)) + ) % Бункеровщик (если есть) находится в нужной локации + % и не участвует в операциях перемещения. + ) + ); + + % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. + constraint forall (op in 1..n_operations, t in 2..n_intervals) ( + (op_start[op, t] /\ (not is_fixed[op, t])) -> not is_op_possible[op, t - 1] + ); + +% Оптимизация - судно возвращается откуда перед этим пришло -> оно сделало или делает что-то "полезное". + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 1..n_locations : prev_m_obj_loc; + array [0..n_moving_obj, 0..(n_intervals + 1)] of var bool : is_obj_involved_in_useful_operation; + + constraint forall (t in 0..(n_intervals + 1)) (prev_m_obj_loc[0, t] = 1); + constraint forall (t in 0..(n_intervals + 1)) (is_obj_involved_in_useful_operation[0, t] = false); + + % Определение prev_m_obj_loc + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( + (m_obj_loc[obj, t - 1] != m_obj_loc[obj, t]) -> (prev_m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) + ); + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( + (m_obj_loc[obj, t - 1] == m_obj_loc[obj, t]) -> (prev_m_obj_loc[obj, t] = prev_m_obj_loc[obj, t - 1]) + ); + constraint forall (obj in 1..n_moving_obj) (prev_m_obj_loc[obj, 0] = m_obj_loc[obj, 0]); + + % Определение is_obj_involved_in_useful_operation + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( + is_obj_involved_in_useful_operation[obj, t] = ( + (participation_as_resource[obj, t] != 0) + \/ (exists (op in related_cargo_op[obj]) (op_status[op, t])) + \/ (is_obj_involved_in_fixed_op[obj, t]) + \/ (exists (op in related_unmooring_op[obj]) (op_status[op, t])) + ) + ); + constraint forall (obj in 1..n_moving_obj) (is_obj_involved_in_useful_operation[obj, 0] = false); + + % Успел ли объект поучаствовать в полезной операции к концу данного интервала. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var bool : is_attended_useful_op_in_cur_loc; + % Определение is_attended_useful_op_in_cur_loc + constraint forall (t in 0..(n_intervals + 1)) (is_attended_useful_op_in_cur_loc[0, t] = false); + + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( + is_attended_useful_op_in_cur_loc[obj, t] = ( + (is_attended_useful_op_in_cur_loc[obj, t - 1] /\ (m_obj_loc[obj, t - 1] == m_obj_loc[obj, t])) % Предыдущее значение в текущей локации. + \/ + is_obj_involved_in_useful_operation[obj, t] + \/ + is_obj_involved_in_useful_operation[obj, t - 1] % Учитывает случай когда операция перемещения, из-за которой объект попал в локацию была нужна. + ) + ); + + % Сама оптимизация - если объект + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((m_obj_loc[obj, t - 1] != m_obj_loc[obj, t]) /\ (prev_m_obj_loc[obj, t - 1] == m_obj_loc[obj, t]) + ) -> is_attended_useful_op_in_cur_loc[obj, t - 1] + ); + +% Оптимизация - если объект не может совершить в данной локации операции без выхода за границы хранилища, а так же если он +% может уйти только своим ходом, то он либо уходит немедленно, либо остаётся на месте навсегда. + + array [1..n_all_storage_sections, 1..n_locations] of int : min_positive_cargo_val; % Объём максимальной положительной операции, которая может быть произведена с этой секцией в этом хранилище. Если в локации таковой нет, то это значение объёма хранилища + 1. + array [1..n_all_storage_sections, 1..n_locations] of int : max_negative_cargo_val; + + 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; + + array [0..n_moving_obj, 0..(n_intervals + 1)] of var bool : can_obj_theoretically_use_cargo_op; + % Определение can_obj_theoretically_use_cargo_op. + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( + can_obj_theoretically_use_cargo_op[obj, t] = ( + is_sections_of_moving_obj_empty[obj] + \/ + exists (section in sections_of_moving_obj[obj]) ( + (storage_used_volume[section, t - 1] + min_positive_cargo_val[section, main_location[m_obj_loc[obj, t]]] <= max_storage_vol[section]) + \/ (storage_used_volume[section, t - 1] + max_negative_cargo_val[section, main_location[m_obj_loc[obj, t]]] >= 0) + ) + ) + ); + constraint forall (t in 0..(n_intervals + 1)) (can_obj_theoretically_use_cargo_op[0, t] = false); + constraint forall (obj in 1..n_moving_obj) (can_obj_theoretically_use_cargo_op[obj, 0] = false); + + % Остановился ли объект окончательно, начиная с данного интервала. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var bool : is_obj_totally_terminated; + constraint forall (obj in 1..n_moving_obj) (is_obj_totally_terminated[obj, n_intervals + 1] = true); + constraint forall (t in 0..(n_intervals + 1)) (is_obj_totally_terminated[0, t] = true); + + constraint forall (obj in 1..n_moving_obj, t in 0..n_intervals) ( + is_obj_totally_terminated[obj, t] = ( + (current_moving_operation[obj, t] = 0) + /\ (not is_involved_in_cargo_op[obj, t]) + /\ (is_obj_totally_terminated[obj, t + 1]) + ) + ); + + % Само ограничение. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + ( (can_obj_leave_loc_only_alone[obj, m_obj_loc[obj, t]]) + /\ (not can_obj_theoretically_use_cargo_op[obj, t]) + /\ (not is_fixed_op_planned_in_future[obj, m_obj_loc[obj, t], t]) + ) -> + (is_obj_totally_terminated[obj, t] \/ (current_moving_operation[obj, t] != 0)) + ); + +% Критерий оптимизации + array [1..(n_intervals + 1)] of var bool : is_not_terminated; + % В конце всё остановится. + constraint (is_not_terminated[n_intervals + 1] == false); + + % Действия ещё не остановились, если в текущий интервал что-нибудь происходит или они не остановятся в следующий интервал. + constraint forall (t in 1..n_intervals) ( + is_not_terminated[t] == ( + (exists (op in 1..n_operations) (op_status[op, t])) + \/ + is_not_terminated[t + 1] + ) + ); + + solve minimize sum(is_not_terminated); + +output [show(sum(is_not_terminated)), "\n", + "op_status = ", show(op_status), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "op_start = ", show(op_start), "\n\n", + "is_not_terminated = ", show(is_not_terminated), "\n\n", + "storage_used_volume = ", show(storage_used_volume), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "current_moving_operation = ", show(current_moving_operation), "\n\n", + "resources_counter {", show(n_intervals), "} = ", show(resources_counter), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "participation_as_resource = ", show(participation_as_resource), "\n\n", + + "is_involved_in_cargo_op = {", show(n_intervals), "} ", show(is_involved_in_cargo_op), "\n\n", + + "m_obj_loc = ", show(m_obj_loc), "\n\n", +/* + "prev_m_obj_loc = {", show(n_intervals + 2), "} ", show(prev_m_obj_loc), "\n\n", + "is_obj_involved_in_useful_operation = {", show(n_intervals + 2), "} ", show(is_obj_involved_in_useful_operation), "\n\n", + "is_attended_useful_op_in_cur_loc = {", show(n_intervals + 2), "} ", show(is_attended_useful_op_in_cur_loc), "\n\n", +*/ + + "can_obj_theoretically_use_cargo_op = {", show(n_intervals + 2), "} ", show(can_obj_theoretically_use_cargo_op), "\n\n", + "is_obj_totally_terminated = {", show(n_intervals + 2), "} ", show(is_obj_totally_terminated), "\n\n", + + "main_location = {", show(n_locations), "} ", show(main_location), "\n\n", + + "is_fixed_op_planned_in_future = {", show(n_locations), " ", show(n_intervals), "} ", show(is_fixed_op_planned_in_future), "\n\n", + "can_obj_leave_loc_only_alone {", show(n_locations), "} = ", show(can_obj_leave_loc_only_alone), "\n\n", +/* + "is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n", + "debug_1 {", show(n_intervals), "} = ", show(debug_1), "\n\n", + "is_enough_free_resources {", show(n_intervals), "} = ", show(is_enough_free_resources), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + + "possible_resources_counter {", show(n_intervals), "} = ", show(possible_resources_counter), "\n\n", +*/ + ""]; diff --git a/src/constraints/conversion_2_greedy.mzn b/src/constraints/conversion_2_greedy.mzn new file mode 100644 index 0000000000000000000000000000000000000000..13da1abb0b31e5794b6f1c952754051d46bc616a --- /dev/null +++ b/src/constraints/conversion_2_greedy.mzn @@ -0,0 +1,762 @@ +include "globals.mzn"; + +int : n_intervals; +int : n_operations; +int : n_locations; +int : n_moving_obj; + +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_status; +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_start; + +constraint forall (t in 0..(n_intervals + 1)) (op_status[0, t] = false); % Фиктивная операция. +constraint forall (t in 0..(n_intervals + 1)) ( op_start[0, t] = false); % Фиктивная операция. + +array [0..n_moving_obj, 0..n_operations] of bool : moving_op_of_obj; + +% Определение current_moving_operation. + % Текущая операция операция перемещения, в которой задействован данный объект. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : current_moving_operation; + + constraint forall (t in 0..(n_intervals + 1)) (current_moving_operation[0, t] = 0); % Фиктивный объект. + + % Крайние значения. + constraint forall (obj in 1..n_moving_obj, t in {0, n_intervals + 1}) ( + current_moving_operation[obj, t] = 0 + ); + + % Текущая операция лежит в множестве тех, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> moving_op_of_obj[obj, current_moving_operation[obj, t]] + ); + % Если операция, затрагивающая данный объект в качестве главного, выполняется - то именно она текущая операция перемещения для этого объекта. + constraint forall (op in 1..n_operations, t in 1..n_intervals where is_moving_operation[op]) ( + op_status[op, t] -> (current_moving_operation[main_obj_of_operation[op], t] = op) + ); + % Связь current_moving_operation c op_status. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> (op_status[current_moving_operation[obj, t], t]) + ); + +% Определение current_moored_obj. + % Объект, пришвартованный к данной локации. + array [0..n_locations, 0..(n_intervals + 1)] of var 0..n_moving_obj : current_moored_obj; + + constraint forall (t in 0..(n_intervals + 1)) (current_moored_obj[0, t] = 0); % Фиктивная локация. + + % Фиксирование неиспользуемых значений. + constraint forall (loc in 1..n_locations, t in 0..(n_intervals + 1) where loc mod 2 = 1) ( + current_moored_obj[loc, t] = 0 + ); + + % Крайние значения. + constraint forall (loc in 1..n_locations, t in {0, n_intervals + 1}) ( + current_moored_obj[loc, t] = 0 + ); + + % Операции с условной швартовкой. + int : op_with_nominally_mooring_max_size; + array [0..n_locations, 0..n_moving_obj] of 0..op_with_nominally_mooring_max_size : op_with_nominally_mooring_sizes; + array [0..n_locations, 0..n_moving_obj, 1..op_with_nominally_mooring_max_size] of 1..n_operations : op_with_nominally_mooring; + + % current_moored_obj соответствуе какому-либо реально пришвартованному объекту. + constraint forall (loc in 1..n_locations, t in 1..n_intervals, obj = current_moored_obj[loc, t] + where loc mod 2 = 0) ( + (obj != 0) -> ((m_obj_loc[obj, t] = loc) \/ + (exists (op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]]) + (op_status[op, t])) + ) + ); + + % Если объект пришвартован или швартуется, то current_moored_obj об это знает. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals, loc = m_obj_loc[obj, t]) ( + (loc mod 2 = 0) -> (current_moored_obj[loc, t] = obj) + ); + + % Если выполняется операция, где судно условно пришвартовано, то current_moored_obj знает об этом. + constraint forall (loc in 1..n_locations, + obj in 1..n_moving_obj, + op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]], + t in 1..n_intervals) ( + op_status[op, t] -> (current_moored_obj[loc, t] = obj) + ); + +array [1..n_locations] of 0..n_locations : twin_location = [i - 1 + (i mod 2) * 2 | i in 1..n_locations]; + +array [0..n_operations] of 0..n_locations : operations_destination; % Локация в которой окажется объект после завершения операции. + +% Определение m_obj_loc. + % Местоположение объекта или пункт назначения (если объект движется) перед началом определённого интервала. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_locations : m_obj_loc; + + constraint forall (t in 0..(n_intervals + 1)) (m_obj_loc[0, t] = 0); % Фиктивный объект. + + % Главный объект (субъект) операции. + array [0..n_operations] of 0..n_moving_obj : main_obj_of_operation; + + % Является ли операция швартовкой/отшвартовкой. + array [0..n_operations] of bool : is_mooring_op; + + % За фиктивный нулевой интервал объект не успевает ничего сделать с начальным положением. + constraint forall (obj in 1..n_moving_obj) ( + m_obj_loc[obj, 1] = m_obj_loc[obj, 0] + ); + + % Направление движения/местоположение объекта может измениться только если перед этим началась операция перемещения, и он не вспомогательный при операции швартовки. + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] != current_moving_operation[obj, t - 2]) /\ + (current_moving_operation[obj, t - 1] != 0) /\ + ((obj = main_obj_of_operation[current_moving_operation[obj, t - 1]]) + \/ + (not is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = operations_destination[current_moving_operation[obj, t - 1]]) + ); + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] = current_moving_operation[obj, t - 2]) \/ + (current_moving_operation[obj, t - 1] = 0) \/ + ((obj != main_obj_of_operation[current_moving_operation[obj, t - 1]]) + /\ + ( is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) + ); + +% Начальное состояние. + array [0..n_moving_obj] of 0..n_locations : initial_m_obj_loc; + constraint forall (i in 1..n_moving_obj) (m_obj_loc[i, 0] = initial_m_obj_loc[i]); + +% Конечное состояние. + array [0..n_moving_obj] of 0..n_locations : final_m_obj_loc; + constraint forall (i in 1..n_moving_obj) ( + (final_m_obj_loc[i] != 0) -> + (m_obj_loc[i, n_intervals + 1] = final_m_obj_loc[i]) + ); + +% Определение op_status, op_start. + constraint forall (i in 1..n_operations, j in {0, n_intervals + 1}) (op_status[i, j] == 0); % Краевые значения. + + constraint forall (op in 1..n_operations, j in {0, n_intervals + 1}) (op_start[op, j] = false); + constraint forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] = (op_status[i, j] /\ not op_status[i, j - 1])); + +% Связь ресурсов с операцией и основным объектом. + % Операции, которые могут задействовать данный объект как ресурс. + array [0..n_moving_obj] of set of 1..n_operations : operations_that_used_obj_as_resource; + + % Является ли данная операция операцией перемещения. + array [0..n_operations] of bool : is_moving_operation; + + % Операция, в которой участвует данный объект как ресурс. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : participation_as_resource; + + constraint forall (t in 0..(n_intervals + 1)) (participation_as_resource[0, t] = 0); % Фиктивный объект. + + % Граничные значения. + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, 0] = 0); + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, n_intervals + 1] = 0); + + % Только те операции, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) + -> participation_as_resource[obj, t] in operations_that_used_obj_as_resource[obj] + ); + + % Связь с текущими операциями перемещения. + % Если объект задействован в операции перемещения, которая использует его как ресурс, + % то participation_as_resource должен указывать на эту операцию. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] in operations_that_used_obj_as_resource[obj]) + -> + (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + % Если объект участвует как ресурс в операции перемещения, то это согласованно с current_moving_operation. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + ((participation_as_resource[obj, t] != 0) /\ + (is_moving_operation[participation_as_resource[obj, t]]) + ) -> (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + + % { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) -> op_status[participation_as_resource[obj, t], t] + ); + + % От начала операции и до конца её ресурсы не могут измениться (в том числе и для погрузки). + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals - 1)) ( + ((participation_as_resource[obj, t] != 0) /\ + (op_status[participation_as_resource[obj, t], t + 1]) + ) -> (participation_as_resource[obj, t + 1] = participation_as_resource[obj, t]) + ); + + int : n_resources_types; % Количество различных типов ресурсов. + array [1..n_resources_types] of set of 1..n_moving_obj : objects_of_type; % Все объекты конкретного типа. + + int : n_resources_counters; % Количество счётчиков ресурсов. + % Счётчик ресурсов. + array [1..n_resources_counters , 1..n_intervals] of var int : resources_counter; + array [1..n_resources_counters] of 1..n_resources_types : counter_type; % Типы ресурсов, за которыми следят счётчики. + array [1..n_resources_counters] of 1..n_operations : operation_of_counter; % Операция, которой принадлежит данный счётчик. + array [1..n_resources_counters] of int : required_counter_values; % Необходимые значения на счётчиках ресурсов для выполнения операции. + array [0..n_operations] of set of 1..n_resources_counters : counters_of_operation; % Счётчики, которые относятся к данной операции. + + % Участие всех необходимых ресурсов в операции. + constraint forall (t in 1..n_intervals, op in 1..n_operations, counter in counters_of_operation[op]) ( + op_status[op, t] -> (resources_counter[counter, t] = required_counter_values[counter]) + ); + + % Определение resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + participation_as_resource[obj, t] = operation_of_counter[counter] + ) + ); + +% Участие объекта в операциях грузообработки. + array [0..n_moving_obj, 1..n_intervals] of var bool : is_involved_in_cargo_op; + + constraint forall (t in 1..n_intervals) (is_involved_in_cargo_op[0, t] = false); % Фиктивный объект. + + % Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. + 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] = ( + (exists (op in related_cargo_op[obj]) (op_status[op, t])) + \/ + ((participation_as_resource[obj, t] != 0) /\ (not is_moving_operation[participation_as_resource[obj, t]])) + ) + ); + % Операции перемещения исключают операции грузообработки и наоборот. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + is_involved_in_cargo_op[obj, t] -> (current_moving_operation[obj, t] = 0) + ); + +% Наличие всех объектов на месте во время начала операции перемещения + готовность к началу. + % Требуемое положение конкретных типов объектов в момент начала операций. + array [1..n_resources_counters] of 1..n_locations : operations_resources_start_loc; + + % Наличие на месте всех ресурсов. + constraint forall ( + op in 1..n_operations, + t in 1..n_intervals, + counter in counters_of_operation[op], + obj in objects_of_type[counter_type[counter]]) ( + ((participation_as_resource[obj, t] = op) /\ (op_start[op, t]) + ) -> (m_obj_loc[obj, t] == operations_resources_start_loc[counter]) + ); + + % Требуемое положение главного объекта в момент начала операций. + array [0..n_operations] of 0..n_locations : main_obj_start_loc; + % Требуемое положение бункеровщика в момент начала операции. + array [0..n_operations] of 0..n_locations : bunker_start_loc; + + % Бункеровщик, участвующий в операции погрузки (0, если такогого нет или это не погрузка). + array [0..n_operations] of 0..n_moving_obj : bunker_of_cargo_op; + + % Наличие главных объектов на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = main_obj_of_operation[op]) ( + op_start[op, t] -> (m_obj_loc[obj, t] == main_obj_start_loc[op]) + ); + + % Наличие бункеровщиков на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = bunker_of_cargo_op[op] where obj != 0) ( + op_start[op, t] -> (m_obj_loc[obj, t] == bunker_start_loc[op]) + ); + +% Непрерывность перемещения и швартовки. + array [0..n_operations] of int : operations_duration; + array [0..n_operations] of bool : is_continuous_operation; + + constraint forall (i in 1..n_operations, len = operations_duration[i] where is_continuous_operation[i]) ( + (forall (j in 1..(n_intervals - len + 1)) ( + (op_start[i, j] == 1) -> ( + (forall (k in 1..(len - 1)) (op_status[i, j + k])) + /\ + (not op_status[i, j + len]) + ) + )) /\ + (forall (j in (n_intervals - len + 2)..(n_intervals + 1)) (op_start[i, j] == false)) + ); + +% Конфликтующие операции. + array [0..n_operations] of set of 1..n_operations : conflicting_operations; + + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1), conf_op in conflicting_operations[op]) ( + op_status[op, t] -> not op_status[conf_op, t] + ); + +% Окна непогоды. + array [0..n_operations, 0..n_intervals] of bool : bad_weather; + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + bad_weather[op, t] -> (op_status[op, t] = false) + ); + +% Грузообработка. + int : n_cargo_types; + int : n_all_storage_sections; + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of var int : storage_used_volume; + + constraint forall (t in 0..(n_intervals + 1)) (storage_used_volume[0, t] = 0); % Фиктивный объект. + + % Ограничения на вместимость. + array [0..n_all_storage_sections] of int : max_storage_vol; + % Максимальный объём. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + (storage_used_volume[storage, t]) <= max_storage_vol[storage] + ); + % Неотрицательность объёма. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + 0 <= storage_used_volume[storage, t] + ); + + % Ограничения на граничные значения. + array [0..n_all_storage_sections] of int : initial_storage_vol; + array [0..n_all_storage_sections] of int : final_storage_vol; + + constraint forall (storage in 1..n_all_storage_sections) ( % Initial values. + storage_used_volume[storage, 0] = initial_storage_vol[storage] + ); + + constraint forall (storage in 1..n_all_storage_sections % Final values. + where final_storage_vol[storage] >= 0) ( + storage_used_volume[storage, n_intervals + 1] = final_storage_vol[storage] + ); + + % Изменение грузов в хранилищах. + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of int : cargo_flows; + + int : n_loading_op; + + array [0..n_operations] of int : loading_op_delta_of_main_obj; + array [0..n_operations] of int : loading_op_abs_delta; + array [0..n_operations] of {1, -1} : loading_op_direction; + + array [0..n_operations] of 1..n_all_storage_sections : operations_main_stor; + array [0..n_operations] of 1..n_all_storage_sections : operations_secondary_stor; + array [0..n_operations] of 1..n_cargo_types : operations_cargo_t; + + array [1..n_loading_op] of int : loading_op_delta; + array [1..n_loading_op] of {1, -1} : loading_op_local_direction; + array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций. + + array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations; + array [1..n_moving_obj] of set of 1..n_all_storage_sections : sections_of_moving_obj; + array [1..n_moving_obj] of bool : is_sections_of_moving_obj_empty; + + array [0..n_all_storage_sections] of int : storage_greedy_upper_limit; + array [0..n_all_storage_sections] of int : storage_greedy_lower_limit; + + 0..n_all_storage_sections : n_sections_of_real_storage_and_bunkers; + array [0..n_sections_of_real_storage_and_bunkers] of 0..n_all_storage_sections : number_of_connected_sections; + + 0..n_all_storage_sections : max_number_of_connected_sections; + + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections, 1..(n_intervals + 1)] of var int : nominal_cargo_value; + array [0..n_sections_of_real_storage_and_bunkers, 0..(max_number_of_connected_sections + 1), 1..(n_intervals + 1)] of var int : cargo_overflow_remains; + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections, 1..(n_intervals + 1)] of var int : real_cargo_value; + array [0..n_sections_of_real_storage_and_bunkers, 1..(n_intervals + 1)] of var int : total_sum; + + % Определение real_cargo_value + array [0..n_operations] of 0..n_all_storage_sections : operations_main_stor_no_in_secondary; + array [0..n_operations] of 0..n_all_storage_sections : operations_secondary_stor_no_in_main; + + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections] of set of 1..n_operations : connected_op_to_pair_of_sections; +/* + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections, 1..(n_intervals + 1)] of var int : debug_1; + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1) where operations_main_stor_no_in_secondary[op] != 0) ( + op_status[op, t] -> ( + debug_1[operations_secondary_stor[op], operations_main_stor_no_in_secondary[op], t] = + min(storage_greedy_upper_limit[operations_main_stor[op]] - storage_used_volume[operations_main_stor[op], t - 1], + loading_op_delta_of_main_obj[op]) + ) + ); + + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + section_2 in 1..number_of_connected_sections[section_1], + t in 1..(n_intervals + 1)) ( + (forall (op in connected_op_to_pair_of_sections[section_1, section_2]) (not op_status[op, t])) + -> + (debug_1[section_1, section_2, t] = 0) + ); +*/ + % Определение nominal_cargo_value + % Операция грузообработки активна -> нужные номинальные значения согласованы с ней. + constraint forall (op in 1..n_operations, + t in 1..(n_intervals + 1), + section_1 = operations_main_stor[op], + section_2 = operations_secondary_stor[op], + pos = operations_main_stor_no_in_secondary[op] + 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])) + ) + ); + constraint forall (op in 1..n_operations, + t in 1..(n_intervals + 1), + section_1 = operations_main_stor[op], + section_2 = operations_secondary_stor[op], + pos = operations_main_stor_no_in_secondary[op] + 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])) + ) + ); + constraint forall (op in 1..n_operations, + t in 1..(n_intervals + 1), + section_1 = operations_main_stor[op], + section_2 = operations_secondary_stor[op], + pos = operations_main_stor_no_in_secondary[op] + 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]) + /\ (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 = 0. + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + section_2 in 1..number_of_connected_sections[section_1], + t in 1..(n_intervals + 1)) ( + (forall (op in connected_op_to_pair_of_sections[section_1, section_2]) (not op_status[op, t])) + -> + (nominal_cargo_value[section_1, section_2, t] = 0) + ); + + % Крайние значения. + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + section_2 in (number_of_connected_sections[section_1] + 1)..max_number_of_connected_sections, + t in 1..(n_intervals + 1)) ( + nominal_cargo_value[section_1, section_2, t] = 0 + ); + constraint forall (section_1 in 1..n_sections_of_real_storage_and_bunkers, + t in 1..(n_intervals + 1)) ( + nominal_cargo_value[section_1, 0, t] = 0 + ); + constraint forall (section_2 in 0..max_number_of_connected_sections, + t in 1..(n_intervals + 1)) ( + nominal_cargo_value[0, section_2, t] = 0 + ); + + % Определение cargo_overflow_remains. + % 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]) + ); + 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 (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 (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 (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in 1..number_of_connected_sections[section]) ( + ((((cargo_overflow_remains[section, i + 1, t] < 0) /\ (nominal_cargo_value[section, i, t] < 0)) + \/ + ((cargo_overflow_remains[section, i + 1, t] > 0) /\ (nominal_cargo_value[section, i, t] > 0)) + ) /\ (abs(cargo_overflow_remains[section, i + 1, t]) >= abs(nominal_cargo_value[section, i, t])) + ) -> ( + cargo_overflow_remains[section, i, t] = + cargo_overflow_remains[section, i + 1, t] - + nominal_cargo_value[section, i, t] + ) + ); + + % Иначе оно полностью перекрыло переполнение. + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in 1..number_of_connected_sections[section]) ( + (((cargo_overflow_remains[section, i + 1, t] <= 0) /\ (nominal_cargo_value[section, i, t] >= 0)) + \/ + ((cargo_overflow_remains[section, i + 1, t] >= 0) /\ (nominal_cargo_value[section, i, t] <= 0)) + \/ + (abs(cargo_overflow_remains[section, i + 1, t]) < abs(nominal_cargo_value[section, i, t])) + ) -> ( + cargo_overflow_remains[section, i, t] = 0 + ) + ); + + % Крайние значения. + constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( + cargo_overflow_remains[section, 0, t] = 0 + ); + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in (number_of_connected_sections[section] + 2)..max_number_of_connected_sections) ( + cargo_overflow_remains[section, i, t] = 0 + ); + constraint forall (section_2 in 0..(max_number_of_connected_sections + 1), + t in 1..(n_intervals + 1)) ( + cargo_overflow_remains[0, section_2, t] = 0 + ); + + % Определение real_cargo_value + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in 1..number_of_connected_sections[section]) ( + real_cargo_value[section, i, t] = nominal_cargo_value[section, i, t] + - cargo_overflow_remains[section, i + 1, t] + + cargo_overflow_remains[section, i, t] + ); + % Крайние значения. + constraint forall (t in 1..(n_intervals + 1), section in 1..n_sections_of_real_storage_and_bunkers) ( + real_cargo_value[section, 0, t] = 0 + ); + constraint forall (t in 1..(n_intervals + 1), + section in 1..n_sections_of_real_storage_and_bunkers, + i in (number_of_connected_sections[section] + 1)..max_number_of_connected_sections) ( + real_cargo_value[section, i, t] = 0 + ); + constraint forall (section_2 in 0..max_number_of_connected_sections, + t in 1..(n_intervals + 1)) ( + real_cargo_value[0, section_2, t] = 0 + ); + + array [0..n_all_storage_sections] of set of 1..n_all_storage_sections : all_used_positions_in_real_cargo_value; + array [1..n_all_storage_sections, 1..n_all_storage_sections] of 0..max_number_of_connected_sections : positions_of_connected_sections; + + + constraint forall (storage in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in 1..number_of_connected_sections[storage]) (real_cargo_value[storage, i, t])) + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); + constraint forall (storage in (n_sections_of_real_storage_and_bunkers + 1)..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); + +/* + constraint forall (storage in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( + debug_storage_used_volume[storage, t] = ( + debug_storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in 1..number_of_connected_sections[storage]) (real_cargo_value[storage, i, t])) + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); + + constraint forall (storage in (n_sections_of_real_storage_and_bunkers + 1)..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + debug_storage_used_volume[storage, t] = ( + debug_storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (i in all_used_positions_in_real_cargo_value[storage]) (-real_cargo_value[i, positions_of_connected_sections[storage, i], t])) + ) + ); +*/ + + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of var int : debug_storage_used_volume; + constraint forall (t in 0..(n_intervals + 1)) (debug_storage_used_volume[0, t] = 0); % Фиктивный объект. + + constraint forall (storage in 1..n_all_storage_sections) ( % Initial values. + debug_storage_used_volume[storage, 0] = initial_storage_vol[storage] + ); + +/* + constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + sum (inv_op in involved_operations[storage]) ( + loading_op_delta[inv_op] * + op_status[loading_op_n[inv_op], t] + ) + ) + ); +*/ +% Фиксированные операции. + int : n_fixed_op; + array [1..n_fixed_op] of 1..n_operations : fixed_op; + array [1..n_fixed_op] of set of 1..n_moving_obj : fixed_op_resources; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_start; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_end; % Включительно. + array [1..n_fixed_op] of int : fixed_op_intensity; + + array [0..n_operations, 0..n_intervals] of bool : is_fixed; + array [0..n_moving_obj, 0..(n_intervals + 1)] of bool : is_obj_involved_in_fixed_op; + + constraint forall (no in 1..n_fixed_op, op = fixed_op[no]) ( + forall (t in fixed_op_start[no]..fixed_op_end[no]) ( + (op_status[op, t]) /\ + forall (obj in fixed_op_resources[no]) ( + participation_as_resource[obj, t] = op + ) + ) + ); +/* +% Оптимизация - сдвиг в начало. + % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). + array [0..n_operations, 1..n_intervals] of var bool : is_op_possible; + + constraint forall (t in 1..n_intervals) (is_op_possible[0, t] = false); % Фиктивный объект. + + % Счётчик ресурсов, которые могут быть потенциально задействованы в операции. + array [1..n_resources_counters , 1..n_intervals] of var int : possible_resources_counter; + + % Определение possible_resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + possible_resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + (participation_as_resource[obj, t] = 0) /\ + (current_moving_operation[obj, t] = 0) /\ + (m_obj_loc[obj, t] = operations_resources_start_loc[counter]) + ) + ); + + % Достаточно ли свободных ресурсов для операции. + array [0..n_operations, 1..n_intervals] of var bool : is_enough_free_resources; + + constraint forall (t in 1..n_intervals) (is_enough_free_resources[0, t] = false); % Фиктивный объект. + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_enough_free_resources[op, t] = forall (counter in counters_of_operation[op]) ( + possible_resources_counter[counter, t] >= required_counter_values[counter] + ) + ); + + % Определение is_op_possible. + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_op_possible[op, t] = ( + (bad_weather[op, t] = false) /\ % Погода не мешает. + (m_obj_loc[main_obj_of_operation[op], t] = main_obj_start_loc[op]) + /\ % Главный объект на месте. + (current_moving_operation[main_obj_of_operation[op], t] = 0) + /\ % Главный объект не участвует в операции перемещеня. + (is_enough_free_resources[op, t] = true) /\ % Достаточно свободных ресурсов на нужном месте. + (forall (conf_op in conflicting_operations[op]) (op_status[conf_op, t] = false)) + /\ % Не выполняется ни одной конфликтующей операции. + (is_moving_operation[op] -> not is_involved_in_cargo_op[main_obj_of_operation[op], t]) + /\ % Если это операция перемещения, то главный объект + % не участвует в операциях погрузки. + ((is_mooring_op[op] /\ (operations_destination[op] mod 2 = 0)) -> ( + current_moored_obj[operations_destination[op], t] = 0) + ) /\ % Если это операция пришвартовки, то в этот интервал + % причал должен быть свободным. + ((not is_moving_operation[op]) -> ( + let {1..n_all_storage_sections : m_stor = operations_main_stor[op]; + 1..n_all_storage_sections : s_stor = operations_secondary_stor[op]; + int : delta = loading_op_delta_of_main_obj[op]; + } in + (storage_used_volume[m_stor, t] + delta >= 0) /\ + (storage_used_volume[m_stor, t] + delta <= max_storage_vol[m_stor]) /\ + (storage_used_volume[s_stor, t] - delta >= 0) /\ + (storage_used_volume[s_stor, t] - delta <= max_storage_vol[s_stor]) + )) /\ % Если это операция грузообработки, то она не выведет + % объём берегового хранилища и хранилища судна за + % границы дозволенного. + (((not is_moving_operation[op]) /\ (main_obj_start_loc[op] mod 2 = 1)) -> + ((current_moored_obj[twin_location[main_obj_start_loc[op]], t] = 0) \/ + (current_moored_obj[twin_location[main_obj_start_loc[op]], t] = main_obj_of_operation[op])) + ) /\ % Если это операция грузообработки без пришвартовки, + % то причал должен быть свободен в этот интервал, либо + % главный объект должен быть уже условно пришвартован. + (((bunker_of_cargo_op[op] != 0) /\ (op_status[op, t])) -> + ((m_obj_loc[bunker_of_cargo_op[op], t] = bunker_start_loc[op]) /\ + (current_moving_operation[bunker_of_cargo_op[op], t] = 0)) + ) % Бункеровщик (если есть) находится в нужной локации + % и не участвует в операциях перемещения. + ) + ); + + % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. + constraint forall (op in 1..n_operations, t in 2..n_intervals) ( + (op_start[op, t] /\ (not is_fixed[op, t])) -> not is_op_possible[op, t - 1] + ); +*/ + +% Для оптимизаций. + array [1..n_all_storage_sections, 1..n_locations] of int : min_positive_cargo_val; % Объём максимальной положительной операции, которая может быть произведена с этой секцией в этом хранилище. Если в локации таковой нет, то это значение объёма хранилища + 1. + array [1..n_all_storage_sections, 1..n_locations] of int : max_negative_cargo_val; + + 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; + +% Критерий оптимизации + array [1..(n_intervals + 1)] of var bool : is_not_terminated; + % В конце всё остановится. + constraint (is_not_terminated[n_intervals + 1] == false); + + % Действия ещё не остановились, если в текущий интервал что-нибудь происходит или они не остановятся в следующий интервал. + constraint forall (t in 1..n_intervals) ( + is_not_terminated[t] == ( + (exists (op in 1..n_operations) (op_status[op, t])) + \/ + is_not_terminated[t + 1] + ) + ); + + solve minimize sum(is_not_terminated); + +output [show(sum(is_not_terminated)), "\n", + "op_status = ", show(op_status), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "op_start = ", show(op_start), "\n\n", + "is_not_terminated = ", show(is_not_terminated), "\n\n", + "storage_used_volume = ", show(storage_used_volume), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "current_moving_operation = ", show(current_moving_operation), "\n\n", + "resources_counter {", show(n_intervals), "} = ", show(resources_counter), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "participation_as_resource = ", show(participation_as_resource), "\n\n", + + "is_involved_in_cargo_op = {", show(n_intervals), "} ", show(is_involved_in_cargo_op), "\n\n", + + "current_moored_obj = ", show(current_moored_obj), "\n\n", + + "nominal_cargo_value {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(nominal_cargo_value), "\n\n", + "cargo_overflow_remains {", show(max_number_of_connected_sections + 2), " ", show(n_intervals + 1), "} = ", show(cargo_overflow_remains), "\n\n", + "real_cargo_value {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(real_cargo_value), "\n\n", + + % "debug_1 {", show(max_number_of_connected_sections + 1), " ", show(n_intervals + 1), "} = ", show(debug_1), "\n\n", + + + % "debug_storage_used_volume = ", show(debug_storage_used_volume), "\n\n", + + "total_sum {", show(n_intervals + 1), "} = ", show(total_sum), "\n\n", + + +/* + "is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n", + "debug_1 {", show(n_intervals), "} = ", show(debug_1), "\n\n", + "is_enough_free_resources {", show(n_intervals), "} = ", show(is_enough_free_resources), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "possible_resources_counter {", show(n_intervals), "} = ", show(possible_resources_counter), "\n\n", +*/ + ""]; diff --git a/src/constraints/conversion_2_greedy_v2.mzn b/src/constraints/conversion_2_greedy_v2.mzn new file mode 100644 index 0000000000000000000000000000000000000000..23db4cac5455681110fc03676f03a82395229983 --- /dev/null +++ b/src/constraints/conversion_2_greedy_v2.mzn @@ -0,0 +1,686 @@ +include "globals.mzn"; + +int : n_intervals; +int : n_operations; +int : n_locations; +int : n_moving_obj; + +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_status; +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_start; + +constraint forall (t in 0..(n_intervals + 1)) (op_status[0, t] = false); % Фиктивная операция. +constraint forall (t in 0..(n_intervals + 1)) ( op_start[0, t] = false); % Фиктивная операция. + +array [0..n_moving_obj, 0..n_operations] of bool : moving_op_of_obj; + +% Определение current_moving_operation. + % Текущая операция операция перемещения, в которой задействован данный объект. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : current_moving_operation; + + constraint forall (t in 0..(n_intervals + 1)) (current_moving_operation[0, t] = 0); % Фиктивный объект. + + % Крайние значения. + constraint forall (obj in 1..n_moving_obj, t in {0, n_intervals + 1}) ( + current_moving_operation[obj, t] = 0 + ); + + % Текущая операция лежит в множестве тех, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> moving_op_of_obj[obj, current_moving_operation[obj, t]] + ); + % Если операция, затрагивающая данный объект в качестве главного, выполняется - то именно она текущая операция перемещения для этого объекта. + constraint forall (op in 1..n_operations, t in 1..n_intervals where is_moving_operation[op]) ( + op_status[op, t] -> (current_moving_operation[main_obj_of_operation[op], t] = op) + ); + % Связь current_moving_operation c op_status. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> (op_status[current_moving_operation[obj, t], t]) + ); + +% Определение current_moored_obj. + % Объект, пришвартованный к данной локации. + array [0..n_locations, 0..(n_intervals + 1)] of var 0..n_moving_obj : current_moored_obj; + + constraint forall (t in 0..(n_intervals + 1)) (current_moored_obj[0, t] = 0); % Фиктивная локация. + + % Фиксирование неиспользуемых значений. + constraint forall (loc in 1..n_locations, t in 0..(n_intervals + 1) where loc mod 2 = 1) ( + current_moored_obj[loc, t] = 0 + ); + + % Крайние значения. + constraint forall (loc in 1..n_locations, t in {0, n_intervals + 1}) ( + current_moored_obj[loc, t] = 0 + ); + + % Операции с условной швартовкой. + int : op_with_nominally_mooring_max_size; + array [0..n_locations, 0..n_moving_obj] of 0..op_with_nominally_mooring_max_size : op_with_nominally_mooring_sizes; + array [0..n_locations, 0..n_moving_obj, 1..op_with_nominally_mooring_max_size] of 1..n_operations : op_with_nominally_mooring; + + % current_moored_obj соответствуе какому-либо реально пришвартованному объекту. + constraint forall (loc in 1..n_locations, t in 1..n_intervals, obj = current_moored_obj[loc, t] + where loc mod 2 = 0) ( + (obj != 0) -> ((m_obj_loc[obj, t] = loc) \/ + (exists (op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]]) + (op_status[op, t])) + ) + ); + + % Если объект пришвартован или швартуется, то current_moored_obj об это знает. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals, loc = m_obj_loc[obj, t]) ( + (loc mod 2 = 0) -> (current_moored_obj[loc, t] = obj) + ); + + % Если выполняется операция, где судно условно пришвартовано, то current_moored_obj знает об этом. + constraint forall (loc in 1..n_locations, + obj in 1..n_moving_obj, + op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]], + t in 1..n_intervals) ( + op_status[op, t] -> (current_moored_obj[loc, t] = obj) + ); + +array [1..n_locations] of 0..n_locations : twin_location = [i - 1 + (i mod 2) * 2 | i in 1..n_locations]; + +array [0..n_operations] of 0..n_locations : operations_destination; % Локация в которой окажется объект после завершения операции. + +% Определение m_obj_loc. + % Местоположение объекта или пункт назначения (если объект движется) перед началом определённого интервала. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_locations : m_obj_loc; + + constraint forall (t in 0..(n_intervals + 1)) (m_obj_loc[0, t] = 0); % Фиктивный объект. + + % Главный объект (субъект) операции. + array [0..n_operations] of 0..n_moving_obj : main_obj_of_operation; + + % Является ли операция швартовкой/отшвартовкой. + array [0..n_operations] of bool : is_mooring_op; + + % За фиктивный нулевой интервал объект не успевает ничего сделать с начальным положением. + constraint forall (obj in 1..n_moving_obj) ( + m_obj_loc[obj, 1] = m_obj_loc[obj, 0] + ); + + % Направление движения/местоположение объекта может измениться только если перед этим началась операция перемещения, и он не вспомогательный при операции швартовки. + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] != current_moving_operation[obj, t - 2]) /\ + (current_moving_operation[obj, t - 1] != 0) /\ + ((obj = main_obj_of_operation[current_moving_operation[obj, t - 1]]) + \/ + (not is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = operations_destination[current_moving_operation[obj, t - 1]]) + ); + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] = current_moving_operation[obj, t - 2]) \/ + (current_moving_operation[obj, t - 1] = 0) \/ + ((obj != main_obj_of_operation[current_moving_operation[obj, t - 1]]) + /\ + ( is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) + ); + +% Начальное состояние. + array [0..n_moving_obj] of 0..n_locations : initial_m_obj_loc; + constraint forall (i in 1..n_moving_obj) (m_obj_loc[i, 0] = initial_m_obj_loc[i]); + +% Конечное состояние. + array [0..n_moving_obj] of 0..n_locations : final_m_obj_loc; + constraint forall (i in 1..n_moving_obj) ( + (final_m_obj_loc[i] != 0) -> + (m_obj_loc[i, n_intervals + 1] = final_m_obj_loc[i]) + ); + +% Определение op_status, op_start. + constraint forall (i in 1..n_operations, j in {0, n_intervals + 1}) (op_status[i, j] == 0); % Краевые значения. + + constraint forall (op in 1..n_operations, j in {0, n_intervals + 1}) (op_start[op, j] = false); + constraint forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] = (op_status[i, j] /\ not op_status[i, j - 1])); + +% Связь ресурсов с операцией и основным объектом. + % Операции, которые могут задействовать данный объект как ресурс. + array [0..n_moving_obj] of set of 1..n_operations : operations_that_used_obj_as_resource; + + % Является ли данная операция операцией перемещения. + array [0..n_operations] of bool : is_moving_operation; + + % Операция, в которой участвует данный объект как ресурс. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : participation_as_resource; + + constraint forall (t in 0..(n_intervals + 1)) (participation_as_resource[0, t] = 0); % Фиктивный объект. + + % Граничные значения. + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, 0] = 0); + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, n_intervals + 1] = 0); + + % Только те операции, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) + -> participation_as_resource[obj, t] in operations_that_used_obj_as_resource[obj] + ); + + % Связь с текущими операциями перемещения. + % Если объект задействован в операции перемещения, которая использует его как ресурс, + % то participation_as_resource должен указывать на эту операцию. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] in operations_that_used_obj_as_resource[obj]) + -> + (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + % Если объект участвует как ресурс в операции перемещения, то это согласованно с current_moving_operation. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + ((participation_as_resource[obj, t] != 0) /\ + (is_moving_operation[participation_as_resource[obj, t]]) + ) -> (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + + % { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) -> op_status[participation_as_resource[obj, t], t] + ); + + % От начала операции и до конца её ресурсы не могут измениться (в том числе и для погрузки). + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals - 1)) ( + ((participation_as_resource[obj, t] != 0) /\ + (op_status[participation_as_resource[obj, t], t + 1]) + ) -> (participation_as_resource[obj, t + 1] = participation_as_resource[obj, t]) + ); + + int : n_resources_types; % Количество различных типов ресурсов. + array [1..n_resources_types] of set of 1..n_moving_obj : objects_of_type; % Все объекты конкретного типа. + + int : n_resources_counters; % Количество счётчиков ресурсов. + % Счётчик ресурсов. + array [1..n_resources_counters , 1..n_intervals] of var int : resources_counter; + array [1..n_resources_counters] of 1..n_resources_types : counter_type; % Типы ресурсов, за которыми следят счётчики. + array [1..n_resources_counters] of 1..n_operations : operation_of_counter; % Операция, которой принадлежит данный счётчик. + array [1..n_resources_counters] of int : required_counter_values; % Необходимые значения на счётчиках ресурсов для выполнения операции. + array [0..n_operations] of set of 1..n_resources_counters : counters_of_operation; % Счётчики, которые относятся к данной операции. + + % Участие всех необходимых ресурсов в операции. + constraint forall (t in 1..n_intervals, op in 1..n_operations, counter in counters_of_operation[op]) ( + op_status[op, t] -> (resources_counter[counter, t] = required_counter_values[counter]) + ); + + % Определение resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + participation_as_resource[obj, t] = operation_of_counter[counter] + ) + ); + +% Участие объекта в операциях грузообработки. + array [0..n_moving_obj, 1..n_intervals] of var bool : is_involved_in_cargo_op; + + constraint forall (t in 1..n_intervals) (is_involved_in_cargo_op[0, t] = false); % Фиктивный объект. + + % Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. + 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] = ( + (exists (op in related_cargo_op[obj]) (op_status[op, t])) + \/ + ((participation_as_resource[obj, t] != 0) /\ (not is_moving_operation[participation_as_resource[obj, t]])) + ) + ); + % Операции перемещения исключают операции грузообработки и наоборот. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + is_involved_in_cargo_op[obj, t] -> (current_moving_operation[obj, t] = 0) + ); + +% Наличие всех объектов на месте во время начала операции перемещения + готовность к началу. + % Требуемое положение конкретных типов объектов в момент начала операций. + array [1..n_resources_counters] of 1..n_locations : operations_resources_start_loc; + + % Наличие на месте всех ресурсов. + constraint forall ( + op in 1..n_operations, + t in 1..n_intervals, + counter in counters_of_operation[op], + obj in objects_of_type[counter_type[counter]]) ( + ((participation_as_resource[obj, t] = op) /\ (op_start[op, t]) + ) -> (m_obj_loc[obj, t] == operations_resources_start_loc[counter]) + ); + + % Требуемое положение главного объекта в момент начала операций. + array [0..n_operations] of 0..n_locations : main_obj_start_loc; + % Требуемое положение бункеровщика в момент начала операции. + array [0..n_operations] of 0..n_locations : bunker_start_loc; + + % Бункеровщик, участвующий в операции погрузки (0, если такогого нет или это не погрузка). + array [0..n_operations] of 0..n_moving_obj : bunker_of_cargo_op; + + % Наличие главных объектов на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = main_obj_of_operation[op]) ( + op_start[op, t] -> (m_obj_loc[obj, t] == main_obj_start_loc[op]) + ); + + % Наличие бункеровщиков на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = bunker_of_cargo_op[op] where obj != 0) ( + op_start[op, t] -> (m_obj_loc[obj, t] == bunker_start_loc[op]) + ); + +% Непрерывность перемещения и швартовки. + array [0..n_operations] of int : operations_duration; + array [0..n_operations] of bool : is_continuous_operation; + + constraint forall (i in 1..n_operations, len = operations_duration[i] where is_continuous_operation[i]) ( + (forall (j in 1..(n_intervals - len + 1)) ( + (op_start[i, j] == 1) -> ( + (forall (k in 1..(len - 1)) (op_status[i, j + k])) + /\ + (not op_status[i, j + len]) + ) + )) /\ + (forall (j in (n_intervals - len + 2)..(n_intervals + 1)) (op_start[i, j] == false)) + ); + +% Конфликтующие операции. + array [0..n_operations] of set of 1..n_operations : conflicting_operations; + + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1), conf_op in conflicting_operations[op]) ( + op_status[op, t] -> not op_status[conf_op, t] + ); + +% Окна непогоды. + array [0..n_operations, 0..n_intervals] of bool : bad_weather; + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + bad_weather[op, t] -> (op_status[op, t] = false) + ); + +% Грузообработка. + int : n_cargo_types; + int : n_all_storage_sections; + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of var int : storage_used_volume; + + constraint forall (t in 0..(n_intervals + 1)) (storage_used_volume[0, t] = 0); % Фиктивный объект. + + % Ограничения на вместимость. + array [0..n_all_storage_sections] of int : max_storage_vol; + % Максимальный объём. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + (storage_used_volume[storage, t]) <= max_storage_vol[storage] + ); + % Неотрицательность объёма. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + 0 <= storage_used_volume[storage, t] + ); + + % Ограничения на граничные значения. + array [0..n_all_storage_sections] of int : initial_storage_vol; + array [0..n_all_storage_sections] of int : final_storage_vol; + + constraint forall (storage in 1..n_all_storage_sections) ( % Initial values. + storage_used_volume[storage, 0] = initial_storage_vol[storage] + ); + + constraint forall (storage in 1..n_all_storage_sections % Final values. + where final_storage_vol[storage] >= 0) ( + storage_used_volume[storage, n_intervals + 1] = final_storage_vol[storage] + ); + + % Изменение грузов в хранилищах. + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of int : cargo_flows; + + int : n_loading_op; + + array [0..n_operations] of int : loading_op_delta_of_main_obj; + array [0..n_operations] of int : loading_op_abs_delta; + array [0..n_operations] of {1, -1} : loading_op_direction; + + array [0..n_operations] of 1..n_all_storage_sections : operations_main_stor; + array [0..n_operations] of 1..n_all_storage_sections : operations_secondary_stor; + array [0..n_operations] of 1..n_cargo_types : operations_cargo_t; + + array [1..n_loading_op] of int : loading_op_delta; + array [1..n_loading_op] of {1, -1} : loading_op_local_direction; + array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций. + + array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations; + array [1..n_all_storage_sections] of set of 1..n_operations : involved_operations_as_main_stor; + array [1..n_all_storage_sections] of set of 1..n_operations : involved_operations_as_sec_stor; + + array [1..n_moving_obj] of set of 1..n_all_storage_sections : sections_of_moving_obj; + array [1..n_moving_obj] of bool : is_sections_of_moving_obj_empty; + + array [0..n_all_storage_sections] of int : storage_greedy_upper_limit; + array [0..n_all_storage_sections] of int : storage_greedy_lower_limit; + + 0..n_all_storage_sections : n_sections_of_real_storage_and_bunkers; + array [0..n_sections_of_real_storage_and_bunkers] of 0..n_all_storage_sections : number_of_connected_sections; + + 0..n_all_storage_sections : max_number_of_connected_sections; + + array [0..n_operations, 0..(n_intervals + 1)] of var int : nominal_cargo_value; + array [0..n_sections_of_real_storage_and_bunkers, 0..(n_intervals + 1)] of var int : nominal_incoming_sum; + array [0..n_operations, 0..(n_intervals + 1)] of var int : real_cargo_value; + + % Использует ли эта операция секцию как хранилище при погрузке или как бункеровщик при бункеровке. + array [0..n_sections_of_real_storage_and_bunkers, 0..n_operations] of bool : is_op_used_stor_as_secondary; + + 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] + ); + constraint forall (t in 1..(n_intervals + 1)) (current_partial_cargo_op[0, t] = 0); + + % Определение nominal_incoming_sum - номинальный объём груза, который суда вливают в хранилище. + constraint forall (section in 1..n_sections_of_real_storage_and_bunkers, t in 1..(n_intervals + 1)) ( + nominal_incoming_sum[section, t] = sum (op in involved_operations_as_sec_stor[section]) (nominal_cargo_value[op, t]) + ); + constraint forall (t in 0..(n_intervals + 1)) (nominal_incoming_sum[0, t] = 0); + constraint forall (section in 1..n_sections_of_real_storage_and_bunkers) (nominal_incoming_sum[section, 0] = 0); + + % Определение real_cargo_value + array [0..n_operations] of 0..n_all_storage_sections : operations_main_stor_no_in_secondary; + array [0..n_operations] of 0..n_all_storage_sections : operations_secondary_stor_no_in_main; + + array [0..n_sections_of_real_storage_and_bunkers, 0..max_number_of_connected_sections] of set of 1..n_operations : connected_op_to_pair_of_sections; + + % Определение nominal_cargo_value + % Операция грузообработки активна -> нужные номинальные значения согласованы с ней. + constraint forall (op in 1..n_operations, + t in 1..(n_intervals + 1), + section_1 = operations_main_stor[op], + section_2 = operations_secondary_stor[op], + pos = operations_main_stor_no_in_secondary[op] + 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[op, t] = -(loading_op_delta_of_main_obj[op] - (total_vol - storage_greedy_upper_limit[section_1])) + ) + ); + constraint forall (op in 1..n_operations, + t in 1..(n_intervals + 1), + section_1 = operations_main_stor[op], + section_2 = operations_secondary_stor[op], + pos = operations_main_stor_no_in_secondary[op] + 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[op, t] = -(loading_op_delta_of_main_obj[op] - (total_vol - storage_greedy_lower_limit[section_1])) + ) + ); + constraint forall (op in 1..n_operations, + t in 1..(n_intervals + 1), + section_1 = operations_main_stor[op], + section_2 = operations_secondary_stor[op], + pos = operations_main_stor_no_in_secondary[op] + 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]) + /\ (total_vol <= storage_greedy_upper_limit[section_1])) -> ( + nominal_cargo_value[op, t] = -loading_op_delta_of_main_obj[op] + ) + ); + + % Если опреация не активна, то 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 (t in 0..(n_intervals + 1)) (nominal_cargo_value[0, t] = 0); + constraint forall (op in 1..n_operations) (nominal_cargo_value[op, 0] = 0); + + % Обнулим current_partial_cargo_op для операций перемещения. + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1) where is_moving_operation[op]) ( + nominal_cargo_value[op, t] = 0 + ); + + % Определение real_cargo_value + constraint forall (op in 1..n_operations, t in 1..(n_intervals + 1)) ( % Целая операция. + (current_partial_cargo_op[operations_secondary_stor[op], t] != op) -> + (real_cargo_value[op, t] = nominal_cargo_value[op, 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] = storage_greedy_lower_limit[section] - ( + nominal_incoming_sum[section, t] + storage_used_volume[section, t - 1] - nominal_cargo_value[op, 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_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 (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 (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 (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 0..(n_intervals + 1)) (real_cargo_value[0, t] = 0); + constraint forall (op in 1..n_operations) (real_cargo_value[op, 0] = 0); + + array [0..n_all_storage_sections] of set of 1..n_all_storage_sections : all_used_positions_in_real_cargo_value; + array [1..n_all_storage_sections, 1..n_all_storage_sections] of 0..max_number_of_connected_sections : positions_of_connected_sections; + + + constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + (sum (op in involved_operations_as_sec_stor[storage]) ( real_cargo_value[op, t])) + + (sum (op in involved_operations_as_main_stor[storage]) (-real_cargo_value[op, t])) + ) + ); + +/* + constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + sum (inv_op in involved_operations[storage]) ( + loading_op_delta[inv_op] * + op_status[loading_op_n[inv_op], t] + ) + ) + ); +*/ +% Фиксированные операции. + int : n_fixed_op; + array [1..n_fixed_op] of 1..n_operations : fixed_op; + array [1..n_fixed_op] of set of 1..n_moving_obj : fixed_op_resources; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_start; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_end; % Включительно. + array [1..n_fixed_op] of int : fixed_op_intensity; + + array [0..n_operations, 0..n_intervals] of bool : is_fixed; + array [0..n_moving_obj, 0..(n_intervals + 1)] of bool : is_obj_involved_in_fixed_op; + + constraint forall (no in 1..n_fixed_op, op = fixed_op[no]) ( + forall (t in fixed_op_start[no]..fixed_op_end[no]) ( + (op_status[op, t]) + /\ (forall (obj in fixed_op_resources[no]) (participation_as_resource[obj, t] = op)) + /\ (real_cargo_value[op, t] = -fixed_op_intensity[no]) + ) + ); + +% Оптимизация - сдвиг в начало. + % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). + array [0..n_operations, 1..n_intervals] of var bool : is_op_possible; + + constraint forall (t in 1..n_intervals) (is_op_possible[0, t] = false); % Фиктивный объект. + + % Счётчик ресурсов, которые могут быть потенциально задействованы в операции. + array [1..n_resources_counters , 1..n_intervals] of var int : possible_resources_counter; + + % Определение possible_resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + possible_resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + (participation_as_resource[obj, t] = 0) /\ + (current_moving_operation[obj, t] = 0) /\ + (m_obj_loc[obj, t] = operations_resources_start_loc[counter]) + ) + ); + + % Достаточно ли свободных ресурсов для операции. + array [0..n_operations, 1..n_intervals] of var bool : is_enough_free_resources; + + constraint forall (t in 1..n_intervals) (is_enough_free_resources[0, t] = false); % Фиктивный объект. + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_enough_free_resources[op, t] = forall (counter in counters_of_operation[op]) ( + possible_resources_counter[counter, t] >= required_counter_values[counter] + ) + ); + + % Определение is_op_possible. + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_op_possible[op, t] = ( + (bad_weather[op, t] = false) /\ % Погода не мешает. + (m_obj_loc[main_obj_of_operation[op], t] = main_obj_start_loc[op]) + /\ % Главный объект на месте. + (current_moving_operation[main_obj_of_operation[op], t] = 0) + /\ % Главный объект не участвует в операции перемещеня. + (is_enough_free_resources[op, t] = true) /\ % Достаточно свободных ресурсов на нужном месте. + (forall (conf_op in conflicting_operations[op]) (op_status[conf_op, t] = false)) + /\ % Не выполняется ни одной конфликтующей операции. + (is_moving_operation[op] -> not is_involved_in_cargo_op[main_obj_of_operation[op], t]) + /\ % Если это операция перемещения, то главный объект + % не участвует в операциях погрузки. + ((is_mooring_op[op] /\ (operations_destination[op] mod 2 = 0)) -> ( + current_moored_obj[operations_destination[op], t] = 0) + ) /\ % Если это операция пришвартовки, то в этот интервал + % причал должен быть свободным. + ((not is_moving_operation[op]) -> ( + let {1..n_all_storage_sections : m_stor = operations_main_stor[op]; + 1..n_all_storage_sections : s_stor = operations_secondary_stor[op]; + int : delta = loading_op_direction[op]; + } in + (storage_used_volume[m_stor, t] + delta >= storage_greedy_lower_limit[m_stor]) /\ + (storage_used_volume[m_stor, t] + delta <= storage_greedy_upper_limit[m_stor]) /\ + (storage_used_volume[s_stor, t] - delta >= storage_greedy_lower_limit[s_stor]) /\ + (storage_used_volume[s_stor, t] - delta <= storage_greedy_upper_limit[s_stor]) + )) /\ % Если это операция грузообработки, то она не выведет + % объём берегового хранилища и хранилища судна за + % границы дозволенного. + (((not is_moving_operation[op]) /\ (main_obj_start_loc[op] mod 2 = 1)) -> + ((current_moored_obj[twin_location[main_obj_start_loc[op]], t] = 0) \/ + (current_moored_obj[twin_location[main_obj_start_loc[op]], t] = main_obj_of_operation[op])) + ) /\ % Если это операция грузообработки без пришвартовки, + % то причал должен быть свободен в этот интервал, либо + % главный объект должен быть уже условно пришвартован. + (((bunker_of_cargo_op[op] != 0) /\ (op_status[op, t])) -> + ((m_obj_loc[bunker_of_cargo_op[op], t] = bunker_start_loc[op]) /\ + (current_moving_operation[bunker_of_cargo_op[op], t] = 0)) + ) % Бункеровщик (если есть) находится в нужной локации + % и не участвует в операциях перемещения. + ) + ); + + % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. + constraint forall (op in 1..n_operations, t in 2..n_intervals) ( + (op_start[op, t] /\ (not is_fixed[op, t])) -> not is_op_possible[op, t - 1] + ); + +% Для оптимизаций. + array [1..n_all_storage_sections, 1..n_locations] of int : min_positive_cargo_val; % Объём максимальной положительной операции, которая может быть произведена с этой секцией в этом хранилище. Если в локации таковой нет, то это значение объёма хранилища + 1. + array [1..n_all_storage_sections, 1..n_locations] of int : max_negative_cargo_val; + + 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; + +% Критерий оптимизации + array [1..(n_intervals + 1)] of var bool : is_not_terminated; + % В конце всё остановится. + constraint (is_not_terminated[n_intervals + 1] == false); + + % Действия ещё не остановились, если в текущий интервал что-нибудь происходит или они не остановятся в следующий интервал. + constraint forall (t in 1..n_intervals) ( + is_not_terminated[t] == ( + (exists (op in 1..n_operations) (op_status[op, t])) + \/ + is_not_terminated[t + 1] + ) + ); + + solve minimize sum(is_not_terminated); + +output [show(sum(is_not_terminated)), "\n", + "op_status = ", show(op_status), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "op_start = ", show(op_start), "\n\n", + "is_not_terminated = ", show(is_not_terminated), "\n\n", + "storage_used_volume = ", show(storage_used_volume), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "current_moving_operation = ", show(current_moving_operation), "\n\n", + "resources_counter {", show(n_intervals), "} = ", show(resources_counter), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "participation_as_resource = ", show(participation_as_resource), "\n\n", + + "is_involved_in_cargo_op = {", show(n_intervals), "} ", show(is_involved_in_cargo_op), "\n\n", + + "current_moored_obj = ", show(current_moored_obj), "\n\n", + + "nominal_cargo_value {", show(n_intervals + 2), "} = ", show(nominal_cargo_value), "\n\n", + "nominal_incoming_sum {", show(n_intervals + 2), "} = ", show(nominal_incoming_sum), "\n\n", + "real_cargo_value {", show(n_intervals + 2), "} = ", show(real_cargo_value), "\n\n", + "current_partial_cargo_op {", show(n_intervals + 1), "} = ", show(current_partial_cargo_op), "\n\n", + +/* + "is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n", + "debug_1 {", show(n_intervals), "} = ", show(debug_1), "\n\n", + "is_enough_free_resources {", show(n_intervals), "} = ", show(is_enough_free_resources), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "possible_resources_counter {", show(n_intervals), "} = ", show(possible_resources_counter), "\n\n", +*/ + ""]; diff --git a/src/constraints/conversion_2_with_partial_cargo_operations.mzn b/src/constraints/conversion_2_with_partial_cargo_operations.mzn new file mode 100644 index 0000000000000000000000000000000000000000..9c86594df798524ed0b138e7e1586fb040264e68 --- /dev/null +++ b/src/constraints/conversion_2_with_partial_cargo_operations.mzn @@ -0,0 +1,535 @@ +include "globals.mzn"; + +int : n_intervals; +int : n_operations; +int : n_locations; +int : n_moving_obj; + +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_status; +array [0..n_operations, 0..(n_intervals + 1)] of var bool : op_start; + +constraint forall (t in 0..(n_intervals + 1)) (op_status[0, t] = false); % Фиктивная операция. +constraint forall (t in 0..(n_intervals + 1)) ( op_start[0, t] = false); % Фиктивная операция. + +array [0..n_moving_obj, 0..n_operations] of bool : moving_op_of_obj; + +% Определение current_moving_operation. + % Текущая операция операция перемещения, в которой задействован данный объект. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : current_moving_operation; + + constraint forall (t in 0..(n_intervals + 1)) (current_moving_operation[0, t] = 0); % Фиктивный объект. + + % Крайние значения. + constraint forall (obj in 1..n_moving_obj, t in {0, n_intervals + 1}) ( + current_moving_operation[obj, t] = 0 + ); + + % Текущая операция лежит в множестве тех, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> moving_op_of_obj[obj, current_moving_operation[obj, t]] + ); + % Если операция, затрагивающая данный объект в качестве главного, выполняется - то именно она текущая операция перемещения для этого объекта. + constraint forall (op in 1..n_operations, t in 1..n_intervals where is_moving_operation[op]) ( + op_status[op, t] -> (current_moving_operation[main_obj_of_operation[op], t] = op) + ); + % Связь current_moving_operation c op_status. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] != 0) -> (op_status[current_moving_operation[obj, t], t]) + ); + +% Определение current_moored_obj. + % Объект, пришвартованный к данной локации. + array [0..n_locations, 0..(n_intervals + 1)] of var 0..n_moving_obj : current_moored_obj; + + constraint forall (t in 0..(n_intervals + 1)) (current_moored_obj[0, t] = 0); % Фиктивная локация. + + % Фиксирование неиспользуемых значений. + constraint forall (loc in 1..n_locations, t in 0..(n_intervals + 1) where loc mod 2 = 1) ( + current_moored_obj[loc, t] = 0 + ); + + % Крайние значения. + constraint forall (loc in 1..n_locations, t in {0, n_intervals + 1}) ( + current_moored_obj[loc, t] = 0 + ); + + % Операции с условной швартовкой. + int : op_with_nominally_mooring_max_size; + array [0..n_locations, 0..n_moving_obj] of 0..op_with_nominally_mooring_max_size : op_with_nominally_mooring_sizes; + array [0..n_locations, 0..n_moving_obj, 1..op_with_nominally_mooring_max_size] of 1..n_operations : op_with_nominally_mooring; + + % current_moored_obj соответствуе какому-либо реально пришвартованному объекту. + constraint forall (loc in 1..n_locations, t in 1..n_intervals, obj = current_moored_obj[loc, t] + where loc mod 2 = 0) ( + (obj != 0) -> ((m_obj_loc[obj, t] = loc) \/ + (exists (op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]]) + (op_status[op, t])) + ) + ); + + % Если объект пришвартован или швартуется, то current_moored_obj об это знает. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals, loc = m_obj_loc[obj, t]) ( + (loc mod 2 = 0) -> (current_moored_obj[loc, t] = obj) + ); + + % Если выполняется операция, где судно условно пришвартовано, то current_moored_obj знает об этом. + constraint forall (loc in 1..n_locations, + obj in 1..n_moving_obj, + op in [op_with_nominally_mooring[loc, obj, id] | id in 1..op_with_nominally_mooring_sizes[loc, obj]], + t in 1..n_intervals) ( + op_status[op, t] -> (current_moored_obj[loc, t] = obj) + ); + +array [1..n_locations] of 0..n_locations : twin_location = [i - 1 + (i mod 2) * 2 | i in 1..n_locations]; + +array [0..n_operations] of 0..n_locations : operations_destination; % Локация в которой окажется объект после завершения операции. + +% Определение m_obj_loc. + % Местоположение объекта или пункт назначения (если объект движется) перед началом определённого интервала. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_locations : m_obj_loc; + + constraint forall (t in 0..(n_intervals + 1)) (m_obj_loc[0, t] = 0); % Фиктивный объект. + + % Главный объект (субъект) операции. + array [0..n_operations] of 0..n_moving_obj : main_obj_of_operation; + + % Является ли операция швартовкой/отшвартовкой. + array [0..n_operations] of bool : is_mooring_op; + + % За фиктивный нулевой интервал объект не успевает ничего сделать с начальным положением. + constraint forall (obj in 1..n_moving_obj) ( + m_obj_loc[obj, 1] = m_obj_loc[obj, 0] + ); + + % Направление движения/местоположение объекта может измениться только если перед этим началась операция перемещения, и он не вспомогательный при операции швартовки. + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] != current_moving_operation[obj, t - 2]) /\ + (current_moving_operation[obj, t - 1] != 0) /\ + ((obj = main_obj_of_operation[current_moving_operation[obj, t - 1]]) + \/ + (not is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = operations_destination[current_moving_operation[obj, t - 1]]) + ); + constraint forall (obj in 1..n_moving_obj, t in 2..(n_intervals + 1)) ( + ((current_moving_operation[obj, t - 1] = current_moving_operation[obj, t - 2]) \/ + (current_moving_operation[obj, t - 1] = 0) \/ + ((obj != main_obj_of_operation[current_moving_operation[obj, t - 1]]) + /\ + ( is_mooring_op[current_moving_operation[obj, t - 1]]) + ) + ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) + ); + +% Начальное состояние. + array [0..n_moving_obj] of 0..n_locations : initial_m_obj_loc; + constraint forall (i in 1..n_moving_obj) (m_obj_loc[i, 0] = initial_m_obj_loc[i]); + +% Конечное состояние. + array [0..n_moving_obj] of 0..n_locations : final_m_obj_loc; + constraint forall (i in 1..n_moving_obj) ( + (final_m_obj_loc[i] != 0) -> + (m_obj_loc[i, n_intervals + 1] = final_m_obj_loc[i]) + ); + +% Определение op_status, op_start. + constraint forall (i in 1..n_operations, j in {0, n_intervals + 1}) (op_status[i, j] == 0); % Краевые значения. + + constraint forall (op in 1..n_operations, j in {0, n_intervals + 1}) (op_start[op, j] = false); + constraint forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] = (op_status[i, j] /\ not op_status[i, j - 1])); + +% Связь ресурсов с операцией и основным объектом. + % Операции, которые могут задействовать данный объект как ресурс. + array [0..n_moving_obj] of set of 1..n_operations : operations_that_used_obj_as_resource; + + % Является ли данная операция операцией перемещения. + array [0..n_operations] of bool : is_moving_operation; + + % Операция, в которой участвует данный объект как ресурс. + array [0..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : participation_as_resource; + + constraint forall (t in 0..(n_intervals + 1)) (participation_as_resource[0, t] = 0); % Фиктивный объект. + + % Граничные значения. + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, 0] = 0); + constraint forall (obj in 1..n_moving_obj) (participation_as_resource[obj, n_intervals + 1] = 0); + + % Только те операции, которые затрагивают данный объект. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) + -> participation_as_resource[obj, t] in operations_that_used_obj_as_resource[obj] + ); + + % Связь с текущими операциями перемещения. + % Если объект задействован в операции перемещения, которая использует его как ресурс, + % то participation_as_resource должен указывать на эту операцию. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (current_moving_operation[obj, t] in operations_that_used_obj_as_resource[obj]) + -> + (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + % Если объект участвует как ресурс в операции перемещения, то это согласованно с current_moving_operation. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + ((participation_as_resource[obj, t] != 0) /\ + (is_moving_operation[participation_as_resource[obj, t]]) + ) -> (participation_as_resource[obj, t] = current_moving_operation[obj, t]) + ); + + % { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + (participation_as_resource[obj, t] != 0) -> op_status[participation_as_resource[obj, t], t] + ); + + % От начала операции и до конца её ресурсы не могут измениться (в том числе и для погрузки). + constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals - 1)) ( + ((participation_as_resource[obj, t] != 0) /\ + (op_status[participation_as_resource[obj, t], t + 1]) + ) -> (participation_as_resource[obj, t + 1] = participation_as_resource[obj, t]) + ); + + int : n_resources_types; % Количество различных типов ресурсов. + array [1..n_resources_types] of set of 1..n_moving_obj : objects_of_type; % Все объекты конкретного типа. + + int : n_resources_counters; % Количество счётчиков ресурсов. + % Счётчик ресурсов. + array [1..n_resources_counters , 1..n_intervals] of var int : resources_counter; + array [1..n_resources_counters] of 1..n_resources_types : counter_type; % Типы ресурсов, за которыми следят счётчики. + array [1..n_resources_counters] of 1..n_operations : operation_of_counter; % Операция, которой принадлежит данный счётчик. + array [1..n_resources_counters] of int : required_counter_values; % Необходимые значения на счётчиках ресурсов для выполнения операции. + array [0..n_operations] of set of 1..n_resources_counters : counters_of_operation; % Счётчики, которые относятся к данной операции. + + % Участие всех необходимых ресурсов в операции. + constraint forall (t in 1..n_intervals, op in 1..n_operations, counter in counters_of_operation[op]) ( + op_status[op, t] -> (resources_counter[counter, t] = required_counter_values[counter]) + ); + + % Определение resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + participation_as_resource[obj, t] = operation_of_counter[counter] + ) + ); + +% Участие объекта в операциях грузообработки. + array [0..n_moving_obj, 1..n_intervals] of var bool : is_involved_in_cargo_op; + + constraint forall (t in 1..n_intervals) (is_involved_in_cargo_op[0, t] = false); % Фиктивный объект. + + % Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. + array [0..n_moving_obj] of set of 0..n_operations : related_cargo_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] = ( + (exists (op in related_cargo_op[obj]) (op_status[op, t])) + \/ + ((participation_as_resource[obj, t] != 0) /\ (not is_moving_operation[participation_as_resource[obj, t]])) + ) + ); + % Операции перемещения исключают операции грузообработки и наоборот. + constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( + is_involved_in_cargo_op[obj, t] -> (current_moving_operation[obj, t] = 0) + ); + +% Наличие всех объектов на месте во время начала операции перемещения + готовность к началу. + % Требуемое положение конкретных типов объектов в момент начала операций. + array [1..n_resources_counters] of 1..n_locations : operations_resources_start_loc; + + % Наличие на месте всех ресурсов. + constraint forall ( + op in 1..n_operations, + t in 1..n_intervals, + counter in counters_of_operation[op], + obj in objects_of_type[counter_type[counter]]) ( + ((participation_as_resource[obj, t] = op) /\ (op_start[op, t]) + ) -> (m_obj_loc[obj, t] == operations_resources_start_loc[counter]) + ); + + % Требуемое положение главного объекта в момент начала операций. + array [0..n_operations] of 0..n_locations : main_obj_start_loc; + % Требуемое положение бункеровщика в момент начала операции. + array [0..n_operations] of 0..n_locations : bunker_start_loc; + + % Бункеровщик, участвующий в операции погрузки (0, если такогого нет или это не погрузка). + array [0..n_operations] of 0..n_moving_obj : bunker_of_cargo_op; + + % Наличие главных объектов на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = main_obj_of_operation[op]) ( + op_start[op, t] -> (m_obj_loc[obj, t] == main_obj_start_loc[op]) + ); + + % Наличие бункеровщиков на месте. + constraint forall (op in 1..n_operations, + t in 1..n_intervals, + obj = bunker_of_cargo_op[op] where obj != 0) ( + op_start[op, t] -> (m_obj_loc[obj, t] == bunker_start_loc[op]) + ); + +% Непрерывность перемещения и швартовки. + array [0..n_operations] of int : operations_duration; + array [0..n_operations] of bool : is_continuous_operation; + + constraint forall (i in 1..n_operations, len = operations_duration[i] where is_continuous_operation[i]) ( + (forall (j in 1..(n_intervals - len + 1)) ( + (op_start[i, j] == 1) -> ( + (forall (k in 1..(len - 1)) (op_status[i, j + k])) + /\ + (not op_status[i, j + len]) + ) + )) /\ + (forall (j in (n_intervals - len + 2)..(n_intervals + 1)) (op_start[i, j] == false)) + ); + +% Конфликтующие операции. + array [0..n_operations] of set of 1..n_operations : conflicting_operations; + + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1), conf_op in conflicting_operations[op]) ( + op_status[op, t] -> not op_status[conf_op, t] + ); + +% Окна непогоды. + array [0..n_operations, 0..n_intervals] of bool : bad_weather; + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + bad_weather[op, t] -> (op_status[op, t] = false) + ); + +% Грузообработка. + int : n_cargo_types; + int : n_all_storage_sections; + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of var int : storage_used_volume; + + constraint forall (t in 0..(n_intervals + 1)) (storage_used_volume[0, t] = 0); % Фиктивный объект. + + % Ограничения на вместимость. + array [0..n_all_storage_sections] of int : max_storage_vol; + % Максимальный объём. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + (storage_used_volume[storage, t]) <= max_storage_vol[storage] + ); + % Неотрицательность объёма. + constraint forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( + 0 <= storage_used_volume[storage, t] + ); + + % Ограничения на граничные значения. + array [0..n_all_storage_sections] of int : initial_storage_vol; + array [0..n_all_storage_sections] of int : final_storage_vol; + + constraint forall (storage in 1..n_all_storage_sections) ( % Initial values. + storage_used_volume[storage, 0] = initial_storage_vol[storage] + ); + + constraint forall (storage in 1..n_all_storage_sections % Final values. + where final_storage_vol[storage] >= 0) ( + storage_used_volume[storage, n_intervals + 1] = final_storage_vol[storage] + ); + + % Изменение грузов в хранилищах. + array [0..n_all_storage_sections, 0..(n_intervals + 1)] of int : cargo_flows; + + int : n_loading_op; + + array [0..n_operations] of int : loading_op_delta_of_main_obj; + array [0..n_operations] of int : loading_op_abs_delta; + array [0..n_operations] of {1, -1} : loading_op_direction; + + array [0..n_operations] of 1..n_all_storage_sections : operations_main_stor; + array [0..n_operations] of 1..n_all_storage_sections : operations_secondary_stor; + array [0..n_operations] of 1..n_cargo_types : operations_cargo_t; + + array [1..n_loading_op] of int : loading_op_delta; + array [1..n_loading_op] of {1, -1} : loading_op_local_direction; + array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций. + + array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations; + + % Интенсивность операций погрузки. + array [0..n_operations, 0..(n_intervals + 1)] of var int : cargo_op_intensity; + + constraint forall (t in 0..(n_intervals + 1)) (cargo_op_intensity[0, t] = 0); % Фиктивная операция. + + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1)) (cargo_op_intensity[op, t] >= 0); + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1)) (cargo_op_intensity[op, t] <= loading_op_abs_delta[op]); + + % Связь с операциями грузообработки. + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1) where not is_moving_operation[op]) ( + (cargo_op_intensity[op, t] > 0) -> op_status[op, t] + ); + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1) where is_moving_operation[op]) ( + cargo_op_intensity[op, t] = 0 + ); + constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1) where not is_moving_operation[op]) ( + op_status[op, t] -> (cargo_op_intensity[op, t] > 0) + ); + + constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) ( + storage_used_volume[storage, t] = ( + storage_used_volume[storage, t - 1] + + cargo_flows[storage, t] + + sum (inv_op in involved_operations[storage]) ( + cargo_op_intensity[loading_op_n[inv_op], t] * + loading_op_local_direction[inv_op] + ) + ) + ); + + +% Фиксированные операции. + int : n_fixed_op; + array [1..n_fixed_op] of 1..n_operations : fixed_op; + array [1..n_fixed_op] of set of 1..n_moving_obj : fixed_op_resources; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_start; + array [1..n_fixed_op] of 1..n_intervals : fixed_op_end; % Включительно. + array [1..n_fixed_op] of int : fixed_op_intensity; + + array [0..n_operations, 0..n_intervals] of bool : is_fixed; + + constraint forall (no in 1..n_fixed_op, op = fixed_op[no]) ( + forall (t in fixed_op_start[no]..fixed_op_end[no]) ( + (op_status[op, t]) /\ + forall (obj in fixed_op_resources[no]) ( + participation_as_resource[obj, t] = op + ) /\ + (cargo_op_intensity[op, t] = fixed_op_intensity[no]) + ) + ); + +% Оптимизация - сдвиг в начало. + % Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). + array [0..n_operations, 1..n_intervals] of var bool : is_op_possible; + + constraint forall (t in 1..n_intervals) (is_op_possible[0, t] = false); % Фиктивный объект. + + % Счётчик ресурсов, которые могут быть потенциально задействованы в операции. + array [1..n_resources_counters , 1..n_intervals] of var int : possible_resources_counter; + + % Определение possible_resources_counter. + constraint forall (counter in 1..n_resources_counters, t in 1..n_intervals) ( + possible_resources_counter[counter, t] = sum (obj in objects_of_type[counter_type[counter]]) ( + (participation_as_resource[obj, t] = 0) /\ + (current_moving_operation[obj, t] = 0) /\ + (m_obj_loc[obj, t] = operations_resources_start_loc[counter]) + ) + ); + + % Достаточно ли свободных ресурсов для операции. + array [0..n_operations, 1..n_intervals] of var bool : is_enough_free_resources; + + constraint forall (t in 1..n_intervals) (is_enough_free_resources[0, t] = false); % Фиктивный объект. + + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_enough_free_resources[op, t] = forall (counter in counters_of_operation[op]) ( + possible_resources_counter[counter, t] >= required_counter_values[counter] + ) + ); + + array [1..n_operations, 1..n_intervals] of var bool : is_cargo_op_not_exceeds_storage_limits; + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_cargo_op_not_exceeds_storage_limits[op, t] = + ((not is_moving_operation[op]) -> ( + let {1..n_all_storage_sections : m_stor = operations_main_stor[op]; + 1..n_all_storage_sections : s_stor = operations_secondary_stor[op]; + int : delta = loading_op_direction[op]; + } in + (storage_used_volume[m_stor, t] + delta >= 0) /\ + (storage_used_volume[m_stor, t] + delta <= max_storage_vol[m_stor]) /\ + (storage_used_volume[s_stor, t] - delta >= 0) /\ + (storage_used_volume[s_stor, t] - delta <= max_storage_vol[s_stor]) + )) + ); + + % Определение is_op_possible. + constraint forall (op in 1..n_operations, t in 1..n_intervals) ( + is_op_possible[op, t] = ( + (bad_weather[op, t] = false) /\ % Погода не мешает. + (m_obj_loc[main_obj_of_operation[op], t] = main_obj_start_loc[op]) + /\ % Главный объект на месте. + (current_moving_operation[main_obj_of_operation[op], t] = 0) + /\ % Главный объект не участвует в операции перемещеня. + (is_enough_free_resources[op, t] = true) /\ % Достаточно свободных ресурсов на нужном месте. + (forall (conf_op in conflicting_operations[op]) (op_status[conf_op, t] = false)) + /\ % Не выполняется ни одной конфликтующей операции. + (is_moving_operation[op] -> not is_involved_in_cargo_op[main_obj_of_operation[op], t]) + /\ % Если это операция перемещения, то главный объект + % не участвует в операциях погрузки. + ((is_mooring_op[op] /\ (operations_destination[op] mod 2 = 0)) -> ( + current_moored_obj[operations_destination[op], t] = 0) + ) /\ % Если это операция пришвартовки, то в этот интервал + % причал должен быть свободным. + (is_cargo_op_not_exceeds_storage_limits[op, t]) % Если это операция грузообработки, то она не выведет + /\ % объём берегового хранилища и хранилища судна за + % границы дозволенного (если исполнится при минимальной + % интенсивности 1). + (((not is_moving_operation[op]) /\ (main_obj_start_loc[op] mod 2 = 1)) -> + ((current_moored_obj[twin_location[main_obj_start_loc[op]], t] = 0) \/ + (current_moored_obj[twin_location[main_obj_start_loc[op]], t] = main_obj_of_operation[op])) + ) /\ % Если это операция грузообработки без пришвартовки, + % то причал должен быть свободен в этот интервал, либо + % главный объект должен быть уже условно пришвартован. + (((bunker_of_cargo_op[op] != 0) /\ (op_status[op, t])) -> + ((m_obj_loc[bunker_of_cargo_op[op], t] = bunker_start_loc[op]) /\ + (current_moving_operation[bunker_of_cargo_op[op], t] = 0)) + ) % Бункеровщик (если есть) находится в нужной локации + % и не участвует в операциях перемещения. + ) + ); + + % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. + constraint forall (op in 1..n_operations, t in 2..n_intervals) ( + (op_start[op, t] /\ (not is_fixed[op, t])) -> not is_op_possible[op, t - 1] + ); + +% Оптимизация - есть две соседние операции погрузки - первая операция должна быть максимально загруженной. + constraint forall (op in 1..n_operations, t in 2..n_intervals) ( + ((cargo_op_intensity[op, t - 1] != 0) /\ (cargo_op_intensity[op, t] != 0)) -> ( + (cargo_op_intensity[op, t - 1] = loading_op_abs_delta[op]) \/ % Операция достигла предела интенсивности. + (not is_cargo_op_not_exceeds_storage_limits[op, t - 1]) % Или операция нарушит границы хранилищ + \/ % при увеличении интенсивности. + (is_fixed[op, t]) % Или операция фиксирована. + ) + ); + +% Критерий оптимизации + array [1..(n_intervals + 1)] of var bool : is_not_terminated; + % В конце всё остановится. + constraint (is_not_terminated[n_intervals + 1] == false); + + % Действия ещё не остановились, если в текущий интервал что-нибудь происходит или они не остановятся в следующий интервал. + constraint forall (t in 1..n_intervals) ( + is_not_terminated[t] == ( + (exists (op in 1..n_operations) (op_status[op, t])) + \/ + is_not_terminated[t + 1] + ) + ); + + solve minimize sum(is_not_terminated); + +output [show(sum(is_not_terminated)), "\n", + "op_status = ", show(op_status), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "op_start = ", show(op_start), "\n\n", + "is_not_terminated = ", show(is_not_terminated), "\n\n", + "storage_used_volume = ", show(storage_used_volume), "\n\n", + "m_obj_loc = ", show(m_obj_loc), "\n\n", + "current_moving_operation = ", show(current_moving_operation), "\n\n", + "resources_counter {", show(n_intervals), "} = ", show(resources_counter), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "participation_as_resource = ", show(participation_as_resource), "\n\n", + + "is_involved_in_cargo_op = {", show(n_intervals), "} ", show(is_involved_in_cargo_op), "\n\n", + + "current_moored_obj = ", show(current_moored_obj), "\n\n", + "cargo_op_intensity = ", show(cargo_op_intensity), "\n\n", + + + "is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n", + /* + "is_enough_free_resources {", show(n_intervals), "} = ", show(is_enough_free_resources), "\n\n", + "operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n", + "possible_resources_counter {", show(n_intervals), "} = ", show(possible_resources_counter), "\n\n", +*/ + ""]; diff --git a/src/inport/Berth.java b/src/inport/Berth.java index 2e56e4939913957e3a241f8e865b77fdaf3b99f0..009db9f535819357719107075d69fde3217355ad 100644 --- a/src/inport/Berth.java +++ b/src/inport/Berth.java @@ -69,7 +69,7 @@ public class Berth { @Override public String toString() { - return id + ";" + name; + return id + "; " + name; } public Berth(String s) { diff --git a/src/inport/Bunker.java b/src/inport/Bunker.java index 3be110471fec467ac14e52363b8f4bbe5ffa6fc0..bd575d6db255069f87ec43666758e23c7400a1c3 100644 --- a/src/inport/Bunker.java +++ b/src/inport/Bunker.java @@ -4,30 +4,26 @@ */ package inport; +import javafx.util.Pair; + +import java.util.ArrayList; +import java.util.Map; + /** * * @author topazh_ag */ -public class Bunker extends MovingObject { +public class Bunker extends TransportShip { - public Bunker(int id, String name) { - super(id, name); + public Bunker(int id, String name, ArrayList> storageSections) { + super(id, name, storageSections); } public Bunker() { super( ); } - - @Override - public String toString() { - return getId() + ";" + getName(); - } - - public Bunker(String s) { - super(s); + public Bunker(String s, Map mCargo) { + super(s, mCargo); } - - - } diff --git a/src/inport/Cargo.java b/src/inport/Cargo.java index 3b8b5638dd7de495f46f046c0bf8f0b96474471f..6578a6f0a22600f9a4dacbb45c46ca8260a7d1db 100644 --- a/src/inport/Cargo.java +++ b/src/inport/Cargo.java @@ -79,7 +79,7 @@ public class Cargo { @Override public String toString() { - return id + ";" + name + ";" + cost; + return id + "; " + name + "; " + cost; } public Cargo(String s) { diff --git a/src/inport/CargoFlow.java b/src/inport/CargoFlow.java index f3cd6d077ccb0d7a754bb0cb9372cbdac1c60d67..d7a25fef20e7ecb56a95d94c563cb044d369baef 100644 --- a/src/inport/CargoFlow.java +++ b/src/inport/CargoFlow.java @@ -117,7 +117,7 @@ public class CargoFlow { res += s + ":" + flow.get(s); first = false; } - return storage.getId() + ";[" + res +"]"; + return storage.getId() + "; [" + res +"]"; } public CargoFlow(String s, Map mp, Map cp) { diff --git a/src/inport/ConversionException.java b/src/inport/ConversionException.java deleted file mode 100644 index f266122b06e46bc76ee81ea6a260e238d18b21d3..0000000000000000000000000000000000000000 --- a/src/inport/ConversionException.java +++ /dev/null @@ -1,7 +0,0 @@ -package inport; - -public class ConversionException extends Exception { - ConversionException(String mess) { - super(mess); - } -} diff --git a/src/inport/ConversionUtil.java b/src/inport/ConversionUtil.java deleted file mode 100644 index 5ea02a7c99183ba85cbc02b72260f9e3f5af8311..0000000000000000000000000000000000000000 --- a/src/inport/ConversionUtil.java +++ /dev/null @@ -1,929 +0,0 @@ -package inport; - -import javafx.util.Pair; - -import java.io.*; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Function; - -public class ConversionUtil { - static class PairComparator 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); - } - - 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 { - 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 (ArrayList 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); - - writer.write(name + " = array3d(1.." + dim1 + ", 1.." + dim2 + ", 1.." + name + "_max_size, ["); - - boolean isFirst = true; - for (ArrayList> a1 : operations) { - for (ArrayList a2 : a1) { - for (int i = 0; i < maxSize; i++) { - if (isFirst) { - isFirst = false; - } else { - writer.write(", "); - } - writer.write(Integer.toString(i < a2.size() ? a2.get(i) : 1)); - } - } - } - writer.write("]);\n"); - } - - static private void writeArrayOfSetAs2DArray(FileWriter writer, - String name, - ArrayList> operations) throws IOException { - writeArrayOfSetAs2DArray(writer, name, operations, true); - } - - static private void writeArrayOfSetAs2DArray(FileWriter writer, - String name, - ArrayList> operations, - boolean addAdditionalInfo) 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() + ", 1.." + maxSize + ", ["); - - boolean isFirst = true; - for (ArrayList s : operations) { - 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 { - writer.write(name + " = \n"); - boolean isFirst0 = true; - for (ArrayList a : operations) { - if (isFirst0) { - isFirst0 = false; - writer.write(" [| "); - } else { - writer.write(" | "); - } - boolean isFirst1 = true; - for (T val : a) { - if (isFirst1) { - isFirst1 = false; - } else { - writer.write(", "); - } - writer.write(toMZNFormat.apply(val)); - } - writer.write("\n"); - } - writer.write(" |];\n"); - } - - static private void writeArray(FileWriter writer, String name, ArrayList data, Function f) throws IOException { - writer.write(name + " = ["); - for (int i = 0; i < data.size(); i++) { - if (i != 0) { - 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); - } - - 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 ArrayList integerArray(int size, int initVal) { - ArrayList res = new ArrayList<>(); - for (int i = 0; i < size; i++) { - res.add(initVal); - } - return res; - } - - static private MovingObject getExecutor(OperationTemplate t) { - if (t instanceof LoadingTemplate) { - return ((LoadingTemplate) t).getLoader(); - } - if (t instanceof MooringTemplate) { - return ((MooringTemplate) t).getMoorer(); - } - if (t instanceof MovingTemplate) { - return ((MovingTemplate) t).getMover(); - } - return null; - } - - static private List getResources(OperationTemplate t) { - List res = new ArrayList<>(); - if (t instanceof LoadingTemplate) { - res.addAll(((LoadingTemplate) t).getResources()); - } - if (t instanceof MooringTemplate) { - res.addAll(((MooringTemplate) t).getResources()); - } - if (t instanceof MovingTemplate) { - res.addAll(((MovingTemplate) t).getResources()); - } - return res; - } - - static private boolean isCompatible(OperationTemplate t1, OperationTemplate t2) { - MovingObject exec1 = getExecutor(t1); - Berth place1 = t1.getStartLocation(); - List resources1 = getResources(t1); - - MovingObject exec2 = getExecutor(t2); - Berth place2 = t2.getStartLocation(); - List resources2 = getResources(t2); - // Пересекаемость ресурсов - for (Object res2 : resources2) - if (resources1.contains(res2)) - return false; - // Выполнитель = ресурс - if (resources1.contains(exec2)) - return false; - // Ресурс = выполнитель - if (resources2.contains(exec1)) - return false; - - // Выполнитель = выполнитель - if (exec1.equals(exec2)) - { - // Это не погрузка - if (!(t1 instanceof LoadingTemplate) || (!(t2 instanceof LoadingTemplate))) - return false; - // Разные причалы - if (!place1.equals(place2)) - return false; - Storage s1 = ((LoadingTemplate)t1).getStorage(); - Storage s2 = ((LoadingTemplate)t2).getStorage(); - // В одно хранилище - if (s1.equals(s2)) - return false; - } - else - // На одном причале и это не перемещения - if (place1.equals(place2) && (!(t1 instanceof MovingTemplate)) && (!(t2 instanceof MovingTemplate))) - return false; - - return true; - } - - private 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 final BiFunction getLocNById; - - private final ArrayList movingObjects; - private final Function mObjToN; - - private final ArrayList operationTemplates; - - private final ArrayList storages; - private final ArrayList cargoes; - - private final int nObjWithStorage; - - private final Map storNById; - private final Map cargoNById; - - 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()); - } - - getLocNById = (Integer id, Boolean isMoored) -> locationNumberById.get(new Pair<>(id, isMoored)); - - movingObjects = new ArrayList<>(); - Map mObjNumberById = new TreeMap<>(); - for (MovingObject obj : task.getShips()) { - mObjNumberById.put(obj.getId(), movingObjects.size()); - movingObjects.add(obj); - } - for (MovingObject obj : task.getTows()) { - mObjNumberById.put(obj.getId(), movingObjects.size()); - movingObjects.add(obj); - } - for (MovingObject obj : task.getEquipments()) { - mObjNumberById.put(obj.getId(), movingObjects.size()); - movingObjects.add(obj); - } - - mObjToN = (MovingObject obj) -> mObjNumberById.get(obj.getId()); - operationTemplates = new ArrayList<>(task.getTemplates()); - - storages = new ArrayList<>(task.getStorages()); - cargoes = new ArrayList<>(task.getCargoes()); - - storNById = new TreeMap<>(); - for (int i = 0; i < storages.size(); i++) { - storNById.put(storages.get(i).getId(), i); - } - - cargoNById = new TreeMap<>(); - for (int i = 0; i < task.getCargoes().size(); i++) { - cargoNById.put(cargoes.get(i).getId(), i); - } - - nObjWithStorage = movingObjects.size() + storages.size(); - } - - /* Операции прибытия/отбытия в локацию. (В том числе и швартовка.) */ - 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.apply(obj)); - } - movingObjN.add(mObjToN.apply(op.getMover())); - - for (Integer n : movingObjN) { - arrivalOp .get(n).get(getLocNById.apply(op.getDestination().getId(), false)).add(i + 1); - departureOp.get(n).get(getLocNById.apply(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.apply(obj)); - } - movingObjN.add(mObjToN.apply(op.getMoorer())); - - for (Integer n : movingObjN) { - arrivalOp .get(n).get(getLocNById.apply(op.getStartLocation().getId(), op.isDirect())).add(i + 1); - departureOp.get(n).get(getLocNById.apply(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.apply(state.getVessel()), getLocNById.apply(state.getLocation().getId(), false)); - } - writeArray(writer, "initial_m_obj_loc", initialStates, (Integer p) -> p + 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 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); - writeArray(writer, "is_continuous_operation", isMovingObj); - } - - /* Конечные положения объектов. */ - private void finalLocations() throws IOException { - ArrayList finalStates = integerArray(movingObjects.size(), -1); - for (MovingObjectState state : task.getVesselEndState()) { - finalStates.set(mObjToN.apply(state.getVessel()), getLocNById.apply(state.getLocation().getId(), false)); - } - writeArray(writer, "final_m_obj_loc", finalStates, (Integer p) -> p + 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.apply(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.apply(op.getStartLocation().getId(), false)); - for (MovingObject obj : op.getResources()) { - addResource.accept(obj, getLocNById.apply(op.getStartLocation().getId(), false)); - } - } else if (operationTemplate instanceof MooringTemplate) { // Швартовка. - MooringTemplate op = (MooringTemplate) operationTemplate; - addResource.accept(op.getMoorer(), getLocNById.apply(op.getStartLocation().getId(), !op.isDirect())); - for (MovingObject obj : op.getResources()) { - addResource.accept(obj, getLocNById.apply(op.getStartLocation().getId(), false)); - } - } else if (operationTemplate instanceof LoadingTemplate) { // Погрузка. - LoadingTemplate op = (LoadingTemplate) operationTemplate; - addResource.accept(op.getLoader(), getLocNById.apply(op.getStartLocation().getId(), op.getWithMooring())); - for (MovingObject obj : op.getResources()) { - addResource.accept(obj, getLocNById.apply(op.getStartLocation().getId(), false)); - } - } - } - writeArrayOfSetAs2DArray(writer, "operations_resources", operationsResources); - writeArrayOfSetAs2DArray(writer, "operations_resources_start_loc", operationsResourcesStartLoc, 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 { - ArrayList maxStorageVol = new ArrayList<>(); - - for (MovingObject obj : movingObjects) { - if (obj instanceof TransportShip) { - maxStorageVol.add((int)Math.ceil(((TransportShip) obj).getCargoMax())); - } else { - maxStorageVol.add(0); - } - } - for (Storage storage : storages) { - maxStorageVol.add((int)Math.ceil(storage.getVolume())); - } - writeArray(writer, "max_storage_vol", maxStorageVol); - writer.write("\n"); - } - - /* Граничные состояния хранилищ. */ - private void boundaryStorageStates() throws IOException { - // TODO выделить отдельно общий код. - ArrayList> initialStorageVol = new ArrayList<>(); - ArrayList> finalStorageVol = new ArrayList<>(); - - for (int i = 0; i < nObjWithStorage; i++) { - initialStorageVol.add(integerArray(cargoes.size(), 0)); - finalStorageVol .add(integerArray(cargoes.size(), -1)); - } - for (StorageState st : task.getStorageInitialState()) { - int cargoN = cargoNById.get(st.getCargo().getId()); - int val = (int)st.getCargoState(); - - if (st.getStorage() instanceof Storage) { - Storage storage = (Storage) st.getStorage(); - int stN = storNById.get(storage.getId()); - initialStorageVol.get(movingObjects.size() + stN).set(cargoN, val); - } else if (st.getStorage() instanceof TransportShip) { - TransportShip ship = (TransportShip) st.getStorage(); - initialStorageVol.get(mObjToN.apply(ship)).set(cargoN, val); - } - } - for (StorageState st : task.getStorageEndState()) { - int cargoN = cargoNById.get(st.getCargo().getId()); - int val = (int)st.getCargoState(); - - if (st.getStorage() instanceof Storage) { - Storage storage = (Storage) st.getStorage(); - int stN = storNById.get(storage.getId()); - finalStorageVol.get(movingObjects.size() + stN).set(cargoN, val); - } else if (st.getStorage() instanceof TransportShip) { - TransportShip ship = (TransportShip) st.getStorage(); - finalStorageVol.get(mObjToN.apply(ship)).set(cargoN, val); - } - } - write2DArrayOfInt(writer, "initial_storage_vol", initialStorageVol); - write2DArrayOfInt(writer, "final_storage_vol", finalStorageVol); - } - - /* Потоки грузов. */ - private void cargoFlows() throws IOException { - ArrayList>> cargoFlows = new ArrayList<>(); - for (int i = 0; i < nObjWithStorage; i++) { - cargoFlows.add(new ArrayList<>()); - for (int j = 0; j < n_intervals + 2; j++) { - cargoFlows.get(i).add(new ArrayList<>()); - for (int k = 0; k < cargoes.size(); k++) { - cargoFlows.get(i).get(j).add(0); - } - } - } - for (CargoFlow flow : task.getCargoFlows()) { - int storageN = storNById.get(flow.getStorage().getId()); - int cargoN = cargoNById.get(flow.getCargo().getId()); - for (int i = 1; i < n_intervals + 2; i++) { - cargoFlows.get(storageN + movingObjects.size()).get(i).set(cargoN, (int)flow.getCurrentValue(i - 0.1)); - } - } - writer.write("cargo_flows = array3d(1..n_obj_with_storage, 0..(n_intervals + 1), 1..n_cargo_types, ["); - boolean isFirst = true; - for (int i = 0; i < nObjWithStorage; i++) { - for (int j = 0; j < n_intervals + 2; j++) { - for (int k = 0; k < cargoes.size(); k++) { - if (isFirst) { - isFirst = false; - } else { - writer.write(", "); - } - writer.write(cargoFlows.get(i).get(j).get(k).toString()); - } - } - } - writer.write("]);\n\n"); - } - - /* Грузовые операции со всеми хранилищами. */ - private void cargoOperations() throws IOException { - ArrayList>> involvedOperations = new ArrayList<>(); - ArrayList loadingOpDelta = new ArrayList<>(); - ArrayList loadingOpN = new ArrayList<>(); - - for (int i = 0; i < nObjWithStorage; i++) { - involvedOperations.add(new ArrayList<>()); - for (int j = 0; j < cargoes.size(); j++) { - involvedOperations.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 storageN = storNById.get(op.getStorage().getId()); - int shipN = mObjToN.apply(op.getLoader()); - int cargoN = cargoNById.get(op.getCargo().getId()); - - loadingOpDelta.add(-(int)op.getIntensity()); - loadingOpN.add(i); - involvedOperations.get(storageN + movingObjects.size()).get(cargoN).add(loadingOpDelta.size()); - - loadingOpDelta.add((int)op.getIntensity()); - loadingOpN.add(i); - involvedOperations.get(shipN).get(cargoN).add(loadingOpDelta.size()); - } - } - writer.write("n_loading_op = " + loadingOpDelta.size() + ";\n"); -// write2DArrayOfSet(writer, "involved_operations", involvedOperations); - write2DArrayOfSetAs3DArray(writer, "involved_operations", involvedOperations); - writeArray(writer, "loading_op_delta", loadingOpDelta); - writeArray(writer, "loading_op_n", loadingOpN, (Integer i) -> i + 1); - 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.apply(obj)).add(op + 1); - BiConsumer addMovingOp = (MovingObject obj, Integer op) -> - movingOpOfObj.get(mObjToN.apply(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.apply(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 movingObjectLocationDefinition() throws IOException { - ArrayList> movingOpOfObj = new ArrayList<>(); - ArrayList operationsDestination = new ArrayList<>(); - - for (int i = 0; i < movingObjects.size(); i++) { - movingOpOfObj.add(new ArrayList<>()); - } - - BiConsumer addMovingOp = (MovingObject obj, Integer op) -> - movingOpOfObj.get(mObjToN.apply(obj)).add(op + 1); - - for (int i = 0; i < operationTemplates.size(); i++) { - OperationTemplate t = operationTemplates.get(i); - - if ((t instanceof MovingTemplate) || (t instanceof MooringTemplate)) { - addMovingOp.accept(getExecutor(t), i); - for (MovingObject obj : getResources(t)) { - addMovingOp.accept(obj, i); - } - } - if (t instanceof MovingTemplate) { - MovingTemplate op = (MovingTemplate)t; - operationsDestination.add(getLocNById.apply(op.getDestination().getId(), false)); - } else if (t instanceof MooringTemplate) { - MooringTemplate op = (MooringTemplate)t; - operationsDestination.add(getLocNById.apply(op.getStartLocation().getId(), op.isDirect())); - } else { - // TODO аккуратно обработать погрузку. - operationsDestination.add(getLocNById.apply(t.getStartLocation().getId(), false)); - } - } - - writeArrayOfSetAs2DArray(writer, "moving_op_of_obj", movingOpOfObj); - writeArray(writer, "operations_destination", operationsDestination, (Integer val) -> val + 1); - writer.write("\n"); - } - - void portToMiniZinc_0() throws IOException { - 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 { - 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(); - 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(); - } - } - } - } - - 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) throws IOException { - Task taskData = new Task(task, fileName); - taskData.portToMiniZinc_1(); - } - - private static class OperationsComparator implements Comparator { - public int compare(Operation op1, Operation op2) { - return Double.compare(op1.getStart(), op2.getStart()); - } - } - - static public void resolveMiniZincResults(TaskCase task, String fileName) throws IOException, ParserException { - ArrayList operations = null; - Integer result = null; - - try (FileInputStream fstream = new FileInputStream(fileName)) { - BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); - - String line; - - while (((line = br.readLine()) != null)) { - line = line.trim(); - if (line.equals("")) { - continue; - } - String regexpr = "^\\[.*]\\z"; - if (line.matches(regexpr)) { - if (operations != null) { - continue; - } - String []rawTokens = line.split("[\\s\\[\\],]"); - ArrayList tokens = new ArrayList<>(); - for (String str : rawTokens) { - if (!str.isEmpty()) { - tokens.add(str); - } - } - final int n_intervals = (int)task.getPlanningInterval(); - - if (tokens.size() != (n_intervals + 2) * task.getTemplates().size()) { - throw new ParserException("Invalid length of \"op_status\""); - } - - operations = new ArrayList<>(); - - for (int i = 0; i < task.getTemplates().size(); i++) { - int duration = 0; - for (int j = 0; j < n_intervals + 2; j++) { - if (tokens.get(i * (n_intervals + 2) + j).equals("true")) { - duration++; - } else if (duration != 0) { - Operation op = new Operation(); - op.setStart(j - duration - 1); - op.setDuration(duration); - op.setTemplate(task.getTemplates().get(i)); - - operations.add(op); - - duration = 0; - } - } - } - continue; - } - if (line.matches("\\d+")) { - if (result != null) { - continue; - } - result = Integer.parseInt(line); - continue; - } - if (line.equals("=====UNSATISFIABLE=====")) { - throw new ParserException("No solution."); - } - break; - } - if (operations == null) { - throw new ParserException("No \"op_status\" in input"); - } - if (result == null) { - throw new ParserException("No result in input"); - } - operations.sort(new OperationsComparator()); - task.setSolution(operations); - task.setSolution_result(result); - } - } -} diff --git a/src/inport/ConversionUtils/MZnFormat.java b/src/inport/ConversionUtils/MZnFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..5d3398e290a4627f8eb5baffa0e1eadf2c6af772 --- /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 0000000000000000000000000000000000000000..9474c60e4aa75e80cfb43426d0b0dd8daf77ad0e --- /dev/null +++ b/src/inport/ConversionUtils/MZnResultsResolver.java @@ -0,0 +1,243 @@ +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 if (arrays.containsKey("real_cargo_value")) { // Жадный алгоритм. + cargoOpIntensity = arrays.get("real_cargo_value"); + } 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(Math.abs(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/ParserException.java b/src/inport/ConversionUtils/ParserException.java new file mode 100644 index 0000000000000000000000000000000000000000..f74c4e1822cb6a8aae5c2afc15221fc5d8d67574 --- /dev/null +++ b/src/inport/ConversionUtils/ParserException.java @@ -0,0 +1,7 @@ +package inport.ConversionUtils; + +public class ParserException extends RuntimeException { + ParserException(String mess) { + super(mess); + } +} diff --git a/src/inport/ConversionUtils/Task.java b/src/inport/ConversionUtils/Task.java new file mode 100644 index 0000000000000000000000000000000000000000..e25d247ac1935ad743884b93edd4e845b311e760 --- /dev/null +++ b/src/inport/ConversionUtils/Task.java @@ -0,0 +1,1569 @@ +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 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); + } + } + + private 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<>())); + } + } + + private void addIsOpUsedStorAsSecondary() throws IOException { + ArrayList> is_op_used_stor_as_secondary = new ArrayList<>(); + for (int i = 0; i <= nSectionsOfRealStorageAndBunkers; i++) { + is_op_used_stor_as_secondary.add(new ArrayList<>()); + for (int j = 0; j <= operationTemplates.size(); j++) { + is_op_used_stor_as_secondary.get(i).add(false); + } + } + for (int j = 0; j < operationTemplates.size(); j++) { + if (operationTemplates.get(j) instanceof LoadingTemplate) { + LoadingTemplate op = (LoadingTemplate) operationTemplates.get(j); + int section; + if (op.getBunker().isPresent()) { + section = sectionIdToN(op.getBunker().get(), op.getCargo()); + } else { + section = sectionIdToN(op.getStorage(), op.getCargo()); + } + is_op_used_stor_as_secondary.get(section + 1).set(j + 1, true); + } + } + locWrite2DArray(writer, "is_op_used_stor_as_secondary", is_op_used_stor_as_secondary, Objects::toString, true); + } + + private void addInvolvedOperations() throws IOException { + ArrayList> involved_operations_as_main_stor = arrayOfIntegerSet(sectionNById.size()); + ArrayList> involved_operations_as_sec_stor = arrayOfIntegerSet(sectionNById.size()); + for (int i = 0; i < operationTemplates.size(); i++) { + if (operationTemplates.get(i) instanceof LoadingTemplate) { + LoadingTemplate op = (LoadingTemplate) operationTemplates.get(i); + int section_1 = sectionIdToN(op.getLoader(), op.getCargo()); + int section_2; + if (op.getBunker().isPresent()) { + section_2 = sectionIdToN(op.getBunker().get(), op.getCargo()); + } else { + section_2 = sectionIdToN(op.getStorage(), op.getCargo()); + } + involved_operations_as_main_stor.get(section_1).add(i + 1); + involved_operations_as_sec_stor .get(section_2).add(i + 1); + } + } + writeArray(writer, "involved_operations_as_main_stor", involved_operations_as_main_stor, MZnFormat::setToString); + writeArray(writer, "involved_operations_as_sec_stor", involved_operations_as_sec_stor, MZnFormat::setToString); + } + + void portToMiniZinc_2_greedy() { + if (!task.isTypified()) { + throw new ParserException("Attempt to convert untyped task as typified."); + } + try { + portToMiniZinc_2(); + dataForGreediness(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + void portToMiniZinc_2_greedy_v2() { + if (!task.isTypified()) { + throw new ParserException("Attempt to convert untyped task as typified."); + } + try { + portToMiniZinc_2_greedy(); + addIsOpUsedStorAsSecondary(); + addInvolvedOperations(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + static public void portToMiniZinc_0(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_0); + } + 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 public void portToMiniZincGreedyV2(TaskCase task, String fileName) { + startConversion(task, fileName, Task::portToMiniZinc_2_greedy_v2); + } + + static private void startConversion(TaskCase task, String fileName, Consumer conversion) { + try { + 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 0000000000000000000000000000000000000000..943f61e5c5e237e9e75cc411946de3d4ba65a632 --- /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/LoadingEquipment.java b/src/inport/LoadingEquipment.java index be591e81e2b0ef9294a5b3059a1efd07f2f31adc..37b9fa0b6eb3ad5c6d974ae2fe6af507ad66b2d1 100644 --- a/src/inport/LoadingEquipment.java +++ b/src/inport/LoadingEquipment.java @@ -4,12 +4,13 @@ */ package inport; +import java.util.OptionalInt; + /** * * @author topazh_ag */ public class LoadingEquipment extends MovingObject{ - public LoadingEquipment() { super(); @@ -21,11 +22,19 @@ public class LoadingEquipment extends MovingObject{ @Override public String toString() { - return getId() + ";" + getName(); + String res = getId() + "; " + getName(); + if (getType().isPresent()) { + res += "; " + getType().getAsInt(); + } + return res; } public LoadingEquipment(String s) { - super(s); + super(s); + String[] tokens = s.split(";"); + if (tokens.length >= 3) { + setType(OptionalInt.of(Integer.parseInt(tokens[2].trim()))); + } } } diff --git a/src/inport/LoadingTemplate.java b/src/inport/LoadingTemplate.java index 6878aae0cbb45e8ce77a0e6b5ef378d16ce61a6c..ec1bdbc7909872b8beca8c6ce5eb385d3de613d4 100644 --- a/src/inport/LoadingTemplate.java +++ b/src/inport/LoadingTemplate.java @@ -6,6 +6,8 @@ package inport; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; /** * @@ -14,12 +16,37 @@ import java.util.List; public class LoadingTemplate extends OperationTemplate { private TransportShip loader; + private OptionalInt loaderType = OptionalInt.empty(); + private Optional bunker = Optional.empty(); + private OptionalInt bunkerType = OptionalInt.empty(); private Storage storage; private List resources; + private List resourcesTypes; private double intensity; private boolean withMooring; private Cargo cargo; + public OptionalInt getBunkerType() { + return bunkerType; + } + public void setBunkerType(OptionalInt bunkerType) { + this.bunkerType = bunkerType; + } + + public Optional getBunker() { + return bunker; + } + public void setBunker(Optional bunker) { + this.bunker = bunker; + } + + public OptionalInt getLoaderType() { + return loaderType; + } + public void setLoaderType(OptionalInt loaderType) { + this.loaderType = loaderType; + } + /** * Get the value of resources * @@ -37,7 +64,14 @@ public class LoadingTemplate extends OperationTemplate { public void setResources(List resources) { this.resources = resources; } - + + public List getResourcesTypes() { + return resourcesTypes; + } + public void setResourcesTypes(List resourcesTypes) { + this.resourcesTypes = resourcesTypes; + } + public TransportShip getLoader() { return loader; } @@ -78,37 +112,63 @@ public class LoadingTemplate extends OperationTemplate { return cargo; } - public LoadingTemplate(TransportShip loader, Berth berth, Storage storage, double intensity, int id) { + public LoadingTemplate(TransportShip loader, + Berth berth, + Storage storage, + Cargo cargo, + Optional bunker, + List resourcesTypes, + boolean withMooring, + double intensity, + int id) { super(id, berth); this.loader = loader; this.storage = storage; + this.bunker = bunker; this.resources = new ArrayList<>(); + this.resourcesTypes = new ArrayList<>(resourcesTypes); + this.withMooring = withMooring; this.intensity = intensity; + this.cargo = cargo; } public LoadingTemplate() { this.resources = new ArrayList<>(); + this.resourcesTypes = new ArrayList<>(); } @Override public String toString() { String res = ""; boolean first = true; - for(LoadingEquipment eq : resources) - { + for(LoadingEquipment eq : resources) { if (!first) res += "," + eq.getId(); else res += eq.getId(); first = false; } - int source = loader.getId(); - if (intensity>0) - source = storage.getId(); - int target = loader.getId(); - if (intensity<=0) - target = storage.getId(); - return getId() + ";" + "loa;" + twtoString() + ";" + source + ";" + cargo.getId() + ";" + target + ";" - + getStartLocation().getId() + ";[" + res +"];" + Math.abs(intensity) + ";" + (withMooring ? "M" : "U"); - } + for (Integer t : getResourcesTypes()) { + if (!first) + res += ", " + t; + else + res += t; + first = false; + } + + int source = (loaderType.isPresent() ? loaderType.getAsInt() : loader.getId()); + int target; + if (bunkerType.isPresent()) { + target = bunkerType.getAsInt(); + } else target = bunker.map(MovingObject::getId).orElseGet(() -> storage.getId()); + + if (intensity > 0) { + int temp = source; + source = target; + target = temp; + } + return getId() + "; " + "loa; " + twtoString() + "; " + source + "; " + cargo.getId() + "; " + target + "; " + + getStartLocation().getId() + "; [" + res +"]; " + Math.abs(intensity) + "; " + + (withMooring ? "M" : "U"); + } } diff --git a/src/inport/Main.java b/src/inport/Main.java index 7a1175092232cc81f2413237dea59c34ef319def..d69cc352fd0c9d068e91b61a8370c0dc244cfda8 100644 --- a/src/inport/Main.java +++ b/src/inport/Main.java @@ -1,19 +1,53 @@ package inport; import java.io.*; +import java.util.ArrayList; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.BiFunction; + +import static inport.Testing.*; + +import inport.ConversionUtils.MZnResultsResolver; +import inport.ConversionUtils.ParserException; +import inport.ConversionUtils.Task; public class Main { + private static final int DEFAULT_TIME_LIMIT_S = 3600; - private static void removeDirectory(File dir) { - if (dir.isDirectory()) { - File[] files = dir.listFiles(); - if (files != null && files.length > 0) { - for (File aFile : files) { - removeDirectory(aFile); + private enum ConversionType { + Undefined ("", (TaskCase t, Integer i) -> ""), + WithoutSplitting("Without splitting", Testing::solveTask_2), + WithSplitting ("With splitting", Testing::solveTaskWithPartialCargoOp), + Greedy ("Greedy", Testing::solveTaskWithGreedyConstraints), + Greedy_v2 ("Greedy v2", Testing::solveTaskWithGreedyConstraintsV2); + + private final String text; + private final BiFunction solver; + ConversionType(String text, BiFunction solver) { + this.text = text; + this.solver = solver; + } + public static ConversionType fromString(String text) { + for (ConversionType t : ConversionType.values()) { + if (t.text.equalsIgnoreCase(text)) { + return t; } } + return Undefined; } - dir.delete(); + } + + private static String undefinedTypeErrorMess(String undefType) { + StringBuilder s = new StringBuilder("Undefined conversion type - \"" + undefType + "\".\n"); + ArrayList values = new ArrayList<>(); + for (ConversionType conversionType : ConversionType.values()) { + if (! conversionType.equals(ConversionType.Undefined)) { + values.add("\"" + conversionType.text + "\""); + } + } + s.append("Conversion type can be one of ").append(String.join(", ", values)).append("."); + return s.toString(); } public static void main(String[] args) { @@ -26,59 +60,37 @@ public class Main { switch (type) { case "solve" : { String fileName = args[1]; - - File directory = new File("temp_data"); - if (!directory.exists()) { - directory.mkdir(); - } - - String tempDir = "temp_data/"; - String minizincData = tempDir + "minizinc_data.dzn"; - String solverResults = tempDir + "solver_results.txt"; - String constraints = tempDir + "constraints.mzn"; + long start = System.currentTimeMillis(); TaskCase task = new TaskCase(); try { - try (FileWriter res = new FileWriter(constraints)) { - BufferedReader reader = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream("/constraints/conversion_1.mzn"))); - String line; - while ((line = reader.readLine()) != null) { - res.write(line + "\n"); - } - } task.deserialize(fileName); - ConversionUtil.portToMiniZinc_1(task, minizincData); - - long start = System.currentTimeMillis(); - - Process p = Runtime.getRuntime().exec("minizinc --solver Chuffed " + constraints + " " + minizincData); - p.waitFor(); - - long finish = System.currentTimeMillis(); - - System.out.println((finish - start) + " milliseconds"); - - try (FileWriter res = new FileWriter(solverResults)) { - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + } catch (IOException e) { + System.out.println(e.getMessage()); + break; + } - String line; - while ((line = reader.readLine()) != null) { - res.write(line + "\n"); - } + String error; + if (!task.isTypified()) { + error = solveTask_1(task, DEFAULT_TIME_LIMIT_S); + } else { + ConversionType t = (args.length == 2) ? ConversionType.WithoutSplitting + : ConversionType.fromString(args[2]); + if (t.equals(ConversionType.Undefined)) { + System.out.println(undefinedTypeErrorMess(args[2])); + return; } + error = t.solver.apply(task, DEFAULT_TIME_LIMIT_S); + } + + long finish = System.currentTimeMillis(); + System.out.println((finish - start) + " milliseconds"); - ConversionUtil.resolveMiniZincResults(task, solverResults); + if (!error.isEmpty()) { + System.out.println("Error : " + error); + } else { task.serialize(fileName); - } catch (IOException | InterruptedException ex) { - System.out.println(ex.getMessage()); - } catch (ParserException ex) { - if (ex.getMessage().equals("No solution.")) { - System.out.println(ex.getMessage()); - } else { - System.out.println("ParserException : " + ex.getMessage()); - } } - removeDirectory(directory); break; } case "to_MiniZinc_0" : { @@ -87,7 +99,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()); } @@ -99,7 +111,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()); } @@ -114,7 +126,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) { @@ -122,8 +134,246 @@ public class Main { } break; } + case "debug" : { + ConversionType t = (args.length == 2) ? ConversionType.WithoutSplitting + : ConversionType.fromString(args[2]); + if (t.equals(ConversionType.Undefined)) { + System.out.println(undefinedTypeErrorMess(args[2])); + return; + } + debug(t.solver, DEFAULT_TIME_LIMIT_S); + break; + } + case "debug read-write" : { + debugReadWrite(); + break; + } + case "testing" : + ConversionType t = (args.length == 2) ? ConversionType.WithoutSplitting + : ConversionType.fromString(args[2]); + if (t.equals(ConversionType.Undefined)) { + System.out.println(undefinedTypeErrorMess(args[2])); + return; + } + testGroup("with_typing", t.solver, DEFAULT_TIME_LIMIT_S); + test_2(DEFAULT_TIME_LIMIT_S); + break; + case "test_experiment": + testGroup("experiments", Testing::solveTask_2, DEFAULT_TIME_LIMIT_S); + break; + case "different_parameters": + try { + testingWithDiffParameters( + "tests/with_typing/Case2.tipp", + 1, 30, + 16, 35, + 1.1, 30); + +// testingWithDiffParameters( +// "tests/with_typing/TaskT.tipp", +// 10, 10, +// 32, 32, +// 1.1, 10); + + } catch (IOException ex) { + System.out.println(ex.getMessage()); + } + break; default: System.out.println("Unknown type \"" + type + "\""); } } + + private static void debug(BiFunction solver, int timeLimitS) { + String fileName = "experiment/in.ipp"; + String solverResults = "temp_data/solver_results.txt"; + String output = "experiment/debug_info.txt"; + + TaskCase task = new TaskCase(); + try { + task.deserialize(fileName); + } catch (IOException e) { + System.out.println(e.getMessage()); + return; + } + + long start = System.currentTimeMillis(); + + String error = solver.apply(task, timeLimitS); + + long finish = System.currentTimeMillis(); + System.out.println(" " + (finish - start) / 1000.0 + " s"); + + if (!error.isEmpty()) { + System.out.println("Error : " + error); + return; + } else { + task.serialize(fileName); + } + + debugInfo(task, solverResults, output); + } + + private static void debugReadWrite() { + String fileName = "experiment/in.ipp"; + + TaskCase task = new TaskCase(); + try { + task.deserialize(fileName); + } catch (IOException e) { + System.out.println(e.getMessage()); + return; + } + task.serialize(fileName); + } + + private static void debugInfo(TaskCase task, String solverResults, String output) { + try (FileInputStream fstream = new FileInputStream(solverResults)) { + BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); + FileWriter writer = new FileWriter(output, false); + + { + ArrayList operations = new ArrayList<>(task.getTemplates()); + if (task.isTypified()) { + operations = Task.renumberOperations(task); + } + writer.write("operations :\n"); + int no = 1; + for (OperationTemplate op : operations) { + writer.write(" " + no + " " + op.toString() + "\n"); + no++; + } + writer.write("\n"); + } + Task t = new Task(task, ""); + { + ArrayList movingObjects = Task.calcMovingObjects(task); + + Map objByNo = new TreeMap<>(); + for (MovingObject obj : movingObjects) { + objByNo.put(t.getMObjNumberById().get(obj.getId()), obj); + } + + writer.write("moving_objects : \n"); + for (int i = 0; i < movingObjects.size(); i++) { + writer.write(" " + (i + 1) + " " + objByNo.get(i).toString() + "\n"); + } + writer.write("\n"); + } + + String line; + int linesNumber = 0; + + while (((line = br.readLine()) != null)) { + line = line.trim(); + if (line.equals("")) { + continue; + } + linesNumber++; + if (linesNumber <= 1) { + continue; + } + int pos = 0; + while ((pos < line.length()) && (line.charAt(pos) != ' ')) { + pos++; + } + String name = line.substring(0, pos); + + if (name.equals("----------")) { + break; + } + + while ((pos < line.length()) && (line.charAt(pos) != '[') && (line.charAt(pos) != '{')) { + pos++; + } + + int arrayFirstDim = ((int) task.getPlanningInterval()) + 2; + int arraySecondDim = 0; + + 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()); + } + if (dimensions.length > 1) { + arraySecondDim = Integer.valueOf(dimensions[1].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()); + } + + { // bool to int + for (int i = 0; i < elements.size(); i++) { + if (elements.get(i).equals("true")) { + elements.set(i, "1"); + } + if (elements.get(i).equals("false")) { + elements.set(i, "0"); + } + } + } + + int maxLength = 0; + for (String val : elements) { + maxLength = Math.max(maxLength, val.length()); + } + + if ((arrayFirstDim != 0) && (elements.size() % arrayFirstDim == 0) && ((arraySecondDim == 0) || (elements.size() % (arrayFirstDim * arraySecondDim) != 0))) { + writer.write(name + " :\n"); + for (int i = 0; i < elements.size(); i += arrayFirstDim) { + writer.write(" "); + for (int j = 0; j < arrayFirstDim; j++) { + String val = elements.get(i + j); + for (int k = val.length(); k < maxLength; k++) { + writer.write(" "); + } + writer.write(val + " "); + } + writer.write("\n"); + } + writer.write("\n"); + } else if ((arrayFirstDim != 0) && (arraySecondDim != 0) && (elements.size() % (arrayFirstDim * arraySecondDim) == 0)) { + writer.write(name + " :\n"); + for (int i = 0; i < elements.size(); i += arrayFirstDim * arraySecondDim) { + for (int j = 0; j < arrayFirstDim; j++) { + writer.write(" "); + for (int k = 0; k < arraySecondDim; k++) { + String val = elements.get(i + j * arraySecondDim + k); + for (int l = val.length(); l < maxLength; l++) { + writer.write(" "); + } + writer.write(val + " "); + } + writer.write("\n"); + } + writer.write("\n"); + } + writer.write("\n"); + } + } + + writer.close(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } } diff --git a/src/inport/MooringTemplate.java b/src/inport/MooringTemplate.java index a496339c7645ec92ff2c7ab0d00d62c4ec4b47ac..1a2184b4bbd188c58127092e2a78d7c34b25d975 100644 --- a/src/inport/MooringTemplate.java +++ b/src/inport/MooringTemplate.java @@ -4,6 +4,9 @@ */ package inport; +import java.util.List; +import java.util.OptionalInt; + /** * * @author topazh_ag @@ -11,8 +14,16 @@ package inport; public class MooringTemplate extends TowUsingTemplate { private TransportShip moorer; + private OptionalInt moorerType = OptionalInt.empty(); private boolean direct; + public OptionalInt getMoorerType() { + return moorerType; + } + public void setMoorerType(OptionalInt moorerType) { + this.moorerType = moorerType; + } + /** * Get the value of direction * @@ -49,10 +60,11 @@ public class MooringTemplate extends TowUsingTemplate { this.moorer = moorer; } - public MooringTemplate(TransportShip moorer, Berth berth, double duration, boolean direct, int id) { + public MooringTemplate(TransportShip moorer, Berth berth, List resourcesTypes, double duration, boolean direct, int id) { super(duration, id, berth); this.moorer = moorer; this.direct = direct; + this.setResourcesTypes(resourcesTypes); } public MooringTemplate() { @@ -63,18 +75,31 @@ public class MooringTemplate extends TowUsingTemplate { public String toString() { String res = ""; boolean first = true; - for(Tow eq : getResources()) - { + for(Tow eq : getResources()) { if (!first) res += "," + eq.getId(); else res += eq.getId(); first = false; } + for (Integer t : getResourcesTypes()) { + if (!first) + res += "," + t; + else + res += t; + first = false; + } String code = "mrn"; if (!direct) code = "unm"; - return getId() + ";" + code + ";" + twtoString() + ";" + moorer.getId() + ";" + getStartLocation().getId() + ";[" + res +"];"+getDuration(); + + String result = getId() + "; " + code + "; " + twtoString() + "; "; + if (moorerType.isPresent()) { + result += moorerType.getAsInt(); + } else { + result += moorer.getId(); + } + return result + "; " + getStartLocation().getId() + "; [" + res +"]; "+getDuration(); } } diff --git a/src/inport/MovingObject.java b/src/inport/MovingObject.java index a0adedc9ce2b837e64de9816628c05c8d5271b34..e925b1665a685afa6eae451bd9ef9336e772da4e 100644 --- a/src/inport/MovingObject.java +++ b/src/inport/MovingObject.java @@ -4,6 +4,8 @@ */ package inport; +import java.util.OptionalInt; + /** * * @author topazh_ag @@ -12,6 +14,7 @@ public class MovingObject { private int id; private String name; + private OptionalInt type; /** * Get the value of name @@ -49,18 +52,34 @@ public class MovingObject { this.id = id; } + public OptionalInt getType() { + return type; + } + public void setType(OptionalInt type) { + this.type = type; + } + public MovingObject(int id, String name) { this.id = id; this.name = name; + this.type = OptionalInt.empty(); + } + + public MovingObject(int id, String name, int typeId) { + this.id = id; + this.name = name; + this.type = OptionalInt.of(typeId); } public MovingObject() { + type = OptionalInt.empty(); } public MovingObject(String s) { String[] tokens = s.split(";"); id = Integer.parseInt(tokens[0].trim()); - name = tokens[1].trim(); + name = tokens[1].trim(); + type = OptionalInt.empty(); } } diff --git a/src/inport/MovingObjectState.java b/src/inport/MovingObjectState.java index ebaeb3b0c33aa81fd5874de801b928b491c128ce..3e405530352f620bad5d051b0e312f52ec8f09b7 100644 --- a/src/inport/MovingObjectState.java +++ b/src/inport/MovingObjectState.java @@ -64,7 +64,7 @@ public class MovingObjectState { @Override public String toString() { - return getVessel().getId() + ";" + getLocation().getId(); + return getVessel().getId() + "; " + getLocation().getId(); } diff --git a/src/inport/MovingTemplate.java b/src/inport/MovingTemplate.java index 80063e601c72f14f52ee6b6ffc4a83d67e01c70f..b63ea82e58ff6c65c1fd9c8691eef4ee9e9d1a68 100644 --- a/src/inport/MovingTemplate.java +++ b/src/inport/MovingTemplate.java @@ -4,6 +4,9 @@ */ package inport; +import java.util.List; +import java.util.OptionalInt; + /** * * @author topazh_ag @@ -11,6 +14,7 @@ package inport; public class MovingTemplate extends TowUsingTemplate { private MovingObject mover; + private OptionalInt moverType = OptionalInt.empty(); private Berth destination; @@ -50,10 +54,18 @@ public class MovingTemplate extends TowUsingTemplate { this.mover = mover; } - public MovingTemplate(MovingObject mover, Berth source, Berth destination, double duration, int id) { + public OptionalInt getMoverType() { + return moverType; + } + public void setMoverType(OptionalInt moverType) { + this.moverType = moverType; + } + + public MovingTemplate(MovingObject mover, Berth source, Berth destination, List resourcesTypes, double duration, int id) { super(duration, id, source); this.mover = mover; - this.destination = destination; + this.destination = destination; + this.setResourcesTypes(resourcesTypes); } public MovingTemplate() { @@ -64,15 +76,28 @@ public class MovingTemplate extends TowUsingTemplate { public String toString() { String res = ""; boolean first = true; - for(Tow eq : getResources()) - { + for(Tow eq : getResources()) { if (!first) res += "," + eq.getId(); else res += eq.getId(); first = false; } - return getId() + ";" + "mov;" + twtoString() + ";" + mover.getId() + ";" + getStartLocation().getId() + ";" + destination.getId() + ";[" + res +"];"+getDuration(); + for (Integer t : getResourcesTypes()) { + if (!first) + res += "," + t; + else + res += t; + first = false; + } + + String result = getId() + "; " + "mov; " + twtoString() + "; "; + if (getMoverType().isPresent()) { + result += getMoverType().getAsInt(); + } else { + result += mover.getId(); + } + return result + "; " + getStartLocation().getId() + "; " + destination.getId() + "; [" + res +"]; "+getDuration(); } diff --git a/src/inport/Operation.java b/src/inport/Operation.java index e97d0b857c8f1c19605007d017253c35e6d289bb..a1615a4884578b8eaaa8f800b52748cfd4534eb3 100644 --- a/src/inport/Operation.java +++ b/src/inport/Operation.java @@ -4,6 +4,10 @@ */ package inport; +import inport.ConversionUtils.Utils; + +import java.util.*; + /** * * @author topazh_ag @@ -11,8 +15,48 @@ package inport; public class Operation { private OperationTemplate template; + private boolean fixation = false; private double start; private double duration; + private MovingObject executor; + private Optional bunker = Optional.empty(); + private Optional intensity = Optional.empty(); + private List resources; + + public void setIntensity(Optional intensity) { + this.intensity = intensity; + } + public Optional getIntensity() { + return intensity; + } + + public Optional getBunker() { + return bunker; + } + public void setBunker(Optional bunker) { + this.bunker = bunker; + } + + public boolean getFixation() { + return fixation; + } + public void setFixation(boolean fixation) { + this.fixation = fixation; + } + + public List getResources() { + return resources; + } + public void setResources(List resources) { + this.resources = resources; + } + + public MovingObject getExecutor() { + return executor; + } + public void setExecutor(MovingObject executor) { + this.executor = executor; + } /** * Get the value of duration @@ -75,8 +119,75 @@ public class Operation { @Override public String toString() { - return template.getId() + "; R; " + start + "; " + duration; + if (executor == null) { + executor = Utils.getExecutor(template); + } + if (resources == null) { + resources = Utils.getResources(template); + } + StringBuilder sb = new StringBuilder(); + sb.append(template.getId()).append("; "); + sb.append(fixation ? "F" : "R").append("; ").append(start).append("; ").append(duration); + sb.append(" (").append(executor.getId()).append(" "); + sb.append(bunker.map(b -> b.getId() + " ").orElse("")).append("["); + boolean isFirst = true; + for (MovingObject obj : resources) { + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + sb.append(obj.getId()); + } + sb.append("]"); + sb.append(intensity.map(i -> " " + i).orElse("")); + sb.append(")"); + return sb.toString(); } - + public Operation(String str, + Map m_vessel, + Map m_bunker, + Map m_equipment, + Map m_template) { + + String lStr = str.substring(0, str.indexOf('(')).trim(); + String rStr = str.substring(str.indexOf('(') + 1, str.indexOf(')')).trim(); + + { + String[] items = lStr.split(";"); + setStart(Double.parseDouble(items[2].trim())); + setDuration(Double.parseDouble(items[3].trim())); + setTemplate(m_template.get(Integer.parseInt(items[0].trim()))); + + setFixation(items[1].trim().equals("F")); + } + { + String[] items = rStr.substring(rStr.indexOf('[') + 1, rStr.indexOf(']')).split(","); + ArrayList resources = new ArrayList<>(); + for (String item : items) { + if (item.trim().isEmpty()) { + continue; + } + resources.add(m_equipment.get(Integer.valueOf(item.trim()))); + } + setResources(resources); + } + { + String[] items = rStr.substring(0, rStr.indexOf('[')).split(" "); + + MovingObject ex = m_vessel.get(Integer.valueOf(items[0].trim())); + if (ex == null) { + ex = m_bunker.get(Integer.valueOf(items[0].trim())); + } + setExecutor(ex); + if (items.length > 1) { + setBunker(Optional.of(m_bunker.get(Integer.valueOf(items[1].trim())))); + } + } + String intensity = rStr.substring(rStr.indexOf(']') + 1).trim(); + if (! intensity.isEmpty()) { + setIntensity(Optional.of(Integer.valueOf(intensity))); + } + } } diff --git a/src/inport/ParserException.java b/src/inport/ParserException.java deleted file mode 100644 index 45cd39ac3008a17325aedbd5c74ba18019d0ac97..0000000000000000000000000000000000000000 --- a/src/inport/ParserException.java +++ /dev/null @@ -1,7 +0,0 @@ -package inport; - -public class ParserException extends Exception { - ParserException(String mess) { - super(mess); - } -} diff --git a/src/inport/Storage.java b/src/inport/Storage.java index 0ceed25c3ae18dbd3d71838d785f15e421bab090..a05bd4b5d2b64664a6816723b5308ff7f286849d 100644 --- a/src/inport/Storage.java +++ b/src/inport/Storage.java @@ -4,6 +4,9 @@ */ package inport; +import javafx.util.Pair; + +import java.util.ArrayList; import java.util.Map; /** @@ -13,44 +16,13 @@ import java.util.Map; public class Storage { private int id; private String name; - private double volume; - private Cargo cargo; - - /** - * Get the value of cargo - * - * @return the value of cargo - */ - public Cargo getCargo() { - return cargo; - } - - /** - * Set the value of cargo - * - * @param cargo new value of cargo - */ - public void setCargo(Cargo cargo) { - this.cargo = cargo; - } + private ArrayList> storageSections = new ArrayList<>(); - - /** - * Get the value of volume - * - * @return the value of volume - */ - public double getVolume() { - return volume; + public ArrayList> getStorageSections() { + return storageSections; } - - /** - * Set the value of volume - * - * @param volume new value of volume - */ - public void setVolume(double volume) { - this.volume = volume; + public void setStorageSections(ArrayList> storageSections) { + this.storageSections = storageSections; } /** @@ -89,11 +61,10 @@ public class Storage { this.id = id; } - public Storage(int id, String name, double volume, Cargo cargo) { + public Storage(int id, String name, double volume, ArrayList> storageSections) { this.id = id; this.name = name; - this.volume = volume; - this.cargo = cargo; + this.storageSections = storageSections; } public Storage() { @@ -101,15 +72,38 @@ public class Storage { @Override public String toString() { - return id + ";" + name + ";" + cargo.getId() + ";" +volume; + return id + "; " + name + "; " + storageSectionsToString(storageSections); } public Storage(String s, Map cargoes) { String[] tokens = s.split(";"); id = Integer.parseInt(tokens[0].trim()); name = tokens[1].trim(); - volume = Double.parseDouble(tokens[3].trim()); - int key = Integer.parseInt(tokens[2].trim()); - cargo = cargoes.get(key); + storageSections = storageSectionsFromString(tokens[2], cargoes); + } + + static String storageSectionsToString(ArrayList> storageSections) { + ArrayList sections = new ArrayList<>(); + for (Pair p : storageSections) { + sections.add("(" + p.getKey().getId() + ", " + p.getValue() + ")"); + } + return "[" + String.join(", ",sections) + "]"; + } + static ArrayList> storageSectionsFromString(String str, Map cargoes) { + ArrayList> storageSections = new ArrayList<>(); + String sections = str.substring(str.indexOf('[') + 1, str.indexOf(']')); + for (int pos = 0; pos < sections.length(); ) { + int p1 = sections.indexOf('(', pos); + int p2 = sections.indexOf(')', pos); + if ((p1 >= 0) && (p2 >= 0) && (p1 < p2)) { + int type = Integer.parseInt(sections.substring(p1 + 1, sections.indexOf(',', p1)).trim()); + double cargoMax = Double.parseDouble(sections.substring(sections.indexOf(',', p1) + 1, p2).trim()); + storageSections.add(new Pair<>(cargoes.get(type), cargoMax)); + pos = p2 + 1; + } else { + break; + } + } + return storageSections; } } diff --git a/src/inport/StorageState.java b/src/inport/StorageState.java index d2f9650d283b30e520763a5313123d58b9afa6ec..f05b8cb2e619be13430cc30d59280802de489277 100644 --- a/src/inport/StorageState.java +++ b/src/inport/StorageState.java @@ -76,21 +76,30 @@ public class StorageState { @Override public String toString() { if (storage instanceof Storage) - return cargo.getId() + ";" + ((Storage)storage).getId() + ";" + cargoState; + return cargo.getId() + "; " + ((Storage)storage).getId() + "; " + cargoState; if (storage instanceof TransportShip) - return cargo.getId() + ";" + ((TransportShip)storage).getId() + ";" + cargoState; + return cargo.getId() + "; " + ((TransportShip)storage).getId() + "; " + cargoState; return ""; } - public StorageState(String s, Map mp, Map vp, Map cp) { + public StorageState(String s, + Map mp, + Map vp, + Map bunkers, + Map cp) { String[] tokens = s.split(";"); int key = Integer.parseInt(tokens[0].trim()); cargo = cp.get(key); key = Integer.parseInt(tokens[1].trim()); - if (mp.containsKey(key)) + if (mp.containsKey(key)) { storage = mp.get(key); - if (vp.containsKey(key)) + } + if (vp.containsKey(key)) { storage = vp.get(key); + } + if (bunkers.containsKey(key)) { + storage = bunkers.get(key); + } cargoState = Double.parseDouble(tokens[2].trim()); } diff --git a/src/inport/TaskCase.java b/src/inport/TaskCase.java index 0da26c7131810bf60f00f5f3515625749a2ba1e7..940a959bc96b0d36133c1ac6365bb8edd9ac43e8 100644 --- a/src/inport/TaskCase.java +++ b/src/inport/TaskCase.java @@ -11,11 +11,9 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,18 +22,29 @@ import java.util.logging.Logger; * @author topazh_ag */ public class TaskCase { - + // С типизацией ли + private boolean typified = false; + // Статическая структура порта - private List cargoes; + private List cargoes; private List berths; - private List storages; + private List storages; private List bunkers; private List tows; private List equipments; - + // Обслуживаемые суда private List ships; - + + // Типы бункеровщиков. + private Map bunkerTypes; + + // Типы обслуживаемых судов + private Map vesselTypes; + + // Типы обслуживаемого оборудования. + private Map equipmentTypes; + // Шаблоны операций private List templates; @@ -52,16 +61,33 @@ public class TaskCase { // Горизонт планирования private double planningInterval; - + + // Зафиксированные операции. + private List fixedOperations; + // Тип критерия оптимизации private int criterionType; - + // План - критерий private double solution_result; - + // План - решение private List solution; + public List getFixedOperations() { + return fixedOperations; + } + public void setFixedOperations(List fixedOperations) { + this.fixedOperations = fixedOperations; + } + + public Map getBunkerTypes() { + return bunkerTypes; + } + public void setBunkerTypes(Map bunkerTypes) { + this.bunkerTypes = bunkerTypes; + } + /** * Get the value of solution * @@ -349,15 +375,41 @@ public class TaskCase { this.berths = berths; } + public void setVesselTypes(Map vesselTypes) { + this.vesselTypes = vesselTypes; + } + public Map getVesselTypes() { + return vesselTypes; + } + + public void setEquipmentTypes(Map equipmentTypes) { + this.equipmentTypes = equipmentTypes; + } + public Map getEquipmentsTypes() { + return equipmentTypes; + } + + public boolean isTypified() { + return typified; + } + public void setTypification(boolean typefied) { + this.typified = typefied; + } + public TaskCase() { cargoes = new ArrayList<>(); berths = new ArrayList<>(); storages = new ArrayList<>(); bunkers = new ArrayList<>(); + tows = new ArrayList<>(); equipments = new ArrayList<>(); ships = new ArrayList<>(); - + + bunkerTypes = new TreeMap<>(); + vesselTypes = new TreeMap<>(); + equipmentTypes = new TreeMap<>(); + templates = new ArrayList<>(); cargoFlows = new ArrayList<>(); @@ -367,30 +419,73 @@ public class TaskCase { vesselEndState = new ArrayList<>(); storageEndState = new ArrayList<>(); - + + fixedOperations = new ArrayList<>(); + solution = new ArrayList<>(); - } - private MovingObjectState fromString(String s, Map m_berth, Map m_vessel) + private MovingObjectState fromString(String s, + Map m_berth, + Map m_vessel, + Map m_bunker) { String[] tkns1 = s.split(";"); MovingObjectState st = new MovingObjectState(); int key = Integer.parseInt(tkns1[0].trim()); - MovingObject vs = m_vessel.get(key); + MovingObject vs = m_vessel.containsKey(key) ? m_vessel.get(key) : m_bunker.get(key); st.setVessel(vs); key = Integer.parseInt(tkns1[1].trim()); st.setLocation(m_berth.get(key)); return st; } - + + private enum Tag { + Undefined (""), + Typified ("Typified"), + Cargoes ("Cargoes"), + Berths ("Berths"), + Storages ("Storages"), + Loading_Equipment_Types("Loading Equipment Types"), + Vessel_Types ("Vessel Types"), + Bunkers ("Bunkers"), + Bunker_Types ("Bunker Types"), + Tows ("Tows"), + Loading_Equipments ("Loading Equipments"), + Transport_Ships ("Transport Ships"), + Templates ("Templates"), + Time_Windows ("Time Windows"), + Cargo_Flows ("Cargo Flows"), + Initial_Vessel_State ("Initial Vessel State"), + Initial_Storage_State ("Initial Storage State"), + Final_Vessel_State ("Final Vessel State"), + Final_Storage_State ("Final Storage State"), + Task_Properties ("Task Properties"), + Fixed_Operations ("Fixed Operations"), + Solution ("Solution"); + + private final String text; + Tag(String text) { + this.text = text; + } + public static Tag fromString(String text) { + for (Tag t : Tag.values()) { + if (t.text.equalsIgnoreCase(text)) { + return t; + } + } + return Undefined; + } + } + public void deserialize(String fileName) throws IOException { cargoes.clear(); berths.clear(); storages.clear(); bunkers.clear(); tows.clear(); equipments.clear(); ships.clear(); templates.clear(); cargoFlows.clear(); vesselInitialState.clear(); storageInitialState.clear(); vesselEndState.clear(); storageEndState.clear(); + bunkerTypes.clear(); + fixedOperations.clear(); solution.clear(); - - String[] tags = {"Cargoes", "Berths", "Storages", "Bunkers", "Tows", "Loading Equipments", "Transport Ships", "Templates", "Time Windows", "Cargo Flows", "Initial Vessel State", "Initial Storage State", "Final Vessel State", "Final Storage State", "Task Properties", "Solution"}; + // Open the file FileInputStream fstream; try @@ -398,64 +493,90 @@ public class TaskCase { fstream = new FileInputStream(fileName); BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); String strLine; - int index = 0; + Tag tag = Tag.Undefined; Map m_cargo = new HashMap<>(); Map m_berth = new HashMap<>(); Map m_storage = new HashMap<>(); Map m_vessel = new HashMap<>(); - Map m_equiopment = new HashMap<>(); + Map m_bunker = new HashMap<>(); + Map m_equipment = new HashMap<>(); Map m_template = new HashMap<>(); //Read File Line By Line - int numInside = 0; + int numInside = 0; while ((strLine = br.readLine()) != null) { numInside ++; boolean serviceString = false; - for (int i = 0; i0) - { + if (crs.length()>0) { key = Integer.parseInt(crs.trim()); - mt.getResources().add((Tow)m_vessel.get(key)); + if (isTypified()) { + mt.getResourcesTypes().add(key); + } else { + mt.getResources().add((Tow) m_vessel.get(key)); + } } mt.setDuration(Double.parseDouble(tokens[7].trim())); templates.add(mt); @@ -470,38 +591,74 @@ public class TaskCase { mt.setDirect(false); mt.setTimeWindow(tokens[2].trim()); int key = Integer.parseInt(tokens[3].trim()); - mt.setMoorer((TransportShip)m_vessel.get(key)); + if (isTypified()) { + mt.setMoorerType(OptionalInt.of(key)); + } else { + mt.setMoorer((TransportShip) m_vessel.get(key)); + } key = Integer.parseInt(tokens[4].trim()); mt.setStartLocation(m_berth.get(key)); String[] rs = tokens[5].trim().replace("[", "").replace("]", "").split(","); for (String crs : rs) - if (crs.length()>0) - { + if (crs.length()>0) { key = Integer.parseInt(crs.trim()); - mt.getResources().add((Tow)m_vessel.get(key)); + if (isTypified()) { + mt.getResourcesTypes().add(key); + } else { + mt.getResources().add((Tow) m_vessel.get(key)); + } } - mt.setDuration(Double.parseDouble(tokens[6].trim())); - templates.add(mt); - m_template.put(mt.getId(), mt); + mt.setDuration(Double.parseDouble(tokens[6].trim())); + templates.add(mt); + m_template.put(mt.getId(), mt); } if (tokens[1].trim().equals("loa")) { LoadingTemplate mt = new LoadingTemplate(); mt.setId(Integer.parseInt(tokens[0].trim())); mt.setTimeWindow(tokens[2].trim()); - int direct = 1; - // Источник. Пока пара - это только хранилище-судно. С бункеровкой будем разбираться потом - int key = Integer.parseInt(tokens[3].trim()); - if (m_vessel.containsKey(key)) - { - mt.setLoader((TransportShip)m_vessel.get(key)); - direct = -1; - } - if (m_storage.containsKey(key)) - { - mt.setStorage((Storage)m_storage.get(key)); - direct = 1; - } + + BiFunction extractDirection = (Integer key, Integer loaderDirection) -> { + int dir = 1; + if ((vesselTypes.containsKey(key)) || (m_vessel.containsKey(key))) { + dir = loaderDirection; + } else + if (m_storage.containsKey(key)) { + dir = -loaderDirection; + } else + if ((m_bunker.containsKey(key)) || (bunkerTypes.containsKey(key))) { + if (mt.getStorage() != null) { + dir = loaderDirection; + } else { + dir = -loaderDirection; + } + } + return dir; + }; + + Consumer addLoaderOrStorage = (Integer key) -> { + if (vesselTypes.containsKey(key)) { + mt.setLoaderType(OptionalInt.of(key)); + } else + if (m_vessel.containsKey(key)) { + mt.setLoader((TransportShip)m_vessel.get(key)); + } else + if (m_storage.containsKey(key)) { + mt.setStorage(m_storage.get(key)); + } else + if (m_bunker.containsKey(key)) { + mt.setBunker(Optional.of(m_bunker.get(key))); + } else if (bunkerTypes.containsKey(key)) { + mt.setBunkerType(OptionalInt.of(key)); + } + }; + + int key; + + // Источник. + key = Integer.parseInt(tokens[3].trim()); + addLoaderOrStorage.accept(key); + // Груз. key = Integer.parseInt(tokens[4].trim());; for (Cargo cargo : cargoes) { @@ -509,126 +666,170 @@ public class TaskCase { mt.setCargo(cargo); } } - // Приемник. Пока пара - это только хранилище-судно. С бункеровкой будем разбираться потом + // Приемник. key = Integer.parseInt(tokens[5].trim()); - if (m_vessel.containsKey(key)) - { - mt.setLoader((TransportShip)m_vessel.get(key)); - direct = 1; - } - if (m_storage.containsKey(key)) - { - mt.setStorage((Storage)m_storage.get(key)); - direct = - 1; - } + addLoaderOrStorage.accept(key); + + int direction = extractDirection.apply(key, 1); + key = Integer.parseInt(tokens[6].trim()); mt.setStartLocation(m_berth.get(key)); String[] rs = tokens[7].trim().replace("[", "").replace("]", "").split(","); for (String crs : rs) - if (crs.length()>0) - { + if (crs.length()>0) { key = Integer.parseInt(crs.trim()); - mt.getResources().add(m_equiopment.get(key)); + if (isTypified()) { + mt.getResourcesTypes().add(key); + } else { + mt.getResources().add(m_equipment.get(key)); + } } - mt.setIntensity(direct*Double.parseDouble(tokens[8].trim())); + mt.setIntensity(direction*Double.parseDouble(tokens[8].trim())); mt.setWithMooring(tokens[9].trim().equals("M")); + if ((mt.getStorage() != null) && (mt.getBunkerType().isPresent())) { + mt.setLoaderType(mt.getBunkerType()); + mt.setBunkerType(OptionalInt.empty()); + } + templates.add(mt); m_template.put(mt.getId(), mt); - } + } + break; + case Time_Windows: break; - case 9: + case Cargo_Flows: cargoFlows.add(new CargoFlow(strLine, m_storage, m_cargo)); break; - case 10: cargoFlows.add(new CargoFlow(strLine, m_storage, m_cargo)); + case Initial_Vessel_State: vesselInitialState.add(fromString(strLine, m_berth, m_vessel, m_bunker)); break; - case 11: vesselInitialState.add(fromString(strLine, m_berth, m_vessel)); - break; - case 12: storageInitialState.add(new StorageState(strLine, m_storage, m_vessel, m_cargo)); + case Initial_Storage_State: storageInitialState.add(new StorageState(strLine, m_storage, m_vessel, m_bunker, m_cargo)); break; - case 13: vesselEndState.add(fromString(strLine, m_berth, m_vessel)); - break; - case 14: storageEndState.add(new StorageState(strLine, m_storage, m_vessel, m_cargo)); - break; - case 15: + case Final_Vessel_State: vesselEndState.add(fromString(strLine, m_berth, m_vessel, m_bunker)); + break; + case Final_Storage_State: storageEndState.add(new StorageState(strLine, m_storage, m_vessel, m_bunker, m_cargo)); + break; + case Task_Properties: { String[] rs = strLine.split(";"); planningInterval = Double.parseDouble(rs[0].trim()); criterionType = Integer.parseInt(rs[1].trim()); } - break; - case 16: // Тут чтение операций если надо. Потом подумаем - break; + break; + case Fixed_Operations: + fixedOperations.add(new Operation(strLine, m_vessel, m_bunker, m_equipment, m_template)); + break; + case Solution: // Чтение операций. + if (numInside == 1) { + solution_result = Double.parseDouble(strLine.trim()); + } else { + solution.add(new Operation(strLine, m_vessel, m_bunker, m_equipment, m_template)); + } + break; default: - break; + break; } } //Close the input stream br.close(); } catch (FileNotFoundException ex) { Logger.getLogger(TaskCase.class.getName()).log(Level.SEVERE, null, ex); - } + } } - + + private static class OperationsComparator implements Comparator { + public int compare(Operation op1, Operation op2) { + return Double.compare(op1.getStart(), op2.getStart()); + } + } + public void serialize(String fileName) { try(FileWriter writer = new FileWriter(fileName, false)) { - // запись всего - writer.write("Cargoes"+"\n"); - for (Cargo c : cargoes) - writer.write(c.toString()+"\n"); - writer.write("Berths"+"\n"); - for (Berth c : berths) - writer.write(c.toString()+"\n"); - writer.write("Storages"+"\n"); - for (Storage c : storages) - writer.write(c.toString()+"\n"); - writer.write("Bunkers"+"\n"); - for (Bunker c : bunkers) - writer.write(c.toString()+"\n"); - writer.write("Tows"+"\n"); - for (Tow c : tows) - writer.write(c.toString()+"\n"); - writer.write("Loading Equipments"+"\n"); - for (LoadingEquipment c : equipments) - writer.write(c.toString()+"\n"); - writer.write("Transport Ships"+"\n"); - for (TransportShip c : ships) - writer.write(c.toString()+"\n"); - writer.write("\n"); - writer.write("Templates"+"\n"); - for (OperationTemplate c : templates) - writer.write(c.toString()+"\n"); - writer.write("\n"); - writer.write("Cargo Flows"+"\n"); - for (CargoFlow c : cargoFlows) - writer.write(c.toString()+"\n"); - writer.write("Initial Vessel State"+"\n"); - for (MovingObjectState c : vesselInitialState) - writer.write(c.toString()+"\n"); - writer.write("Initial Storage State"+"\n"); - for (StorageState c : storageInitialState) - writer.write(c.toString()+"\n"); - writer.write("Final Vessel State"+"\n"); - for (MovingObjectState c : vesselEndState) - writer.write(c.toString()+"\n"); - writer.write("Final Storage State"+"\n"); - for (StorageState c : storageEndState) - writer.write(c.toString()+"\n"); - writer.write("\n"); - writer.write("Task Properties"+"\n"); - writer.write(planningInterval+";"+criterionType+"\n"); - writer.write("\n"); - writer.write("Solution"+"\n"); - writer.write(solution_result+"\n"); - for (Operation c : solution) - writer.write(c.toString()+"\n"); - writer.flush(); + // запись всего + writer.write(Tag.Typified.text + "\n" + (isTypified()? "1" : "0") + "\n"); + + writer.write("\nCargoes"+"\n"); + for (Cargo c : cargoes) + writer.write(c.toString()+"\n"); + writer.write("\nBerths"+"\n"); + for (Berth c : berths) + writer.write(c.toString()+"\n"); + writer.write("\nStorages"+"\n"); + for (Storage c : storages) { + writer.write(c.toString() + "\n"); + } + if (isTypified()) { + writer.write("\n" + Tag.Vessel_Types.text + "\n"); + for (Map.Entry e : vesselTypes.entrySet()) { + writer.write(e.getKey() + "; " + e.getValue() + "\n"); + } + + writer.write("\n" + Tag.Bunker_Types.text + "\n"); + for (Map.Entry e : bunkerTypes.entrySet()) { + writer.write(e.getKey() + "; " + e.getValue() + "\n"); + } + } + + writer.write("\nBunkers"+"\n"); + for (Bunker c : bunkers) + writer.write(c.toString()+"\n"); + writer.write("\nTows"+"\n"); + for (Tow c : tows) { + writer.write(c.toString() + "\n"); + } + if (isTypified()) { + writer.write("\n" + Tag.Loading_Equipment_Types.text + "\n"); + for (Map.Entry e : equipmentTypes.entrySet()) { + writer.write(e.getKey() + "; " + e.getValue() + "\n"); + } + } + writer.write("\nLoading Equipments"+"\n"); + for (LoadingEquipment c : equipments) + writer.write(c.toString()+"\n"); + writer.write("\nTransport Ships"+"\n"); + for (TransportShip c : ships) + writer.write(c.toString()+"\n"); + writer.write("\nTemplates"+"\n"); + for (OperationTemplate c : templates) + writer.write(c.toString()+"\n"); + + writer.write("\nCargo Flows"+"\n"); + for (CargoFlow c : cargoFlows) + writer.write(c.toString()+"\n"); + writer.write("\nInitial Vessel State"+"\n"); + for (MovingObjectState c : vesselInitialState) + writer.write(c.toString()+"\n"); + writer.write("\nInitial Storage State"+"\n"); + for (StorageState c : storageInitialState) + writer.write(c.toString()+"\n"); + writer.write("\nFinal Vessel State"+"\n"); + for (MovingObjectState c : vesselEndState) + writer.write(c.toString()+"\n"); + writer.write("\nFinal Storage State"+"\n"); + for (StorageState c : storageEndState) + writer.write(c.toString()+"\n"); + writer.write("\n"); + writer.write("\nTask Properties"+"\n"); + writer.write(planningInterval+"; "+criterionType+"\n"); + + writer.write("\n" + Tag.Fixed_Operations.text + "\n"); + for (Operation op : fixedOperations) { + writer.write(op.toString() + "\n"); + } + writer.write("\n"); + writer.write("\nSolution"+"\n"); + writer.write(solution_result+"\n"); + + solution.sort(new OperationsComparator()); + + for (Operation c : solution) + writer.write(c.toString()+"\n"); + writer.flush(); } - catch(IOException ex){ - + catch(IOException ex) { System.out.println(ex.getMessage()); - } + } } public void formSolutionFromPB(int res[]) @@ -1203,7 +1404,7 @@ public class TaskCase { writer.write("* Current Storage Volume Constraints \n"); for (Storage st : storages) { - int V = (int)st.getVolume(); + int V = (int) (double) st.getStorageSections().get(0).getValue(); double V0 = 0; for (StorageState sst : storageInitialState) if (sst.getStorage().equals(st)) @@ -1540,7 +1741,7 @@ public class TaskCase { { int i = templates.indexOf(tp); LoadingTemplate ltp = (LoadingTemplate)tp; - if (ltp.getLoader().equals(s) && ltp.getStorage().getCargo().equals(c)) + if (ltp.getLoader().equals(s) && ltp.getStorage().getStorageSections().get(0).getKey().equals(c)) { vc.add(i); int itsv = (int)ltp.getIntensity(); @@ -1582,7 +1783,7 @@ public class TaskCase { nCons++; } // Ограничение на грузоподъемность судна - int maxLoad = (int)(s.getCargoMax()+1.0); + int maxLoad = (int)(s.getStorageSections().get(0).getValue() + 1.0); if (sumplus > (maxLoad - start)) { writer.write(clause + " <= " + (maxLoad - start + epsilon) + " ;\n"); diff --git a/src/inport/Testing.java b/src/inport/Testing.java new file mode 100644 index 0000000000000000000000000000000000000000..07b50ffd1c59b0b0153445f5cc5bda4161d1bb57 --- /dev/null +++ b/src/inport/Testing.java @@ -0,0 +1,327 @@ +package inport; + +import inport.ConversionUtils.MZnResultsResolver; +import inport.ConversionUtils.ParserException; +import inport.ConversionUtils.Task; +import javafx.util.Pair; + +import java.io.*; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +public class Testing { + private static void removeDirectory(File dir) { + if (dir.isDirectory()) { + File[] files = dir.listFiles(); + if (files != null && files.length > 0) { + for (File aFile : files) { + removeDirectory(aFile); + } + } + } + dir.delete(); + } + + public static String solveTask_1(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_1.mzn", + Task::portToMiniZinc_1, + MZnResultsResolver::resolveMiniZincResults, + timeLimitS); + } + + public static String solveTask_2(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2.mzn", + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, + timeLimitS); + } + + public static String solveTaskWithPartialCargoOp(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2_with_partial_cargo_operations.mzn", + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, + timeLimitS); + } + + public static String solveTaskWithGreedyConstraints(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2_greedy.mzn", + Task::portToMiniZincGreedy, + MZnResultsResolver::resolveMiniZincResults, + timeLimitS); + } + + public static String solveTaskWithGreedyConstraintsV2(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2_greedy_v2.mzn", + Task::portToMiniZincGreedyV2, + MZnResultsResolver::resolveMiniZincResults, + timeLimitS); + } + + public static String solveTask_2_0(TaskCase task, int timeLimitS) { + return solveTask( + task, + "conversion_2.0.mzn", + Task::portToMiniZinc_2, + MZnResultsResolver::resolveMiniZincResults, + "temp_data_2", + timeLimitS); + } + + public static String solveTask(TaskCase task, + String constraintName, + BiConsumer converterToMinizincFormat, + BiConsumer interpreter, + int timeLimitS) { + return solveTask(task, constraintName, converterToMinizincFormat, interpreter, "temp_data", timeLimitS); + } + + private final static Lock lock = new ReentrantLock(); + private final static Condition condition = lock.newCondition(); + private static Boolean isDestroyed; + + /* Возвращает описание ошибки, если ошибки не было, то пустую строку. */ + public static String solveTask(TaskCase task, + String constraintName, + BiConsumer converterToMinizincFormat, + BiConsumer interpreter, + String tempDir, + final int timeLimitS) { + File directory = new File(tempDir); + if (!directory.exists()) { + directory.mkdir(); + } + + tempDir = tempDir + "/"; + String minizincData = tempDir + "minizinc_data.dzn"; + String solverResults = tempDir + "solver_results.txt"; + String constraints = tempDir + "constraints.mzn"; + + try { + try (FileWriter res = new FileWriter(constraints)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream("/constraints/" + constraintName))); + String line; + while ((line = reader.readLine()) != null) { + res.write(line + "\n"); + } + } + converterToMinizincFormat.accept(task, minizincData); + + ProcessBuilder pb = new ProcessBuilder("minizinc", + "--solver", "Chuffed", + constraints, minizincData, + "-o", solverResults); + + lock.lock(); + isDestroyed = false; + lock.unlock(); + + final Process process = pb.start(); + + Thread killer = new Thread(() -> { + lock.lock(); + long start = System.currentTimeMillis(); + try { + while (process.isAlive()) { + long currentTimeMillis = System.currentTimeMillis(); + + if (currentTimeMillis - start > timeLimitS * 1000) { + process.destroyForcibly(); + isDestroyed = true; + break; + } + condition.await(timeLimitS * 1000 - (currentTimeMillis - start), TimeUnit.MILLISECONDS); + } + } catch (InterruptedException ex) { + isDestroyed = true; + process.destroyForcibly(); + } finally { + lock.unlock(); + } + }); + + killer.start(); + int exitCode = process.waitFor(); + + lock.lock(); + try { + condition.signal(); + } finally { + lock.unlock(); + } + killer.join(); + assert exitCode == 0; + + lock.lock(); + try { + if (isDestroyed) { + return "Time limit exceeded."; + } + }finally { + lock.unlock(); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); + String output = br.lines().collect(Collectors.joining("\n")); + +// BufferedReader br2 = new BufferedReader(new InputStreamReader(process.getErrorStream())); +// String errors = br.lines().collect(Collectors.joining("\n")); + +// System.out.println("output : " + output); +// System.out.println("errors : " + errors); + + if (output.trim().equals("=====UNSATISFIABLE=====")) { + task.setSolution(new ArrayList<>()); + task.setSolution_result(-1); + } else { + interpreter.accept(task, solverResults); + } + } catch (UncheckedIOException | IOException | InterruptedException | ParserException ex) { + return ex.getMessage(); + } finally { +// removeDirectory(directory); + } + return ""; + } + + private static String testCase(String file, BiFunction solver, int timeLimitS) { + TaskCase task = new TaskCase(); + try { + task.deserialize(file); + } catch (IOException e) { + return "Error : " + e.getMessage(); + } + double expected_result = task.getSolution_result(); + String error = solver.apply(task, timeLimitS); + double result = task.getSolution_result(); + if (!error.isEmpty()) { + return "Error : " + error; + } + if (expected_result != result) { + return "WA : expected " + expected_result + ", found " + result; + } + return "OK"; + } + + public static void testGroup(String group, BiFunction solver, int timeLimitS) { + File testDir = new File("tests/" + group + "/"); + System.out.println(testDir.toString() + " :"); + + int nPassedTests = 0; + + for (File file : testDir.listFiles()) { + System.out.println(" " + file.getName() + " : "); + + long start = System.currentTimeMillis(); + + String res = testCase(testDir.toString() + "/" + file.getName(), solver, timeLimitS); + + long finish = System.currentTimeMillis(); + System.out.println(" " + res + ", " + (finish - start) / 1000.0 + " s"); + if (res.equals("OK")) { + nPassedTests++; + } + } + System.out.println("Passed tests : " + nPassedTests + "/" + testDir.listFiles().length); + } + + public static void test_1(int timeLimitS) { + testGroup("without_typing", Testing::solveTask_1, timeLimitS); + } + + static void test_2(int timeLimitS) { + testGroup("with_typing", Testing::solveTask_2, timeLimitS); + } + public static void testWithPartialOp(int timeLimitS) { + testGroup("with_typing", Testing::solveTaskWithPartialCargoOp, timeLimitS); + } + + static void testingWithDiffParameters(String test, + double cargoMult, double cargoMultMax, + double nIntevals, double nIntervalsMax, + double step, int timeLimitS) throws IOException { + System.out.println(test); + System.out.print("* "); + for (double i = Math.ceil(nIntevals); i <= nIntervalsMax; i = Math.ceil(step * i)) { + System.out.print(i + " "); + } + System.out.println(); + + + File directory = new File("debug_dir/"); + if (!directory.exists()) { + directory.mkdir(); + } + + for (double mult = Math.ceil(cargoMult); mult <= cargoMultMax; mult = Math.ceil(step * mult)) { + System.out.print(mult + " "); + for (double i = Math.ceil(nIntevals); i <= nIntervalsMax; i = Math.ceil(step * i)) { + TaskCase taskCase = new TaskCase(); + taskCase.deserialize(test); + + taskCase.setPlanningInterval(i); + + for (OperationTemplate template : taskCase.getTemplates()) { + if (template instanceof LoadingTemplate) { + LoadingTemplate op = (LoadingTemplate)template; + op.setIntensity(op.getIntensity() * mult); + } + } + for (TransportShip ship : taskCase.getShips()) { + ArrayList> sections = new ArrayList<>(); + for (Pair p : ship.getStorageSections()) { + sections.add(new Pair<>(p.getKey(), p.getValue() * mult)); + } + ship.setStorageSections(sections); + } + for (StorageState state : taskCase.getStorageInitialState()) { + state.setCargoState(state.getCargoState() * mult); + } + for (StorageState state : taskCase.getStorageEndState()) { + state.setCargoState(state.getCargoState() * mult); + } + for (Storage storage : taskCase.getStorages()) { + ArrayList> sections = new ArrayList<>(); + for (Pair p : storage.getStorageSections()) { + sections.add(new Pair<>(p.getKey(), p.getValue() * mult)); + } + storage.setStorageSections(sections); + } + for (Operation operation : taskCase.getSolution()) { + final double m = mult; + operation.setIntensity(operation.getIntensity().map(v -> (int)(v * m))); + } + +// taskCase.serialize(directory + "/" + mult + " " + i + ".tipp"); + + long start = System.currentTimeMillis(); + String result = solveTaskWithPartialCargoOp(taskCase, timeLimitS); + long finish = System.currentTimeMillis(); + + if (result.isEmpty()) { + System.out.print((finish - start) / 1000.0 + " "); + } else if (result.equals("Time limit exceeded.")) { + System.out.print("TL "); + } else { + System.out.print("ER "); + } + } + System.out.println(); + } + } +} diff --git a/src/inport/Tow.java b/src/inport/Tow.java index bbcf746ff8cfdec2da0b3d9b8eecba86a840a0d1..8c18860c403d1117e190b5927d0071f19d3d7c66 100644 --- a/src/inport/Tow.java +++ b/src/inport/Tow.java @@ -4,6 +4,8 @@ */ package inport; +import java.util.OptionalInt; + /** * * @author topazh_ag @@ -19,12 +21,18 @@ public class Tow extends MovingObject { @Override public String toString() { - return getId() + ";" + getName() + ";1000000"; + String res = getId() + "; " + getName() + "; 1000000"; + if (getType().isPresent()) { + res += "; " + getType().getAsInt(); + } + return res; } public Tow(String s) { super(s); + String[] tokens = s.split(";"); + if (tokens.length >= 4) { + setType(OptionalInt.of(Integer.parseInt(tokens[3].trim()))); + } } - - } diff --git a/src/inport/TowUsingTemplate.java b/src/inport/TowUsingTemplate.java index f79ea36c713d9be8e99767450dbd04fc29e6317b..235cf4fa613f4fde8f06262dedbad4e053aee8fb 100644 --- a/src/inport/TowUsingTemplate.java +++ b/src/inport/TowUsingTemplate.java @@ -12,11 +12,10 @@ import java.util.List; * @author topazh_ag */ public abstract class TowUsingTemplate extends OperationTemplate { - private List resources; + private List resourcesTypes; private double duration; - /** * Get the value of resources @@ -36,6 +35,13 @@ public abstract class TowUsingTemplate extends OperationTemplate { this.resources = resources; } + public List getResourcesTypes() { + return resourcesTypes; + } + public void setResourcesTypes(List resourcesTypes) { + this.resourcesTypes = resourcesTypes; + } + /** * Get the value of duration * @@ -59,11 +65,13 @@ public abstract class TowUsingTemplate extends OperationTemplate { public TowUsingTemplate(double duration, int id, Berth startLocation) { super(id, startLocation); this.resources = new ArrayList<>(); + this.resourcesTypes = new ArrayList<>(); this.duration = duration; } public TowUsingTemplate() { this.resources = new ArrayList<>(); + this.resourcesTypes = new ArrayList<>(); } @Override @@ -80,6 +88,4 @@ public abstract class TowUsingTemplate extends OperationTemplate { } return getId() + ";" + "tut" + ";" + ";[" + res +"];"+duration; } - - } diff --git a/src/inport/TransportShip.java b/src/inport/TransportShip.java index 9c64925e886c4f84ff20eaf61d6aa79138b2fe63..514e3adffd1614a477809e361687b11e4cb18001 100644 --- a/src/inport/TransportShip.java +++ b/src/inport/TransportShip.java @@ -4,25 +4,31 @@ */ package inport; +import javafx.util.Pair; + +import java.util.ArrayList; +import java.util.Map; +import java.util.OptionalInt; + /** * * @author topazh_ag */ public class TransportShip extends MovingObject { - - private double cargoMax; - public double getCargoMax() { - return cargoMax; + private ArrayList> storageSections = new ArrayList<>(); + + public ArrayList> getStorageSections() { + return storageSections; } - public void setCargoMax(double cargoMax) { - this.cargoMax = cargoMax; + public void setStorageSections(ArrayList> storageSections) { + this.storageSections = storageSections; } - public TransportShip(int id, String name, double cargoMax) { + public TransportShip(int id, String name, ArrayList> storageSections) { super(id, name); - this.cargoMax = cargoMax; + this.storageSections = storageSections; } public TransportShip() { @@ -30,13 +36,23 @@ public class TransportShip extends MovingObject { @Override public String toString() { - return getId() + ";" + getName() + ";" + cargoMax; + String res = getId() + "; " + getName() + "; " + Storage.storageSectionsToString(storageSections); + + if (getType().isPresent()) { + res += "; " + getType().getAsInt(); + } + return res; } - public TransportShip(String s) { + public TransportShip(String s, Map cargoes) { super(s); String[] tokens = s.split(";"); - cargoMax = Double.parseDouble(tokens[2].trim()); + + storageSections = Storage.storageSectionsFromString(tokens[2], cargoes); + + if (tokens.length >= 4) { + setType(OptionalInt.of(Integer.parseInt(tokens[3].trim()))); + } } } diff --git a/tests/requiring_optimization/Case_SPB.tipp b/tests/requiring_optimization/Case_SPB.tipp new file mode 100644 index 0000000000000000000000000000000000000000..3abeacf29b3c283343ad5bfae0312a0d2d20a1aa --- /dev/null +++ b/tests/requiring_optimization/Case_SPB.tipp @@ -0,0 +1,299 @@ +Typified +1 + +Cargoes +10001; Нефть +10002; Бункеровочный СПГ + +Berths +6; Внешний рейд +5; Петербургский нефтяной терминал 1 +4; Петербургский нефтяной терминал 2 +3; Петербургский нефтяной терминал 3 +2; Бункеровочный терминал Кировский завод +1; Бункеровочный терминал Горская + +Storages +2001; Гоское хранилище СПГ; [(10002, 1000000)] +2002; Хранилище СПГ Кировского завода; [(10002, 1000000)] +2003; Нефтехранилище; [(10001, 1000000)] + +Vessel Types +1002; Буксиры +1003; Нефтяные танкеры + +Bunker Types +1001; Бункеровщики + +Bunkers +11; Бункеровщик 1; [(10002, 3000)]; 1001 +12; Бункеровщик 2; [(10002, 3000)]; 1001 +13; Бункеровщик 3; [(10002, 3000)]; 1001 +14; Бункеровщик 4; [(10002, 3000)]; 1001 + +Tows +21; Буксир 1; []; 1002 +22; Буксир 2; []; 1002 +23; Буксир 3; []; 1002 +24; Буксир 4; []; 1002 +25; Буксир 5; []; 1002 + +Loading Equipment Types +1004; Насосы + +Loading Equipments +41; Насос 1; 1004 + +Transport Ships +31; Танкер 1; [(10001, 45000), (10002, 4500)]; 1003 +32; Танкер 2; [(10001, 45000), (10002, 4500)]; 1003 +33; Танкер 3; [(10001, 45000), (10002, 4500)]; 1003 +34; Танкер 4; [(10001, 45000), (10002, 4500)]; 1003 +35; Танкер 5; [(10001, 45000), (10002, 4500)]; 1003 +36; Танкер 6; [(10001, 45000), (10002, 4500)]; 1003 +37; Танкер 7; [(10001, 45000), (10002, 4500)]; 1003 +38; Танкер 8; [(10001, 45000), (10002, 4500)]; 1003 + + +Templates +/* Внешний рейд - ПНТ-1, 2, 3 +20165; mov; []; 1001; 6; 5; []; 16 +20265; mov; []; 1002; 6; 5; []; 16 +20365; mov; []; 1003; 6; 5; []; 16 + +20164; mov; []; 1001; 6; 4; []; 16 +20264; mov; []; 1002; 6; 4; []; 16 +20364; mov; []; 1003; 6; 4; []; 16 + +20163; mov; []; 1001; 6; 3; []; 16 +20263; mov; []; 1002; 6; 3; []; 16 +20363; mov; []; 1003; 6; 3; []; 16 + +20156; mov; []; 1001; 5; 6; []; 16 +20256; mov; []; 1002; 5; 6; []; 16 +20356; mov; []; 1003; 5; 6; []; 16 + +20146; mov; []; 1001; 4; 6; []; 16 +20246; mov; []; 1002; 4; 6; []; 16 +20346; mov; []; 1003; 4; 6; []; 16 + +20136; mov; []; 1001; 3; 6; []; 16 +20236; mov; []; 1002; 3; 6; []; 16 +20336; mov; []; 1003; 3; 6; []; 16 + +/* Внешний рейд - Бункеровочный терминал Горская +20161; mov; []; 1001; 6; 1; []; 14 +20261; mov; []; 1002; 6; 1; []; 14 +20361; mov; []; 1003; 6; 1; []; 14 + +20116; mov; []; 1001; 1; 6; []; 14 +20216; mov; []; 1002; 1; 6; []; 14 +20316; mov; []; 1003; 1; 6; []; 14 + +/* Внешний рейд - Бункеровочный терминал Кировский завод +20162; mov; []; 1001; 6; 2; []; 18 +20262; mov; []; 1002; 6; 2; []; 18 + +20126; mov; []; 1001; 2; 6; []; 18 +20226; mov; []; 1002; 2; 6; []; 18 + +/* Бункеровочный терминал Горская - ПНТ-1, 2, 3 +20115; mov; []; 1001; 1; 5; []; 6 +20215; mov; []; 1002; 1; 5; []; 6 +20315; mov; []; 1003; 1; 5; []; 6 + +20114; mov; []; 1001; 1; 4; []; 6 +20214; mov; []; 1002; 1; 4; []; 6 +20314; mov; []; 1003; 1; 4; []; 6 + +20113; mov; []; 1001; 1; 3; []; 6 +20213; mov; []; 1002; 1; 3; []; 6 +20313; mov; []; 1003; 1; 3; []; 6 + +20151; mov; []; 1001; 5; 1; []; 6 +20251; mov; []; 1002; 5; 1; []; 6 +20351; mov; []; 1003; 5; 1; []; 6 + +20141; mov; []; 1001; 4; 1; []; 6 +20241; mov; []; 1002; 4; 1; []; 6 +20341; mov; []; 1003; 4; 1; []; 6 + +20131; mov; []; 1001; 3; 1; []; 6 +20231; mov; []; 1002; 3; 1; []; 6 +20331; mov; []; 1003; 3; 1; []; 6 + +/* Бункеровочный терминал Кировский завод - ПНТ-1, 2, 3 +20125; mov; []; 1001; 2; 5; []; 2 +20225; mov; []; 1002; 2; 5; []; 2 +20325; mov; []; 1003; 2; 5; [1002]; 2 + +20124; mov; []; 1001; 2; 4; []; 2 +20224; mov; []; 1002; 2; 4; []; 2 +20324; mov; []; 1003; 2; 4; [1002]; 2 + +20123; mov; []; 1001; 2; 3; []; 2 +20223; mov; []; 1002; 2; 3; []; 2 +20323; mov; []; 1003; 2; 3; [1002]; 2 + +20152; mov; []; 1001; 5; 2; []; 2 +20252; mov; []; 1002; 5; 2; []; 2 +20352; mov; []; 1003; 5; 2; [1002]; 2 + +20142; mov; []; 1001; 4; 2; []; 2 +20242; mov; []; 1002; 4; 2; []; 2 +20342; mov; []; 1003; 4; 2; [1002]; 2 + +20132; mov; []; 1001; 3; 2; []; 2 +20232; mov; []; 1002; 3; 2; []; 2 +20332; mov; []; 1003; 3; 2; [1002]; 2 + +/* ПНТ - ПНТ +20134; mov; []; 1001; 3; 4; []; 1 +20234; mov; []; 1002; 3; 4; []; 1 +20334; mov; []; 1003; 3; 4; []; 1 + +20135; mov; []; 1001; 3; 5; []; 1 +20235; mov; []; 1002; 3; 5; []; 1 +20335; mov; []; 1003; 3; 5; []; 1 + +20145; mov; []; 1001; 4; 5; []; 1 +20245; mov; []; 1002; 4; 5; []; 1 +20345; mov; []; 1003; 4; 5; []; 1 + +20143; mov; []; 1001; 4; 3; []; 1 +20243; mov; []; 1002; 4; 3; []; 1 +20343; mov; []; 1003; 4; 3; []; 1 + +20153; mov; []; 1001; 5; 3; []; 1 +20253; mov; []; 1002; 5; 3; []; 1 +20353; mov; []; 1003; 5; 3; []; 1 + +20154; mov; []; 1001; 5; 4; []; 1 +20254; mov; []; 1002; 5; 4; []; 1 +20354; mov; []; 1003; 5; 4; []; 1 + +/* Швартовка - отшвартовка +30031; mrn; []; 1003; 1; [1002, 1002]; 4 +30032; mrn; []; 1003; 2; [1002, 1002]; 4 +30033; mrn; []; 1003; 3; [1002, 1002]; 4 +30034; mrn; []; 1003; 4; [1002, 1002]; 4 +30035; mrn; []; 1003; 5; [1002, 1002]; 4 + +30011; mrn; []; 1001; 1; [1002, 1002]; 4 +30012; mrn; []; 1001; 2; [1002, 1002]; 4 + +30131; unm; []; 1003; 1; [1002, 1002]; 4 +30132; unm; []; 1003; 2; [1002, 1002]; 4 +30133; unm; []; 1003; 3; [1002, 1002]; 4 +30134; unm; []; 1003; 4; [1002, 1002]; 4 +30135; unm; []; 1003; 5; [1002, 1002]; 4 + +30111; unm; []; 1001; 1; [1002, 1002]; 4 +30112; unm; []; 1001; 2; [1002, 1002]; 4 + +/* Разгрузка танкеров на ПНТ +40001; loa; []; 1003; 10001; 2003; 3; []; 3000; M +40002; loa; []; 1003; 10001; 2003; 4; []; 3000; M +40003; loa; []; 1003; 10001; 2003; 5; []; 3000; M + +/* Заправка СПГ на бункеровочных причалах. +40011; loa; []; 2001; 10002; 1003; 1; []; 300; M +40012; loa; []; 2002; 10002; 1003; 2; []; 300; M +40013; loa; []; 2001; 10002; 1001; 1; []; 300; M +40014; loa; []; 2002; 10002; 1001; 2; []; 300; M + +/* Бункеровка на всех причалах. +40021; loa; []; 1001; 10002; 1003; 1; []; 300; M +40022; loa; []; 1001; 10002; 1003; 2; []; 300; M +40023; loa; []; 1001; 10002; 1003; 3; []; 300; M +40024; loa; []; 1001; 10002; 1003; 4; []; 300; M +40025; loa; []; 1001; 10002; 1003; 5; []; 300; M + +Cargo Flows + +Initial Vessel State +/* Танкеры. +31; 6 +32; 6 +33; 6 +34; 6 +35; 6 +36; 6 +37; 6 +38; 6 + +/* Бункеровщики. +11; 1 +12; 1 +13; 2 +14; 2 + +/* Буксиры. +21; 3 +22; 3 +23; 3 +24; 3 +25; 3 + +Initial Storage State +10002; 2001; 500000 +10002; 2002; 500000 +10001; 2003; 500000 + +10001; 31; 45000 +10002; 31; 0 +10001; 32; 45000 +10002; 32; 0 +10001; 33; 45000 +10002; 33; 0 +10001; 34; 45000 +10002; 34; 0 +10001; 35; 45000 +10002; 35; 0 +10001; 36; 45000 +10002; 36; 0 +10001; 37; 45000 +10002; 37; 0 +10001; 38; 45000 +10002; 38; 0 + +/* Бункеровщики пусты. +10002; 11; 0 +10002; 12; 0 +10002; 13; 0 +10002; 14; 0 + +Final Vessel State +31; 6 +32; 6 +33; 6 +34; 6 +35; 6 +36; 6 +37; 6 +38; 6 + +Final Storage State +10001; 31; 0 +10002; 31; 4500 +10001; 32; 0 +10002; 32; 4500 +10001; 33; 0 +10002; 33; 4500 +10001; 34; 0 +10002; 34; 4500 +10001; 35; 0 +10002; 35; 4500 +10001; 36; 0 +10002; 36; 4500 +10001; 37; 0 +10002; 37; 4500 +10001; 38; 0 +10002; 38; 4500 + +Task Properties +16.0; 0 + + +Solution +16.0 diff --git a/tests/requiring_optimization/Case_SPB_lite_1.tipp b/tests/requiring_optimization/Case_SPB_lite_1.tipp new file mode 100644 index 0000000000000000000000000000000000000000..25327bfeb3e9c05bedf67ef59050a2903e473c18 --- /dev/null +++ b/tests/requiring_optimization/Case_SPB_lite_1.tipp @@ -0,0 +1,236 @@ +/* Оставлен 1 танкер, 2 буксира, 1 бункеровщик +Typified +1 + +Cargoes +10001; Нефть +10002; Бункеровочный СПГ + +Berths +6; Внешний рейд +5; Петербургский нефтяной терминал 1 +4; Петербургский нефтяной терминал 2 +3; Петербургский нефтяной терминал 3 +2; Бункеровочный терминал Кировский завод +1; Бункеровочный терминал Горская + +Storages +2001; Гоское хранилище СПГ; [(10002, 1000000)] +2002; Хранилище СПГ Кировского завода; [(10002, 1000000)] +2003; Нефтехранилище; [(10001, 1000000)] + +Vessel Types +1002; Буксиры +1003; Нефтяные танкеры + +Bunker Types +1001; Бункеровщики + +Bunkers +11; Бункеровщик 1; [(10002, 3000)]; 1001 + +Tows +21; Буксир 1; []; 1002 +22; Буксир 2; []; 1002 + +Loading Equipment Types +1004; Насосы + +Loading Equipments +41; Насос 1; 1004 + +Transport Ships +31; Танкер 1; [(10001, 45000), (10002, 4500)]; 1003 + + +Templates +/* Внешний рейд - ПНТ-1, 2, 3 +20165; mov; []; 1001; 6; 5; []; 16 +20265; mov; []; 1002; 6; 5; []; 16 +20365; mov; []; 1003; 6; 5; []; 16 + +20164; mov; []; 1001; 6; 4; []; 16 +20264; mov; []; 1002; 6; 4; []; 16 +20364; mov; []; 1003; 6; 4; []; 16 + +20163; mov; []; 1001; 6; 3; []; 16 +20263; mov; []; 1002; 6; 3; []; 16 +20363; mov; []; 1003; 6; 3; []; 16 + +20156; mov; []; 1001; 5; 6; []; 16 +20256; mov; []; 1002; 5; 6; []; 16 +20356; mov; []; 1003; 5; 6; []; 16 + +20146; mov; []; 1001; 4; 6; []; 16 +20246; mov; []; 1002; 4; 6; []; 16 +20346; mov; []; 1003; 4; 6; []; 16 + +20136; mov; []; 1001; 3; 6; []; 16 +20236; mov; []; 1002; 3; 6; []; 16 +20336; mov; []; 1003; 3; 6; []; 16 + +/* Внешний рейд - Бункеровочный терминал Горская +20161; mov; []; 1001; 6; 1; []; 14 +20261; mov; []; 1002; 6; 1; []; 14 +20361; mov; []; 1003; 6; 1; []; 14 + +20116; mov; []; 1001; 1; 6; []; 14 +20216; mov; []; 1002; 1; 6; []; 14 +20316; mov; []; 1003; 1; 6; []; 14 + +/* Внешний рейд - Бункеровочный терминал Кировский завод +20162; mov; []; 1001; 6; 2; []; 18 +20262; mov; []; 1002; 6; 2; []; 18 + +20126; mov; []; 1001; 2; 6; []; 18 +20226; mov; []; 1002; 2; 6; []; 18 + +/* Бункеровочный терминал Горская - ПНТ-1, 2, 3 +20115; mov; []; 1001; 1; 5; []; 6 +20215; mov; []; 1002; 1; 5; []; 6 +20315; mov; []; 1003; 1; 5; []; 6 + +20114; mov; []; 1001; 1; 4; []; 6 +20214; mov; []; 1002; 1; 4; []; 6 +20314; mov; []; 1003; 1; 4; []; 6 + +20113; mov; []; 1001; 1; 3; []; 6 +20213; mov; []; 1002; 1; 3; []; 6 +20313; mov; []; 1003; 1; 3; []; 6 + +20151; mov; []; 1001; 5; 1; []; 6 +20251; mov; []; 1002; 5; 1; []; 6 +20351; mov; []; 1003; 5; 1; []; 6 + +20141; mov; []; 1001; 4; 1; []; 6 +20241; mov; []; 1002; 4; 1; []; 6 +20341; mov; []; 1003; 4; 1; []; 6 + +20131; mov; []; 1001; 3; 1; []; 6 +20231; mov; []; 1002; 3; 1; []; 6 +20331; mov; []; 1003; 3; 1; []; 6 + +/* Бункеровочный терминал Кировский завод - ПНТ-1, 2, 3 +20125; mov; []; 1001; 2; 5; []; 2 +20225; mov; []; 1002; 2; 5; []; 2 +20325; mov; []; 1003; 2; 5; [1002]; 2 + +20124; mov; []; 1001; 2; 4; []; 2 +20224; mov; []; 1002; 2; 4; []; 2 +20324; mov; []; 1003; 2; 4; [1002]; 2 + +20123; mov; []; 1001; 2; 3; []; 2 +20223; mov; []; 1002; 2; 3; []; 2 +20323; mov; []; 1003; 2; 3; [1002]; 2 + +20152; mov; []; 1001; 5; 2; []; 2 +20252; mov; []; 1002; 5; 2; []; 2 +20352; mov; []; 1003; 5; 2; [1002]; 2 + +20142; mov; []; 1001; 4; 2; []; 2 +20242; mov; []; 1002; 4; 2; []; 2 +20342; mov; []; 1003; 4; 2; [1002]; 2 + +20132; mov; []; 1001; 3; 2; []; 2 +20232; mov; []; 1002; 3; 2; []; 2 +20332; mov; []; 1003; 3; 2; [1002]; 2 + +/* ПНТ - ПНТ +20134; mov; []; 1001; 3; 4; []; 1 +20234; mov; []; 1002; 3; 4; []; 1 +20334; mov; []; 1003; 3; 4; []; 1 + +20135; mov; []; 1001; 3; 5; []; 1 +20235; mov; []; 1002; 3; 5; []; 1 +20335; mov; []; 1003; 3; 5; []; 1 + +20145; mov; []; 1001; 4; 5; []; 1 +20245; mov; []; 1002; 4; 5; []; 1 +20345; mov; []; 1003; 4; 5; []; 1 + +20143; mov; []; 1001; 4; 3; []; 1 +20243; mov; []; 1002; 4; 3; []; 1 +20343; mov; []; 1003; 4; 3; []; 1 + +20153; mov; []; 1001; 5; 3; []; 1 +20253; mov; []; 1002; 5; 3; []; 1 +20353; mov; []; 1003; 5; 3; []; 1 + +20154; mov; []; 1001; 5; 4; []; 1 +20254; mov; []; 1002; 5; 4; []; 1 +20354; mov; []; 1003; 5; 4; []; 1 + +/* Швартовка - отшвартовка +30031; mrn; []; 1003; 1; [1002, 1002]; 4 +30032; mrn; []; 1003; 2; [1002, 1002]; 4 +30033; mrn; []; 1003; 3; [1002, 1002]; 4 +30034; mrn; []; 1003; 4; [1002, 1002]; 4 +30035; mrn; []; 1003; 5; [1002, 1002]; 4 + +30011; mrn; []; 1001; 1; [1002, 1002]; 4 +30012; mrn; []; 1001; 2; [1002, 1002]; 4 + +30131; unm; []; 1003; 1; [1002, 1002]; 4 +30132; unm; []; 1003; 2; [1002, 1002]; 4 +30133; unm; []; 1003; 3; [1002, 1002]; 4 +30134; unm; []; 1003; 4; [1002, 1002]; 4 +30135; unm; []; 1003; 5; [1002, 1002]; 4 + +30111; unm; []; 1001; 1; [1002, 1002]; 4 +30112; unm; []; 1001; 2; [1002, 1002]; 4 + +/* Разгрузка танкеров на ПНТ +40001; loa; []; 1003; 10001; 2003; 3; []; 3000; M +40002; loa; []; 1003; 10001; 2003; 4; []; 3000; M +40003; loa; []; 1003; 10001; 2003; 5; []; 3000; M + +/* Заправка СПГ на бункеровочных причалах. +40011; loa; []; 2001; 10002; 1003; 1; []; 300; M +40012; loa; []; 2002; 10002; 1003; 2; []; 300; M +40013; loa; []; 2001; 10002; 1001; 1; []; 300; M +40014; loa; []; 2002; 10002; 1001; 2; []; 300; M + +/* Бункеровка на всех причалах. +40021; loa; []; 1001; 10002; 1003; 1; []; 300; M +40022; loa; []; 1001; 10002; 1003; 2; []; 300; M +40023; loa; []; 1001; 10002; 1003; 3; []; 300; M +40024; loa; []; 1001; 10002; 1003; 4; []; 300; M +40025; loa; []; 1001; 10002; 1003; 5; []; 300; M + +Cargo Flows + +Initial Vessel State +/* Танкеры. +31; 6 + +/* Бункеровщики. +11; 2 + +/* Буксиры. +21; 3 +22; 3 + +Initial Storage State +10002; 2001; 500000 +10002; 2002; 500000 +10001; 2003; 500000 + +10001; 31; 45000 +10002; 31; 0 + +/* Бункеровщики пусты. +10002; 11; 0 + +Final Vessel State +31; 6 + +Final Storage State +10001; 31; 0 +10002; 31; 4500 + +Task Properties +16.0; 0 + + +Solution +80.0 diff --git a/tests/requiring_optimization/Case_SPB_lite_2.tipp b/tests/requiring_optimization/Case_SPB_lite_2.tipp new file mode 100644 index 0000000000000000000000000000000000000000..ece51c28e55c79f0c9d04e86afd417941c40a777 --- /dev/null +++ b/tests/requiring_optimization/Case_SPB_lite_2.tipp @@ -0,0 +1,125 @@ +/* Оставлен один ПНТ, удалён Бункеровочный терминал Горская +Typified +1 + +Cargoes +10001; Нефть +10002; Бункеровочный СПГ + +Berths +6; Внешний рейд +5; Петербургский нефтяной терминал 1 +2; Бункеровочный терминал Кировский завод + +Storages +2002; Хранилище СПГ Кировского завода; [(10002, 1000000)] +2003; Нефтехранилище; [(10001, 1000000)] + +Vessel Types +1002; Буксиры +1003; Нефтяные танкеры + +Bunker Types +1001; Бункеровщики + +Bunkers +11; Бункеровщик 1; [(10002, 3000)]; 1001 + +Tows +21; Буксир 1; []; 1002 +22; Буксир 2; []; 1002 + +Loading Equipment Types +1004; Насосы + +Loading Equipments +41; Насос 1; 1004 + +Transport Ships +31; Танкер 1; [(10001, 45000), (10002, 4500)]; 1003 + + +Templates +/* Внешний рейд - ПНТ-1, 2, 3 +20165; mov; []; 1001; 6; 5; []; 16 +20265; mov; []; 1002; 6; 5; []; 16 +20365; mov; []; 1003; 6; 5; []; 16 + +20156; mov; []; 1001; 5; 6; []; 16 +20256; mov; []; 1002; 5; 6; []; 16 +20356; mov; []; 1003; 5; 6; []; 16 + +/* Внешний рейд - Бункеровочный терминал Кировский завод +20162; mov; []; 1001; 6; 2; []; 18 +20262; mov; []; 1002; 6; 2; []; 18 + +20126; mov; []; 1001; 2; 6; []; 18 +20226; mov; []; 1002; 2; 6; []; 18 + +/* Бункеровочный терминал Кировский завод - ПНТ-1, 2, 3 +20125; mov; []; 1001; 2; 5; []; 2 +20225; mov; []; 1002; 2; 5; []; 2 +20325; mov; []; 1003; 2; 5; [1002]; 2 + +20152; mov; []; 1001; 5; 2; []; 2 +20252; mov; []; 1002; 5; 2; []; 2 +20352; mov; []; 1003; 5; 2; [1002]; 2 + +/* Швартовка - отшвартовка +30032; mrn; []; 1003; 2; [1002, 1002]; 4 +30035; mrn; []; 1003; 5; [1002, 1002]; 4 + +30012; mrn; []; 1001; 2; [1002, 1002]; 4 + +30132; unm; []; 1003; 2; [1002, 1002]; 4 +30135; unm; []; 1003; 5; [1002, 1002]; 4 + +30112; unm; []; 1001; 2; [1002, 1002]; 4 + +/* Разгрузка танкеров на ПНТ +40003; loa; []; 1003; 10001; 2003; 5; []; 3000; M + +/* Заправка СПГ на бункеровочных причалах. +40012; loa; []; 2002; 10002; 1003; 2; []; 300; M +40014; loa; []; 2002; 10002; 1001; 2; []; 300; M + +/* Бункеровка на всех причалах. +40022; loa; []; 1001; 10002; 1003; 2; []; 300; M +40025; loa; []; 1001; 10002; 1003; 5; []; 300; M + +Cargo Flows + +Initial Vessel State +/* Танкеры. +31; 6 + +/* Бункеровщики. +11; 2 + +/* Буксиры. +21; 5 +22; 5 + +Initial Storage State +10002; 2002; 500000 +10001; 2003; 500000 + +10001; 31; 45000 +10002; 31; 0 + +/* Бункеровщики пусты. +10002; 11; 0 + +Final Vessel State +31; 6 + +Final Storage State +10001; 31; 0 +10002; 31; 4500 + +Task Properties +100.0; 0 + + +Solution +16.0 diff --git a/tests/requiring_optimization/Case_SPB_lite_3.tipp b/tests/requiring_optimization/Case_SPB_lite_3.tipp new file mode 100644 index 0000000000000000000000000000000000000000..5607fbe7dcc6406a0716fb32efe5c504c6998707 --- /dev/null +++ b/tests/requiring_optimization/Case_SPB_lite_3.tipp @@ -0,0 +1,142 @@ +/* Теперь буксир 1, он один нужен для швартовки. +/* Результат : 638.79 s, ответ - 75 +Typified +1 + +Cargoes +10001; Нефть +10002; Бункеровочный СПГ + +Berths +6; Внешний рейд +5; Петербургский нефтяной терминал 1 +2; Бункеровочный терминал Кировский завод + +Storages +2002; Хранилище СПГ Кировского завода; [(10002, 1000000)] +2003; Нефтехранилище; [(10001, 1000000)] + +Vessel Types +1002; Буксиры +1003; Нефтяные танкеры + +Bunker Types +1001; Бункеровщики + +Bunkers +11; Бункеровщик 1; [(10002, 3000)]; 1001 + +Tows +21; Буксир 1; []; 1002 + +Loading Equipment Types + +Loading Equipments + +Transport Ships +31; Танкер 1; [(10001, 45000), (10002, 4500)]; 1003 + + +Templates +/* Внешний рейд - ПНТ-1, 2, 3 +20165; mov; []; 1001; 6; 5; []; 16 +20265; mov; []; 1002; 6; 5; []; 16 +20365; mov; []; 1003; 6; 5; []; 16 + +20156; mov; []; 1001; 5; 6; []; 16 +20256; mov; []; 1002; 5; 6; []; 16 +20356; mov; []; 1003; 5; 6; []; 16 + +/* Внешний рейд - Бункеровочный терминал Кировский завод +20162; mov; []; 1001; 6; 2; []; 18 +20262; mov; []; 1002; 6; 2; []; 18 + +20126; mov; []; 1001; 2; 6; []; 18 +20226; mov; []; 1002; 2; 6; []; 18 + +/* Бункеровочный терминал Кировский завод - ПНТ-1, 2, 3 +20125; mov; []; 1001; 2; 5; []; 2 +20225; mov; []; 1002; 2; 5; []; 2 +20325; mov; []; 1003; 2; 5; [1002]; 2 + +20152; mov; []; 1001; 5; 2; []; 2 +20252; mov; []; 1002; 5; 2; []; 2 +20352; mov; []; 1003; 5; 2; [1002]; 2 + +/* Швартовка - отшвартовка +30032; mrn; []; 1003; 2; [1002]; 4 +30035; mrn; []; 1003; 5; [1002]; 4 + +30012; mrn; []; 1001; 2; [1002]; 4 + +30132; unm; []; 1003; 2; [1002]; 4 +30135; unm; []; 1003; 5; [1002]; 4 + +30112; unm; []; 1001; 2; [1002]; 4 + +/* Разгрузка танкеров на ПНТ +40003; loa; []; 1003; 10001; 2003; 5; []; 3000; M + +/* Заправка СПГ на бункеровочных причалах. +40012; loa; []; 2002; 10002; 1003; 2; []; 300; M +40014; loa; []; 2002; 10002; 1001; 2; []; 300; M + +/* Бункеровка на всех причалах. +40022; loa; []; 1001; 10002; 1003; 2; []; 300; M +40025; loa; []; 1001; 10002; 1003; 5; []; 300; M + +Cargo Flows + +Initial Vessel State +/* Танкеры. +31; 6 + +/* Бункеровщики. +11; 2 + +/* Буксиры. +21; 5 + +Initial Storage State +10002; 2002; 500000 +10001; 2003; 500000 + +10001; 31; 45000 +10002; 31; 0 + +/* Бункеровщики пусты. +10002; 11; 0 + +Final Vessel State +31; 6 + +Final Storage State +10001; 31; 0 +10002; 31; 4500 + +Task Properties +80.0; 0 + + +Solution +75.0 +20365; R; 0.0; 16.0 (31 []) +20252; R; 0.0; 2.0 (21 []) +30012; R; 2.0; 4.0 (11 [21]) +20225; R; 6.0; 2.0 (21 []) +40014; R; 6.0; 10.0 (11 [] 300) +30035; R; 16.0; 4.0 (31 [21]) +20252; R; 20.0; 2.0 (21 []) +40003; R; 20.0; 15.0 (31 [] 3000) +30112; R; 22.0; 4.0 (11 [21]) +20225; R; 26.0; 2.0 (21 []) +30135; R; 35.0; 4.0 (31 [21]) +20352; R; 39.0; 2.0 (31 [21]) +30032; R; 41.0; 4.0 (31 [21]) +40012; R; 45.0; 7.0 (31 [] 300) +40022; R; 45.0; 8.0 (31 11 [] 300) +20125; R; 53.0; 2.0 (11 []) +30132; R; 53.0; 4.0 (31 [21]) +20325; R; 57.0; 2.0 (31 [21]) +20356; R; 59.0; 16.0 (31 []) +20252; R; 59.0; 2.0 (21 []) diff --git a/tests/requiring_optimization/Case_SPB_lite_4.tipp b/tests/requiring_optimization/Case_SPB_lite_4.tipp new file mode 100644 index 0000000000000000000000000000000000000000..aeb19884bb2eba74edc474eff1ffba1433f5add4 --- /dev/null +++ b/tests/requiring_optimization/Case_SPB_lite_4.tipp @@ -0,0 +1,100 @@ +/* Убираем буксиры и швертовку. +Typified +1 + +Cargoes +10001; Нефть +10002; Бункеровочный СПГ + +Berths +6; Внешний рейд +5; Петербургский нефтяной терминал 1 +2; Бункеровочный терминал Кировский завод + +Storages +2002; Хранилище СПГ Кировского завода; [(10002, 1000000)] +2003; Нефтехранилище; [(10001, 1000000)] + +Vessel Types +1003; Нефтяные танкеры + +Bunker Types +1001; Бункеровщики + +Bunkers +11; Бункеровщик 1; [(10002, 3000)]; 1001 + +Tows + +Loading Equipment Types +1004; Насосы + +Loading Equipments +41; Насос 1; 1004 + +Transport Ships +31; Танкер 1; [(10001, 45000), (10002, 4500)]; 1003 + + +Templates +/* Внешний рейд - ПНТ-1, 2, 3 +20165; mov; []; 1001; 6; 5; []; 16 +20365; mov; []; 1003; 6; 5; []; 16 + +20156; mov; []; 1001; 5; 6; []; 16 +20356; mov; []; 1003; 5; 6; []; 16 + +/* Внешний рейд - Бункеровочный терминал Кировский завод +20162; mov; []; 1001; 6; 2; []; 18 +20126; mov; []; 1001; 2; 6; []; 18 + +/* Бункеровочный терминал Кировский завод - ПНТ-1, 2, 3 +20125; mov; []; 1001; 2; 5; []; 2 +20325; mov; []; 1003; 2; 5; []; 2 + +20152; mov; []; 1001; 5; 2; []; 2 +20352; mov; []; 1003; 5; 2; []; 2 + +/* Разгрузка танкеров на ПНТ +40003; loa; []; 1003; 10001; 2003; 5; []; 3000; U + +/* Заправка СПГ на бункеровочных причалах. +40012; loa; []; 2002; 10002; 1003; 2; []; 300; U +40014; loa; []; 2002; 10002; 1001; 2; []; 300; U + +/* Бункеровка на всех причалах. +40022; loa; []; 1001; 10002; 1003; 2; []; 300; U +40025; loa; []; 1001; 10002; 1003; 5; []; 300; U + +Cargo Flows + +Initial Vessel State +/* Танкеры. +31; 6 + +/* Бункеровщики. +11; 2 + +Initial Storage State +10002; 2002; 500000 +10001; 2003; 500000 + +10001; 31; 45000 +10002; 31; 0 + +/* Бункеровщики пусты. +10002; 11; 0 + +Final Vessel State +31; 6 + +Final Storage State +10001; 31; 0 +10002; 31; 4500 + +Task Properties +80.0; 0 + + +Solution +16.0 diff --git a/tests/requiring_optimization/mp.tipp b/tests/requiring_optimization/mp.tipp new file mode 100644 index 0000000000000000000000000000000000000000..a4fcdc4d4a266e1f0f843e2d182980e1d58f5430 --- /dev/null +++ b/tests/requiring_optimization/mp.tipp @@ -0,0 +1,124 @@ +Typified +1 + +Cargoes +363; Груз1 +364; Груз2 +365; Груз3 +Berths +366; Рейд +367; Терминал1 +368; Терминал2 +Storages +369; Хранилище1; [(363, 400)] +370; Хранилище2; [(364, 400)] +371; Хранилище3; [(365, 400)] + +Vessel Types +1001; Тип судна1 +1002; Тип буксира1 + +Tows +374; Буксир1; []; 1002 +375; Буксир2; []; 1002 +376; Буксир3; []; 1002 +Transport Ships +377; Судно1; [(363, 400), (364, 400), (365, 400)]; 1001 +378; Судно2; [(363, 400), (364, 400), (365, 400)]; 1001 +379; Судно3; [(363, 400), (364, 400), (365, 400)]; 1001 + +Loading Equipment Types +1003; Тип насоса1 +1004; Тип насоса2 +1005; Тип насоса3 + +Loading Equipments +381; Насос1; 1003 +382; Насос2; 1004 +383; Плавучий насос; 1005 +Templates + +85; mov; []; 1001; 366; 367; []; 3 +88; mov; []; 1001; 366; 367; [1002]; 1 + +97; mov; []; 1001; 366; 368; []; 3 +100; mov; []; 1001; 366; 368; [1002]; 1 + +109; mov; []; 1001; 367; 366; []; 3 +112; mov; []; 1001; 367; 366; [1002]; 1 + +121; mov; []; 1001; 368; 366; []; 3 +124; mov; []; 1001; 368; 366; [1002]; 1 + +245; unm; []; 1001; 368; [1002, 1002]; 1 +191; mrn; []; 1001; 368; [1002, 1002]; 1 +218; unm; []; 1001; 367; [1002, 1002]; 1 +164; mrn; []; 1001; 367; [1002, 1002]; 1 + +144; mov; []; 1002; 368; 366; []; 1 +139; mov; []; 1002; 367; 366; []; 1 +133; mov; []; 1002; 366; 367; []; 1 +136; mov; []; 1002; 366; 368; []; 1 + +146; mov; []; 1005; 367; 368; [1002, 1002]; 1 +155; mov; []; 1005; 368; 367; [1002, 1002]; 1 + +4; loa; []; 369; 363; 1001; 367; [1003]; 5; M +10; loa; []; 370; 364; 1001; 367; [1003]; 4; M +12; loa; []; 370; 364; 1001; 367; [1005]; 10; M +16; loa; []; 371; 365; 1001; 367; [1003]; 8; M + +2; loa; []; 1001; 363; 369; 367; [1003]; 5; M +6; loa; []; 1001; 364; 370; 367; [1003]; 4; M +8; loa; []; 1001; 364; 370; 367; [1005]; 10; M +14; loa; []; 1001; 365; 371; 367; [1003]; 8; M + +20; loa; []; 369; 363; 1001; 368; [1004]; 10; M +24; loa; []; 370; 364; 1001; 368; [1005]; 10; M +28; loa; []; 371; 365; 1001; 368; [1004]; 4; M + +18; loa; []; 1001; 363; 369; 368; [1004]; 10; M +22; loa; []; 1001; 364; 370; 368; [1005]; 10; M +26; loa; []; 1001; 365; 371; 368; [1004]; 4; M + +Initial Vessel State +377; 366 +378; 366 +379; 366 +374; 367 +375; 368 +376; 366 +381; 367 +382; 368 +383; 368 +Final Vessel State +377; 366 +378; 366 +379; 366 +Initial Storage State +363; 377; 10 +364; 377; 20 +365; 377; 12 +363; 378; 20 +364; 378; 0 +365; 378; 0 +363; 379; 0 +364; 379; 8 +365; 379; 12 +363; 369; 10 +364; 370; 8 +365; 371; 12 +Final Storage State +363; 377; 0 +364; 377; 0 +365; 377; 0 +363; 378; 0 +364; 378; 20 +365; 378; 32 +363; 379; 40 +364; 379; 0 +365; 379; 0 +Task Properties +50; 0 +Solution +1 diff --git a/tests/with_typing/Bunkers.tipp b/tests/with_typing/Bunkers.tipp new file mode 100644 index 0000000000000000000000000000000000000000..2d7694a5f7b729a37cdf4cfbba6f5ff82ab9739f --- /dev/null +++ b/tests/with_typing/Bunkers.tipp @@ -0,0 +1,84 @@ +Typified +1 + +Cargoes +10001; Нечто; 0.0 +10002; Топливо; 0.0 + +Berths +1; Raid +2; Pier 1 +3; Pier 2 + +Storages +4; Storage 1; [(10001, 10000.0)] + +Vessel Types +1001; Тип судна 1 + +Bunker Types +2001; Тип бункировщика 1 + +Bunkers +201; Bunker 1; [(10002, 2000.0)]; 2001 +202; Bunker 2; [(10002, 2000.0)]; 2001 + +Tows + +Loading Equipment Types + +Loading Equipments + +Transport Ships +101; Ship 1; [(10001, 2000.0), (10002, 200.0)]; 1001 +102; Ship 2; [(10001, 2000.0), (10002, 200.0)]; 1001 + +Templates +7; mov; []; 1001; 1; 2; []; 1.0 +8; mov; []; 1001; 2; 1; []; 1.0 +9; mov; []; 1001; 1; 3; []; 1.0 +10; mov; []; 1001; 3; 1; []; 1.0 +11; mov; []; 1001; 2; 3; []; 1.0 +12; mov; []; 1001; 3; 2; []; 1.0 +13; mov; []; 2001; 3; 2; []; 1.0 +14; mov; []; 2001; 3; 2; []; 1.0 +19; loa; []; 4; 10001; 1001; 2; []; 20.0; U +20; loa; []; 2001; 10002; 1001; 2; []; 2.0; U + +Cargo Flows + +Initial Vessel State +101; 1 +102; 1 +201; 2 +202; 2 + +Initial Storage State +10001; 101; 0.0 +10002; 101; 0.0 +10001; 102; 0.0 +10002; 102; 0.0 +10002; 201; 4.0 +10002; 202; 4.0 +10001; 4; 10000.0 + +Final Vessel State +101; 1 +102; 1 + +Final Storage State +10001; 101; 60.0 +10002; 101; 4.0 +10001; 102; 60.0 +10002; 102; 4.0 + + +Task Properties +20.0; 0 + +Fixed Operations +20; F; 1.0; 2.0 (101 202 [] 2) + +Solution +8.0 +20; F; 1.0; 2.0 (101 202 [] 2) diff --git a/tests/with_typing/Case1.tipp b/tests/with_typing/Case1.tipp new file mode 100644 index 0000000000000000000000000000000000000000..28454682aa77d56a1815c15263a3e58f6159af5b --- /dev/null +++ b/tests/with_typing/Case1.tipp @@ -0,0 +1,72 @@ +Typified +1 + +Cargoes +313; Груз1; 0.0 + +Berths +314; Рейд +315; Терминал1 +316; Терминал2 + +Storages +317; Хранилище1; [(313, 270.0)] + +Vessel Types +1001; Тип судна1 +1002; Тип буксира1 + +Bunkers + +Tows +320; Буксир1; []; 1002 + +Loading Equipment Types +1003; Кран + +Loading Equipments +323; Плавучий кран; 1003 + +Transport Ships +321; Судно1; [(313, 1000000.0)]; 1001 + +Templates +8; mov; []; 1002; 314; 316; []; 1.0 +9; mov; []; 1002; 315; 316; []; 3.0 +5; mov; []; 1002; 315; 314; []; 1.0 +7; mov; []; 1002; 316; 314; []; 1.0 +11; mov; []; 1001; 314; 315; [1002]; 2.0 +6; mov; []; 1001; 314; 316; [1002]; 2.0 +10; mov; []; 1003; 316; 315; [1002]; 3.0 +2; loa; []; 1001; 313; 317; 315; [1003]; 20.0; U +4; loa; []; 1001; 313; 317; 316; [1003]; 15.0; U + +Cargo Flows + +Initial Vessel State +321; 314 +323; 316 +320; 315 + +Initial Storage State +313; 317; 0.0 +313; 321; 100.0 + +Final Vessel State + +Final Storage State +313; 321; 0.0 + + +Task Properties +18.0; 0 + + +Solution +13.0 +5; R; 0.0; 1.0 (320 []) +8; R; 1.0; 1.0 (320 []) +10; R; 2.0; 3.0 (323 [320]) +5; R; 5.0; 1.0 (320 []) +11; R; 6.0; 2.0 (321 [320]) +2; R; 8.0; 5.0 (321 [323]) diff --git a/tests/with_typing/Case2.tipp b/tests/with_typing/Case2.tipp new file mode 100644 index 0000000000000000000000000000000000000000..94526323a3139384fc624b790713833ec4a70d84 --- /dev/null +++ b/tests/with_typing/Case2.tipp @@ -0,0 +1,111 @@ +Typified +1 + +Cargoes +83; Груз1; 0.0 +84; Груз2; 0.0 +85; Груз3; 0.0 + +Berths +86; Рейд +87; Терминал1 +88; Терминал2 + +Storages +89; Хранилище1; [(83, 100.0)] +90; Хранилище2; [(84, 100.0)] +91; Хранилище3; [(85, 100.0)] + +Vessel Types +1001; Тип судна1 +1002; Тип буксира1 + +Bunkers + +Tows +94; Буксир1; []; 1002 +95; Буксир2; []; 1002 + +Loading Equipment Types +1003; Тип крана 1 +1004; Тип крана 1 +1005; Тип крана 1 + +Loading Equipments +99; Плавучий кран 1; 1003 +100; Плавучий кран 2; 1004 +101; Плавучий кран 3; 1005 + +Transport Ships +96; Судно1; [(83, 1000.0), (84, 1000.0), (85, 1000.0)]; 1001 + +Templates +10; mrn; []; 1001; 88; [1002,1002]; 1.0 +13; mov; []; 1002; 86; 88; []; 1.0 +16; mov; []; 1002; 87; 88; []; 3.0 +15; mov; []; 1002; 87; 86; []; 1.0 +11; mov; []; 1002; 88; 86; []; 1.0 +8; mov; []; 1001; 86; 88; [1002]; 2.0 +2; loa; []; 1001; 83; 89; 88; [1003, 1004]; 2.0; M +4; loa; []; 1001; 84; 90; 88; [1003, 1005]; 1.0; M +5; loa; []; 1001; 84; 90; 88; [1004, 1005]; 1.0; M +7; loa; []; 1001; 85; 91; 88; [1005]; 1.0; M + +Cargo Flows + +Initial Vessel State +96; 86 +99; 88 +100; 88 +101; 88 +94; 87 +95; 88 + +Initial Storage State +83; 89; 0.0 +84; 90; 0.0 +85; 91; 0.0 +83; 96; 6.0 +84; 96; 6.0 +85; 96; 6.0 + +Final Vessel State + +Final Storage State +83; 96; 0.0 +84; 96; 0.0 +85; 96; 0.0 + + +Task Properties +26.0; 0 + + +Solution +16.0 +15; R; 0.0; 1.0 (94 []) +8; R; 1.0; 2.0 (96 [94]) +10; R; 3.0; 1.0 (96 [94, 95]) +11; R; 3.0; 1.0 (95 []) +2; R; 4.0; 2.0 (96 [99, 100]) +7; R; 4.0; 2.0 (96 [101]) +5; R; 6.0; 1.0 (96 [100, 101]) +13; R; 7.0; 1.0 (95 []) +7; R; 7.0; 2.0 (96 [101]) +11; R; 8.0; 1.0 (94 []) +11; R; 8.0; 1.0 (95 []) +13; R; 9.0; 1.0 (95 []) +4; R; 9.0; 2.0 (96 [99, 101]) +11; R; 11.0; 1.0 (95 []) +5; R; 11.0; 1.0 (96 [100, 101]) +13; R; 12.0; 1.0 (94 []) +13; R; 12.0; 1.0 (95 []) +7; R; 12.0; 1.0 (96 [101]) +11; R; 13.0; 1.0 (95 []) +5; R; 13.0; 1.0 (96 [100, 101]) +13; R; 14.0; 1.0 (95 []) +4; R; 14.0; 1.0 (96 [99, 101]) +11; R; 15.0; 1.0 (94 []) +11; R; 15.0; 1.0 (95 []) +2; R; 15.0; 1.0 (96 [99, 100]) +7; R; 15.0; 1.0 (96 [101]) diff --git a/tests/with_typing/FixedOperations.tipp b/tests/with_typing/FixedOperations.tipp new file mode 100644 index 0000000000000000000000000000000000000000..ca8ac7ed72be18a9d0b2b05b25b3bc0816f187d3 --- /dev/null +++ b/tests/with_typing/FixedOperations.tipp @@ -0,0 +1,72 @@ +Typified +1 + +Cargoes +0; LNG; 0.0 + +Berths +1; Raid +2; Pier 1 +3; Pier 2 + +Storages +4; Storage 1; [(0, 1000.0)] + +Vessel Types +1001; Тип судна1 + +Bunkers + +Tows + +Loading Equipment Types + +Loading Equipments + +Transport Ships +5; Ship 1; [(0, 200.0)]; 1001 +6; Ship 2; [(0, 200.0)]; 1001 + +Templates +7; mov; []; 1001; 1; 2; []; 1.0 +8; mov; []; 1001; 2; 1; []; 1.0 +9; mov; []; 1001; 1; 3; []; 1.0 +10; mov; []; 1001; 3; 1; []; 1.0 +11; mov; []; 1001; 2; 3; []; 1.0 +12; mov; []; 1001; 3; 2; []; 1.0 +19; loa; []; 4; 0; 1001; 2; []; 10.0; U +20; loa; []; 4; 0; 1001; 3; []; 5.0; U + +21; mov; []; 1001; 1; 1; []; 3.0 + +Cargo Flows + +Initial Vessel State +5; 1 +6; 1 + +Initial Storage State +0; 5; 0.0 +0; 6; 0.0 +0; 4; 1000.0 + +Final Vessel State +5; 1 +6; 1 + +Final Storage State +0; 5; 100.0 +0; 6; 100.0 + + +Task Properties +30.0; 0 + +Fixed Operations +21; F; 0.0; 3.0 (5 []) +19; F; 6.0; 3.0 (5 [] 10) + +Solution +18.0 +21; F; 0.0; 3.0 (5 []) +19; F; 6.0; 3.0 (5 [] 10) diff --git a/tests/with_typing/TaskBK.tipp b/tests/with_typing/TaskBK.tipp new file mode 100644 index 0000000000000000000000000000000000000000..e71b630feee8fb6e5cf156adfd3801300cb16ab4 --- /dev/null +++ b/tests/with_typing/TaskBK.tipp @@ -0,0 +1,71 @@ +Typified +1 + +Cargoes +0; LNG; 0.0 + +Berths +1; Raid +2; Pier 1 +3; Pier 2 + +Storages +4; Storage 1; [(0, 270.0)] + +Vessel Types +1001; Тип судна1 +1002; Тип бункеровщика1 + +Bunkers + +Tows +6; Tow 1; []; 1002 + +Loading Equipment Types +1003; Кран + +Loading Equipments +5; Плавучий кран; 1003 + +Transport Ships +7; Ship 1; [(0, 2000.0)]; 1001 + +Templates +8; mov; []; 1001; 1; 2; [1002]; 2.0 +9; mov; []; 1001; 2; 1; [1002]; 2.0 +10; mov; []; 1002; 3; 1; []; 2.0 +11; mov; []; 1002; 2; 1; []; 2.0 +12; mov; []; 1002; 2; 3; []; 1.0 +13; mov; []; 1003; 3; 2; [1002]; 2.0 +14; loa; []; 1001; 0; 4; 2; [1003]; 20.0; U + +Cargo Flows + +Initial Vessel State +7; 1 +6; 2 +5; 3 + +Initial Storage State +0; 4; 0.0 +0; 7; 100.0 + +Final Vessel State +7; 1 + +Final Storage State +0; 7; 0.0 + + +Task Properties +25.0; 0 + + +Solution +14.0 +11; R; 0.0; 2.0 (6 []) +8; R; 2.0; 2.0 (7 [6]) +12; R; 4.0; 1.0 (6 []) +13; R; 5.0; 2.0 (5 [6]) +14; R; 7.0; 5.0 (7 [5]) +9; R; 12.0; 2.0 (7 [6]) diff --git a/tests/with_typing/TaskT.tipp b/tests/with_typing/TaskT.tipp new file mode 100644 index 0000000000000000000000000000000000000000..52fdbb404cf7cf4984e68823e5caaad3758c7520 --- /dev/null +++ b/tests/with_typing/TaskT.tipp @@ -0,0 +1,77 @@ +Typified +1 + +Cargoes +0; LNG; 0.0 + +Berths +1; Raid +2; Pier 1 +3; Pier 2 + +Storages +4; Storage 1; [(0, 200)] + +Vessel Types +1001; Тип судна1 + +Bunker Types + +Bunkers + +Tows + +Loading Equipment Types + +Loading Equipments + +Transport Ships +5; Ship 1; [(0, 40.0)]; 1001 +6; Ship 2; [(0, 40.0)]; 1001 + +Templates +7; mov; []; 1001; 1; 2; []; 1.0 +8; mov; []; 1001; 2; 1; []; 1.0 +9; mov; []; 1001; 1; 3; []; 1.0 +10; mov; []; 1001; 3; 1; []; 1.0 +11; mov; []; 1001; 2; 3; []; 1.0 +12; mov; []; 1001; 3; 2; []; 1.0 +19; loa; []; 4; 0; 1001; 2; []; 2.0; U +20; loa; []; 4; 0; 1001; 3; []; 1.0; U + +Cargo Flows + +Initial Vessel State +5; 1 +6; 1 + +Initial Storage State +0; 5; 0.0 +0; 6; 0.0 +0; 4; 200.0 + +Final Vessel State +5; 1 +6; 1 + +Final Storage State +0; 5; 20.0 +0; 6; 20.0 + + +Task Properties +24.0; 0 + + +Solution +16.0 +7; R; 0.0; 1.0 (6 []) +9; R; 0.0; 1.0 (5 []) +19; R; 1.0; 7.0 (6 [] 10) +20; R; 1.0; 6.0 (5 [] 5) +12; R; 7.0; 1.0 (5 []) +11; R; 8.0; 1.0 (6 []) +19; R; 8.0; 7.0 (5 [] 10) +20; R; 9.0; 6.0 (6 [] 5) +8; R; 15.0; 1.0 (5 []) +10; R; 15.0; 1.0 (6 []) diff --git a/tests/with_typing/TwoTransports.tipp b/tests/with_typing/TwoTransports.tipp new file mode 100644 index 0000000000000000000000000000000000000000..9a0fff5f9099bd59ea21473cfe5478df9b636bd9 --- /dev/null +++ b/tests/with_typing/TwoTransports.tipp @@ -0,0 +1,64 @@ +Typified +1 + +Cargoes +83; Груз1; 0.0 + +Berths +86; Рейд + +Storages +89; Хранилище1; [(83, 1000.0)] + +Vessel Types +1001; Тип судна1 + +Bunkers + +Tows + +Loading Equipment Types + +Loading Equipments + +Transport Ships +101; Судно1; [(83, 1000000.0)]; 1001 +102; Судно2; [(83, 1000000.0)]; 1001 + +Templates +1; mrn; []; 1001; 86; []; 1.0 +2; unm; []; 1001; 86; []; 1.0 +3; loa; []; 1001; 83; 89; 86; []; 10.0; M + +Cargo Flows + +Initial Vessel State +101; 86 +102; 86 + +Initial Storage State +83; 89; 100.0 +83; 101; 10.0 +83; 102; 10.0 + +Final Vessel State +101; 86 +102; 86 + +Final Storage State +83; 101; 0.0 +83; 102; 0.0 + + +Task Properties +10.0; 0 + + +Solution +6.0 +1; R; 0.0; 1.0 (101 []) +3; R; 1.0; 1.0 (101 []) +2; R; 2.0; 1.0 (101 []) +1; R; 3.0; 1.0 (102 []) +3; R; 4.0; 1.0 (102 []) +2; R; 5.0; 1.0 (102 []) diff --git a/tests/with_typing/mixed_load_op_on_mooring.tipp b/tests/with_typing/mixed_load_op_on_mooring.tipp new file mode 100644 index 0000000000000000000000000000000000000000..735ada14486f6bbfbdbcb8d844a35ad664316f38 --- /dev/null +++ b/tests/with_typing/mixed_load_op_on_mooring.tipp @@ -0,0 +1,83 @@ +Typified +1 + +Cargoes +0; LNG; 0.0 + +Berths +1; Raid +2; Pier 1 + +Storages +4; Storage 1; [(0, 10000.0)] + +Vessel Types +1001; Тип судна1 +1002; Тип судна2 + +Bunkers + +Tows + +Loading Equipment Types + +Loading Equipments + +Transport Ships +5; Ship 1; [(0, 2000.0)]; 1001 +6; Ship 2; [(0, 2000.0)]; 1002 + +Templates +7; mov; []; 1001; 1; 2; []; 2.0 +8; mov; []; 1001; 2; 1; []; 1.0 +9; mov; []; 1002; 1; 2; []; 1.0 +10; mov; []; 1002; 2; 1; []; 1.0 +11; mrn; []; 1002; 2; []; 2.0 +12; unm; []; 1002; 2; []; 2.0 +19; loa; []; 4; 0; 1001; 2; []; 100.0; U +20; loa; []; 4; 0; 1002; 2; []; 100.0; M + +Cargo Flows + +Initial Vessel State +5; 1 +6; 1 + +Initial Storage State +0; 5; 0.0 +0; 6; 0.0 +0; 4; 10000.0 + +Final Vessel State +5; 1 +6; 1 + +Final Storage State +0; 5; 1000.0 +0; 6; 1000.0 + + +Task Properties +30.0; 0 + + +Solution +26.0 +7; R; 0.0; 2.0 (5 []) +9; R; 0.0; 1.0 (6 []) +11; R; 1.0; 2.0 (6 []) +8; R; 2.0; 1.0 (5 []) +7; R; 3.0; 2.0 (5 []) +20; R; 3.0; 10.0 (6 []) +12; R; 13.0; 2.0 (6 []) +10; R; 15.0; 1.0 (6 []) +19; R; 15.0; 10.0 (5 []) +9; R; 16.0; 1.0 (6 []) +10; R; 17.0; 1.0 (6 []) +9; R; 18.0; 1.0 (6 []) +10; R; 19.0; 1.0 (6 []) +9; R; 20.0; 1.0 (6 []) +10; R; 21.0; 1.0 (6 []) +9; R; 22.0; 1.0 (6 []) +10; R; 23.0; 1.0 (6 []) +8; R; 25.0; 1.0 (5 []) diff --git a/tests/with_typing/multiTow.TIPP b/tests/with_typing/multiTow.TIPP new file mode 100644 index 0000000000000000000000000000000000000000..e2b833d737b051e99e77f89fa661a421838122f2 --- /dev/null +++ b/tests/with_typing/multiTow.TIPP @@ -0,0 +1,93 @@ +Typified +1 + +Cargoes +13; Груз1; 0.0 + +Berths +10; Рейд +16; Терминал1 + +Storages +18; Хранилище1; [(13, 6.0)] + +Vessel Types +11; Тип судна1 +12; Тип буксира1 + +Bunkers + +Tows +121; Буксир1; []; 12 +122; Буксир2; []; 12 +123; Буксир3; []; 12 +124; Буксир4; []; 12 + +Loading Equipment Types + +Loading Equipments + +Transport Ships +111; Судно1; [(13, 1000000.0)]; 11 +112; Судно2; [(13, 1000000.0)]; 11 + +Templates +61; mov; []; 11; 10; 16; [12,12]; 1.0 +62; mov; []; 11; 16; 10; [12,12]; 1.0 +63; mov; []; 12; 10; 16; []; 1.0 +64; mov; []; 12; 16; 10; []; 1.0 +65; mrn; []; 11; 16; [12,12,12]; 1.0 +66; unm; []; 11; 16; [12,12,12]; 1.0 +67; loa; []; 11; 13; 18; 16; []; 6.0; M +68; loa; []; 18; 13; 11; 16; []; 6.0; M + +Cargo Flows + +Initial Vessel State +111; 10 +112; 10 +121; 16 +122; 16 +123; 10 +124; 10 + +Initial Storage State +13; 111; 12.0 +13; 112; 0.0 +13; 18; 0.0 + +Final Vessel State +111; 10 +112; 10 + +Final Storage State +13; 111; 0.0 +13; 112; 12.0 + + +Task Properties +20.0; 0 + + +Solution +15.0 +61; R; 0.0; 1.0 (111 [123, 124]) +64; R; 0.0; 1.0 (121 []) +64; R; 0.0; 1.0 (122 []) +61; R; 1.0; 1.0 (112 [121, 122]) +65; R; 2.0; 1.0 (111 [121, 122, 124]) +67; R; 3.0; 1.0 (111 []) +66; R; 4.0; 1.0 (111 [121, 123, 124]) +65; R; 5.0; 1.0 (112 [121, 123, 124]) +64; R; 6.0; 1.0 (123 []) +68; R; 6.0; 1.0 (112 []) +66; R; 7.0; 1.0 (112 [121, 122, 124]) +65; R; 8.0; 1.0 (111 [121, 122, 124]) +63; R; 9.0; 1.0 (123 []) +67; R; 9.0; 1.0 (111 []) +66; R; 10.0; 1.0 (111 [121, 122, 123]) +65; R; 11.0; 1.0 (112 [121, 122, 124]) +68; R; 12.0; 1.0 (112 []) +66; R; 13.0; 1.0 (112 [121, 122, 124]) +62; R; 14.0; 1.0 (111 [121, 123]) +62; R; 14.0; 1.0 (112 [122, 124]) diff --git a/tests/with_typing/v2.tipp b/tests/with_typing/v2.tipp new file mode 100644 index 0000000000000000000000000000000000000000..aff244ea18dfd5f8e115fdb883ffbdedbd6c6c92 --- /dev/null +++ b/tests/with_typing/v2.tipp @@ -0,0 +1,92 @@ +Typified +1 + +Cargoes +22; Груз1; 0.0 + +Berths +17; Рейд +18; Терминал1 +19; Терминал2 + +Storages +20; Хранилище1; [(22, 100.0)] +21; Хранилище2; [(22, 100.0)] + +Vessel Types +1001; Тип судна1 +1002; Тип буксира1 + +Bunker Types + +Bunkers + +Tows +27; Буксир1; []; 1002 + +Loading Equipment Types + +Loading Equipments + +Transport Ships +24; Судно1; [(22, 100000.0)]; 1001 +25; Судно2; [(22, 100000.0)]; 1001 + +Templates +4010; mov; []; 1001; 19; 18; [1002]; 1.0 +4; mov; []; 1001; 17; 19; []; 5.0 +4006; mov; []; 1001; 17; 19; [1002]; 2.0 +3; mov; []; 1001; 17; 18; []; 5.0 +4005; mov; []; 1001; 17; 18; [1002]; 2.0 +4009; mov; []; 1001; 18; 19; [1002]; 1.0 +15; mov; []; 1002; 18; 17; []; 1.0 +16; mov; []; 1002; 19; 17; []; 1.0 +18; mov; []; 1002; 19; 18; []; 1.0 +14; mov; []; 1002; 17; 19; []; 1.0 +17; mov; []; 1002; 18; 19; []; 1.0 +13; mov; []; 1002; 17; 18; []; 1.0 +3998; loa; []; 20; 22; 1001; 18; []; 20.0; U +3996; loa; []; 1001; 22; 20; 18; []; 20.0; U +3994; loa; []; 21; 22; 1001; 19; []; 1.0; U +3992; loa; []; 1001; 22; 21; 19; []; 1.0; U + +Cargo Flows + +Initial Vessel State +24; 17 +25; 17 +27; 17 + +Initial Storage State +22; 24; 100.0 +22; 25; 0.0 +22; 20; 20.0 +22; 21; 80.0 + +Final Vessel State + +Final Storage State +22; 24; 0.0 +22; 25; 100.0 + + +Task Properties +16.0; 0 + + +Solution +12.0 +4005; R; 0.0; 2.0 (24 [27]) +15; R; 2.0; 1.0 (27 []) +3996; R; 2.0; 3.0 (24 [] 20) +4005; R; 3.0; 2.0 (25 [27]) +4009; R; 5.0; 1.0 (24 [27]) +3998; R; 5.0; 3.0 (25 [] 20) +3992; R; 6.0; 1.0 (24 [] 1) +4010; R; 7.0; 1.0 (24 [27]) +3996; R; 8.0; 1.0 (24 [] 20) +4009; R; 9.0; 1.0 (24 [27]) +3998; R; 9.0; 2.0 (25 [] 20) +4010; R; 10.0; 1.0 (24 [27]) +4009; R; 11.0; 1.0 (25 [27]) +3996; R; 11.0; 1.0 (24 [] 19) diff --git a/tests/without_typing/Case2.ipp b/tests/without_typing/Case2.ipp new file mode 100644 index 0000000000000000000000000000000000000000..cc79156fdd2fd567c809ac8be8ff0bbf9b899930 --- /dev/null +++ b/tests/without_typing/Case2.ipp @@ -0,0 +1,69 @@ +Cargoes +83;Груз1;0.0 +84;Груз2;0.0 +85;Груз3;0.0 +Berths +86;Рейд +87;Терминал1 +88;Терминал2 +Storages +89;Хранилище1;83;1000.0 +90;Хранилище2;84;1000.0 +91;Хранилище3;85;1000.0 +Bunkers +Tows +94;Буксир1;1000000 +95;Буксир2;1000000 +Loading Equipments +99;Плавучий кран 1 +100;Плавучий кран 2 +101;Плавучий кран 3 +Transport Ships +96;Судно1;1000000.0 + +Templates +10;mrn;[];96;88;[94,95];1.0 + +13;mov;[];94;86;88;[];1.0 +16;mov;[];94;87;88;[];3.0 +15;mov;[];94;87;86;[];1.0 +11;mov;[];94;88;86;[];1.0 + +12;mov;[];95;88;86;[];1.0 +17;mov;[];95;87;88;[];3.0 +14;mov;[];95;86;88;[];1.0 + +8;mov;[];96;86;88;[94];2.0 +9;mov;[];96;86;88;[95];2.0 +2;loa;[];96;83;89;88;[99,100];20.0;M +4;loa;[];96;84;90;88;[99,101];10.0;M +5;loa;[];96;84;90;88;[100,101];10.0;M +7;loa;[];96;85;91;88;[101];10.0;M + +Cargo Flows +Initial Vessel State +96;86 +99;88 +100;88 +101;88 +94;87 +95;88 +Initial Storage State +83;89;0.0 +84;90;0.0 +85;91;0.0 +83;96;60.0 +84;96;60.0 +85;96;60.0 +Final Vessel State +Final Storage State +83;96;0.0 +84;96;0.0 +85;96;0.0 + +Task Properties +20.0;0 + +Solution +16.0 + diff --git a/tests/without_typing/InitDataTopaj4.ipp b/tests/without_typing/InitDataTopaj4.ipp new file mode 100644 index 0000000000000000000000000000000000000000..2807778e63691c529c0f088d82753dd37823b5e0 --- /dev/null +++ b/tests/without_typing/InitDataTopaj4.ipp @@ -0,0 +1,48 @@ +Cargoes +10; Груз1 +Berths +6; Рейд +7; Терминал1 +8; Терминал2 +Storages +9; Хранилище1; 10; 5000 +Transport Ships +12; Судно1; 1000 +13; Судно2; 1000 +Loading Equipments +Templates +4367; mov; []; 12; 6; 7; []; 1 +4374; mov; []; 13; 8; 7; []; 1 +4369; mov; []; 12; 6; 8; []; 1 +4372; mov; []; 13; 7; 8; []; 1 +4370; mov; []; 13; 6; 8; []; 1 +4371; mov; []; 12; 7; 8; []; 1 +4368; mov; []; 13; 6; 7; []; 1 +4373; mov; []; 12; 8; 7; []; 1 +4360; loa; []; 9; 10; 12; 7; []; 100; U +4364; loa; []; 9; 10; 13; 7; []; 100; U +4362; loa; []; 9; 10; 12; 8; []; 50; U +4366; loa; []; 9; 10; 13; 8; []; 50; U +Initial Vessel State +12; 6 +13; 6 +Final Vessel State +Initial Storage State +10; 12; 0 +10; 13; 0 +10; 9; 5000 +Final Storage State +10; 12; 1000 +10; 13; 1000 +Task Properties +50; 0 +Solution +15.0 +4367; R; 0.0; 1.0 +4370; R; 0.0; 1.0 +4360; R; 1.0; 7.0 +4366; R; 1.0; 6.0 +4374; R; 7.0; 1.0 +4371; R; 8.0; 1.0 +4364; R; 8.0; 7.0 +4362; R; 9.0; 6.0 diff --git a/tests/without_typing/TaskBK.ipp b/tests/without_typing/TaskBK.ipp new file mode 100644 index 0000000000000000000000000000000000000000..0ad3821128c061a72cb144a9a2b1c76c7d22ff14 --- /dev/null +++ b/tests/without_typing/TaskBK.ipp @@ -0,0 +1,43 @@ +Cargoes +0;LNG;1.0 +Berths +1;Raid +2;Pier 1 +3;Pier 2 +Storages +4;Storage 1;0;270.0 +Bunkers +Tows +6;Tow 1 +Loading Equipments +5;Плавучий кран +Transport Ships +7;Ship 1;2000.0 + +Templates +8;mov;[];7;1;2;[6];2.0 +9;mov;[];7;2;1;[6];2.0 +10;mov;[];6;3;1;[];2.0 +11;mov;[];6;2;1;[];2.0 +12;mov;[];6;2;3;[];1.0 +13;mov;[];5;3;2;[6];2.0 +14;loa;[];7;0;4;2;[5];20.0; U + +Cargo Flows +Initial Vessel State +7;1 +6;2 +5;3 +Initial Storage State +0;4;0.0 +0;7;100.0 +Final Vessel State +7;1 +Final Storage State +0;7;0.0 + +Task Properties +18.0;0 + +Solution +14.0 diff --git a/tests/without_typing/TaskT.ipp b/tests/without_typing/TaskT.ipp new file mode 100644 index 0000000000000000000000000000000000000000..c52d3b2f8a198aaf6699850d1139b4d115637431 --- /dev/null +++ b/tests/without_typing/TaskT.ipp @@ -0,0 +1,63 @@ +Cargoes +0;LNG;0.0 +Berths +1;Raid +2;Pier 1 +3;Pier 2 +Storages +4;Storage 1;0;10000.0 +Bunkers +Tows +Loading Equipments +Transport Ships +5;Ship 1;2000.0 +6;Ship 2;2000.0 + +Templates +7;mov;[];5;1;2;[];1.0 +8;mov;[];5;2;1;[];1.0 +9;mov;[];5;1;3;[];1.0 +10;mov;[];5;3;1;[];1.0 +11;mov;[];5;2;3;[];1.0 +12;mov;[];5;3;2;[];1.0 +13;mov;[];6;1;2;[];1.0 +14;mov;[];6;2;1;[];1.0 +15;mov;[];6;1;3;[];1.0 +16;mov;[];6;3;1;[];1.0 +17;mov;[];6;2;3;[];1.0 +18;mov;[];6;3;2;[];1.0 +19;loa;[];4;0;5;2;[];100.0; U +20;loa;[];4;0;5;3;[];50.0; U +21;loa;[];4;0;6;2;[];100.0; U +22;loa;[];4;0;6;3;[];50.0; U + +Cargo Flows +Initial Vessel State +5;1 +6;1 +Initial Storage State +0;5;0.0 +0;6;0.0 +0;4;10000.0 +Final Vessel State +5;1 +6;1 +Final Storage State +0;5;1000.0 +0;6;1000.0 + +Task Properties +24.0;0 + +Solution +16.0 +7; R; 1.0; 1.0 +10; R; 16.0; 1.0 +11; R; 9.0; 1.0 +14; R; 16.0; 1.0 +15; R; 1.0; 1.0 +18; R; 8.0; 1.0 +19; R; 2.0; 7.0 +20; R; 10.0; 6.0 +21; R; 9.0; 7.0 +22; R; 2.0; 6.0 diff --git a/tests/without_typing/TwoTransports.ipp b/tests/without_typing/TwoTransports.ipp new file mode 100644 index 0000000000000000000000000000000000000000..a12eb64cbe3d4086b73c52d09c1baca11ce93c12 --- /dev/null +++ b/tests/without_typing/TwoTransports.ipp @@ -0,0 +1,46 @@ +Cargoes +83; Груз1 + +Berths +86; Рейд + +Storages +89; Хранилище1; 83; 1000.0 + +Bunkers +Tows +Loading Equipments +Transport Ships +101; Судно1; 1000000.0 +102; Судно2; 1000000.0 + +Templates +1;mrn;[]; 101; 86; []; 1.0 +2;unm;[]; 101; 86; []; 1.0 +3;loa;[]; 101; 83; 89; 86; []; 10.0; M + +4;mrn;[]; 102; 86; []; 1.0 +5;unm;[]; 102; 86; []; 1.0 +6;loa;[]; 102; 83; 89; 86; []; 10.0; M + +Cargo Flows +Initial Vessel State +101; 86 +102; 86 + +Initial Storage State +83; 89; 100.0 +83; 101; 10.0 +83; 102; 10.0 + +Final Vessel State +Final Storage State +83; 101; 0.0 +83; 102; 0.0 + +Task Properties +20.0;0 + +Solution +6.0 + diff --git a/tests/cargo_handling_and_moving.ipp b/tests/without_typing/cargo_handling_and_moving.ipp similarity index 98% rename from tests/cargo_handling_and_moving.ipp rename to tests/without_typing/cargo_handling_and_moving.ipp index f344fc2112ea5b1ba6fa0ea771586f97fe850c2d..b0868aa0a6a10d977ded970613fe00224fff942e 100644 --- a/tests/cargo_handling_and_moving.ipp +++ b/tests/without_typing/cargo_handling_and_moving.ipp @@ -45,7 +45,7 @@ Final Storage State 0; 11; 2.0 Task Properties -15.0;0 +20.0;0 Solution -12.0 +15.0 diff --git a/tests/shortest_path_with_weather.ipp b/tests/without_typing/shortest_path_with_weather.ipp similarity index 100% rename from tests/shortest_path_with_weather.ipp rename to tests/without_typing/shortest_path_with_weather.ipp diff --git a/tests/simple_cargo_flow.ipp b/tests/without_typing/simple_cargo_flow.ipp similarity index 100% rename from tests/simple_cargo_flow.ipp rename to tests/without_typing/simple_cargo_flow.ipp diff --git a/tests/simple_shortest_path.ipp b/tests/without_typing/simple_shortest_path.ipp similarity index 100% rename from tests/simple_shortest_path.ipp rename to tests/without_typing/simple_shortest_path.ipp diff --git a/tests/without_typing/test_0.ipp b/tests/without_typing/test_0.ipp new file mode 100644 index 0000000000000000000000000000000000000000..abfb3c1f9b8e94418e3b27fa8553c39dc26fc7cc --- /dev/null +++ b/tests/without_typing/test_0.ipp @@ -0,0 +1,41 @@ +Cargoes +83; Груз1 + +Berths +86; Рейд +88; Терминал2 + +Storages +89; Хранилище1; 83; 1000.0 + +Bunkers +Tows +Loading Equipments +Transport Ships +96; Судно1; 1000000.0 + +Templates +10;mrn;[]; 96; 88; []; 1.0 + +8;mov;[]; 96; 86; 88; []; 2.0 + +2;loa;[]; 96; 83; 89; 88; []; 20.0; M + +Cargo Flows +Initial Vessel State +96; 86 + +Initial Storage State +83; 89; 0.0 +83; 96; 60.0 + +Final Vessel State +Final Storage State +83; 89; 60.0 + +Task Properties +20.0;0 + +Solution +6.0 + diff --git "a/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" "b/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" new file mode 100644 index 0000000000000000000000000000000000000000..996dc24e16333c2d788863e1f369cd8fd3ee5225 Binary files /dev/null and "b/\320\237\320\273\320\260\320\275\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265 \320\277\320\276\321\200\321\202\320\276\320\262\321\213\321\205 \320\276\320\277\320\265\321\200\320\260\321\206\320\270\320\271.docx" differ