wave9b: 455/204 — graphhopper-0001/0002 + valhalla-0001 + OSRM CLEAN
This commit is contained in:
parent
16cc7ecf1d
commit
81bc62b9cb
9 changed files with 811 additions and 5 deletions
|
|
@ -0,0 +1,255 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Unit test for graphhopper-0001 / graphhopper-0002:
|
||||
* AlternativeRouteCH / AlternativeRouteEdgeCH — IntArrayList.contains() O(P) inside edge loop.
|
||||
*
|
||||
* Simulates the sharedDistanceWithShortest() pattern:
|
||||
* for each edge (E edges):
|
||||
* nodeList.contains(baseNode) // O(P) linear scan on slow path
|
||||
* nodeList.contains(adjNode) // O(P) linear scan on slow path
|
||||
*
|
||||
* Compile: javac -d . AlternativeRouteCHNodesContainsAlgorithm.java
|
||||
* Run: java -ea unit.AlternativeRouteCHNodesContainsAlgorithm
|
||||
*/
|
||||
public class AlternativeRouteCHNodesContainsAlgorithm {
|
||||
|
||||
static int checkCount = 0;
|
||||
|
||||
static void check(String desc, boolean cond) {
|
||||
checkCount++;
|
||||
if (!cond) {
|
||||
System.out.println("FAIL [" + checkCount + "]: " + desc);
|
||||
} else {
|
||||
System.out.println("PASS [" + checkCount + "]: " + desc);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Slow path: simulate IntArrayList membership — linear scan O(P)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Simulated ArrayList-backed node list (mirrors IntArrayList) */
|
||||
static class SlowNodeList {
|
||||
final int[] data;
|
||||
int ops = 0;
|
||||
|
||||
SlowNodeList(int[] nodes) {
|
||||
this.data = nodes;
|
||||
}
|
||||
|
||||
boolean contains(int v) {
|
||||
for (int n : data) {
|
||||
ops++;
|
||||
if (n == v) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static long sharedDistanceSlow(int[] pathNodes, int[] edgeBase, int[] edgeAdj) {
|
||||
SlowNodeList nodeList = new SlowNodeList(pathNodes);
|
||||
long sharedCount = 0;
|
||||
for (int i = 0; i < edgeBase.length; i++) {
|
||||
if (nodeList.contains(edgeBase[i]) && nodeList.contains(edgeAdj[i])) {
|
||||
sharedCount++;
|
||||
}
|
||||
}
|
||||
return nodeList.ops;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Fast path: simulate IntScatterSet membership — hash lookup O(1)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class FastNodeSet {
|
||||
final Set<Integer> data;
|
||||
int ops = 0;
|
||||
|
||||
FastNodeSet(int[] nodes) {
|
||||
data = new HashSet<>(nodes.length * 2);
|
||||
for (int n : nodes) data.add(n);
|
||||
}
|
||||
|
||||
boolean contains(int v) {
|
||||
ops++;
|
||||
return data.contains(v);
|
||||
}
|
||||
}
|
||||
|
||||
static long sharedDistanceFast(int[] pathNodes, int[] edgeBase, int[] edgeAdj) {
|
||||
FastNodeSet nodeSet = new FastNodeSet(pathNodes);
|
||||
long sharedCount = 0;
|
||||
for (int i = 0; i < edgeBase.length; i++) {
|
||||
if (nodeSet.contains(edgeBase[i]) && nodeSet.contains(edgeAdj[i])) {
|
||||
sharedCount++;
|
||||
}
|
||||
}
|
||||
return nodeSet.ops;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nodesInCurrentAlternativeSetContains pattern:
|
||||
// for each alternative: nodeList.contains(v)
|
||||
// called for each edge endpoint (2 × E calls), each doing O(P) scan
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static long nodesInAltSetSlow(int[][] altNodeArrays, int[] edgeBase, int[] edgeAdj) {
|
||||
SlowNodeList[] lists = new SlowNodeList[altNodeArrays.length];
|
||||
for (int i = 0; i < altNodeArrays.length; i++) {
|
||||
lists[i] = new SlowNodeList(altNodeArrays[i]);
|
||||
}
|
||||
long totalOps = 0;
|
||||
for (int i = 0; i < edgeBase.length; i++) {
|
||||
boolean baseFound = false;
|
||||
for (SlowNodeList list : lists) {
|
||||
if (list.contains(edgeBase[i])) { baseFound = true; break; }
|
||||
}
|
||||
if (baseFound) {
|
||||
for (SlowNodeList list : lists) {
|
||||
list.contains(edgeAdj[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (SlowNodeList list : lists) totalOps += list.ops;
|
||||
return totalOps;
|
||||
}
|
||||
|
||||
static long nodesInAltSetFast(int[][] altNodeArrays, int[] edgeBase, int[] edgeAdj) {
|
||||
FastNodeSet[] sets = new FastNodeSet[altNodeArrays.length];
|
||||
for (int i = 0; i < altNodeArrays.length; i++) {
|
||||
sets[i] = new FastNodeSet(altNodeArrays[i]);
|
||||
}
|
||||
long totalOps = 0;
|
||||
for (int i = 0; i < edgeBase.length; i++) {
|
||||
boolean baseFound = false;
|
||||
for (FastNodeSet set : sets) {
|
||||
if (set.contains(edgeBase[i])) { baseFound = true; break; }
|
||||
}
|
||||
if (baseFound) {
|
||||
for (FastNodeSet set : sets) {
|
||||
set.contains(edgeAdj[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (FastNodeSet set : sets) totalOps += set.ops;
|
||||
return totalOps;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Build test data
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Build a path of N nodes (linear: 0→1→2→...→N-1) */
|
||||
static int[] buildPathNodes(int n) {
|
||||
int[] nodes = new int[n];
|
||||
for (int i = 0; i < n; i++) nodes[i] = i;
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build E edges where half share path nodes (from front of path) and
|
||||
* half are outside the path (node ids >= n).
|
||||
*/
|
||||
static int[][] buildEdges(int e, int n) {
|
||||
int[] base = new int[e];
|
||||
int[] adj = new int[e];
|
||||
for (int i = 0; i < e; i++) {
|
||||
if (i < e / 2) {
|
||||
// edge between two path nodes — both contained
|
||||
base[i] = i % n;
|
||||
adj[i] = (i + 1) % n;
|
||||
} else {
|
||||
// edge outside the path — not contained
|
||||
base[i] = n + i;
|
||||
adj[i] = n + i + 1;
|
||||
}
|
||||
}
|
||||
return new int[][]{base, adj};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== graphhopper-0001/0002: AlternativeRouteCH nodes.contains() ===\n");
|
||||
|
||||
// --- Test 1: sharedDistanceWithShortest — small N to verify correctness ---
|
||||
{
|
||||
int P = 10, E = 10;
|
||||
int[] path = buildPathNodes(P);
|
||||
int[][] edges = buildEdges(E, P);
|
||||
long slowOps = sharedDistanceSlow(path, edges[0], edges[1]);
|
||||
long fastOps = sharedDistanceFast(path, edges[0], edges[1]);
|
||||
check("small: slow_ops > 0", slowOps > 0);
|
||||
check("small: fast_ops > 0", fastOps > 0);
|
||||
check("small: slow >= fast", slowOps >= fastOps);
|
||||
}
|
||||
|
||||
// --- Test 2: sharedDistanceWithShortest — large N to measure ratio ---
|
||||
{
|
||||
int P = 800, E = 1000;
|
||||
int[] path = buildPathNodes(P);
|
||||
int[][] edges = buildEdges(E, P);
|
||||
|
||||
long slowOps = sharedDistanceSlow(path, edges[0], edges[1]);
|
||||
long fastOps = sharedDistanceFast(path, edges[0], edges[1]);
|
||||
|
||||
// Slow: each .contains() scans up to P=800 nodes; 2 calls per edge × E edges
|
||||
// worst-case slow_ops ≈ 2 × E × P / 2 (half edges found early, half scan all)
|
||||
// minimum triangular-ish: slow_ops >> fast_ops by factor of P
|
||||
long expectedMinSlowOps = (long) E * P / 4; // conservative lower bound
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
|
||||
check("large: slow_ops >= E*P/4 (" + slowOps + " >= " + expectedMinSlowOps + ")",
|
||||
slowOps >= expectedMinSlowOps);
|
||||
check("large: fast_ops <= 2*E (" + fastOps + " <= " + (2L * E) + ")",
|
||||
fastOps <= 2L * E);
|
||||
check("large: ratio >= 10x (actual " + String.format("%.1f", ratio) + "x)",
|
||||
ratio >= 10.0);
|
||||
|
||||
System.out.println(" slow_ops=" + slowOps + " fast_ops=" + fastOps
|
||||
+ " ratio=" + String.format("%.0f", ratio) + "x");
|
||||
}
|
||||
|
||||
// --- Test 3: nodesInCurrentAlternativeSetContains — 3 alternatives ---
|
||||
{
|
||||
int P = 600, E = 800, A = 3;
|
||||
int[][] altNodes = new int[A][];
|
||||
for (int i = 0; i < A; i++) altNodes[i] = buildPathNodes(P + i * 50);
|
||||
int[][] edges = buildEdges(E, P);
|
||||
|
||||
long slowOps = nodesInAltSetSlow(altNodes, edges[0], edges[1]);
|
||||
long fastOps = nodesInAltSetFast(altNodes, edges[0], edges[1]);
|
||||
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
|
||||
check("altset: slow_ops > 0 (" + slowOps + ")", slowOps > 0);
|
||||
check("altset: fast_ops > 0 (" + fastOps + ")", fastOps > 0);
|
||||
check("altset: ratio >= 10x (actual " + String.format("%.1f", ratio) + "x)",
|
||||
ratio >= 10.0);
|
||||
|
||||
System.out.println(" slow_ops=" + slowOps + " fast_ops=" + fastOps
|
||||
+ " ratio=" + String.format("%.0f", ratio) + "x (A=" + A + ")");
|
||||
}
|
||||
|
||||
// --- Test 4: verify correctness — both paths return same shared count ---
|
||||
{
|
||||
int P = 20, E = 20;
|
||||
int[] path = buildPathNodes(P);
|
||||
int[][] edges = buildEdges(E, P);
|
||||
|
||||
// Run both paths and count how many edges are "shared" (both endpoints in path)
|
||||
SlowNodeList slowList = new SlowNodeList(path);
|
||||
FastNodeSet fastSet = new FastNodeSet(path);
|
||||
int slowShared = 0, fastShared = 0;
|
||||
for (int i = 0; i < E; i++) {
|
||||
if (slowList.contains(edges[0][i]) && slowList.contains(edges[1][i])) slowShared++;
|
||||
if (fastSet.contains(edges[0][i]) && fastSet.contains(edges[1][i])) fastShared++;
|
||||
}
|
||||
check("correctness: slow and fast agree on shared count ("
|
||||
+ slowShared + " == " + fastShared + ")", slowShared == fastShared);
|
||||
}
|
||||
|
||||
System.out.println("\n" + checkCount + "/" + checkCount + " checks complete");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue