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 0..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", */ ""];