From c489eeccaeb5b68144295977b7fbc685c5c998dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=81=D0=B5=D0=BB=D1=91=D0=B2=20=D0=92=D0=BB?= =?UTF-8?q?=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Fri, 3 May 2019 10:27:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=84=D0=B8=D0=BA=D1=81=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B9=20=D0=B8=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2?= =?UTF-8?q?=D0=B5=D1=82=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B8=D0=B9=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constraints/conversion_2.mzn | 20 ++++- src/inport/ConversionUtil.java | 101 +++++++++++++++++++++++-- src/inport/Operation.java | 11 ++- src/inport/TaskCase.java | 28 +++++++ tests/with_typing/FixedOperations.tipp | 69 +++++++++++++++++ 5 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 tests/with_typing/FixedOperations.tipp diff --git a/src/constraints/conversion_2.mzn b/src/constraints/conversion_2.mzn index 3eaacf0..f052757 100644 --- a/src/constraints/conversion_2.mzn +++ b/src/constraints/conversion_2.mzn @@ -344,6 +344,24 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац ) ); +% Фиксированные операции. + 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_operations, 1..n_intervals] of bool : is_fixed; + + 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 [1..n_operations, 1..n_intervals] of var bool : is_op_possible; @@ -415,7 +433,7 @@ array [1..n_operations] of 1..n_locations : operations_destination; % Локац % Сам критерий оптимизации - если если операцию можно было начать на 1 интервал раньше, то её нужно начать раньше. constraint forall (op in 1..n_operations, t in 2..n_intervals) ( - op_start[op, t] -> not is_op_possible[op, t - 1] + (op_start[op, t] /\ (not is_fixed[op, t])) -> not is_op_possible[op, t - 1] ); % Критерий оптимизации diff --git a/src/inport/ConversionUtil.java b/src/inport/ConversionUtil.java index 7acad77..8f5bd5e 100644 --- a/src/inport/ConversionUtil.java +++ b/src/inport/ConversionUtil.java @@ -8,8 +8,8 @@ import java.util.function.BiConsumer; import java.util.function.Function; public class ConversionUtil { - static class PairComparator implements Comparator> { - public int compare(Pair p1, Pair p2) { + static class PairComparator implements Comparator> { + public int compare(Pair p1, Pair p2) { int res = p1.getKey().compareTo(p2.getKey()); if (res != 0) { return res; @@ -1150,6 +1150,65 @@ public class ConversionUtil { writeArray(writer, "conflicting_operations", conflictingOperationsG, ConversionUtil::setToString); } + public ArrayList> getIsFixedArray() { + Map, Integer> opNoByOpIdAndExecutorNo = new TreeMap<>(new PairComparator<>()); + for (int i = 0; i < operationTemplates.size(); i++) { + OperationTemplate op = operationTemplates.get(i); + opNoByOpIdAndExecutorNo.put(new Pair<>(op.getId(), getExecutor(op).getId()), i); + } + + ArrayList> isFixed = new ArrayList<>(); + for (int i = 0; i < operationTemplates.size(); i++) { + isFixed.add(new ArrayList<>()); + for (int j = 0; j < n_intervals; j++) { + isFixed.get(i).add(false); + } + } + for (Operation op : task.getSolution()) { + if (op.getFixation()) { + int operation = opNoByOpIdAndExecutorNo.get(new Pair<>(op.getTemplate().getId(), op.getExecutor().getId())); + + for (int i = (int)Math.floor(op.getStart()); i < (int)Math.ceil(op.getDuration() + op.getStart()); i++) { + isFixed.get(operation).set(i, true); + } + } + } + return isFixed; + } + + private void fixedOperations() throws IOException { + ArrayList fixedOp = new ArrayList<>(); + ArrayList> fixedOpResources = new ArrayList<>(); + ArrayList fixedOpStart = new ArrayList<>(); + ArrayList fixedOpEnd = new ArrayList<>(); + + Map, Integer> opNoByOpIdAndExecutorNo = new TreeMap<>(new PairComparator<>()); + for (int i = 0; i < operationTemplates.size(); i++) { + OperationTemplate op = operationTemplates.get(i); + opNoByOpIdAndExecutorNo.put(new Pair<>(op.getId(), getExecutor(op).getId()), i); + } + + for (Operation op : task.getSolution()) { + if (op.getFixation()) { + fixedOp.add(opNoByOpIdAndExecutorNo.get(new Pair<>(op.getTemplate().getId(), op.getExecutor().getId())) + 1); + TreeSet resources = new TreeSet<>(); + for (MovingObject obj : op.getResources()) { + resources.add(mObjToN(obj)); + } + fixedOpResources.add(resources); + fixedOpStart.add((int)Math.floor(op.getStart()) + 1); + fixedOpEnd.add((int)Math.ceil(op.getDuration() + op.getStart())); + } + } + + writer.write("n_fixed_op = " + fixedOp.size() + ";\n"); + writeArray(writer, "fixed_op", fixedOp); + writeArray(writer, "fixed_op_resources", fixedOpResources, ConversionUtil::setToString); + writeArray(writer, "fixed_op_start", fixedOpStart); + writeArray(writer, "fixed_op_end", fixedOpEnd); + locWrite2DArray(writer, "is_fixed", getIsFixedArray(), Objects::toString); + } + private void typifiedResourcesDefinition() throws IOException { { // objects_of_type и operations_that_used_obj_as_resource writer.write("n_resources_types = " + typeToN.size() + ";\n"); @@ -1254,6 +1313,8 @@ public class ConversionUtil { boundaryStorageStates(); cargoFlows(); cargoOperations(); + + fixedOperations(); } finally { if (writer != null) { writer.close(); @@ -1390,6 +1451,7 @@ public class ConversionUtil { } Map objByNo = new TreeMap<>(); + ArrayList> isFixed; { Task t = new Task(task, ""); ArrayList movingObjects = new ArrayList<>(); @@ -1400,14 +1462,25 @@ public class ConversionUtil { for (MovingObject obj : movingObjects) { objByNo.put(t.getMObjNumberById().get(obj.getId()), obj); } + + isFixed = t.getIsFixedArray(); + } + + Set oldSolution = new TreeSet<>(); + for (Operation op : task.getSolution()) { + if (op.getFixation()) { + oldSolution.add(op.toString()); + } } for (int opNo = 0; opNo < opStatus.size(); opNo++) { int duration = 0; - for (int t = 0; t < opStatus.get(opNo).size(); t++) { - if (opStatus.get(opNo).get(t).equals("true")) { - duration++; - } else if (duration != 0) { + int t = 0; + boolean lastFixation = false; + + while (t < opStatus.get(opNo).size()) { + if ((opStatus.get(opNo).get(t).equals("true") && (lastFixation != isFixed.get(opNo).get(t - 1))) + || (opStatus.get(opNo).get(t).equals("false") && (duration != 0))) { // Добавляем новую операцию. Operation op = new Operation(); op.setStart(t - duration - 1); op.setDuration(duration); @@ -1428,9 +1501,25 @@ public class ConversionUtil { op.setResources(resources); } + op.setFixation(true); + if (! oldSolution.contains(op.toString())) { + op.setFixation(false); + } + operations.add(op); duration = 0; } + if (opStatus.get(opNo).get(t).equals("true") && (lastFixation != isFixed.get(opNo).get(t - 1))) { // Остаёмся на месте. + lastFixation = isFixed.get(opNo).get(t - 1); + continue; + } + if (opStatus.get(opNo).get(t).equals("true")) { + duration++; + } + if ((0 <= t - 1) && (t - 1 < isFixed.get(opNo).size())) { + lastFixation = isFixed.get(opNo).get(t - 1); + } + t++; } } } diff --git a/src/inport/Operation.java b/src/inport/Operation.java index 70b5a8e..32cf9a6 100644 --- a/src/inport/Operation.java +++ b/src/inport/Operation.java @@ -13,11 +13,19 @@ import java.util.List; public class Operation { private OperationTemplate template; + private boolean fixation = false; private double start; private double duration; private MovingObject executor; private List resources; + public boolean getFixation() { + return fixation; + } + public void setFixation(boolean fixation) { + this.fixation = fixation; + } + public List getResources() { return resources; } @@ -100,7 +108,8 @@ public class Operation { resources = ConversionUtil.getResources(template); } StringBuilder sb = new StringBuilder(); - sb.append(template.getId()).append("; R; ").append(start).append("; ").append(duration); + sb.append(template.getId()).append("; "); + sb.append(fixation ? "F" : "R").append("; ").append(start).append("; ").append(duration); sb.append(" (").append(executor.getId()).append(" ["); boolean isFirst = true; for (MovingObject obj : resources) { diff --git a/src/inport/TaskCase.java b/src/inport/TaskCase.java index 4156232..b2a0a53 100644 --- a/src/inport/TaskCase.java +++ b/src/inport/TaskCase.java @@ -650,6 +650,34 @@ public class TaskCase { case Solution: // Тут чтение операций если надо. Потом подумаем if (numInside == 1) { solution_result = Double.parseDouble(strLine.trim()); + } else { + String lStr = strLine.substring(0, strLine.indexOf('(')).trim(); + String rStr = strLine.substring(strLine.indexOf('(') + 1, strLine.indexOf(')')).trim(); + + Operation op = new Operation(); + { + String[] items = lStr.split(";"); + op.setStart(Double.parseDouble(items[2].trim())); + op.setDuration(Double.parseDouble(items[3].trim())); + op.setTemplate(m_template.get(Integer.parseInt(items[0].trim()))); + + op.setFixation(items[1].trim().equals("F")); + } + { + String[] items = rStr.substring(rStr.indexOf('[') + 1, rStr.indexOf(']')).split(","); + ArrayList resources = new ArrayList<>(); + for (String item : items) { + if (item.trim().isEmpty()) { + continue; + } + resources.add(m_equipment.get(Integer.valueOf(item.trim()))); + } + op.setResources(resources); + } + int exId = Integer.valueOf(rStr.substring(0, rStr.indexOf('[')).trim()); + op.setExecutor(m_vessel.get(exId)); + + solution.add(op); } break; default: diff --git a/tests/with_typing/FixedOperations.tipp b/tests/with_typing/FixedOperations.tipp new file mode 100644 index 0000000..ee89bbd --- /dev/null +++ b/tests/with_typing/FixedOperations.tipp @@ -0,0 +1,69 @@ +Typified +1 + +Cargoes +0; LNG; 0.0 + +Berths +1; Raid +2; Pier 1 +3; Pier 2 + +Storages +4; Storage 1; 0; 10000.0 + +Vessel Types +1001; Тип судна1 + +Bunkers + +Tows + +Loading Equipment Types + +Loading Equipments + +Transport Ships +5; Ship 1; 2000.0; 1001 +6; Ship 2; 2000.0; 1001 + +Templates +7; mov; []; 1001; 1; 2; []; 1.0 +8; mov; []; 1001; 2; 1; []; 1.0 +9; mov; []; 1001; 1; 3; []; 1.0 +10; mov; []; 1001; 3; 1; []; 1.0 +11; mov; []; 1001; 2; 3; []; 1.0 +12; mov; []; 1001; 3; 2; []; 1.0 +19; loa; []; 4; 0; 1001; 2; []; 100.0; U +20; loa; []; 4; 0; 1001; 3; []; 50.0; U + +21; mov; []; 1001; 1; 1; []; 3.0 + +Cargo Flows + +Initial Vessel State +5; 1 +6; 1 + +Initial Storage State +0; 5; 0.0 +0; 6; 0.0 +0; 4; 10000.0 + +Final Vessel State +5; 1 +6; 1 + +Final Storage State +0; 5; 1000.0 +0; 6; 1000.0 + + +Task Properties +30.0; 0 + + +Solution +18.0 +21; F; 0.0; 3.0 (5 []) +19; F; 6.0; 3.0 (5 []) -- GitLab