Repository: graphhopper/graphhopper
Pull request #2283 (2021-04-15 17:10:40)

AlgorithmOptions: Remove weighting and builder
AlgorithmOptions#weighting does not work very well, because the weighting can not be chosen arbitrarily for all algorithms (namely CH). The Builder seems rather unnecessary and makes AlgorithmOptions a lot more complicated than it probably needs to be. It is not even really immutable as it claims to be because of the PMap.

Actually I am still not satisfied and rather want to remove AlgorithmOptions and the RoutingAlgorithmFactory interface entirely, but I did not manage to do this yet. This PR is a step into this direction though. 


Patch:
diff --git a/core/src/main/java/com/graphhopper/routing/AlgorithmOptions.java b/core/src/main/java/com/graphhopper/routing/AlgorithmOptions.java
index 0e87f29cd..b208fadf4 100644
--- a/core/src/main/java/com/graphhopper/routing/AlgorithmOptions.java
+++ b/core/src/main/java/com/graphhopper/routing/AlgorithmOptions.java
@@ -18,91 +18,53 @@
 package com.graphhopper.routing;
 
 import com.graphhopper.routing.util.TraversalMode;
-import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.util.PMap;
 import com.graphhopper.util.Parameters;
 
 /**
- * The algorithm options. Create an immutable object via:
- * <pre>
- * AlgorithmOptions algoOpts = AlgorithmOptions.start().
- *        algorithm(Parameters.Algorithms.DIJKSTRA).
- *        weighting(weighting).
- *        build();
- * </pre>
- * <p>
- *
  * @author Peter Karich
  */
 public class AlgorithmOptions {
-    private final PMap hints = new PMap(5);
+    private PMap hints = new PMap();
     private String algorithm = Parameters.Algorithms.DIJKSTRA_BI;
-    private Weighting weighting;
     private TraversalMode traversalMode = TraversalMode.NODE_BASED;
     private int maxVisitedNodes = Integer.MAX_VALUE;
 
-    private AlgorithmOptions() {
+    public AlgorithmOptions() {
     }
 
-    /**
-     * Default traversal mode NODE_BASED is used.
-     */
-    public AlgorithmOptions(String algorithm, Weighting weighting) {
-        this.algorithm = algorithm;
-        this.weighting = weighting;
+    public AlgorithmOptions(AlgorithmOptions b) {
+        setAlgorithm(b.getAlgorithm());
+        setTraversalMode(b.getTraversalMode());
+        setMaxVisitedNodes(b.getMaxVisitedNodes());
+        setHints(b.getHints());
     }
 
-    public AlgorithmOptions(String algorithm, Weighting weighting, TraversalMode tMode) {
+    public AlgorithmOptions setAlgorithm(String algorithm) {
         this.algorithm = algorithm;
-        this.weighting = weighting;
-        this.traversalMode = tMode;
+        return this;
     }
 
-    /**
-     * This method starts the building process for AlgorithmOptions.
-     */
-    public static Builder start() {
-        return new Builder();
+    public AlgorithmOptions setTraversalMode(TraversalMode traversalMode) {
+        this.traversalMode = traversalMode;
+        return this;
     }
 
-    /**
-     * This method clones the specified AlgorithmOption object with the possibility for further
-     * changes.
-     */
-    public static Builder start(AlgorithmOptions opts) {
-        Builder b = new Builder();
-        if (opts.algorithm != null)
-            b.algorithm(opts.getAlgorithm());
-        if (opts.traversalMode != null)
-            b.traversalMode(opts.getTraversalMode());
-        if (opts.weighting != null)
-            b.weighting(opts.getWeighting());
-        if (opts.maxVisitedNodes >= 0)
-            b.maxVisitedNodes(opts.maxVisitedNodes);
-        if (!opts.hints.isEmpty())
-            b.hints(opts.hints);
+    public AlgorithmOptions setMaxVisitedNodes(int maxVisitedNodes) {
+        this.maxVisitedNodes = maxVisitedNodes;
+        return this;
+    }
 
-        return b;
+    public AlgorithmOptions setHints(PMap pMap) {
+        this.hints = new PMap(pMap);
+        return this;
     }
 
-    /**
-     * @return the traversal mode, where node-based is the default.
-     */
     public TraversalMode getTraversalMode() {
         return traversalMode;
     }
 
-    public boolean hasWeighting() {
-        return weighting != null;
-    }
-
-    public Weighting getWeighting() {
-        assertNotNull(weighting, "weighting");
-        return weighting;
-    }
-
     public String getAlgorithm() {
-        assertNotNull(algorithm, "algorithm");
         return algorithm;
     }
 
@@ -114,57 +76,9 @@ public class AlgorithmOptions {
         return hints;
     }
 
-    private void assertNotNull(Object optionValue, String optionName) {
-        if (optionValue == null)
-            throw new NullPointerException("Option '" + optionName + "' must NOT be null");
-    }
-
     @Override
     public String toString() {
-        return algorithm + ", " + weighting + ", " + traversalMode;
+        return algorithm + ", " + traversalMode;
     }
 
-    public static class Builder {
-        private AlgorithmOptions opts = new AlgorithmOptions();
-        private boolean buildCalled;
-
-        public Builder traversalMode(TraversalMode traversalMode) {
-            if (traversalMode == null)
-                throw new IllegalArgumentException("null as traversal mode is not allowed");
-
-            this.opts.traversalMode = traversalMode;
-            return this;
-        }
-
-        public Builder weighting(Weighting weighting) {
-            this.opts.weighting = weighting;
-            return this;
-        }
-
-        /**
-         * For possible values see {@link Parameters.Algorithms}
-         */
-        public Builder algorithm(String algorithm) {
-            this.opts.algorithm = algorithm;
-            return this;
-        }
-
-        public Builder maxVisitedNodes(int maxVisitedNodes) {
-            this.opts.maxVisitedNodes = maxVisitedNodes;
-            return this;
-        }
-
-        public Builder hints(PMap hints) {
-            this.opts.hints.putAll(hints);
-            return this;
-        }
-
-        public AlgorithmOptions build() {
-            if (buildCalled)
-                throw new IllegalStateException("Cannot call AlgorithmOptions.Builder.build() twice");
-
-            buildCalled = true;
-            return opts;
-        }
-    }
 }
diff --git a/core/src/main/java/com/graphhopper/routing/FlexiblePathCalculator.java b/core/src/main/java/com/graphhopper/routing/FlexiblePathCalculator.java
index 04f947021..fb5e47cb3 100644
--- a/core/src/main/java/com/graphhopper/routing/FlexiblePathCalculator.java
+++ b/core/src/main/java/com/graphhopper/routing/FlexiblePathCalculator.java
@@ -20,6 +20,7 @@ package com.graphhopper.routing;
 
 import com.carrotsearch.hppc.cursors.IntCursor;
 import com.graphhopper.routing.querygraph.QueryGraph;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.util.Parameters;
 import com.graphhopper.util.StopWatch;
 
@@ -31,13 +32,15 @@ import static com.graphhopper.util.EdgeIterator.ANY_EDGE;
 public class FlexiblePathCalculator implements PathCalculator {
     private final QueryGraph queryGraph;
     private final RoutingAlgorithmFactory algoFactory;
+    private Weighting weighting;
     private AlgorithmOptions algoOpts;
     private String debug;
     private int visitedNodes;
 
-    public FlexiblePathCalculator(QueryGraph queryGraph, RoutingAlgorithmFactory algoFactory, AlgorithmOptions algoOpts) {
+    public FlexiblePathCalculator(QueryGraph queryGraph, RoutingAlgorithmFactory algoFactory, Weighting weighting, AlgorithmOptions algoOpts) {
         this.queryGraph = queryGraph;
         this.algoFactory = algoFactory;
+        this.weighting = weighting;
         this.algoOpts = algoOpts;
     }
 
@@ -49,7 +52,7 @@ public class FlexiblePathCalculator implements PathCalculator {
 
     private RoutingAlgorithm createAlgo() {
         StopWatch sw = new StopWatch().start();
-        RoutingAlgorithm algo = algoFactory.createAlgo(queryGraph, algoOpts);
+        RoutingAlgorithm algo = algoFactory.createAlgo(queryGraph, weighting, algoOpts);
         debug = ", algoInit:" + (sw.stop().getNanos() / 1000) + " μs";
         return algo;
     }
@@ -97,11 +100,11 @@ public class FlexiblePathCalculator implements PathCalculator {
         return visitedNodes;
     }
 
-    public AlgorithmOptions getAlgoOpts() {
-        return algoOpts;
+    public Weighting getWeighting() {
+        return weighting;
     }
 
-    public void setAlgoOpts(AlgorithmOptions algoOpts) {
-        this.algoOpts = algoOpts;
+    public void setWeighting(Weighting weighting) {
+        this.weighting = weighting;
     }
 }
\ No newline at end of file
diff --git a/core/src/main/java/com/graphhopper/routing/RoundTripRouting.java b/core/src/main/java/com/graphhopper/routing/RoundTripRouting.java
index 7145213b8..c3ff95f4b 100644
--- a/core/src/main/java/com/graphhopper/routing/RoundTripRouting.java
+++ b/core/src/main/java/com/graphhopper/routing/RoundTripRouting.java
@@ -152,12 +152,10 @@ public class RoundTripRouting {
         RoundTripCalculator(FlexiblePathCalculator pathCalculator) {
             this.pathCalculator = pathCalculator;
             // we make the path calculator use our avoid edges weighting
-            AvoidEdgesWeighting avoidPreviousPathsWeighting = new AvoidEdgesWeighting(pathCalculator.getAlgoOpts().getWeighting())
+            AvoidEdgesWeighting avoidPreviousPathsWeighting = new AvoidEdgesWeighting(pathCalculator.getWeighting())
                     .setEdgePenaltyFactor(5);
             avoidPreviousPathsWeighting.setAvoidedEdges(previousEdges);
-            AlgorithmOptions algoOpts = AlgorithmOptions.start(pathCalculator.getAlgoOpts()).
-                    weighting(avoidPreviousPathsWeighting).build();
-            pathCalculator.setAlgoOpts(algoOpts);
+            pathCalculator.setWeighting(avoidPreviousPathsWeighting);
         }
 
         Path calcPath(int from, int to) {
diff --git a/core/src/main/java/com/graphhopper/routing/Router.java b/core/src/main/java/com/graphhopper/routing/Router.java
index 1e8a145f7..f90c373c4 100644
--- a/core/src/main/java/com/graphhopper/routing/Router.java
+++ b/core/src/main/java/com/graphhopper/routing/Router.java
@@ -121,13 +121,11 @@ public class Router {
             PMap requestHints = new PMap(request.getHints());
             requestHints.putObject(CustomModel.KEY, request.getCustomModel());
             Weighting weighting = createWeighting(profile, requestHints, request.getPoints(), disableCH);
-            AlgorithmOptions algoOpts = AlgorithmOptions.start().
-                    algorithm(request.getAlgorithm()).
-                    traversalMode(traversalMode).
-                    weighting(weighting).
-                    maxVisitedNodes(maxVisitedNodesForRequest).
-                    hints(request.getHints()).
-                    build();
+            AlgorithmOptions algoOpts = new AlgorithmOptions().
+                    setAlgorithm(request.getAlgorithm()).
+                    setTraversalMode(traversalMode).
+                    setMaxVisitedNodes(maxVisitedNodesForRequest).
+                    setHints(request.getHints());
 
             if (ROUND_TRIP.equalsIgnoreCase(request.getAlgorithm())) {
                 return routeRoundTrip(request, algoOpts, weighting, profile, disableLM);
@@ -158,13 +156,10 @@ public class Router {
         ghRsp.addDebugInfo("idLookup:" + sw.stop().getSeconds() + "s");
 
         // use A* for round trips
-        AlgorithmOptions roundTripAlgoOpts = AlgorithmOptions
-                .start(algoOpts)
-                .algorithm(Parameters.Algorithms.ASTAR_BI)
-                .build();
+        AlgorithmOptions roundTripAlgoOpts = new AlgorithmOptions(algoOpts).setAlgorithm(Parameters.Algorithms.ASTAR_BI);
         roundTripAlgoOpts.getHints().putObject(Parameters.Algorithms.AStarBi.EPSILON, 2);
         QueryGraph queryGraph = QueryGraph.create(ghStorage, qResults);
-        FlexiblePathCalculator pathCalculator = createFlexiblePathCalculator(queryGraph, profile, roundTripAlgoOpts, disableLM);
+        FlexiblePathCalculator pathCalculator = createFlexiblePathCalculator(queryGraph, profile, weighting, roundTripAlgoOpts, disableLM);
 
         RoundTripRouting.Result result = RoundTripRouting.calcPaths(qResults, pathCalculator);
         // we merge the different legs of the roundtrip into one response path
@@ -183,7 +178,7 @@ public class Router {
         List<Snap> qResults = ViaRouting.lookup(encodingManager, request.getPoints(), weighting, locationIndex, request.getSnapPreventions(), request.getPointHints());
         ghRsp.addDebugInfo("idLookup:" + sw.stop().getSeconds() + "s");
         QueryGraph queryGraph = QueryGraph.create(ghStorage, qResults);
-        PathCalculator pathCalculator = createPathCalculator(queryGraph, profile, algoOpts, disableCH, disableLM);
+        PathCalculator pathCalculator = createPathCalculator(queryGraph, profile, weighting, algoOpts, disableCH, disableLM);
 
         if (passThrough)
             throw new IllegalArgumentException("Alternative paths and " + PASS_THROUGH + " at the same time is currently not supported");
@@ -214,7 +209,7 @@ public class Router {
         // (base) query graph used to resolve headings, curbsides etc. this is not necessarily the same thing as
         // the (possibly implementation specific) query graph used by PathCalculator
         QueryGraph queryGraph = QueryGraph.create(ghStorage, qResults);
-        PathCalculator pathCalculator = createPathCalculator(queryGraph, profile, algoOpts, disableCH, disableLM);
+        PathCalculator pathCalculator = createPathCalculator(queryGraph, profile, weighting, algoOpts, disableCH, disableLM);
         ViaRouting.Result result = ViaRouting.calcPaths(request.getPoints(), queryGraph, qResults, weighting, pathCalculator, request.getCurbsides(), forceCurbsides, request.getHeadings(), passThrough);
 
         if (request.getPoints().size() != result.paths.size() + 1)
@@ -249,14 +244,14 @@ public class Router {
         }
     }
 
-    private PathCalculator createPathCalculator(QueryGraph queryGraph, Profile profile, AlgorithmOptions algoOpts, boolean disableCH, boolean disableLM) {
+    private PathCalculator createPathCalculator(QueryGraph queryGraph, Profile profile, Weighting weighting, AlgorithmOptions algoOpts, boolean disableCH, boolean disableLM) {
         if (chEnabled && !disableCH) {
             PMap opts = new PMap(algoOpts.getHints());
             opts.putObject(ALGORITHM, algoOpts.getAlgorithm());
             opts.putObject(MAX_VISITED_NODES, algoOpts.getMaxVisitedNodes());
             return createCHPathCalculator(queryGraph, profile, opts);
         } else {
-            return createFlexiblePathCalculator(queryGraph, profile, algoOpts, disableLM);
+            return createFlexiblePathCalculator(queryGraph, profile, weighting, algoOpts, disableLM);
         }
     }
 
@@ -264,7 +259,7 @@ public class Router {
         return new CHPathCalculator(new CHRoutingAlgorithmFactory(getRoutingCHGraph(profile.getName()), queryGraph), opts);
     }
 
-    private FlexiblePathCalculator createFlexiblePathCalculator(QueryGraph queryGraph, Profile profile, AlgorithmOptions algoOpts, boolean disableLM) {
+    private FlexiblePathCalculator createFlexiblePathCalculator(QueryGraph queryGraph, Profile profile, Weighting weighting, AlgorithmOptions algoOpts, boolean disableLM) {
         RoutingAlgorithmFactory algorithmFactory;
         // for now do not allow mixing CH&LM #1082,#1889
         if (lmEnabled && !disableLM) {
@@ -277,7 +272,7 @@ public class Router {
         } else {
             algorithmFactory = new RoutingAlgorithmFactorySimple();
         }
-        return new FlexiblePathCalculator(queryGraph, algorithmFactory, algoOpts);
+        return new FlexiblePathCalculator(queryGraph, algorithmFactory, weighting, algoOpts);
     }
 
     private RoutingCHGraph getRoutingCHGraph(String profileName) {
diff --git a/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactory.java b/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactory.java
index ad490d898..ef8a523ad 100644
--- a/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactory.java
+++ b/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactory.java
@@ -17,6 +17,7 @@
  */
 package com.graphhopper.routing;
 
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 
 /**
@@ -28,5 +29,5 @@ public interface RoutingAlgorithmFactory {
     /**
      * This method creates an algorithm out of this factory based on the specified opts and graph.
      */
-    RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts);
+    RoutingAlgorithm createAlgo(Graph g, Weighting w, AlgorithmOptions opts);
 }
diff --git a/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactorySimple.java b/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactorySimple.java
index 963503770..f6bd5185a 100644
--- a/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactorySimple.java
+++ b/core/src/main/java/com/graphhopper/routing/RoutingAlgorithmFactorySimple.java
@@ -38,10 +38,10 @@ import static com.graphhopper.util.Parameters.Algorithms.AltRoute.*;
  */
 public class RoutingAlgorithmFactorySimple implements RoutingAlgorithmFactory {
     @Override
-    public RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts) {
+    public RoutingAlgorithm createAlgo(Graph g, Weighting w, AlgorithmOptions opts) {
         RoutingAlgorithm ra;
         String algoStr = opts.getAlgorithm();
-        Weighting weighting = g.wrapWeighting(opts.getWeighting());
+        Weighting weighting = g.wrapWeighting(w);
         if (DIJKSTRA_BI.equalsIgnoreCase(algoStr)) {
             ra = new DijkstraBidirectionRef(g, weighting, opts.getTraversalMode());
         } else if (DIJKSTRA.equalsIgnoreCase(algoStr)) {
@@ -58,7 +58,7 @@ public class RoutingAlgorithmFactorySimple implements RoutingAlgorithmFactory {
 
         } else if (ASTAR.equalsIgnoreCase(algoStr)) {
             AStar aStar = new AStar(g, weighting, opts.getTraversalMode());
-            aStar.setApproximation(getApproximation(ASTAR, opts.getHints(), opts.getWeighting(), g.getNodeAccess()));
+            aStar.setApproximation(getApproximation(ASTAR, opts.getHints(), w, g.getNodeAccess()));
             ra = aStar;
 
         } else if (ALT_ROUTE.equalsIgnoreCase(algoStr)) {
diff --git a/core/src/main/java/com/graphhopper/routing/lm/LMRoutingAlgorithmFactory.java b/core/src/main/java/com/graphhopper/routing/lm/LMRoutingAlgorithmFactory.java
index da606fb50..11a3bc594 100644
--- a/core/src/main/java/com/graphhopper/routing/lm/LMRoutingAlgorithmFactory.java
+++ b/core/src/main/java/com/graphhopper/routing/lm/LMRoutingAlgorithmFactory.java
@@ -43,12 +43,12 @@ public class LMRoutingAlgorithmFactory implements RoutingAlgorithmFactory {
     }
 
     @Override
-    public RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts) {
+    public RoutingAlgorithm createAlgo(Graph g, Weighting w, AlgorithmOptions opts) {
         if (!lms.isInitialized())
             throw new IllegalStateException("Initialize landmark storage before creating algorithms");
         int activeLM = Math.max(1, opts.getHints().getInt(Parameters.Landmark.ACTIVE_COUNT, defaultActiveLandmarks));
         final String algoStr = opts.getAlgorithm();
-        final Weighting weighting = g.wrapWeighting(opts.getWeighting());
+        final Weighting weighting = g.wrapWeighting(w);
         if (ASTAR.equalsIgnoreCase(algoStr)) {
             double epsilon = opts.getHints().getDouble(Parameters.Algorithms.AStar.EPSILON, 1);
             AStar algo = new AStar(g, weighting, opts.getTraversalMode());
diff --git a/tools/src/main/java/com/graphhopper/ui/MiniGraphUI.java b/tools/src/main/java/com/graphhopper/ui/MiniGraphUI.java
index 1a8ffb9db..3e09738d8 100644
--- a/tools/src/main/java/com/graphhopper/ui/MiniGraphUI.java
+++ b/tools/src/main/java/com/graphhopper/ui/MiniGraphUI.java
@@ -346,24 +346,24 @@ public class MiniGraphUI {
         } else {
             Weighting weighting = hopper.createWeighting(profile, new PMap());
             final PrepareLandmarks preparation = hopper.getLMPreparationHandler().getPreparation(profile.getName());
-            RoutingAlgorithmFactory algoFactory = (g, opts) -> {
-                RoutingAlgorithm algo = preparation.getRoutingAlgorithmFactory().createAlgo(g, opts);
+            RoutingAlgorithmFactory algoFactory = (g, w, opts) -> {
+                RoutingAlgorithm algo = preparation.getRoutingAlgorithmFactory().createAlgo(g, w, opts);
                 if (algo instanceof AStarBidirection) {
-                    return new DebugAStarBi(g, opts.getWeighting(), opts.getTraversalMode(), mg).
+                    return new DebugAStarBi(g, w, opts.getTraversalMode(), mg).
                             setApproximation(((AStarBidirection) algo).getApproximation());
                 } else if (algo instanceof AStar) {
-                    return new DebugAStar(g, opts.getWeighting(), opts.getTraversalMode(), mg);
+                    return new DebugAStar(g, w, opts.getTraversalMode(), mg);
                 } else if (algo instanceof DijkstraBidirectionRef) {
-                    return new DebugDijkstraBidirection(g, opts.getWeighting(), opts.getTraversalMode(), mg);
+                    return new DebugDijkstraBidirection(g, w, opts.getTraversalMode(), mg);
                 } else if (algo instanceof Dijkstra) {
-                    return new DebugDijkstraSimple(g, opts.getWeighting(), opts.getTraversalMode(), mg);
+                    return new DebugDijkstraSimple(g, w, opts.getTraversalMode(), mg);
                 }
                 return algo;
             };
-            AlgorithmOptions algoOpts = new AlgorithmOptions(Algorithms.ASTAR_BI, weighting);
+            AlgorithmOptions algoOpts = new AlgorithmOptions().setAlgorithm(Algorithms.ASTAR_BI);
             logger.info("algoOpts:" + algoOpts + ", weighting: " + weighting);
             QueryGraph qGraph = QueryGraph.create(graph, fromRes, toRes);
-            return algoFactory.createAlgo(qGraph, algoOpts);
+            return algoFactory.createAlgo(qGraph, weighting, algoOpts);
         }
     }
 


Test patch:
diff --git a/core/src/main/java/com/graphhopper/routing/util/TestAlgoCollector.java b/core/src/main/java/com/graphhopper/routing/util/TestAlgoCollector.java
index a5520be6d..c98e06a1a 100644
--- a/core/src/main/java/com/graphhopper/routing/util/TestAlgoCollector.java
+++ b/core/src/main/java/com/graphhopper/routing/util/TestAlgoCollector.java
@@ -23,6 +23,7 @@ import com.graphhopper.routing.Path;
 import com.graphhopper.routing.RoutingAlgorithm;
 import com.graphhopper.routing.RoutingAlgorithmFactorySimple;
 import com.graphhopper.routing.querygraph.QueryGraph;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.storage.index.Snap;
@@ -62,7 +63,7 @@ public class TestAlgoCollector {
             altPaths.add(path);
         }
 
-        PathMerger pathMerger = new PathMerger(queryGraph.getBaseGraph(), algoEntry.getAlgorithmOptions().getWeighting()).
+        PathMerger pathMerger = new PathMerger(queryGraph.getBaseGraph(), algoEntry.getWeighting()).
                 setCalcPoints(true).
                 setSimplifyResponse(false).
                 setEnableInstructions(true);
@@ -137,26 +138,24 @@ public class TestAlgoCollector {
         private Graph graph;
         private boolean ch;
         private String expectedAlgo;
+        private Weighting weighting;
         private AlgorithmOptions opts;
 
-        public AlgoHelperEntry(Graph g, boolean ch, AlgorithmOptions opts, LocationIndex idx, String expectedAlgo) {
+        public AlgoHelperEntry(Graph g, boolean ch, Weighting weighting, AlgorithmOptions opts, LocationIndex idx, String expectedAlgo) {
             this.graph = g;
             this.ch = ch;
+            this.weighting = weighting;
             this.opts = opts;
             this.idx = idx;
             this.expectedAlgo = expectedAlgo;
         }
 
-        public void setAlgorithmOptions(AlgorithmOptions opts) {
-            this.opts = opts;
-        }
-
         public RoutingAlgorithm createAlgo(Graph graph) {
-            return new RoutingAlgorithmFactorySimple().createAlgo(graph, opts);
+            return new RoutingAlgorithmFactorySimple().createAlgo(graph, weighting, opts);
         }
 
-        public AlgorithmOptions getAlgorithmOptions() {
-            return opts;
+        public Weighting getWeighting() {
+            return weighting;
         }
 
         public LocationIndex getIdx() {
diff --git a/core/src/test/java/com/graphhopper/routing/DijkstraBidirectionCHTest.java b/core/src/test/java/com/graphhopper/routing/DijkstraBidirectionCHTest.java
index 543e0a94f..cfca931a6 100644
--- a/core/src/test/java/com/graphhopper/routing/DijkstraBidirectionCHTest.java
+++ b/core/src/test/java/com/graphhopper/routing/DijkstraBidirectionCHTest.java
@@ -67,7 +67,7 @@ public class DijkstraBidirectionCHTest {
         prepareCH(ghStorage, CHConfig.nodeBased(weighting.getName(), weighting));
 
         // use base graph for solving normal Dijkstra
-        Path p1 = new RoutingAlgorithmFactorySimple().createAlgo(ghStorage, AlgorithmOptions.start().weighting(weighting).build()).calcPath(0, 3);
+        Path p1 = new RoutingAlgorithmFactorySimple().createAlgo(ghStorage, weighting, new AlgorithmOptions()).calcPath(0, 3);
         assertEquals(IntArrayList.from(0, 1, 5, 2, 3), p1.calcNodes());
         assertEquals(p1.toString(), 402.29, p1.getDistance(), 1e-2);
         assertEquals(p1.toString(), 144823, p1.getTime());
@@ -78,13 +78,11 @@ public class DijkstraBidirectionCHTest {
         EncodingManager em = EncodingManager.create("foot,car");
         FlagEncoder footEncoder = em.getEncoder("foot");
         FlagEncoder carEncoder = em.getEncoder("car");
-        AlgorithmOptions footOptions = AlgorithmOptions.start().
-                weighting(new FastestWeighting(footEncoder)).build();
-        AlgorithmOptions carOptions = AlgorithmOptions.start().
-                weighting(new FastestWeighting(carEncoder)).build();
+        FastestWeighting footWeighting = new FastestWeighting(footEncoder);
+        FastestWeighting carWeighting = new FastestWeighting(carEncoder);
 
-        CHConfig footConfig = CHConfig.nodeBased("p_foot", footOptions.getWeighting());
-        CHConfig carConfig = CHConfig.nodeBased("p_car", carOptions.getWeighting());
+        CHConfig footConfig = CHConfig.nodeBased("p_foot", footWeighting);
+        CHConfig carConfig = CHConfig.nodeBased("p_car", carWeighting);
         GraphHopperStorage g = new GraphBuilder(em).setCHConfigs(footConfig, carConfig).create();
         RoutingAlgorithmTest.initFootVsCar(carEncoder, footEncoder, g);
 
@@ -98,13 +96,13 @@ public class DijkstraBidirectionCHTest {
         assertEquals(p1.toString(), 15000, p1.getDistance(), 1e-6);
 
         // use base graph for solving normal Dijkstra via car
-        Path p2 = new RoutingAlgorithmFactorySimple().createAlgo(g, carOptions).calcPath(0, 7);
+        Path p2 = new RoutingAlgorithmFactorySimple().createAlgo(g, carWeighting, new AlgorithmOptions()).calcPath(0, 7);
         assertEquals(IntArrayList.from(0, 4, 6, 7), p2.calcNodes());
         assertEquals(p2.toString(), 15000, p2.getDistance(), 1e-6);
         assertEquals(p2.toString(), 2700 * 1000, p2.getTime());
 
         // use base graph for solving normal Dijkstra via foot
-        Path p4 = new RoutingAlgorithmFactorySimple().createAlgo(g, footOptions).calcPath(0, 7);
+        Path p4 = new RoutingAlgorithmFactorySimple().createAlgo(g, footWeighting, new AlgorithmOptions()).calcPath(0, 7);
         assertEquals(p4.toString(), 17000, p4.getDistance(), 1e-6);
         assertEquals(p4.toString(), 12240 * 1000, p4.getTime());
         assertEquals(IntArrayList.from(0, 4, 5, 7), p4.calcNodes());
diff --git a/core/src/test/java/com/graphhopper/routing/DirectedRoutingTest.java b/core/src/test/java/com/graphhopper/routing/DirectedRoutingTest.java
index 99ec1dd4b..597f87e99 100644
--- a/core/src/test/java/com/graphhopper/routing/DirectedRoutingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/DirectedRoutingTest.java
@@ -173,7 +173,7 @@ public class DirectedRoutingTest {
                 return algoFactory.createAlgo(new PMap().putObject(ALGORITHM, ASTAR_BI));
             }
             case LM:
-                return (BidirRoutingAlgorithm) lm.getRoutingAlgorithmFactory().createAlgo(graph, AlgorithmOptions.start().weighting(weighting).algorithm(ASTAR_BI).traversalMode(TraversalMode.EDGE_BASED).build());
+                return (BidirRoutingAlgorithm) lm.getRoutingAlgorithmFactory().createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR_BI).setTraversalMode(TraversalMode.EDGE_BASED));
             default:
                 throw new IllegalArgumentException("unknown algo " + algo);
         }
diff --git a/core/src/test/java/com/graphhopper/routing/EdgeBasedRoutingAlgorithmTest.java b/core/src/test/java/com/graphhopper/routing/EdgeBasedRoutingAlgorithmTest.java
index 79665253a..7188723fe 100644
--- a/core/src/test/java/com/graphhopper/routing/EdgeBasedRoutingAlgorithmTest.java
+++ b/core/src/test/java/com/graphhopper/routing/EdgeBasedRoutingAlgorithmTest.java
@@ -103,12 +103,10 @@ public class EdgeBasedRoutingAlgorithmTest {
     }
 
     public RoutingAlgorithm createAlgo(Graph g, Weighting weighting, TraversalMode traversalMode) {
-        return createAlgo(g, AlgorithmOptions.start().weighting(weighting).traversalMode(traversalMode).build());
-    }
-
-    public RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts) {
-        opts = AlgorithmOptions.start(opts).algorithm(algoStr).build();
-        return new RoutingAlgorithmFactorySimple().createAlgo(g, opts);
+        AlgorithmOptions opts = new AlgorithmOptions()
+                .setTraversalMode(traversalMode)
+                .setAlgorithm(algoStr);
+        return new RoutingAlgorithmFactorySimple().createAlgo(g, weighting, opts);
     }
 
     private GraphHopperStorage createStorage(EncodingManager em) {
diff --git a/core/src/test/java/com/graphhopper/routing/RandomizedRoutingTest.java b/core/src/test/java/com/graphhopper/routing/RandomizedRoutingTest.java
index 824e4b0c6..4283278c6 100644
--- a/core/src/test/java/com/graphhopper/routing/RandomizedRoutingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/RandomizedRoutingTest.java
@@ -184,9 +184,9 @@ public class RandomizedRoutingTest {
                 return algoFactory.createAlgo(new PMap().putObject(ALGORITHM, ASTAR_BI));
             }
             case LM_BIDIR:
-                return lm.getRoutingAlgorithmFactory().createAlgo(graph, AlgorithmOptions.start().weighting(weighting).algorithm(ASTAR_BI).traversalMode(traversalMode).build());
+                return lm.getRoutingAlgorithmFactory().createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR_BI).setTraversalMode(traversalMode));
             case LM_UNIDIR:
-                return lm.getRoutingAlgorithmFactory().createAlgo(graph, AlgorithmOptions.start().weighting(weighting).algorithm(ASTAR).traversalMode(traversalMode).build());
+                return lm.getRoutingAlgorithmFactory().createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR).setTraversalMode(traversalMode));
             case PERFECT_ASTAR: {
                 AStarBidirection perfectAStarBi = new AStarBidirection(graph, weighting, traversalMode);
                 perfectAStarBi.setApproximation(new PerfectApproximator(graph, weighting, traversalMode, false));
diff --git a/core/src/test/java/com/graphhopper/routing/RoundTripRoutingTest.java b/core/src/test/java/com/graphhopper/routing/RoundTripRoutingTest.java
index a10e69574..dbbbd1516 100644
--- a/core/src/test/java/com/graphhopper/routing/RoundTripRoutingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/RoundTripRoutingTest.java
@@ -82,7 +82,7 @@ public class RoundTripRoutingTest {
 
         QueryGraph queryGraph = QueryGraph.create(g, stagePoints);
         List<Path> paths = RoundTripRouting.calcPaths(stagePoints, new FlexiblePathCalculator(queryGraph,
-                new RoutingAlgorithmFactorySimple(), new AlgorithmOptions(DIJKSTRA_BI, fastestWeighting, tMode))).paths;
+                new RoutingAlgorithmFactorySimple(), fastestWeighting, new AlgorithmOptions().setAlgorithm(DIJKSTRA_BI).setTraversalMode(tMode))).paths;
         // make sure the resulting paths are connected and form a round trip starting and ending at the start node 0
         assertEquals(2, paths.size());
         assertEquals(IntArrayList.from(0, 7, 6, 5), paths.get(0).calcNodes());
@@ -104,7 +104,7 @@ public class RoundTripRoutingTest {
         QueryGraph qGraph = QueryGraph.create(g, Arrays.asList(snap4, snap5));
 
         FlexiblePathCalculator pathCalculator = new FlexiblePathCalculator(
-                qGraph, new RoutingAlgorithmFactorySimple(), new AlgorithmOptions(DIJKSTRA_BI, fastestWeighting, tMode));
+                qGraph, new RoutingAlgorithmFactorySimple(), fastestWeighting, new AlgorithmOptions().setAlgorithm(DIJKSTRA_BI).setTraversalMode(tMode));
         List<Path> paths = RoundTripRouting.calcPaths(Arrays.asList(snap5, snap4, snap5), pathCalculator).paths;
         assertEquals(2, paths.size());
         assertEquals(IntArrayList.from(5, 6, 3), paths.get(0).calcNodes());
@@ -112,7 +112,7 @@ public class RoundTripRoutingTest {
 
         qGraph = QueryGraph.create(g, Arrays.asList(snap4, snap6));
         pathCalculator = new FlexiblePathCalculator(
-                qGraph, new RoutingAlgorithmFactorySimple(), new AlgorithmOptions(DIJKSTRA_BI, fastestWeighting, tMode));
+                qGraph, new RoutingAlgorithmFactorySimple(), fastestWeighting, new AlgorithmOptions().setAlgorithm(DIJKSTRA_BI).setTraversalMode(tMode));
         paths = RoundTripRouting.calcPaths(Arrays.asList(snap6, snap4, snap6), pathCalculator).paths;
         assertEquals(2, paths.size());
         assertEquals(IntArrayList.from(6, 3), paths.get(0).calcNodes());
diff --git a/core/src/test/java/com/graphhopper/routing/lm/LMIssueTest.java b/core/src/test/java/com/graphhopper/routing/lm/LMIssueTest.java
index 7cf97263a..acb4671cb 100644
--- a/core/src/test/java/com/graphhopper/routing/lm/LMIssueTest.java
+++ b/core/src/test/java/com/graphhopper/routing/lm/LMIssueTest.java
@@ -79,9 +79,9 @@ public class LMIssueTest {
             case ASTAR_BIDIR:
                 return new AStarBidirection(graph, weighting, NODE_BASED);
             case LM_BIDIR:
-                return lm.getRoutingAlgorithmFactory().createAlgo(graph, AlgorithmOptions.start().weighting(weighting).algorithm(ASTAR_BI).traversalMode(NODE_BASED).build());
+                return lm.getRoutingAlgorithmFactory().createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR_BI).setTraversalMode(NODE_BASED));
             case LM_UNIDIR:
-                return lm.getRoutingAlgorithmFactory().createAlgo(graph, AlgorithmOptions.start().weighting(weighting).algorithm(ASTAR).traversalMode(NODE_BASED).build());
+                return lm.getRoutingAlgorithmFactory().createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR).setTraversalMode(NODE_BASED));
             case PERFECT_ASTAR:
                 AStarBidirection perfectastarbi = new AStarBidirection(graph, weighting, NODE_BASED);
                 perfectastarbi.setApproximation(new PerfectApproximator(graph, weighting, NODE_BASED, false));
diff --git a/core/src/test/java/com/graphhopper/routing/lm/PrepareLandmarksTest.java b/core/src/test/java/com/graphhopper/routing/lm/PrepareLandmarksTest.java
index 6eb523a8f..e9a1e18c9 100644
--- a/core/src/test/java/com/graphhopper/routing/lm/PrepareLandmarksTest.java
+++ b/core/src/test/java/com/graphhopper/routing/lm/PrepareLandmarksTest.java
@@ -30,7 +30,6 @@ import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Directory;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.storage.RAMDirectory;
-import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.storage.index.LocationIndexTree;
 import com.graphhopper.storage.index.Snap;
 import com.graphhopper.util.GHUtility;
@@ -151,8 +150,8 @@ public class PrepareLandmarksTest {
         PMap hints = new PMap().putObject(Parameters.Landmark.ACTIVE_COUNT, 2);
 
         // landmarks with A*
-        RoutingAlgorithm oneDirAlgoWithLandmarks = prepare.getRoutingAlgorithmFactory().createAlgo(graph,
-                AlgorithmOptions.start().algorithm(ASTAR).weighting(weighting).traversalMode(tm).hints(hints).build());
+        RoutingAlgorithm oneDirAlgoWithLandmarks = prepare.getRoutingAlgorithmFactory().createAlgo(graph, weighting,
+                new AlgorithmOptions().setAlgorithm(ASTAR).setTraversalMode(tm).setHints(hints));
 
         Path path = oneDirAlgoWithLandmarks.calcPath(41, 183);
 
@@ -161,8 +160,8 @@ public class PrepareLandmarksTest {
         assertEquals(expectedAlgo.getVisitedNodes() - 135, oneDirAlgoWithLandmarks.getVisitedNodes());
 
         // landmarks with bidir A*
-        RoutingAlgorithm biDirAlgoWithLandmarks = prepare.getRoutingAlgorithmFactory().createAlgo(graph,
-                AlgorithmOptions.start().algorithm(ASTAR_BI).weighting(weighting).traversalMode(tm).hints(hints).build());
+        RoutingAlgorithm biDirAlgoWithLandmarks = prepare.getRoutingAlgorithmFactory().createAlgo(graph, weighting,
+                new AlgorithmOptions().setAlgorithm(ASTAR_BI).setTraversalMode(tm).setHints(hints));
         path = biDirAlgoWithLandmarks.calcPath(41, 183);
         assertEquals(expectedPath.getWeight(), path.getWeight(), .1);
         assertEquals(expectedPath.calcNodes(), path.calcNodes());
@@ -173,8 +172,8 @@ public class PrepareLandmarksTest {
         Snap fromSnap = index.findClosest(-0.0401, 0.2201, EdgeFilter.ALL_EDGES);
         Snap toSnap = index.findClosest(-0.2401, 0.0601, EdgeFilter.ALL_EDGES);
         QueryGraph qGraph = QueryGraph.create(graph, fromSnap, toSnap);
-        RoutingAlgorithm qGraphOneDirAlgo = prepare.getRoutingAlgorithmFactory().createAlgo(qGraph,
-                AlgorithmOptions.start().algorithm(ASTAR).weighting(weighting).traversalMode(tm).hints(hints).build());
+        RoutingAlgorithm qGraphOneDirAlgo = prepare.getRoutingAlgorithmFactory().createAlgo(qGraph, weighting,
+                new AlgorithmOptions().setAlgorithm(ASTAR).setTraversalMode(tm).setHints(hints));
         path = qGraphOneDirAlgo.calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
 
         expectedAlgo = new AStar(qGraph, weighting, tm);
diff --git a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java
index 5ee3a1319..dc540eda3 100644
--- a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java
@@ -77,26 +77,26 @@ public class RoutingAlgorithmWithOSMTest {
                 .putObject("vehicle", profile.getVehicle())
                 .putObject("weighting", profile.getWeighting());
 
-        AlgorithmOptions defaultOpts = AlgorithmOptions.start(new AlgorithmOptions("", weighting, tMode)).hints(defaultHints).build();
+        AlgorithmOptions defaultOpts = new AlgorithmOptions().setAlgorithm("").setTraversalMode(tMode).setHints(defaultHints);
         List<AlgoHelperEntry> algos = new ArrayList<>();
-        algos.add(new AlgoHelperEntry(ghStorage, false, AlgorithmOptions.start(defaultOpts).algorithm(ASTAR).build(), idx, "astar|beeline|" + addStr + weighting));
+        algos.add(new AlgoHelperEntry(ghStorage, false, weighting, new AlgorithmOptions(defaultOpts).setAlgorithm(ASTAR), idx, "astar|beeline|" + addStr + weighting));
         // later: include dijkstraOneToMany
-        algos.add(new AlgoHelperEntry(ghStorage, false, AlgorithmOptions.start(defaultOpts).algorithm(DIJKSTRA).build(), idx, "dijkstra|" + addStr + weighting));
+        algos.add(new AlgoHelperEntry(ghStorage, false, weighting, new AlgorithmOptions(defaultOpts).setAlgorithm(DIJKSTRA), idx, "dijkstra|" + addStr + weighting));
 
-        AlgorithmOptions astarbiOpts = AlgorithmOptions.start(defaultOpts).algorithm(ASTAR_BI).build();
+        AlgorithmOptions astarbiOpts = new AlgorithmOptions(defaultOpts).setAlgorithm(ASTAR_BI);
         astarbiOpts.getHints().putObject(ASTAR_BI + ".approximation", "BeelineSimplification");
-        AlgorithmOptions dijkstrabiOpts = AlgorithmOptions.start(defaultOpts).algorithm(DIJKSTRA_BI).build();
-        algos.add(new AlgoHelperEntry(ghStorage, false, astarbiOpts, idx, "astarbi|beeline|" + addStr + weighting));
-        algos.add(new AlgoHelperEntry(ghStorage, false, dijkstrabiOpts, idx, "dijkstrabi|" + addStr + weighting));
+        AlgorithmOptions dijkstrabiOpts = new AlgorithmOptions(defaultOpts).setAlgorithm(DIJKSTRA_BI);
+        algos.add(new AlgoHelperEntry(ghStorage, false, weighting, astarbiOpts, idx, "astarbi|beeline|" + addStr + weighting));
+        algos.add(new AlgoHelperEntry(ghStorage, false, weighting, dijkstrabiOpts, idx, "dijkstrabi|" + addStr + weighting));
 
         // add additional preparations if CH and LM preparation are enabled
         if (hopper.getLMPreparationHandler().isEnabled()) {
             final PMap lmHints = new PMap(defaultHints).putObject(Parameters.Landmark.DISABLE, false);
-            final AlgorithmOptions opts = AlgorithmOptions.start(astarbiOpts).hints(lmHints).build();
-            algos.add(new AlgoHelperEntry(ghStorage, false, opts, idx, "astarbi|landmarks|" + weighting) {
+            final AlgorithmOptions opts = new AlgorithmOptions(astarbiOpts).setHints(lmHints);
+            algos.add(new AlgoHelperEntry(ghStorage, false, weighting, opts, idx, "astarbi|landmarks|" + weighting) {
                 @Override
                 public RoutingAlgorithm createAlgo(Graph graph) {
-                    return hopper.getLMPreparationHandler().getPreparation(profile.getName()).getRoutingAlgorithmFactory().createAlgo(graph, opts);
+                    return hopper.getLMPreparationHandler().getPreparation(profile.getName()).getRoutingAlgorithmFactory().createAlgo(graph, weighting, opts);
                 }
             });
         }
@@ -105,8 +105,8 @@ public class RoutingAlgorithmWithOSMTest {
             final PMap chHints = new PMap(defaultHints);
             chHints.putObject(Parameters.CH.DISABLE, false);
             chHints.putObject(Parameters.Routing.EDGE_BASED, tMode.isEdgeBased());
-            final AlgorithmOptions dijkstraOpts = AlgorithmOptions.start(dijkstrabiOpts).hints(chHints).build();
-            algos.add(new AlgoHelperEntry(ghStorage, true, dijkstraOpts, idx, "dijkstrabi|ch|prepare|" + profile.getWeighting()) {
+            final AlgorithmOptions dijkstraOpts = new AlgorithmOptions(dijkstrabiOpts).setHints(chHints);
+            algos.add(new AlgoHelperEntry(ghStorage, true, weighting, dijkstraOpts, idx, "dijkstrabi|ch|prepare|" + profile.getWeighting()) {
                 @Override
                 public RoutingAlgorithm createAlgo(Graph g) {
                     PrepareContractionHierarchies pch = hopper.getCHPreparationHandler().getPreparation(profile.getName());
@@ -117,8 +117,8 @@ public class RoutingAlgorithmWithOSMTest {
                 }
             });
 
-            final AlgorithmOptions astarOpts = AlgorithmOptions.start(astarbiOpts).hints(chHints).build();
-            algos.add(new AlgoHelperEntry(ghStorage, true, astarOpts, idx, "astarbi|ch|prepare|" + profile.getWeighting()) {
+            final AlgorithmOptions astarOpts = new AlgorithmOptions(astarbiOpts).setHints(chHints);
+            algos.add(new AlgoHelperEntry(ghStorage, true, weighting, astarOpts, idx, "astarbi|ch|prepare|" + profile.getWeighting()) {
                 public RoutingAlgorithm createAlgo(Graph g) {
                     PrepareContractionHierarchies pch = hopper.getCHPreparationHandler().getPreparation(profile.getName());
                     RoutingCHGraph routingCHGraph = ghStorage.getRoutingCHGraph(pch.getCHConfig().getName());
@@ -735,8 +735,8 @@ public class RoutingAlgorithmWithOSMTest {
                         @Override
                         public void run() {
                             OneRun oneRun = instances.get(instanceIndex);
-                            AlgorithmOptions opts = AlgorithmOptions.start().weighting(weighting).algorithm(algoStr).build();
-                            testCollector.assertDistance(encodingManager, new AlgoHelperEntry(g, false, opts, idx, algoStr + "|" + weighting),
+                            AlgorithmOptions opts = new AlgorithmOptions().setAlgorithm(algoStr);
+                            testCollector.assertDistance(encodingManager, new AlgoHelperEntry(g, false, weighting, opts, idx, algoStr + "|" + weighting),
                                     oneRun.getList(idx, filter), oneRun);
                             integ.addAndGet(1);
                         }