Skip to content

Commit 26ecb28

Browse files
author
Bytekeeper
committed
Replace UnitFinder/TreeMap with KDtree (d2) for a large performance improvement
1 parent 24438fc commit 26ecb28

File tree

11 files changed

+652
-501
lines changed

11 files changed

+652
-501
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ plugins {
22
java
33
id("maven")
44
id("me.champeau.gradle.jmh") version "0.4.8"
5-
id("com.github.ben-manes.versions") version "0.21.0"
5+
id("com.github.ben-manes.versions") version "0.22.0"
66
}
77

88
group = "org.bk"
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.bk.ass.query;
2+
3+
import org.bk.ass.path.Position;
4+
import org.openbw.bwapi4j.test.BWDataProvider;
5+
import org.openjdk.jmh.annotations.*;
6+
7+
import java.util.ArrayList;
8+
import java.util.Collection;
9+
import java.util.List;
10+
import java.util.SplittableRandom;
11+
import java.util.function.Function;
12+
13+
@Measurement(iterations = 2, time = 2)
14+
@Warmup(iterations = 2, time = 2)
15+
@Fork(2)
16+
public class PositionQueriesBenchmark {
17+
18+
@State(Scope.Thread)
19+
public static class MyState {
20+
21+
PositionQueries<Position> positionQueries;
22+
List<PositionAndId> entities;
23+
List<Position> items;
24+
25+
@Setup
26+
public void setup() {
27+
SplittableRandom rnd = new SplittableRandom(815);
28+
entities = new ArrayList<>();
29+
items = new ArrayList<>();
30+
for (int i = 0; i < 1000; i++) {
31+
int x = rnd.nextInt(0, 10000);
32+
int y = rnd.nextInt(0, 10000);
33+
entities.add(new PositionAndId(i, x, y));
34+
items.add(new Position(x, y));
35+
}
36+
positionQueries = new PositionQueries<>(items, Function.identity());
37+
}
38+
}
39+
40+
static {
41+
try {
42+
BWDataProvider.injectValues();
43+
} catch (Exception e) {
44+
throw new RuntimeException(e);
45+
}
46+
}
47+
48+
49+
@Benchmark
50+
public PositionQueries<Position> queryCreation(MyState state) {
51+
return new PositionQueries<>(state.items, Function.identity());
52+
}
53+
54+
55+
@Benchmark
56+
public Collection<Position> inRadius(MyState state) {
57+
return state.positionQueries.inRadius(5000, 5000, 1000);
58+
}
59+
60+
@Benchmark
61+
public Position nearest(MyState state) {
62+
return state.positionQueries.nearest(2500, 2500);
63+
}
64+
}

src/jmh/java/org/bk/ass/query/UnitFinderBenchmark.java

Lines changed: 0 additions & 65 deletions
This file was deleted.

src/main/java/org/bk/ass/cluster/StableDBScanner.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.bk.ass.cluster;
22

33
import org.bk.ass.collection.UnorderedCollection;
4-
import org.bk.ass.query.UnitFinder;
4+
import org.bk.ass.query.PositionQueries;
55

66
import java.util.*;
77
import java.util.Map.Entry;
@@ -14,7 +14,7 @@
1414
* is split into multiple clusters. In that case, only a part of the elements are retained in the
1515
* previous cluster. <br>
1616
* Make sure to call {@link #scan(int)} to actually perform clustering. Calling {@link
17-
* #updateDB(UnitFinder, int)} or {@link #updateDB(Collection, Function)} will reset the clustering
17+
* #updateDB(PositionQueries, int)} or {@link #updateDB(Collection, Function)} will reset the clustering
1818
* process. Make sure to always cluster all elements or to check if the clustering is done with
1919
* {@link #isComplete()}.<br>
2020
* The clustering is ongoing, each call to {@link #scan(int)} will continue or restart the
@@ -35,8 +35,8 @@ public class StableDBScanner<U> {
3535
private Map<U, Cluster<U>> elementToCluster = Collections.emptyMap();
3636
private ClusterSurrogate<U> currentCluster;
3737

38-
public StableDBScanner(UnitFinder<U> unitFinder, int minPoints, int radius) {
39-
this(unitFinder, minPoints, u -> unitFinder.inRadius(u, radius));
38+
public StableDBScanner(PositionQueries<U> positionQueries, int minPoints, int radius) {
39+
this(positionQueries, minPoints, u -> positionQueries.inRadius(u, radius));
4040
}
4141

4242
public StableDBScanner(int minPoints) {
@@ -65,8 +65,8 @@ public StableDBScanner<U> updateDB(Collection<U> db, Function<U, Collection<U>>
6565
return this;
6666
}
6767

68-
public StableDBScanner<U> updateDB(UnitFinder<U> unitFinder, int radius) {
69-
return updateDB(unitFinder, u -> unitFinder.inRadius(u, radius));
68+
public StableDBScanner<U> updateDB(PositionQueries<U> positionQueries, int radius) {
69+
return updateDB(positionQueries, u -> positionQueries.inRadius(u, radius));
7070
}
7171

7272
/**
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.bk.ass.query;
2+
3+
public class Distances {
4+
public static final DistanceProvider EUCLIDEAN_DISTANCE =
5+
(ax, ay, bx, by) -> (int) Math.sqrt((float) (bx - ax) * (bx - ax) + (by - ay) * (by - ay));
6+
7+
/**
8+
* When using this, all radius queries need to be made with the squared radius
9+
*/
10+
public static final DistanceProvider EUCLIDEAN_DISTANCE_SQUARED =
11+
(ax, ay, bx, by) -> (bx - ax) * (bx - ax) + (by - ay) * (by - ay);
12+
13+
/**
14+
* Use this to query using the distance approximation used in OpenBW
15+
*/
16+
public static final DistanceProvider BW_DISTANCE_APPROXIMATION =
17+
(ax, ay, bx, by) -> {
18+
int min = Math.abs(ax - bx);
19+
int max = Math.abs(ay - by);
20+
int minCalc;
21+
if (max < min) {
22+
minCalc = max;
23+
max = min;
24+
min = minCalc;
25+
}
26+
27+
if (min < max >> 2) {
28+
return max;
29+
} else {
30+
minCalc = 3 * min >> 3;
31+
return (minCalc >> 5) + minCalc + max - (max >> 4) - (max >> 6);
32+
}
33+
};
34+
35+
private Distances() {
36+
// Utility class
37+
}
38+
}

src/main/java/org/bk/ass/query/PositionAndId.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.bk.ass.query;
22

3+
import org.bk.ass.path.Position;
4+
35
import java.util.Objects;
46

57
/**
@@ -16,6 +18,10 @@ public PositionAndId(int id, int x, int y) {
1618
this.id = id;
1719
}
1820

21+
public Position toPosition() {
22+
return new Position(x, y);
23+
}
24+
1925
@Override
2026
public String toString() {
2127
return "id: " + id + " (" + x + ", " + y + ")";

0 commit comments

Comments
 (0)