Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections-api</artifactId>
<version>13.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>13.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
37 changes: 21 additions & 16 deletions src/test/java/com/github/bibenga/alns/tsp/Tsp.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.random.RandomGenerator;
import java.util.stream.IntStream;

import org.eclipse.collections.api.map.primitive.IntIntMap;
import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap;
import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet;

import com.github.bibenga.alns.ALNS;
import com.github.bibenga.alns.State;
import com.github.bibenga.alns.accept.HillClimbing;
Expand All @@ -29,7 +31,7 @@ public static void main(String[] args) throws Exception {

Random rng = new Random(42);

TspState initSol = new TspState(nodes, new HashMap<>(), dists);
TspState initSol = new TspState(nodes, new IntIntHashMap(), dists);
initSol = (TspState) greedyRepair(initSol, rng);

System.out.println("optimal solution: 564");
Expand Down Expand Up @@ -248,7 +250,7 @@ private static State randomRemoval(State state, RandomGenerator rng) {
int removed = 0;
while (removed < toRemove) {
int node = destroyed.nodes[rng.nextInt(destroyed.nodes.length)];
if (destroyed.edges.remove(node) != null) {
if (destroyed.edges.removeKeyIfAbsent(node, -1) != -1) {
removed++;
}
}
Expand Down Expand Up @@ -285,9 +287,11 @@ private static State worstRemoval(State state, RandomGenerator rng) {
private static State greedyRepair(State state, RandomGenerator rng) {
TspState cur = (TspState) state;

boolean[] visited = new boolean[cur.nodes.length];
for (int v : cur.edges.values())
visited[v] = true;
var visited = new IntHashSet();
for (var it = cur.edges.values().intIterator(); it.hasNext();) {
var v = it.next();
visited.add(v);
}

int[] idx = IntStream.range(0, cur.nodes.length).toArray();
shuffleArray(idx, rng);
Expand All @@ -306,21 +310,21 @@ private static State greedyRepair(State state, RandomGenerator rng) {
if (node == -1)
throw new RuntimeException("node not found");

final int finalNode = node;
final int fNode = node;
List<Integer> unvisited = new ArrayList<>();
for (int other : cur.nodes) {
if (other != finalNode && !visited[other] && !wouldFormSubcycle(finalNode, other, cur))
if (other != fNode && !visited.contains(other) && !wouldFormSubcycle(fNode, other, cur))
unvisited.add(other);
}
if (unvisited.isEmpty())
throw new RuntimeException("unvisited is empty");

int nearest = unvisited.stream()
.min(Comparator.comparingDouble(a -> cur.dists[finalNode][a]))
.min(Comparator.comparingDouble(a -> cur.dists[fNode][a]))
.orElseThrow();

cur.edges.put(node, nearest);
visited[nearest] = true;
visited.add(nearest);
}
return cur;
}
Expand All @@ -336,8 +340,8 @@ static void shuffleArray(int[] arr, RandomGenerator rnd) {

private static boolean wouldFormSubcycle(int fromNode, int toNode, TspState state) {
for (int step = 1; step < state.nodes.length; step++) {
Integer next = state.edges.get(toNode);
if (next == null)
int next = state.edges.getIfAbsent(toNode, -1);
if (next == -1)
return false;
toNode = next;
if (fromNode == toNode && step != state.nodes.length - 1)
Expand All @@ -346,7 +350,7 @@ private static boolean wouldFormSubcycle(int fromNode, int toNode, TspState stat
return false;
}

static void writeDotFile(String filename, double[][] coords, Map<Integer, Integer> edges) throws IOException {
static void writeDotFile(String filename, double[][] coords, IntIntMap edges) throws IOException {
final double k = 3;
double minX = Double.MAX_VALUE, minY = Double.MAX_VALUE;
double maxX = -Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
Expand All @@ -367,8 +371,9 @@ static void writeDotFile(String filename, double[][] coords, Map<Integer, Intege
" %d [label=\"%d\", fontsize=48, pos=\"%f,%f!\", shape=circle, width=2, height=2, fixedsize=true];%n",
i, i, x, y);
}
for (Map.Entry<Integer, Integer> e : edges.entrySet())
w.printf(" %d -> %d [arrowsize=4, penwidth=3];%n", e.getKey(), e.getValue());
edges.forEachKeyValue((key, value) -> {
w.printf(" %d -> %d [arrowsize=4, penwidth=3];%n", key, value);
});
w.println("}");
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/test/java/com/github/bibenga/alns/tsp/TspState.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package com.github.bibenga.alns.tsp;

import java.util.HashMap;
import java.util.Map;
import org.eclipse.collections.api.map.primitive.MutableIntIntMap;
import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap;

import com.github.bibenga.alns.State;

class TspState implements State {
final int[] nodes;
final Map<Integer, Integer> edges;
final MutableIntIntMap edges;
final double[][] dists;
private double objective = Double.NaN;

TspState(int[] nodes, Map<Integer, Integer> edges, double[][] dists) {
TspState(int[] nodes, MutableIntIntMap edges, double[][] dists) {
this.nodes = nodes;
this.edges = edges;
this.dists = dists;
}

@Override
public TspState clone() {
return new TspState(nodes, new HashMap<>(edges), dists);
return new TspState(nodes, new IntIntHashMap(edges), dists);
}

@Override
Expand Down