using CP; int n_intervals = ...; int n_operations = ...; int n_locations = ...; int n_moving_obj = ...; dvar boolean op_status[0..n_operations][0..(n_intervals + 1)]; dvar boolean op_start[0..n_operations][0..(n_intervals + 1)]; int moving_op_of_obj[0..n_moving_obj][0..n_operations] = ...; // Текущая операция операция перемещения, в которой задействован данный объект. dvar int current_moving_operation[0..n_moving_obj][0..(n_intervals + 1)] in 0..n_operations; // Является ли данная операция операцией перемещения. int is_moving_operation[0..n_operations] = ...; // Главный объект (субъект) операции. int main_obj_of_operation[0..n_operations] = ...; // Объект, пришвартованный к данной локации. dvar int current_moored_obj[0..n_locations, 0..(n_intervals + 1)] in 0..n_moving_obj; // Операции с условной швартовкой. int op_with_nominally_mooring_max_size = ...; int op_with_nominally_mooring_sizes[0..n_locations, 0..n_moving_obj] = ...; int op_with_nominally_mooring[0..n_locations, 0..n_moving_obj, 1..op_with_nominally_mooring_max_size] = ...; // Местоположение объекта или пункт назначения (если объект движется) перед началом определённого интервала. dvar int m_obj_loc[0..n_moving_obj, 0..(n_intervals + 1)] in 0..n_locations; int twin_location[1..n_locations]; int main_location[1..n_locations]; execute initializeArray { for(var i = 1; i <= n_locations; i++) { twin_location[i] = i - 1 + (i % 2) * 2; main_location[i] = i - ((i + 1) % 2); } } int operations_destination[0..n_operations] = ...; // Локация в которой окажется объект после завершения операции. // Является ли операция швартовкой/отшвартовкой. int is_mooring_op[0..n_operations] = ...; int initial_m_obj_loc[0..n_moving_obj] = ...; int final_m_obj_loc[0..n_moving_obj] = ...; // Операции, которые могут задействовать данный объект как ресурс. {int} operations_that_used_obj_as_resource [0..n_moving_obj] = ...; // Операция, в которой участвует данный объект как ресурс. dvar int participation_as_resource[0..n_moving_obj, 0..(n_intervals + 1)] in 0..n_operations; int n_resources_types = ...; // Количество различных типов ресурсов. {int} objects_of_type[1..n_resources_types] = ...; // Все объекты конкретного типа. int n_resources_counters = ...; // Количество счётчиков ресурсов. // Счётчик ресурсов. dvar int resources_counter[1..n_resources_counters , 1..n_intervals]; int counter_type[1..n_resources_counters] = ...; // Типы ресурсов, за которыми следят счётчики. int operation_of_counter[1..n_resources_counters] = ...; // Операция, которой принадлежит данный счётчик. int required_counter_values[1..n_resources_counters] = ...; // Необходимые значения на счётчиках ресурсов для выполнения операции. {int} counters_of_operation[0..n_operations] = ...; // Счётчики, которые относятся к данной операции. dvar boolean is_involved_in_cargo_op[0..n_moving_obj, 0..n_intervals]; // Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика. {int} related_cargo_op[0..n_moving_obj] = ...; // Операции отшвартовки, которые используют объект в качестве главного. {int} related_unmooring_op[0..n_moving_obj] = ...; // Требуемое положение конкретных типов объектов в момент начала операций. int operations_resources_start_loc[1..n_resources_counters] = ...; // Требуемое положение главного объекта в момент начала операций. int main_obj_start_loc[0..n_operations] = ...; // Требуемое положение бункеровщика в момент начала операции. int bunker_start_loc[0..n_operations] = ...; // Бункеровщик, участвующий в операции погрузки (0, если такогого нет или это не погрузка). int bunker_of_cargo_op[0..n_operations] = ...; int operations_duration[0..n_operations] = ...; int is_continuous_operation[0..n_operations] = ...; {int} conflicting_operations[0..n_operations] = ...; int bad_weather[0..n_operations, 0..n_intervals] = ...; int n_cargo_types = ...; int n_all_storage_sections = ...; dvar int storage_used_volume[0..n_all_storage_sections, 0..(n_intervals + 1)]; int max_storage_vol[0..n_all_storage_sections] = ...; int initial_storage_vol[0..n_all_storage_sections] = ...; int final_storage_vol[0..n_all_storage_sections] = ...; int cargo_flows[0..n_all_storage_sections, 0..(n_intervals + 1)] = ...; int n_loading_op = ...; int loading_op_delta_of_main_obj[0..n_operations] = ...; int loading_op_abs_delta[0..n_operations] = ...; int loading_op_direction[0..n_operations] = ...; int operations_main_stor[0..n_operations] = ...; int operations_secondary_stor[0..n_operations] = ...; int operations_cargo_t[0..n_operations] = ...; int loading_op_delta[1..n_loading_op] = ...; int loading_op_local_direction[1..n_loading_op] = ...; int loading_op_n[1..n_loading_op] = ...; // Номера среди общего списка операций. {int} involved_operations[1..n_all_storage_sections] = ...; {int} sections_of_moving_obj[1..n_moving_obj] = ...; int is_sections_of_moving_obj_empty[1..n_moving_obj] = ...; // Интенсивность операций погрузки. dvar int cargo_op_intensity[0..n_operations, 0..(n_intervals + 1)]; int n_fixed_op = ...; int fixed_op[1..n_fixed_op] = ...; {int} fixed_op_resources[1..n_fixed_op] = ...; int fixed_op_start[1..n_fixed_op] = ...; int fixed_op_end[1..n_fixed_op] = ...; // Включительно. int fixed_op_intensity[1..n_fixed_op] = ...; int is_fixed[0..n_operations, 0..n_intervals] = ...; int is_obj_involved_in_fixed_op[0..n_moving_obj, 0..(n_intervals + 1)] = ...; int min_positive_cargo_val[1..n_all_storage_sections, 1..n_locations] = ...; // Объём максимальной положительной операции, которая может быть произведена с этой секцией в этом хранилище. Если в локации таковой нет, то это значение объёма хранилища + 1. int max_negative_cargo_val[1..n_all_storage_sections, 1..n_locations] = ...; int can_obj_leave_loc_only_alone[1..n_moving_obj, 1..n_locations] = ...; int is_fixed_op_planned_in_future[1..n_moving_obj, 1..n_locations, 1..n_intervals] = ...; // Возможно ли начать операцию в данный интервал (если предположить, что операция длится 1 интервал). dvar boolean is_op_possible[0..n_operations, 1..n_intervals]; // Счётчик ресурсов, которые могут быть потенциально задействованы в операции. dvar int possible_resources_counter[1..n_resources_counters , 1..n_intervals]; dvar boolean is_enough_free_resources[0..n_operations, 1..n_intervals]; dvar boolean can_obj_theoretically_use_cargo_op[0..n_moving_obj, 0..(n_intervals + 1)]; // Остановился ли объект окончательно, начиная с данного интервала. dvar boolean is_obj_totally_terminated[0..n_moving_obj, 0..(n_intervals + 1)]; dvar int prev_m_obj_loc[0..n_moving_obj, 0..(n_intervals + 1)] in 1..n_locations; dvar boolean is_obj_involved_in_useful_operation[0..n_moving_obj, 0..(n_intervals + 1)]; // Успел ли объект поучаствовать в полезной операции к концу данного интервала. dvar boolean is_attended_useful_op_in_cur_loc[0..n_moving_obj, 0..(n_intervals + 1)]; dvar boolean is_cargo_op_not_exceeds_storage_limits[1..n_operations, 1..n_intervals]; dvar boolean is_not_terminated[1..(n_intervals + 1)]; minimize sum (i in 1..(n_intervals + 1)) is_not_terminated[i]; subject to { forall (t in 0..(n_intervals + 1)) (op_status[0, t] == 0); // Фиктивная операция. forall (t in 0..(n_intervals + 1)) ( op_start[0, t] == 0); // Фиктивная операция. // Определение current_moving_operation. forall (t in 0..(n_intervals + 1)) (current_moving_operation[0, t] == 0); // Фиктивный объект. // Крайние значения. forall (obj in 1..n_moving_obj, t in {0, n_intervals + 1}) ( current_moving_operation[obj, t] == 0 ); // Текущая операция лежит в множестве тех, которые затрагивают данный объект. 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]] != 0) ); // Если операция, затрагивающая данный объект в качестве главного, выполняется - то именно она текущая операция перемещения для этого объекта. forall (op in 1..n_operations, t in 1..n_intervals : (is_moving_operation[op] == 1)) ( (op_status[op, t] == 1) => (current_moving_operation[main_obj_of_operation[op], t] == op) ); // Связь current_moving_operation c op_status. 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] == 1) ); // Определение current_moored_obj. forall (t in 0..(n_intervals + 1)) (current_moored_obj[0, t] == 0); // Фиктивная локация. // Фиксирование неиспользуемых значений. forall (loc in 1..n_locations, t in 0..(n_intervals + 1) : loc mod 2 == 1) ( current_moored_obj[loc, t] == 0 ); // Крайние значения. forall (loc in 1..n_locations, t in {0, n_intervals + 1}) ( current_moored_obj[loc, t] == 0 ); // current_moored_obj соответствуе какому-либо реально пришвартованному объекту. forall (loc in 1..n_locations, t in 1..n_intervals : loc mod 2 == 0) ( (current_moored_obj[loc, t] != 0) => ((m_obj_loc[current_moored_obj[loc, t], t] == loc) || (or (id in 1..op_with_nominally_mooring_max_size) // new!!! op_status[op_with_nominally_mooring[loc, current_moored_obj[loc, t], id], t] == true )) ); // Если объект пришвартован или швартуется, то current_moored_obj об это знает. forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( (m_obj_loc[obj, t] mod 2 == 0) => (current_moored_obj[m_obj_loc[obj, t], t] == obj) ); // Если выполняется операция, где судно условно пришвартовано, то current_moored_obj знает об этом. forall (loc in 1..n_locations, obj in 1..n_moving_obj, op_id in 1..op_with_nominally_mooring_sizes[loc, obj], t in 1..n_intervals) ( (op_status[op_with_nominally_mooring[loc, obj, op_id], t] == 1) => (current_moored_obj[loc, t] == obj) ); // Определение m_obj_loc. forall (t in 0..(n_intervals + 1)) (m_obj_loc[0, t] == 0); // Фиктивный объект. // За фиктивный нулевой интервал объект не успевает ничего сделать с начальным положением. forall (obj in 1..n_moving_obj) ( m_obj_loc[obj, 1] == m_obj_loc[obj, 0] ); // Направление движения/местоположение объекта может измениться только если перед этим началась операция перемещения, и он не вспомогательный при операции швартовки. 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]] == 0) ) ) => (m_obj_loc[obj, t] == operations_destination[current_moving_operation[obj, t - 1]]) ); 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]] == 1) ) ) => (m_obj_loc[obj, t] == m_obj_loc[obj, t - 1]) ); // Начальное состояние. forall (i in 1..n_moving_obj) (m_obj_loc[i, 0] == initial_m_obj_loc[i]); // Конечное состояние. 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. forall (i in 1..n_operations, j in {0, n_intervals + 1}) (op_status[i, j] == 0); // Краевые значения. forall (op in 1..n_operations, j in {0, n_intervals + 1}) (op_start[op, j] == 0); forall (i in 1..n_operations, j in 1..(n_intervals + 1)) (op_start[i, j] == ((op_status[i, j] == 1) && (op_status[i, j - 1] == 0))); // Связь ресурсов с операцией и основным объектом. forall (t in 0..(n_intervals + 1)) (participation_as_resource[0, t] == 0); // Фиктивный объект. // Граничные значения. forall (obj in 1..n_moving_obj) (participation_as_resource[obj, 0] == 0); forall (obj in 1..n_moving_obj) (participation_as_resource[obj, n_intervals + 1] == 0); // Только те операции, которые затрагивают данный объект. 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 должен указывать на эту операцию. 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. 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]] == 1) ) => (participation_as_resource[obj, t] == current_moving_operation[obj, t]) ); // { Объект участвует где-то в качестве ресурса - соответствующая операция обязана быть активной. } 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] == 1) ); // От начала операции и до конца её ресурсы не могут измениться (в том числе и для погрузки). 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] == 1) ) => (participation_as_resource[obj, t + 1] == participation_as_resource[obj, t]) ); // Участие всех необходимых ресурсов в операции. forall (t in 1..n_intervals, op in 1..n_operations, counter in counters_of_operation[op]) ( (op_status[op, t] == 1) => (resources_counter[counter, t] == required_counter_values[counter]) ); // Определение resources_counter. 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] ) ); // Участие объекта в операциях грузообработки. forall (t in 1..n_intervals) (is_involved_in_cargo_op[0, t] == 0); // Фиктивный объект. forall (obj in 1..n_moving_obj) (is_involved_in_cargo_op[obj, 0] == 0); // Определение is_involved_in_cargo_op. forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( is_involved_in_cargo_op[obj, t] == ( (or (op in related_cargo_op[obj]) (op_status[op, t] == true)) || ((participation_as_resource[obj, t] != 0) && (is_moving_operation[participation_as_resource[obj, t]] == 0)) ) ); // Операции перемещения исключают операции грузообработки и наоборот. forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( (is_involved_in_cargo_op[obj, t] == 1) => (current_moving_operation[obj, t] == 0) ); // Наличие всех объектов на месте во время начала операции перемещения + готовность к началу. // Наличие на месте всех ресурсов. 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] == 1) ) => (m_obj_loc[obj, t] == operations_resources_start_loc[counter]) ); // Наличие главных объектов на месте. forall (op in 1..n_operations, t in 1..n_intervals) ( (op_start[op, t] == 1) => (m_obj_loc[main_obj_of_operation[op], t] == main_obj_start_loc[op]) ); // Наличие бункеровщиков на месте. forall (op in 1..n_operations, t in 1..n_intervals : bunker_of_cargo_op[op] != 0) ( (op_start[op, t] == 1) => (m_obj_loc[bunker_of_cargo_op[op], t] == bunker_start_loc[op]) ); // Непрерывность перемещения и швартовки. forall (i in 1..n_operations : is_continuous_operation[i] == 1) forall (j in 1..(n_intervals - operations_duration[i] + 1)) forall (k in 1..(operations_duration[i] - 1)) (op_start[i, j] == 1) => ( (op_status[i, j + k] == 1) && (op_status[i, j + operations_duration[i]] == 0) ) ; forall (i in 1..n_operations : is_continuous_operation[i] == 1) forall (j in (n_intervals - operations_duration[i] + 2)..(n_intervals + 1)) (op_start[i, j] == 0) ; // Конфликтующие операции. forall (op in 1..n_operations, t in 0..(n_intervals + 1), conf_op in conflicting_operations[op]) ( (op_status[op, t] == 1) => (op_status[conf_op, t] == 0) ); // Окна непогоды. forall (op in 1..n_operations, t in 1..n_intervals) ( (bad_weather[op, t] == 1) => (op_status[op, t] == 0) ); // Грузообработка. forall (t in 0..(n_intervals + 1)) (storage_used_volume[0, t] == 0); // Фиктивный объект. // Ограничения на вместимость. // Максимальный объём. forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( (storage_used_volume[storage, t]) <= max_storage_vol[storage] ); // Неотрицательность объёма. forall (storage in 1..n_all_storage_sections, t in 0..(n_intervals + 1)) ( 0 <= storage_used_volume[storage, t] ); // Ограничения на граничные значения. forall (storage in 1..n_all_storage_sections) ( // Initial values. storage_used_volume[storage, 0] == initial_storage_vol[storage] ); forall (storage in 1..n_all_storage_sections // Final values. : final_storage_vol[storage] >= 0) ( storage_used_volume[storage, n_intervals + 1] == final_storage_vol[storage] ); // Изменение грузов в хранилищах. forall (t in 0..(n_intervals + 1)) (cargo_op_intensity[0, t] == 0); // Фиктивная операция. forall (op in 1..n_operations, t in 0..(n_intervals + 1)) (cargo_op_intensity[op, t] >= 0); forall (op in 1..n_operations, t in 0..(n_intervals + 1)) (cargo_op_intensity[op, t] <= loading_op_abs_delta[op]); // Связь с операциями грузообработки. forall (op in 1..n_operations, t in 0..(n_intervals + 1) : (is_moving_operation[op] == 0)) ( (cargo_op_intensity[op, t] > 0) => (op_status[op, t] == 1) ); forall (op in 1..n_operations, t in 0..(n_intervals + 1) : (is_moving_operation[op] == 0)) ( cargo_op_intensity[op, t] == 0 ); forall (op in 1..n_operations, t in 0..(n_intervals + 1) : (is_moving_operation[op] == 0)) ( (op_status[op, t] == 1) => (cargo_op_intensity[op, t] > 0) ); 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] ) ) ); // Фиксированные операции. forall (no in 1..n_fixed_op) forall (t in fixed_op_start[no]..fixed_op_end[no]) ((op_status[fixed_op[no], t] == 1) && (cargo_op_intensity[fixed_op[no], t] == fixed_op_intensity[no])) ; forall (no in 1..n_fixed_op) forall (t in fixed_op_start[no]..fixed_op_end[no]) forall (obj in fixed_op_resources[no]) ( participation_as_resource[obj, t] == fixed_op[no] ) ; // Оптимизация - сдвиг в начало. forall (t in 1..n_intervals) (is_op_possible[0, t] == false); // Фиктивный объект. // Определение possible_resources_counter. 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]) ) ); // Достаточно ли свободных ресурсов для операции. forall (t in 1..n_intervals) (is_enough_free_resources[0, t] == false); // Фиктивный объект. forall (op in 1..n_operations, t in 1..n_intervals) ( is_enough_free_resources[op, t] == and (counter in counters_of_operation[op]) ( possible_resources_counter[counter, t] >= required_counter_values[counter] ) ); forall (op in 1..n_operations, t in 1..n_intervals) ( is_cargo_op_not_exceeds_storage_limits[op, t] == ((is_moving_operation[op] == 0) => ( (storage_used_volume[operations_main_stor[op], t] + loading_op_direction[op] >= 0) && (storage_used_volume[operations_main_stor[op], t] + loading_op_direction[op] <= max_storage_vol[operations_main_stor[op]]) && (storage_used_volume[operations_secondary_stor[op], t] - loading_op_direction[op] >= 0) && (storage_used_volume[operations_secondary_stor[op], t] - loading_op_direction[op] <= max_storage_vol[operations_secondary_stor[op]]) )) ); // Определение is_op_possible. forall (op in 1..n_operations, t in 1..n_intervals) ( is_op_possible[op, t] == ( (bad_weather[op, t] == 0) && // Погода не мешает. (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) && // Достаточно свободных ресурсов на нужном месте. (and (conf_op in conflicting_operations[op]) (op_status[conf_op, t] == false)) && // Не выполняется ни одной конфликтующей операции. ((is_moving_operation[op] == 1) => is_involved_in_cargo_op[main_obj_of_operation[op], t] == false) && // Если это операция перемещения, то главный объект // не участвует в операциях погрузки. (((is_mooring_op[op] == 1) && (operations_destination[op] mod 2 == 0)) => ( current_moored_obj[operations_destination[op], t] == 0) ) && // Если это операция пришвартовки, то в этот интервал // причал должен быть свободным. (is_cargo_op_not_exceeds_storage_limits[op, t] == 1) && // Если это операция грузообработки, то она не выведет // объём берегового хранилища и хранилища судна за // границы дозволенного. (((is_moving_operation[op] == 0) && (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] == 0)) => ((m_obj_loc[bunker_of_cargo_op[op], t] == bunker_start_loc[op]) && (current_moving_operation[bunker_of_cargo_op[op], t] == 0)) ) // Бункеровщик (если есть) находится в нужной локации // и не участвует в операциях перемещения. ) ); // Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. forall (op in 1..n_operations, t in 2..n_intervals) ( ((op_start[op, t] == 1) && (is_fixed[op, t] == 0)) => (is_op_possible[op, t - 1] == 0) ); // Оптимизация - есть две соседние операции погрузки - первая операция должна быть максимально загруженной. 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]) || // Операция достигла предела интенсивности. (is_cargo_op_not_exceeds_storage_limits[op, t - 1] == 0) // Или операция нарушит границы хранилищ || // при увеличении интенсивности. (is_fixed[op, t] == 1) // Или операция фиксирована. ) ); // Оптимизация - судно возвращается откуда перед этим пришло -> оно сделало или делает что-то "полезное". forall (t in 0..(n_intervals + 1)) (prev_m_obj_loc[0, t] == 1); forall (t in 0..(n_intervals + 1)) (is_obj_involved_in_useful_operation[0, t] == 0); // Определение prev_m_obj_loc 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]) ); 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]) ); forall (obj in 1..n_moving_obj) (prev_m_obj_loc[obj, 0] == m_obj_loc[obj, 0]); // Определение is_obj_involved_in_useful_operation 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) || (or (op in related_cargo_op[obj]) (op_status[op, t] == 1)) || (is_obj_involved_in_fixed_op[obj, t] == 1) || (or (op in related_unmooring_op[obj]) (op_status[op, t] == 1)) ) ); forall (obj in 1..n_moving_obj) (is_obj_involved_in_useful_operation[obj, 0] == 0); // Определение is_attended_useful_op_in_cur_loc forall (t in 0..(n_intervals + 1)) (is_attended_useful_op_in_cur_loc[0, t] == 0); 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] == 1) && (m_obj_loc[obj, t - 1] == m_obj_loc[obj, t])) // Предыдущее значение в текущей локации. || (is_obj_involved_in_useful_operation[obj, t] == 1) || (is_obj_involved_in_useful_operation[obj, t - 1] == 1) // Учитывает случай когда операция перемещения, из-за которой объект попал в локацию была нужна. ) ); // Сама оптимизация - если объект 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] == 1) ); // Оптимизация - если объект не может совершить в данной локации операции без выхода за границы хранилища, а так же если он // может уйти только своим ходом, то он либо уходит немедленно, либо остаётся на месте навсегда. // Определение can_obj_theoretically_use_cargo_op. 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] == 1) || or (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) ) ) ); forall (t in 0..(n_intervals + 1)) (can_obj_theoretically_use_cargo_op[0, t] == false); forall (obj in 1..n_moving_obj) (can_obj_theoretically_use_cargo_op[obj, 0] == false); forall (obj in 1..n_moving_obj) (is_obj_totally_terminated[obj, n_intervals + 1] == true); forall (t in 0..(n_intervals + 1)) (is_obj_totally_terminated[0, t] == true); forall (obj in 1..n_moving_obj, t in 0..n_intervals) ( is_obj_totally_terminated[obj, t] == ( (current_moving_operation[obj, t] == 0) && (is_involved_in_cargo_op[obj, t] == 0) && (is_obj_totally_terminated[obj, t + 1] == 1) ) ); // Само ограничение. forall (obj in 1..n_moving_obj, t in 1..n_intervals) ( ( (can_obj_leave_loc_only_alone[obj, m_obj_loc[obj, t]] == 1) && (can_obj_theoretically_use_cargo_op[obj, t] == 0) && (is_fixed_op_planned_in_future[obj, m_obj_loc[obj, t], t] == 0) ) => ((is_obj_totally_terminated[obj, t] == 1) || (current_moving_operation[obj, t] != 0)) ); // Критерий оптимизации // В конце всё остановится. (is_not_terminated[n_intervals + 1] == 0); // Действия ещё не остановились, если в текущий интервал что-нибудь происходит или они не остановятся в следующий интервал. forall (t in 1..n_intervals) ( is_not_terminated[t] == ( (or (op in 1..n_operations) (op_status[op, t] == true)) || (is_not_terminated[t + 1] == 1) ) ); } execute { writeln("op_status = ", op_status, ";"); writeln("m_obj_loc = ", m_obj_loc, ";"); writeln("op_start = ", op_start, ";"); writeln("is_not_terminated = ", is_not_terminated, ";"); writeln("storage_used_volume = ", storage_used_volume, ";"); writeln("current_moving_operation = ", current_moving_operation, ";"); writeln("resources_counter = ", resources_counter, ";"); writeln("operation_of_counter = ", operation_of_counter, ";"); writeln("participation_as_resource = ", participation_as_resource, ";"); writeln("is_involved_in_cargo_op = ", is_involved_in_cargo_op, ";"); writeln("cargo_op_intensity = ", cargo_op_intensity, ";"); writeln("is_op_possible = ", is_op_possible, ";"); }