/* * Licensed to GraphHopper GmbH under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * GraphHopper GmbH licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.graphhopper.routing.lm; import com.graphhopper.routing.*; import com.graphhopper.routing.util.*; import com.graphhopper.routing.weighting.FastestWeighting; import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.storage.*; import com.graphhopper.storage.index.LocationIndex; import com.graphhopper.storage.index.LocationIndexTree; import com.graphhopper.storage.index.QueryResult; import com.graphhopper.util.Helper; import java.io.File; import org.junit.Before; import org.junit.Test; import java.util.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Karich */ public class PrepareLandmarksTest /* extends AbstractRoutingAlgorithmTester */ { private GraphHopperStorage graph; private FlagEncoder encoder; private TraversalMode tm; @Before public void setUp() { encoder = new CarFlagEncoder(); tm = TraversalMode.NODE_BASED; GraphHopperStorage tmp = new GraphHopperStorage(new RAMDirectory(), new EncodingManager(encoder), false, new GraphExtension.NoOpExtension()); tmp.create(1000); graph = tmp; } @Test public void testLandmarkStorageAndRouting() { // create graph with lat,lon // 0 1 2 ... // 15 16 17 ... Random rand = new Random(0); int width = 15, height = 15; for (int hIndex = 0; hIndex < height; hIndex++) { for (int wIndex = 0; wIndex < width; wIndex++) { int node = wIndex + hIndex * width; long flags = encoder.setProperties(20 + rand.nextDouble() * 30, true, true); // do not connect first with last column! if (wIndex + 1 < width) graph.edge(node, node + 1).setFlags(flags); // avoid dead ends if (hIndex + 1 < height) graph.edge(node, node + width).setFlags(flags); AbstractRoutingAlgorithmTester.updateDistancesFor(graph, node, -hIndex / 50.0, wIndex / 50.0); } } Directory dir = new RAMDirectory(); LocationIndex index = new LocationIndexTree(graph, dir); index.prepareIndex(); int lm = 5, activeLM = 2; Weighting weighting = new FastestWeighting(encoder); LandmarkStorage store = new LandmarkStorage(graph, dir, lm, weighting, tm); store.setMinimumNodes(2); store.createLandmarks(); // landmarks should be the 4 corners of the grid: int[] intList = store.getLandmarks(1); Arrays.sort(intList); assertEquals("[0, 14, 70, 182, 224]", Arrays.toString(intList)); // two landmarks: one for subnetwork 0 (all empty) and one for subnetwork 1 assertEquals(2, store.getSubnetworksWithLandmarks()); assertEquals(0, store.getFromWeight(0, 224)); double factor = store.getFactor(); assertEquals(4671, Math.round(store.getFromWeight(0, 47) * factor)); assertEquals(3640, Math.round(store.getFromWeight(0, 52) * factor)); long weight1_224 = store.getFromWeight(1, 224); assertEquals(5525, Math.round(weight1_224 * factor)); long weight1_47 = store.getFromWeight(1, 47); assertEquals(921, Math.round(weight1_47 * factor)); // grid is symmetric assertEquals(weight1_224, store.getToWeight(1, 224)); assertEquals(weight1_47, store.getToWeight(1, 47)); // prefer the landmarks before and behind the goal int activeLandmarkIndices[] = new int[activeLM]; int activeFroms[] = new int[activeLM]; int activeTos[] = new int[activeLM]; Arrays.fill(activeLandmarkIndices, -1); store.initActiveLandmarks(27, 47, activeLandmarkIndices, activeFroms, activeTos, false); List<Integer> list = new ArrayList<>(); for (int idx : activeLandmarkIndices) { list.add(store.getLandmarks(1)[idx]); } // TODO should better select 0 and 224? assertEquals(Arrays.asList(224, 70), list); AlgorithmOptions opts = AlgorithmOptions.start().weighting(weighting).traversalMode(tm). build(); PrepareLandmarks prepare = new PrepareLandmarks(new RAMDirectory(), graph, weighting, tm, 4, 2); prepare.setMinimumNodes(2); prepare.doWork(); AStar expectedAlgo = new AStar(graph, weighting, tm); Path expectedPath = expectedAlgo.calcPath(41, 183); // landmarks with A* RoutingAlgorithm oneDirAlgoWithLandmarks = prepare.getDecoratedAlgorithm(graph, new AStar(graph, weighting, tm), opts); Path path = oneDirAlgoWithLandmarks.calcPath(41, 183); assertEquals(expectedPath.getWeight(), path.getWeight(), .1); assertEquals(expectedPath.calcNodes(), path.calcNodes()); assertEquals(expectedAlgo.getVisitedNodes(), oneDirAlgoWithLandmarks.getVisitedNodes() + 142); // landmarks with bidir A* opts.getHints().put("lm.recalc_count", 50); RoutingAlgorithm biDirAlgoWithLandmarks = prepare.getDecoratedAlgorithm(graph, new AStarBidirection(graph, weighting, tm), opts); path = biDirAlgoWithLandmarks.calcPath(41, 183); assertEquals(expectedPath.getWeight(), path.getWeight(), .1); assertEquals(expectedPath.calcNodes(), path.calcNodes()); assertEquals(expectedAlgo.getVisitedNodes(), biDirAlgoWithLandmarks.getVisitedNodes() + 164); // landmarks with A* and a QueryGraph. We expect slightly less optimal as two more cycles needs to be traversed // due to the two more virtual nodes but this should not harm in practise QueryGraph qGraph = new QueryGraph(graph); QueryResult fromQR = index.findClosest(-0.0401, 0.2201, EdgeFilter.ALL_EDGES); QueryResult toQR = index.findClosest(-0.2401, 0.0601, EdgeFilter.ALL_EDGES); qGraph.lookup(fromQR, toQR); RoutingAlgorithm qGraphOneDirAlgo = prepare.getDecoratedAlgorithm(qGraph, new AStar(qGraph, weighting, tm), opts); path = qGraphOneDirAlgo.calcPath(fromQR.getClosestNode(), toQR.getClosestNode()); expectedAlgo = new AStar(qGraph, weighting, tm); expectedPath = expectedAlgo.calcPath(fromQR.getClosestNode(), toQR.getClosestNode()); assertEquals(expectedPath.getWeight(), path.getWeight(), .1); assertEquals(expectedPath.calcNodes(), path.calcNodes()); assertEquals(expectedAlgo.getVisitedNodes(), qGraphOneDirAlgo.getVisitedNodes() + 133); } @Test public void testStoreAndLoad() { graph.edge(0, 1, 80_000, true); graph.edge(1, 2, 80_000, true); String fileStr = "./target/tmp-lm"; Helper.removeDir(new File(fileStr)); Directory dir = new RAMDirectory(fileStr, true).create(); Weighting weighting = new FastestWeighting(encoder); PrepareLandmarks plm = new PrepareLandmarks(dir, graph, weighting, tm, 2, 2); plm.setMinimumNodes(2); plm.doWork(); double expectedFactor = plm.getLandmarkStorage().getFactor(); assertTrue(plm.getLandmarkStorage().isInitialized()); assertEquals(Arrays.toString(new int[]{ 2, 0 }), Arrays.toString(plm.getLandmarkStorage().getLandmarks(1))); assertEquals(4791, Math.round(plm.getLandmarkStorage().getFromWeight(0, 1) * expectedFactor)); dir = new RAMDirectory(fileStr, true); plm = new PrepareLandmarks(dir, graph, weighting, tm, 2, 2); assertTrue(plm.loadExisting()); assertEquals(expectedFactor, plm.getLandmarkStorage().getFactor(), 1e-6); assertEquals(Arrays.toString(new int[]{ 2, 0 }), Arrays.toString(plm.getLandmarkStorage().getLandmarks(1))); assertEquals(4791, Math.round(plm.getLandmarkStorage().getFromWeight(0, 1) * expectedFactor)); Helper.removeDir(new File(fileStr)); } }