@Override
  public RoutingAlgorithm createAlgo() {
    checkGraph();
    // do not change weight within DijkstraBidirectionRef => so use ShortestWeighting
    DijkstraBidirectionRef dijkstrabi =
        new DijkstraBidirectionRef(g, prepareEncoder, shortestWeighting) {
          @Override
          protected void initCollections(int nodes) {
            // algorithm with CH does not need that much memory pre allocated
            super.initCollections(Math.min(initialCollectionSize, nodes));
          }

          @Override
          protected QueryGraph createQueryGraph() {
            return new QueryGraph(graph) {
              @Override
              protected void updateDistance(EdgeIteratorState edge) {
                edge.setDistance(prepareWeighting.calcWeight(edge));
              }
            };
          }

          @Override
          public boolean finished() {
            // we need to finish BOTH searches for CH!
            if (finishedFrom && finishedTo) return true;

            // changed also the final finish condition for CH
            return currFrom.weight >= bestPath.getWeight() && currTo.weight >= bestPath.getWeight();
          }

          @Override
          public void initPath() {
            // CH changes the weight in prepareEdges to the weight
            // now we need to transform it back to the real weight
            Weighting w = createWeighting();
            bestPath = new Path4CH(graph, flagEncoder, w);
          }

          @Override
          public String getName() {
            return "dijkstrabiCH";
          }

          @Override
          public String toString() {
            return getName() + "|" + prepareWeighting;
          }
        };

    if (!removesHigher2LowerEdges) dijkstrabi.setEdgeFilter(new LevelEdgeFilter(g));

    return dijkstrabi;
  }
  public AStarBidirection createAStar() {
    checkGraph();
    AStarBidirection astar =
        new AStarBidirection(g, prepareEncoder, shortestWeighting) {
          @Override
          protected void initCollections(int nodes) {
            // algorithm with CH does not need that much memory pre allocated
            super.initCollections(Math.min(initialCollectionSize, nodes));
          }

          @Override
          protected QueryGraph createQueryGraph() {
            return new QueryGraph(graph) {
              @Override
              protected void updateDistance(EdgeIteratorState edge) {
                edge.setDistance(prepareWeighting.calcWeight(edge));
              }
            };
          }

          @Override
          protected boolean finished() {
            // we need to finish BOTH searches for CH!
            if (finishedFrom && finishedTo) return true;

            // changed finish condition for CH
            double tmpWeight = bestPath.getWeight() * approximationFactor;
            return currFrom.weight >= tmpWeight && currTo.weight >= tmpWeight;
          }

          @Override
          protected void initPath() {
            // CH changes the weight in prepareEdges to the weight
            // now we need to transform it back to the real weight
            Weighting wc = createWeighting();
            bestPath = new Path4CH(graph, flagEncoder, wc);
          }

          @Override
          public String getName() {
            return "astarbiCH";
          }

          @Override
          public String toString() {
            return getName() + "|" + prepareWeighting;
          }
        };

    if (!removesHigher2LowerEdges) astar.setEdgeFilter(new LevelEdgeFilter(g));

    return astar;
  }
  @Override
  public PrepareContractionHierarchies doWork() {
    checkGraph();
    if (prepareEncoder == null) throw new IllegalStateException("No vehicle encoder set.");

    if (prepareWeighting == null) throw new IllegalStateException("No weight calculation set.");

    allSW.start();
    super.doWork();

    initFromGraph();
    if (!prepareEdges()) return this;

    if (!prepareNodes()) return this;

    contractNodes();
    return this;
  }
 PrepareContractionHierarchies initFromGraph() {
   checkGraph();
   vehicleInExplorer = g.createEdgeExplorer(new DefaultEdgeFilter(prepareEncoder, true, false));
   vehicleOutExplorer = g.createEdgeExplorer(new DefaultEdgeFilter(prepareEncoder, false, true));
   vehicleAllExplorer = g.createEdgeExplorer(new DefaultEdgeFilter(prepareEncoder, true, true));
   vehicleAllTmpExplorer = g.createEdgeExplorer(new DefaultEdgeFilter(prepareEncoder, true, true));
   calcPrioAllExplorer = g.createEdgeExplorer(new DefaultEdgeFilter(prepareEncoder, true, true));
   levelEdgeFilter = new IgnoreNodeFilter(g);
   // Use an alternative to PriorityQueue as it has some advantages:
   //   1. Gets automatically smaller if less entries are stored => less total RAM used (as Graph
   // is increasing until the end)
   //   2. is slightly faster
   //   but we need additional priorities array to keep old value which is necessary for update
   // method
   sortedNodes = new GHTreeMapComposed();
   oldPriorities = new int[g.getNodes()];
   algo = new DijkstraOneToMany(g, prepareEncoder, shortestWeighting);
   return this;
 }