include "globals.mzn"; int : n_intervals; int : n_operations; int : n_locations; int : n_moving_obj; array [1..n_operations, 0..(n_intervals + 1)] of var bool : op_status; array [1..n_operations, 0..(n_intervals + 1)] of var bool : op_start; array [1..n_operations, 0..(n_intervals + 1)] of var bool : op_fin; int : moving_op_of_obj_max_size; array [1..n_moving_obj] of 0..moving_op_of_obj_max_size : moving_op_of_obj_sizes; array [1..n_moving_obj, 0..moving_op_of_obj_max_size] of 1..n_operations : moving_op_of_obj; % Операции перемещения затрагивающие данный объект. % Определение current_moving_operation. % Текущая операция операция перемещения, в которой задействован данный объект. array [1..n_moving_obj, 0..(n_intervals + 1)] of var 0..moving_op_of_obj_max_size : current_moving_operation; % Текущая операция лежит в множестве тех, которые затрагивают данный объект. constraint forall (obj in 1..n_moving_obj, t in 0..(n_intervals + 1)) ( current_moving_operation[obj, t] <= moving_op_of_obj_sizes[obj] ); % Если операция, затрагивающая данный объект в качестве главного, выполняется - то именно она текущая операция перемещения для этого объекта. constraint forall (op in 1..n_operations, t in 0..(n_intervals + 1), obj = main_obj_of_operation[op] where is_moving_operation[op]) ( op_status[op, t] -> ((current_moving_operation[obj, t] != 0) /\ (moving_op_of_obj[obj, current_moving_operation[obj, t]] = op)) ); % Если операция, затрагивающая данный объект в качестве ресурса % TODO упростить в conversion_1 % Связь current_moving_operation c op_status. constraint forall (obj in 1..n_moving_obj, t in 0..(n_intervals + 1)) ( (current_moving_operation[obj, t] != 0) -> (op_status[moving_op_of_obj[obj, current_moving_operation[obj, t]], t]) ); % Ограничение на количество пришвартованных кораблей. % Счётчик объектов в локации (только в чётных - в состоянии пришвартованности). array [1..n_locations, 0..(n_intervals + 1)] of var int : obj_in_loc_counter; % Определение obj_in_loc_counter. constraint forall (loc in 1..n_locations, t in 0..(n_intervals + 1)) ( obj_in_loc_counter[loc, t] = sum (obj in 1..n_moving_obj) (m_obj_loc[obj, t] = loc) ); % Само ограничение. constraint forall (loc in 1..n_locations, t in 0..(n_intervals + 1) where (loc mod 2) = 0) ( obj_in_loc_counter[loc, t] <= 1 ); % Определение is_m_obj_in_movement_before_start. % Находится ли объект в движении перед началом интервала. array [1..n_moving_obj, 0..(n_intervals + 1)] of var bool : is_m_obj_in_movement_before_start; % В начале никто не движется. constraint forall (obj in 1..n_moving_obj) (not is_m_obj_in_movement_before_start[obj, 0]); % Перед первым интервалом все тоже стоят на месте. constraint forall (obj in 1..n_moving_obj) (not is_m_obj_in_movement_before_start[obj, 1]); % Если в предыдущем интервале объект не движется - то в начале этого он не движется, иначе он движется если предыдущая операция не закончилась. constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( (current_moving_operation[obj, t - 1] = 0) -> is_m_obj_in_movement_before_start[obj, t] = false ); constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) ( (current_moving_operation[obj, t - 1] != 0) -> is_m_obj_in_movement_before_start[obj, t] = (current_moving_operation[obj, t - 1] == current_moving_operation[obj, t]) ); array [1..n_operations] of 1..n_locations : operations_destination; % Локация в которой окажется объект после завершения операции. % Определение m_obj_loc. % Местоположение объекта или пункт назначения (если объект движется) перед началом определённого интервала. array [1..n_moving_obj, 0..(n_intervals + 1)] of var 1..n_locations : m_obj_loc; % Главный объект (субъект) операции. array [1..n_operations] of 1..n_moving_obj : main_obj_of_operation; % Является ли операция швартовкой/отшвартовкой. array [1..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] ); % TODO исправить в conversion_1.mzn % Направление движения/местоположение объекта может измениться только если перед этим началась операция перемещения. 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[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) \/ (not is_mooring_op[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) ) ) -> (m_obj_loc[obj, t] = operations_destination[moving_op_of_obj[obj, 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[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) /\ (is_mooring_op[moving_op_of_obj[obj, current_moving_operation[obj, t - 1]]]) ) ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) ); 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) ) -> (m_obj_loc[obj, t] = m_obj_loc[obj, t - 1]) ); % Начальное состояние. array [1..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 [1..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 и op_fin. 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 /\ op_fin[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])); constraint forall (i in 1..n_operations, j in 1..n_intervals ) (op_fin [i, j] = (op_status[i, j] /\ not op_status[i, j + 1])); % Связь ресурсов с операцией и основным объектом. % Операции, которые могут задействовать данный объект как ресурс. array [1..n_moving_obj] of set of 1..n_operations : operations_that_used_obj_as_resource; % Является ли данная операция операцией перемещения. array [1..n_operations] of bool : is_moving_operation; % Операция, в которой участвует данный объект как ресурс. array [1..n_moving_obj, 0..(n_intervals + 1)] of var 0..n_operations : participation_as_resource; % Граничные значения. 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 и % current_moving_operation должны указывать на одну и ту же операцию. % { Если объект движется, и движется как ресурс, то participation_as_resource должен отображать этот факт. } 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]] in operations_that_used_obj_as_resource[obj]) -> (participation_as_resource[obj, t] = moving_op_of_obj[obj, 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]] /\ (not is_mooring_op[participation_as_resource[obj, t]]) ) -> ( (current_moving_operation[obj, t] != 0) /\ (participation_as_resource[obj, t] = moving_op_of_obj[obj, current_moving_operation[obj, t]]) ) ) /\ (not (is_moving_operation[participation_as_resource[obj, t]] /\ (not is_mooring_op[participation_as_resource[obj, t]]) ) -> current_moving_operation[obj, t] = 0) ) ); % { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } 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 [1..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 [1..n_resources_counters] of 1..n_locations : operations_resources_start_loc; % Требуемое положение главного объекта в момент начала операций. array [1..n_operations] of 1..n_locations : main_obj_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]) /\ (not is_m_obj_in_movement_before_start[obj, t]) /\ ((not is_moving_operation[op]) -> (current_moving_operation[obj, t] = 0)) ) ); % Наличие и готовность главных объектов (субъектов). 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]) /\ (not is_m_obj_in_movement_before_start[obj, t]) /\ ((not is_moving_operation[op]) -> (current_moving_operation[obj, t] = 0)) ) ); % Непрерывность перемещения и швартовки. array [1..n_operations] of int : operations_duration; array [1..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)) ); % Конфликтующие операции. int : n_conflicting_op; array [1..n_conflicting_op] of 1..n_operations : confl_op_1; array [1..n_conflicting_op] of 1..n_operations : confl_op_2; constraint forall (t in 0..(n_intervals + 1), i in 1..n_conflicting_op) ( op_status[confl_op_1[i], t] -> not op_status[confl_op_2[i], t] ); % Окна непогоды. int : n_bad_weather_windows; array [1..n_bad_weather_windows] of 1..n_operations : bw_op; array [1..n_bad_weather_windows] of 0..(n_intervals + 1) : bw_start; array [1..n_bad_weather_windows] of 0..(n_intervals + 1) : bw_fin; % Включительно. constraint forall (i in 1..n_bad_weather_windows, t in bw_start[i]..bw_fin[i]) ( op_status[bw_op[i], t] == false ); % Грузообработка. int : n_cargo_types; int : n_obj_with_storage; array [1..n_obj_with_storage, 0..(n_intervals + 1), 1..n_cargo_types] of var int : storage_used_volume; % Первые n_moving_obj соответствуют наполненности соответствующих движущихся объектов. % Ограничения на вместимость. array [1..n_obj_with_storage] of int : max_storage_vol; % Масимальный объём. constraint forall (storage in 1..n_obj_with_storage, t in 0..(n_intervals + 1)) ( sum (cargo in 1..n_cargo_types) (storage_used_volume[storage, t, cargo]) <= max_storage_vol[storage] ); % Неотрицательность объёма. constraint forall (storage in 1..n_obj_with_storage, t in 0..(n_intervals + 1), cargo in 1..n_cargo_types) ( 0 <= storage_used_volume[storage, t, cargo] ); % Ограничения на граничные значения. array [1..n_obj_with_storage, 1..n_cargo_types] of int : initial_storage_vol; array [1..n_obj_with_storage, 1..n_cargo_types] of int : final_storage_vol; constraint forall (storage in 1..n_obj_with_storage, cargo in 1..n_cargo_types) ( % Initial values. storage_used_volume[storage, 0, cargo] = initial_storage_vol[storage, cargo] ); constraint forall (storage in 1..n_obj_with_storage, cargo in 1..n_cargo_types) ( % Final values. if final_storage_vol[storage, cargo] >= 0 then storage_used_volume[storage, n_intervals + 1, cargo] == final_storage_vol[storage, cargo] else true endif ); % Изменение грузов в хранилищах. array [1..n_obj_with_storage, 0..(n_intervals + 1), 1..n_cargo_types] of int : cargo_flows; int : n_loading_op; array [1..n_loading_op] of int : loading_op_delta; array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций. int : involved_operations_max_size; array [1..n_obj_with_storage, 1..n_cargo_types] of 0..involved_operations_max_size : involved_operations_sizes; array [1..n_obj_with_storage, 1..n_cargo_types, 1..involved_operations_max_size] of 1..n_loading_op : involved_operations; constraint forall (storage in 1..n_obj_with_storage, cargo in 1..n_cargo_types, t in 1..(n_intervals + 1)) ( storage_used_volume[storage, t, cargo] == ( storage_used_volume[storage, t - 1, cargo] + cargo_flows[storage, t, cargo] + sum (inv_op_no in 1..involved_operations_sizes[storage, cargo]) ( loading_op_delta[involved_operations[storage, cargo, inv_op_no]] * op_status[loading_op_n[involved_operations[storage, cargo, inv_op_no]], t] ) ) ); % Критерий оптимизации array [0..(n_intervals + 1)] of var bool : is_not_terminated; constraint (is_not_terminated[0] == false /\ 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_fin = ", show(op_fin), "\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", "is_m_obj_in_movement_before_start = ", show(is_m_obj_in_movement_before_start), "\n\n", "obj_in_loc_counter = ", show(obj_in_loc_counter), "\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", "real_current_moving_operation = ", show(current_moving_operation), "\n\n", "moving_op_of_obj {", show(moving_op_of_obj_max_size + 1), "}= ", show(moving_op_of_obj), "\n\n", ""];