Skip to content

Commit

Permalink
Use LMProfile instead of just Weighting for LMPreparationHandler (#1899)
Browse files Browse the repository at this point in the history
  • Loading branch information
easbar committed Feb 12, 2020
1 parent ca78601 commit e2686bd
Show file tree
Hide file tree
Showing 16 changed files with 176 additions and 118 deletions.
15 changes: 11 additions & 4 deletions core/src/main/java/com/graphhopper/GraphHopper.java
Expand Up @@ -28,6 +28,7 @@
import com.graphhopper.routing.ch.CHPreparationHandler;
import com.graphhopper.routing.ch.CHRoutingAlgorithmFactory;
import com.graphhopper.routing.lm.LMPreparationHandler;
import com.graphhopper.routing.lm.LMProfile;
import com.graphhopper.routing.profiles.DefaultEncodedValueFactory;
import com.graphhopper.routing.profiles.EncodedValueFactory;
import com.graphhopper.routing.profiles.EnumEncodedValue;
Expand Down Expand Up @@ -774,7 +775,7 @@ public boolean load(String graphHopperFolder) {

GHLock lock = null;
try {
// create locks only if writes are allowed, if they are not allowed a lock cannot be created
// create locks only if writes are allowed, if they are not allowed a lock cannot be created
// (e.g. on a read only filesystem locks would fail)
if (ghStorage.getDirectory().getDefaultType().isStoring() && isAllowWrites()) {
lockFactory.setLockDir(new File(ghLocation));
Expand Down Expand Up @@ -821,6 +822,9 @@ public final CHPreparationHandler getCHPreparationHandler() {

private void initCHPreparationHandler() {
if (!chPreparationHandler.hasCHProfiles()) {
if (chPreparationHandler.getCHProfileStrings().isEmpty())
throw new IllegalStateException("Potential bug: chProfileStrings is empty");

for (FlagEncoder encoder : encodingManager.fetchEdgeEncoders()) {
for (String chWeightingStr : chPreparationHandler.getCHProfileStrings()) {
// ghStorage is null at this point
Expand Down Expand Up @@ -851,14 +855,17 @@ public final LMPreparationHandler getLMPreparationHandler() {
}

private void initLMPreparationHandler() {
if (lmPreparationHandler.hasWeightings())
if (lmPreparationHandler.hasLMProfiles())
return;

if (lmPreparationHandler.getLMProfileStrings().isEmpty()) {
throw new IllegalStateException("Potential bug: lmProfileStrings is empty");
}
for (FlagEncoder encoder : encodingManager.fetchEdgeEncoders()) {
for (String lmWeightingStr : lmPreparationHandler.getWeightingsAsStrings()) {
for (String lmWeightingStr : lmPreparationHandler.getLMProfileStrings()) {
// note that we do not consider turn costs during LM preparation?
Weighting weighting = createWeighting(new HintsMap(lmWeightingStr), encoder, NO_TURN_COST_PROVIDER);
lmPreparationHandler.addWeighting(weighting);
lmPreparationHandler.addLMProfile(new LMProfile(weighting));
}
}
}
Expand Down
Expand Up @@ -79,19 +79,19 @@ public void init(GraphHopperConfig ghConfig) {

if ("no".equals(chWeightingsStr) || "false".equals(chWeightingsStr)) {
// default is fastest and we need to clear this explicitly
chProfileStrings.clear();
setCHProfilesAsStrings(Collections.<String>emptyList());
} else if (!chWeightingsStr.isEmpty()) {
setCHProfilesAsStrings(Arrays.asList(chWeightingsStr.split(",")));
}

boolean enableThis = !chProfileStrings.isEmpty();
boolean enableThis = !getCHProfileStrings().isEmpty();
setEnabled(enableThis);
if (enableThis)
setDisablingAllowed(ghConfig.getBool(CH.INIT_DISABLING_ALLOWED, isDisablingAllowed()));

String edgeBasedCHStr = ghConfig.get(CH.PREPARE + "edge_based", "off").trim();
edgeBasedCHStr = edgeBasedCHStr.equals("false") ? "off" : edgeBasedCHStr;
edgeBasedCHMode = EdgeBasedCHMode.valueOf(edgeBasedCHStr.toUpperCase(Locale.ROOT));
setEdgeBasedCHMode(EdgeBasedCHMode.valueOf(edgeBasedCHStr.toUpperCase(Locale.ROOT)));

pMap = ghConfig.asPMap();
}
Expand Down Expand Up @@ -185,9 +185,6 @@ public EdgeBasedCHMode getEdgeBasedCHMode() {
}

public List<String> getCHProfileStrings() {
if (chProfileStrings.isEmpty())
throw new IllegalStateException("Potential bug: chProfileStrings is empty");

return new ArrayList<>(chProfileStrings);
}

Expand All @@ -200,9 +197,6 @@ public CHPreparationHandler setCHProfileStrings(String... profileStrings) {
* @see #addCHProfileAsString(String)
*/
public CHPreparationHandler setCHProfilesAsStrings(List<String> profileStrings) {
if (profileStrings.isEmpty())
throw new IllegalArgumentException("It is not allowed to pass an empty list of CH profile strings");

chProfileStrings.clear();
for (String profileString : profileStrings) {
profileString = toLowerCase(profileString);
Expand Down
Expand Up @@ -26,8 +26,6 @@
import com.graphhopper.routing.RoutingAlgorithmFactorySimple;
import com.graphhopper.routing.ch.CHPreparationHandler;
import com.graphhopper.routing.util.HintsMap;
import com.graphhopper.routing.weighting.AbstractWeighting;
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.Graph;
import com.graphhopper.storage.GraphHopperStorage;
import com.graphhopper.storage.StorableProperties;
Expand Down Expand Up @@ -59,8 +57,8 @@ public class LMPreparationHandler {
private final List<PrepareLandmarks> preparations = new ArrayList<>();
// input weighting list from configuration file
// one such entry can result into multiple Weighting objects e.g. fastest & car,foot => fastest|car and fastest|foot
private final List<String> weightingsAsStrings = new ArrayList<>();
private final List<Weighting> weightings = new ArrayList<>();
private final List<String> lmProfileStrings = new ArrayList<>();
private final List<LMProfile> lmProfiles = new ArrayList<>();
private final Map<String, Double> maximumWeights = new HashMap<>();
private boolean enabled = false;
private int minNodes = -1;
Expand Down Expand Up @@ -89,10 +87,10 @@ public void init(GraphHopperConfig ghConfig) {
String lmWeightingsStr = ghConfig.get(Landmark.PREPARE + "weightings", "");
if (!lmWeightingsStr.isEmpty() && !lmWeightingsStr.equalsIgnoreCase("no") && !lmWeightingsStr.equalsIgnoreCase("false")) {
List<String> tmpLMWeightingList = Arrays.asList(lmWeightingsStr.split(","));
setWeightingsAsStrings(tmpLMWeightingList);
setLMProfileStrings(tmpLMWeightingList);
}

boolean enableThis = !weightingsAsStrings.isEmpty();
boolean enableThis = !getLMProfileStrings().isEmpty();
setEnabled(enableThis);
if (enableThis)
setDisablingAllowed(ghConfig.getBool(Landmark.INIT_DISABLING_ALLOWED, isDisablingAllowed()));
Expand Down Expand Up @@ -137,40 +135,34 @@ public void setPreparationThreads(int preparationThreads) {
}

/**
* Enables the use of contraction hierarchies to reduce query times. Enabled by default.
* Enables the use of landmarks to reduce query times.
*
* @param weightingList A list containing multiple weightings like: "fastest", "shortest" or
* your own weight-calculation type.
* @param lmProfilesStrings A list containing multiple lm profiles like: "fastest", "shortest" or
* your own weight-calculation type.
*/
public LMPreparationHandler setWeightingsAsStrings(List<String> weightingList) {
if (weightingList.isEmpty())
throw new IllegalArgumentException("It is not allowed to pass an emtpy weightingList");

weightingsAsStrings.clear();
for (String strWeighting : weightingList) {
strWeighting = toLowerCase(strWeighting);
strWeighting = strWeighting.trim();
addWeighting(strWeighting);
public LMPreparationHandler setLMProfileStrings(List<String> lmProfilesStrings) {
lmProfileStrings.clear();
for (String profileStr : lmProfilesStrings) {
profileStr = toLowerCase(profileStr);
profileStr = profileStr.trim();
addLMProfileAsString(profileStr);
}
return this;
}

public List<String> getWeightingsAsStrings() {
if (this.weightingsAsStrings.isEmpty())
throw new IllegalStateException("Potential bug: weightingsAsStrings is empty");

return this.weightingsAsStrings;
public List<String> getLMProfileStrings() {
return lmProfileStrings;
}

public LMPreparationHandler addWeighting(String weighting) {
String[] str = weighting.split("\\|");
public LMPreparationHandler addLMProfileAsString(String profile) {
String[] str = profile.split("\\|");
double value = -1;
if (str.length > 1) {
PMap map = new PMap(weighting);
PMap map = new PMap(profile);
value = map.getDouble("maximum", -1);
}

weightingsAsStrings.add(str[0]);
lmProfileStrings.add(str[0]);
maximumWeights.put(str[0], value);
return this;
}
Expand All @@ -179,26 +171,26 @@ public LMPreparationHandler addWeighting(String weighting) {
* Decouple weightings from PrepareLandmarks as we need weightings for the graphstorage and the
* graphstorage for the preparation.
*/
public LMPreparationHandler addWeighting(Weighting weighting) {
weightings.add(weighting);
public LMPreparationHandler addLMProfile(LMProfile lmProfile) {
lmProfiles.add(lmProfile);
return this;
}

public LMPreparationHandler addPreparation(PrepareLandmarks plm) {
preparations.add(plm);
int lastIndex = preparations.size() - 1;
if (lastIndex >= weightings.size())
throw new IllegalStateException("Cannot access weighting for PrepareLandmarks with " + plm.getWeighting()
+ ". Call add(Weighting) before");
if (lastIndex >= lmProfiles.size())
throw new IllegalStateException("Cannot access profile for PrepareLandmarks with " + plm.getLMProfile()
+ ". Call add(LMProfile) before");

if (preparations.get(lastIndex).getWeighting() != weightings.get(lastIndex))
throw new IllegalArgumentException("Weighting of PrepareContractionHierarchies " + preparations.get(lastIndex).getWeighting()
+ " needs to be identical to previously added " + weightings.get(lastIndex));
if (preparations.get(lastIndex).getLMProfile() != lmProfiles.get(lastIndex))
throw new IllegalArgumentException("LMProfile of PrepareLandmarks " + preparations.get(lastIndex).getLMProfile()
+ " needs to be identical to previously added " + lmProfiles.get(lastIndex));
return this;
}

public boolean hasWeightings() {
return !weightings.isEmpty();
public boolean hasLMProfiles() {
return !lmProfiles.isEmpty();
}

public boolean hasPreparations() {
Expand All @@ -209,10 +201,6 @@ public int size() {
return preparations.size();
}

public List<Weighting> getWeightings() {
return weightings;
}

public List<PrepareLandmarks> getPreparations() {
return preparations;
}
Expand All @@ -230,10 +218,10 @@ public RoutingAlgorithmFactory getAlgorithmFactory(HintsMap map) {
return new LMRoutingAlgorithmFactory(preparations.get(0), new RoutingAlgorithmFactorySimple());
}

List<Weighting> lmWeightings = new ArrayList<>(preparations.size());
List<String> lmProfiles = new ArrayList<>(preparations.size());
for (final PrepareLandmarks p : preparations) {
lmWeightings.add(p.getWeighting());
if (p.getWeighting().matches(map))
lmProfiles.add(p.getLMProfile().getName());
if (p.getLMProfile().getWeighting().matches(map))
return new LMRoutingAlgorithmFactory(p, new RoutingAlgorithmFactorySimple());
}

Expand All @@ -244,7 +232,7 @@ public RoutingAlgorithmFactory getAlgorithmFactory(HintsMap map) {
String requestedString = (map.getWeighting().isEmpty() ? "*" : map.getWeighting()) + "|" +
(map.getVehicle().isEmpty() ? "*" : map.getVehicle());
throw new IllegalArgumentException("Cannot find matching LM profile for your request." +
"\nrequested: " + requestedString + "\navailable: " + lmWeightings);
"\nrequested: " + requestedString + "\navailable: " + lmProfiles);
}

/**
Expand All @@ -271,9 +259,9 @@ public RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts) {
}

/**
* This method calculates the landmark data for all weightings (optionally in parallel) or if already existent loads it.
* This method calculates the landmark data for all profiles (optionally in parallel) or if already existent loads it.
*
* @return true if the preparation data for at least one weighting was calculated.
* @return true if the preparation data for at least one profile was calculated.
* @see CHPreparationHandler#prepare(StorableProperties, boolean) for a very similar method
*/
public boolean loadOrDoWork(final StorableProperties properties, final boolean closeEarly) {
Expand All @@ -283,14 +271,14 @@ public boolean loadOrDoWork(final StorableProperties properties, final boolean c
for (final PrepareLandmarks plm : preparations) {
counter++;
final int tmpCounter = counter;
final String name = AbstractWeighting.weightingToFileName(plm.getWeighting());
final String name = plm.getLMProfile().getName();
completionService.submit(new Runnable() {
@Override
public void run() {
if (plm.loadExisting())
return;

LOGGER.info(tmpCounter + "/" + getPreparations().size() + " calling LM prepare.doWork for " + plm.getWeighting() + " ... (" + getMemInfo() + ")");
LOGGER.info(tmpCounter + "/" + getPreparations().size() + " calling LM prepare.doWork for " + plm.getLMProfile().getWeighting() + " ... (" + getMemInfo() + ")");
prepared.set(true);
Thread.currentThread().setName(name);
plm.doWork();
Expand Down Expand Up @@ -321,7 +309,7 @@ public void run() {
public void createPreparations(GraphHopperStorage ghStorage, LocationIndex locationIndex) {
if (!isEnabled() || !preparations.isEmpty())
return;
if (weightings.isEmpty())
if (lmProfiles.isEmpty())
throw new IllegalStateException("No landmark weightings found");

List<LandmarkSuggestion> lmSuggestions = new ArrayList<>(lmSuggestionsLocations.size());
Expand All @@ -335,14 +323,14 @@ public void createPreparations(GraphHopperStorage ghStorage, LocationIndex locat
}
}

for (Weighting weighting : getWeightings()) {
Double maximumWeight = maximumWeights.get(weighting.getName());
for (LMProfile lmProfile : lmProfiles) {
Double maximumWeight = maximumWeights.get(lmProfile.getWeighting().getName());
if (maximumWeight == null)
throw new IllegalStateException("maximumWeight cannot be null. Default should be just negative. " +
"Couldn't find " + weighting.getName() + " in " + maximumWeights);
"Couldn't find " + lmProfile.getName() + " in " + maximumWeights);

PrepareLandmarks tmpPrepareLM = new PrepareLandmarks(ghStorage.getDirectory(), ghStorage,
weighting, landmarkCount, activeLandmarkCount).
lmProfile, landmarkCount, activeLandmarkCount).
setLandmarkSuggestions(lmSuggestions).
setMaximumWeight(maximumWeight).
setLogDetails(logDetails);
Expand Down
64 changes: 64 additions & 0 deletions core/src/main/java/com/graphhopper/routing/lm/LMProfile.java
@@ -0,0 +1,64 @@
/*
* 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.weighting.AbstractWeighting;
import com.graphhopper.routing.weighting.Weighting;

import java.util.Objects;

public class LMProfile {
private final String profileName;
private final Weighting weighting;

public LMProfile(Weighting weighting) {
this(AbstractWeighting.weightingToFileName(weighting), weighting);
}

public LMProfile(String profileName, Weighting weighting) {
this.profileName = profileName;
this.weighting = weighting;
}

public String getName() {
return profileName;
}

public Weighting getWeighting() {
return weighting;
}

@Override
public String toString() {
return profileName;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LMProfile lmProfile = (LMProfile) o;
return Objects.equals(profileName, lmProfile.profileName);
}

@Override
public int hashCode() {
return profileName.hashCode();
}
}

0 comments on commit e2686bd

Please sign in to comment.