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