diff --git a/pom.xml b/pom.xml
index 6f3182a..cc6aa32 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
ifmo.ru
virgo-solver
- 0.1.4
+ 0.1.5
UTF-8
diff --git a/src/main/java/ru/itmo/ctlab/virgo/Main.java b/src/main/java/ru/itmo/ctlab/virgo/Main.java
index d26aa01..b5a9221 100644
--- a/src/main/java/ru/itmo/ctlab/virgo/Main.java
+++ b/src/main/java/ru/itmo/ctlab/virgo/Main.java
@@ -1,6 +1,5 @@
package ru.itmo.ctlab.virgo;
-import ilog.cplex.IloCplex;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import ru.itmo.ctlab.gmwcs.solver.TreeSolverKt;
@@ -16,12 +15,9 @@
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -32,7 +28,7 @@
import static ru.itmo.ctlab.virgo.gmwcs.graph.Elem.extract;
public class Main {
- public static final String VERSION = "0.1.4";
+ public static final String VERSION = "0.1.5";
private static void checkCplex() {
PrintStream stdout = System.out;
@@ -51,7 +47,6 @@ private static void checkCplex() {
System.exit(1);
} finally {
System.setOut(stdout);
- System.out.println("aaa");
}
}
diff --git a/src/main/java/ru/itmo/ctlab/virgo/gmwcs/graph/Elem.java b/src/main/java/ru/itmo/ctlab/virgo/gmwcs/graph/Elem.java
index 50163aa..dbe71a6 100644
--- a/src/main/java/ru/itmo/ctlab/virgo/gmwcs/graph/Elem.java
+++ b/src/main/java/ru/itmo/ctlab/virgo/gmwcs/graph/Elem.java
@@ -61,7 +61,7 @@ public boolean equals(Object o) {
@Override
public int compareTo(Elem u) {
if (u.weight != weight) {
- return Double.compare(u.weight, weight);
+ return Double.compare(weight, u.weight);
}
return Integer.compare(u.getNum(), num);
}
diff --git a/src/main/java/ru/itmo/ctlab/virgo/sgmwcs/solver/Dijkstra.java b/src/main/java/ru/itmo/ctlab/virgo/sgmwcs/solver/Dijkstra.java
index 40422a1..da606b6 100644
--- a/src/main/java/ru/itmo/ctlab/virgo/sgmwcs/solver/Dijkstra.java
+++ b/src/main/java/ru/itmo/ctlab/virgo/sgmwcs/solver/Dijkstra.java
@@ -66,6 +66,8 @@ public void solve(Node u) {
Set visitedDests = new HashSet<>();
path.put(u, Collections.emptySet());
while ((cur = q.poll()) != null) {
+ if (visitedDests.contains(cur))
+ continue;
if (dests.contains(cur)
&& visitedDests.add(cur)
&& visitedDests.containsAll(dests)) {
diff --git a/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Dijkstra.kt b/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Dijkstra.kt
index 69badb4..c58fd5f 100644
--- a/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Dijkstra.kt
+++ b/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Dijkstra.kt
@@ -6,32 +6,30 @@ import ru.itmo.ctlab.virgo.gmwcs.graph.Elem
import ru.itmo.ctlab.virgo.gmwcs.graph.Node
import ru.itmo.ctlab.virgo.gmwcs.graph.Graph
import java.util.*
+import kotlin.math.abs
/**
* Created by Nikolay Poperechnyi on 04/10/2017.
*/
-class Dijkstra(private val graph: Graph, private val from: Node,
- private val save: Boolean = false) {
+class Dijkstra(private val graph: Graph, private val from: Node) {
private val s = from.num
private val n = graph.vertexSet().maxBy { it.num }!!.num + 1
- private val paths = Array(n, {emptyList()})
+ private val visited = BooleanArray(n) { false }
- private val visited = BooleanArray(n, { false })
-
- private var d = DoubleArray(n, { Double.MAX_VALUE })
+ private var d = DoubleArray(n) { Double.MAX_VALUE }
private fun solve(neighbors: Set) {
if (d[s] != Double.MAX_VALUE) return
- val queue = PriorityQueue(
- { n1, n2 -> (d[n1.num] - d[n2.num]).compareTo(0) }
- )
+ val queue = PriorityQueue { n1, n2 -> (d[n1.num] - d[n2.num]).compareTo(0) }
d[s] = 0.0
queue.add(from)
while (queue.isNotEmpty()) {
val cur = queue.poll()
+ if (visited[cur.num])
+ continue
visited[cur.num] = true
// Stop searching if shortest paths are found
if (neighbors.contains(cur) && neighbors.all { visited[it.num] })
@@ -39,7 +37,7 @@ class Dijkstra(private val graph: Graph, private val from: Node,
for (adj in graph.neighborListOf(cur).filter { !visited[it.num] }) {
// 0 for positive, -weight for negative
val e = graph.getEdge(cur, adj)
- val ew = if (cur != from) maxOf(p(e, cur), p(e), p(cur)) else p(e)
+ val ew = p(e, adj)
val w = d[cur.num] + ew
if (d[adj.num] > w) {
d[adj.num] = w
@@ -54,14 +52,14 @@ class Dijkstra(private val graph: Graph, private val from: Node,
private fun distances(neighbors: Set): Map {
solve(neighbors)
- return neighbors.map({ Pair(it, d[it.num] + p(from)) }).toMap()
+ return neighbors.associateWith { d[it.num] + p(from) }
}
fun negativeEdges(neighbors: Set): List {
solve(neighbors)
return graph.edgesOf(from).filter {
val end = graph.opposite(from, it)
- it.weight < 0 && p(it) > d[end.num]
+ it.weight < 0 && !almostEquals(d[end.num] - p(it), p(end))
// it.weight <= 0 && d[end] < -it.weight
}
}
@@ -69,11 +67,17 @@ class Dijkstra(private val graph: Graph, private val from: Node,
fun negativeVertex(dest: Node, candidate: Node): Boolean {
solve(setOf(dest))
// test is passed if candidate for removal is not in the solution
- val candPathW = d[candidate.num] + p(graph.getEdge(candidate, dest)) + p(candidate)
- return d[dest.num] != candPathW
+ val candPathW = p(graph.getEdge(from, candidate),
+ graph.getEdge(candidate, dest),
+ candidate)
+ return !almostEquals(d[dest.num], candPathW)
+ }
+
+ private fun almostEquals(a: Double, b: Double): Boolean {
+ return abs(a - b) < 1e-10
}
private fun p(vararg e: Elem): Double {
- return -minOf(e.sumByDouble { it.weight }, 0.0)
+ return -e.sumByDouble { minOf(it.weight, 0.0) }
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Preprocessor.kt b/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Preprocessor.kt
index b9a6074..9bf4a54 100644
--- a/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Preprocessor.kt
+++ b/src/main/kotlin/ru/itmo/ctlab/gmwcs/solver/preprocessing/Preprocessor.kt
@@ -91,7 +91,7 @@ fun l(graph: Graph, toRemove: MutableNodeSet = mutableSetOf()): NodeSet {
continue
val e = graph.edgesOf(n).iterator().next()
val opposite = graph.opposite(n, e)
- if (n.weight + e.weight >= 0) {
+ if (n.weight + e.weight > 0) {
opposite.absorb(n)
opposite.absorb(e)
toRemove.add(n)
@@ -112,12 +112,19 @@ fun mergeNegative(graph: Graph, toRemove: MutableNodeSet = mutableSetOf()): Node
continue
val l = graph.opposite(v, edges[0])
val r = graph.opposite(v, edges[1])
- toRemove.add(v) //TODO: 2 nodes 1 edge invariant broken here
+ toRemove.add(v)
graph.removeVertex(v)
if (l != r) {
edges[0].absorb(v)
edges[0].absorb(edges[1])
graph.addEdge(l, r, edges[0])
+ val es = graph.getAllEdges(l, r).sorted()
+ val maxE = es[es.size - 1]
+ for (e in es.subList(0, es.size - 1)) {
+ if (e.weight >= 0)
+ maxE.absorb(e)
+ graph.removeEdge(e)
+ }
}
}
return toRemove
@@ -183,12 +190,12 @@ private fun contract(graph: Graph, e: Edge) {
fun negativeVertices(graph: Graph,
toRemove: MutableNodeSet = mutableSetOf()): NodeSet {
- graph.vertexSet().filterTo(toRemove, { vertexTest(graph, it) })
+ graph.vertexSet().filterTo(toRemove) { vertexTest(graph, it) }
return toRemove
}
private fun vertexTest(graph: Graph, v: Node): Boolean {
- return if (v.weight <= 0
+ return if (v.weight < 0
&& graph.neighborListOf(v).size == 2
&& graph.edgesOf(v).all { it.weight <= 0 }) {
val neighbors = graph.neighborListOf(v)
diff --git a/src/test/java/ru/itmo/ctlab/virgo/sgmwcs/SGMWCSTest.java b/src/test/java/ru/itmo/ctlab/virgo/sgmwcs/SGMWCSTest.java
index 33ac6f8..755805d 100644
--- a/src/test/java/ru/itmo/ctlab/virgo/sgmwcs/SGMWCSTest.java
+++ b/src/test/java/ru/itmo/ctlab/virgo/sgmwcs/SGMWCSTest.java
@@ -6,14 +6,16 @@
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
-import ru.itmo.ctlab.virgo.sgmwcs.graph.*;
-import ru.itmo.ctlab.virgo.sgmwcs.solver.*;
import ru.itmo.ctlab.virgo.SolverException;
+import ru.itmo.ctlab.virgo.sgmwcs.graph.Edge;
+import ru.itmo.ctlab.virgo.sgmwcs.graph.Graph;
+import ru.itmo.ctlab.virgo.sgmwcs.graph.Node;
+import ru.itmo.ctlab.virgo.sgmwcs.graph.Unit;
+import ru.itmo.ctlab.virgo.sgmwcs.solver.*;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.*;
-import java.util.stream.IntStream;
import static ru.itmo.ctlab.virgo.sgmwcs.solver.Utils.copy;
import static ru.itmo.ctlab.virgo.sgmwcs.solver.Utils.sum;
@@ -35,11 +37,11 @@ public class SGMWCSTest {
}
}
- private List tests;
- private ComponentSolver solver;
- private ReferenceSolver referenceSolver;
- private RLTSolver rltSolver;
- private Random random;
+ private final List tests;
+ private final ComponentSolver solver;
+ private final ReferenceSolver referenceSolver;
+ private final RLTSolver rltSolver;
+ private final Random random;
public SGMWCSTest() {
random = new Random(SEED);
@@ -95,7 +97,7 @@ public void test01_empty() throws SolverException {
solver.setLogLevel(0);
List res = solver.solve(graph, new Signals());
if (!(res == null || res.isEmpty())) {
- Assert.assertTrue("An empty graph can't contain non-empty subgraph", false);
+ Assert.fail("An empty graph can't contain non-empty subgraph");
}
}
@@ -305,8 +307,8 @@ private void makeConnectedGraphs(int minSize, int maxSize) {
}
fillEdgesRandomly(graph, count, nodesArray, edges, size);
Map weights = new HashMap<>();
- nodes.forEach(weights::put);
- edges.forEach(weights::put);
+ weights.putAll(nodes);
+ weights.putAll(edges);
tests.add(new TestCase(graph, weights, random));
}
}
@@ -323,8 +325,8 @@ private void makeUnconnectedGraphs() {
Arrays.sort(nodesArray);
fillEdgesRandomly(graph, m, nodesArray, edges, 1);
Map weights = new HashMap<>();
- nodes.forEach(weights::put);
- edges.forEach(weights::put);
+ weights.putAll(nodes);
+ weights.putAll(edges);
tests.add(new TestCase(graph, weights, random));
}
}