diff --git a/src/constraints/conversion_2_with_partial_cargo_operations.mod b/src/constraints/conversion_2_with_partial_cargo_operations.mod new file mode 100644 index 0000000000000000000000000000000000000000..42d749d9f3aae1d145e5d7cce47fc8705d22b99d --- /dev/null +++ b/src/constraints/conversion_2_with_partial_cargo_operations.mod @@ -0,0 +1,670 @@ +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, ";"); +} +