Commit 5ef77a15 authored by Vladislav Kiselev's avatar Vladislav Kiselev

Новая оптимизация.

parent 8853ebdd
......@@ -81,7 +81,7 @@ array [0..n_moving_obj, 0..n_operations] of bool : moving_op_of_obj;
);
array [1..n_locations] of 0..n_locations : twin_location = [i - 1 + (i mod 2) * 2 | i in 1..n_locations];
% TODO нумерация с нуля
array [1..n_locations] of 1..n_locations : main_location = [i - ((i + 1) mod 2)| i in 1..n_locations];
array [0..n_operations] of 0..n_locations : operations_destination; % Локация в которой окажется объект после завершения операции.
......@@ -212,9 +212,10 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац
);
% Участие объекта в операциях грузообработки.
array [0..n_moving_obj, 1..n_intervals] of var bool : is_involved_in_cargo_op;
array [0..n_moving_obj, 0..n_intervals] of var bool : is_involved_in_cargo_op;
constraint forall (t in 1..n_intervals) (is_involved_in_cargo_op[0, t] = false); % Фиктивный объект.
constraint forall (obj in 1..n_moving_obj) (is_involved_in_cargo_op[obj, 0] = false);
% Операции погрузки, которые используют этот объект в качестве главного или в качестве бункеровщика.
array [0..n_moving_obj] of set of 0..n_operations : related_cargo_op;
......@@ -222,11 +223,9 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац
% Операции отшвартовки, которые используют объект в качестве главного.
array [0..n_moving_obj] of set of 1..n_operations : related_unmooring_op;
% TODO узнать про where
% Определение 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 1..n_operations where (not is_moving_operation[op]) /\ (main_obj_of_operation[op] = obj)) (
(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]]))
......@@ -351,6 +350,8 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац
array [1..n_loading_op] of 1..n_operations : loading_op_n; % Номера среди общего списка операций.
array [1..n_all_storage_sections] of set of 1..n_loading_op : involved_operations;
array [1..n_moving_obj] of set of 1..n_all_storage_sections : sections_of_moving_obj;
array [1..n_moving_obj] of bool : is_sections_of_moving_obj_empty;
constraint forall (storage in 1..n_all_storage_sections, t in 1..(n_intervals + 1)) (
storage_used_volume[storage, t] = (
......@@ -509,6 +510,51 @@ array [0..n_operations] of 0..n_locations : operations_destination; % Локац
) -> is_attended_useful_op_in_cur_loc[obj, t - 1]
);
% Оптимизация - если объект не может совершить в данной локации операции без выхода за границы хранилища, а так же если он
% может уйти только своим ходом, то он либо уходит немедленно, либо остаётся на месте навсегда.
array [1..n_all_storage_sections, 1..n_locations] of int : min_positive_cargo_val; % Объём максимальной положительной операции, которая может быть произведена с этой секцией в этом хранилище. Если в локации таковой нет, то это значение объёма хранилища + 1.
array [1..n_all_storage_sections, 1..n_locations] of int : max_negative_cargo_val;
array [1..n_moving_obj, 1..n_locations] of bool : can_obj_leave_loc_only_alone;
array [1..n_moving_obj, 1..n_locations, 1..n_intervals] of bool : is_fixed_op_planned_in_future;
array [0..n_moving_obj, 0..(n_intervals + 1)] of var bool : can_obj_theoretically_use_cargo_op;
% Определение can_obj_theoretically_use_cargo_op.
constraint forall (obj in 1..n_moving_obj, t in 1..(n_intervals + 1)) (
can_obj_theoretically_use_cargo_op[obj, t] = (
is_sections_of_moving_obj_empty[obj]
\/
exists (section in sections_of_moving_obj[obj]) (
(storage_used_volume[section, t - 1] + min_positive_cargo_val[section, main_location[m_obj_loc[obj, t]]] <= max_storage_vol[section])
\/ (storage_used_volume[section, t - 1] + max_negative_cargo_val[section, main_location[m_obj_loc[obj, t]]] >= 0)
)
)
);
constraint forall (t in 0..(n_intervals + 1)) (can_obj_theoretically_use_cargo_op[0, t] = false);
constraint forall (obj in 1..n_moving_obj) (can_obj_theoretically_use_cargo_op[obj, 0] = false);
% Остановился ли объект окончательно, начиная с данного интервала.
array [0..n_moving_obj, 0..(n_intervals + 1)] of var bool : is_obj_totally_terminated;
constraint forall (obj in 1..n_moving_obj) (is_obj_totally_terminated[obj, n_intervals + 1] = true);
constraint forall (t in 0..(n_intervals + 1)) (is_obj_totally_terminated[0, t] = true);
constraint forall (obj in 1..n_moving_obj, t in 0..n_intervals) (
is_obj_totally_terminated[obj, t] = (
(current_moving_operation[obj, t] = 0)
/\ (not is_involved_in_cargo_op[obj, t])
/\ (is_obj_totally_terminated[obj, t + 1])
)
);
% Само ограничение.
constraint forall (obj in 1..n_moving_obj, t in 1..n_intervals) (
( (can_obj_leave_loc_only_alone[obj, m_obj_loc[obj, t]])
/\ (not can_obj_theoretically_use_cargo_op[obj, t])
/\ (not is_fixed_op_planned_in_future[obj, m_obj_loc[obj, t], t])
) ->
(is_obj_totally_terminated[obj, t] \/ (current_moving_operation[obj, t] != 0))
);
% Критерий оптимизации
array [1..(n_intervals + 1)] of var bool : is_not_terminated;
......@@ -541,16 +587,25 @@ output [show(sum(is_not_terminated)), "\n",
"is_involved_in_cargo_op = {", show(n_intervals), "} ", show(is_involved_in_cargo_op), "\n\n",
"m_obj_loc = ", show(m_obj_loc), "\n\n",
/*
"prev_m_obj_loc = {", show(n_intervals + 2), "} ", show(prev_m_obj_loc), "\n\n",
"is_obj_involved_in_useful_operation = {", show(n_intervals + 2), "} ", show(is_obj_involved_in_useful_operation), "\n\n",
"is_attended_useful_op_in_cur_loc = {", show(n_intervals + 2), "} ", show(is_attended_useful_op_in_cur_loc), "\n\n",
*/
"can_obj_theoretically_use_cargo_op = {", show(n_intervals + 2), "} ", show(can_obj_theoretically_use_cargo_op), "\n\n",
"is_obj_totally_terminated = {", show(n_intervals + 2), "} ", show(is_obj_totally_terminated), "\n\n",
"main_location = {", show(n_locations), "} ", show(main_location), "\n\n",
"is_fixed_op_planned_in_future = {", show(n_locations), " ", show(n_intervals), "} ", show(is_fixed_op_planned_in_future), "\n\n",
"can_obj_leave_loc_only_alone {", show(n_locations), "} = ", show(can_obj_leave_loc_only_alone), "\n\n",
/*
"is_op_possible {", show(n_intervals), "} = ", show(is_op_possible), "\n\n",
"debug_1 {", show(n_intervals), "} = ", show(debug_1), "\n\n",
"is_enough_free_resources {", show(n_intervals), "} = ", show(is_enough_free_resources), "\n\n",
"operation_of_counter {", show(n_resources_counters), "} = ", show(operation_of_counter), "\n\n",
"possible_resources_counter {", show(n_intervals), "} = ", show(possible_resources_counter), "\n\n",
*/
""];
......@@ -116,6 +116,26 @@ public class ConversionUtil {
writer.write("]);\n");
}
static private <T> void write3dArray(FileWriter writer,
String name,
ArrayList<ArrayList<ArrayList<T>>> array,
Function<T, String> toString) throws IOException {
int dim1 = array.size();
int dim2 = (dim1 > 0) ? array.get(0).size() : 0;
int dim3 = (dim2 > 0) ? array.get(0).get(0).size() : 0;
writer.write(name + " = array3d(1.." + dim1 + ", 1.." + dim2 + ", 1.." + dim3 + ", ");
ArrayList<String> values = new ArrayList<>();
for (ArrayList<ArrayList<T>> a2 : array) {
for (ArrayList<T> a1 : a2) {
for (T val : a1) {
values.add(toString.apply(val));
}
}
}
writer.write("[" + String.join(", ", values) + "]);\n");
}
static private void writeArrayOfSetAs2DArray(FileWriter writer,
String name,
ArrayList<ArrayList<Integer>> operations) throws IOException {
......@@ -896,6 +916,21 @@ public class ConversionUtil {
bunker_of_cargo_op.add(0);
}
}
ArrayList<ArrayList<Integer>> sections_of_moving_obj = arrayOfIntegerArrays(movingObjects.size());
for (int i = 0; i < movingObjects.size(); i++) {
if (movingObjects.get(i) instanceof TransportShip) {
TransportShip ship = ((TransportShip) movingObjects.get(i));
for (Pair<Cargo, Double> p : ship.getStorageSections()) {
sections_of_moving_obj.get(i).add(sectionIdToN(ship, p.getKey()) + 1);
}
}
}
ArrayList<Boolean> is_sections_of_moving_obj_empty = new ArrayList<>();
for (ArrayList<Integer> sections : sections_of_moving_obj) {
is_sections_of_moving_obj_empty.add(sections.isEmpty());
}
writer.write("n_loading_op = " + loadingOpDelta.size() + ";\n");
writeArray(writer, "involved_operations", involvedOperations, ConversionUtil::arrayToStringAsSet);
......@@ -913,6 +948,9 @@ public class ConversionUtil {
writeArray(writer, "operations_cargo_t", operations_cargo_t, Optional.of(1));
writeArray(writer, "bunker_of_cargo_op", bunker_of_cargo_op, Optional.of(0));
writeArray(writer, "sections_of_moving_obj", sections_of_moving_obj, ConversionUtil::arrayToStringAsSet);
writeArray(writer, "is_sections_of_moving_obj_empty", is_sections_of_moving_obj_empty);
writer.write("\n");
}
......@@ -1319,6 +1357,17 @@ public class ConversionUtil {
}
}
}
{ // Взаимоисключение всех возможных пар операций перемещения с одним деятелем и пунктом отправления.
if ((operationTemplates.get(i) instanceof MovingTemplate) &&
(operationTemplates.get(j) instanceof MovingTemplate)) {
MovingTemplate op1 = (MovingTemplate) operationTemplates.get(i);
MovingTemplate op2 = (MovingTemplate) operationTemplates.get(j);
if ((op1.getMover() == op2.getMover()) && (op1.getStartLocation() == op2.getStartLocation())) {
conflictingOperationsG.get(i).add(j + 1);
}
}
}
}
}
writeArray(writer, "conflicting_operations", conflictingOperationsG, ConversionUtil::setToString,
......@@ -1358,6 +1407,8 @@ public class ConversionUtil {
ArrayList<Integer> fixedOpEnd = new ArrayList<>();
ArrayList<Integer> fixedOpIntensity = new ArrayList<>();
ArrayList<ArrayList<ArrayList<Boolean>>> is_fixed_op_planned_in_future = new ArrayList<>();
class OperationData implements Comparable<OperationData> {
private int opId, executorId;
private OptionalInt bunkerId;
......@@ -1404,6 +1455,16 @@ public class ConversionUtil {
}
}
for (int i = 0; i < movingObjects.size(); i++) {
is_fixed_op_planned_in_future.add(new ArrayList<>());
for (int j = 0; j < locationNumberById.size(); j++) {
is_fixed_op_planned_in_future.get(i).add(new ArrayList<>());
for (int k = 0; k < n_intervals; k++) {
is_fixed_op_planned_in_future.get(i).get(j).add(false);
}
}
}
for (Operation op : task.getFixedOperations()) {
if (op.getFixation()) {
OptionalInt bunkerId = op.getBunker().map(b -> OptionalInt.of(b.getId())).orElse(OptionalInt.empty());
......@@ -1427,6 +1488,12 @@ public class ConversionUtil {
}
}
int loc = getLocNById(op.getTemplate().getStartLocation().getId(), false);
int executor = mObjToN(op.getExecutor());
for (int i = 0; i < end; i++) {
is_fixed_op_planned_in_future.get(executor).get(loc).set(i, true);
}
fixedOp.add(opNo + 1);
TreeSet<Integer> resources = new TreeSet<>();
for (MovingObject obj : op.getResources()) {
......@@ -1447,6 +1514,8 @@ public class ConversionUtil {
writeArray(writer, "fixed_op_intensity", fixedOpIntensity);
locWrite2DArray(writer, "is_fixed", getIsFixedArray(), Objects::toString, true);
locWrite2DArray(writer, "is_obj_involved_in_fixed_op", is_obj_involved_in_fixed_op, Objects::toString, true);
write3dArray(writer, "is_fixed_op_planned_in_future", is_fixed_op_planned_in_future, Objects::toString);
}
void defDataForCurMovingOp() throws IOException {
......@@ -1548,6 +1617,62 @@ public class ConversionUtil {
writeArray(writer, "bunker_start_loc", bunkerStartLoc, (Integer val) -> val + 1, Optional.of(-1));
}
void dataForOptimization3() throws IOException {
ArrayList<ArrayList<Integer>> min_positive_cargo_val = arrayOfIntegerArrays(sectionNById.size());
ArrayList<ArrayList<Integer>> max_negative_cargo_val = arrayOfIntegerArrays(sectionNById.size());
ArrayList<ArrayList<Boolean>> can_obj_leave_loc_only_alone = new ArrayList<>();
for (int i = 0; i < sectionNById.size(); i++) {
for (int j = 0; j < locationNumberById.size(); j++) {
min_positive_cargo_val.get(i).add(maxStorageVol.get(i) + 1);
max_negative_cargo_val.get(i).add(-maxStorageVol.get(i) - 1);
}
}
for (int i = 0; i < movingObjects.size(); i++) {
can_obj_leave_loc_only_alone.add(new ArrayList<>());
for (int j = 0; j < locationNumberById.size(); j++) {
can_obj_leave_loc_only_alone.get(i).add((j + 1) % 2 == 1);
}
}
for (OperationTemplate t : operationTemplates) {
if (t instanceof LoadingTemplate) {
LoadingTemplate op = (LoadingTemplate) t;
int val = (int) op.getIntensity();
int loc = getLocNById(op.getStartLocation().getId(), false) ;
ArrayList<Pair<Integer, Integer>> sections = new ArrayList<>();
sections.add(new Pair<>(sectionIdToN(op.getLoader(), op.getCargo()), val));
if (op.getBunker().isPresent()) {
sections.add(new Pair<>(sectionIdToN(op.getBunker().get(), op.getCargo()), -val));
} else {
sections.add(new Pair<>(sectionIdToN(op.getStorage(), op.getCargo()), -val));
}
for (Pair<Integer, Integer> p : sections) {
if (p.getValue() > 0) {
min_positive_cargo_val.get(p.getKey()).set(loc, Math.min(p.getValue(), min_positive_cargo_val.get(p.getKey()).get(loc)));
} else {
max_negative_cargo_val.get(p.getKey()).set(loc, Math.max(p.getValue(), max_negative_cargo_val.get(p.getKey()).get(loc)));
}
}
} else if (t instanceof MovingTemplate) {
int loc = getLocNById(t.getStartLocation().getId(), false);
int obj = mObjToN(getExecutor(t));
if (! ((MovingTemplate) t).getResourcesTypes().isEmpty()) {
can_obj_leave_loc_only_alone.get(obj).set(loc, false);
}
}
}
write2DArrayOfInt(writer, "min_positive_cargo_val", min_positive_cargo_val, false);
write2DArrayOfInt(writer, "max_negative_cargo_val", max_negative_cargo_val, false);
locWrite2DArray(writer, "can_obj_leave_loc_only_alone", can_obj_leave_loc_only_alone, Objects::toString);
writer.write("\n");
}
/* С типизацией. */
void portToMiniZinc_2() throws IOException {
if (!task.isTypified()) {
......@@ -1588,6 +1713,7 @@ public class ConversionUtil {
boundaryStorageStates();
cargoFlows();
cargoOperations();
dataForOptimization3();
fixedOperations();
} finally {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment