1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

move io to jsprit-io

This commit is contained in:
oblonski 2016-06-17 18:51:14 +02:00
parent 3966590fc7
commit 667db19f32
33 changed files with 169 additions and 2300 deletions

View file

@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.algorithm;
import org.apache.commons.configuration.XMLConfiguration;
public class AlgorithmConfig {
private XMLConfiguration xmlConfig;
public AlgorithmConfig() {
xmlConfig = new XMLConfiguration();
}
public XMLConfiguration getXMLConfiguration() {
return xmlConfig;
}
}

View file

@ -0,0 +1,91 @@
/*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.algorithm;
import com.graphhopper.jsprit.core.util.Resource;
import org.apache.commons.configuration.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class AlgorithmConfigXmlReader {
private static Logger log = LoggerFactory.getLogger(AlgorithmConfigXmlReader.class.getName());
private AlgorithmConfig algorithmConfig;
private boolean schemaValidation = true;
/**
* @param schemaValidation the schemaValidation to set
*/
public AlgorithmConfigXmlReader setSchemaValidation(boolean schemaValidation) {
this.schemaValidation = schemaValidation;
return this;
}
public AlgorithmConfigXmlReader(AlgorithmConfig algorithmConfig) {
this.algorithmConfig = algorithmConfig;
}
public void read(URL url) {
log.debug("read algorithm: " + url);
algorithmConfig.getXMLConfiguration().setURL(url);
algorithmConfig.getXMLConfiguration().setAttributeSplittingDisabled(true);
algorithmConfig.getXMLConfiguration().setDelimiterParsingDisabled(true);
if (schemaValidation) {
final InputStream resource = Resource.getAsInputStream("algorithm_schema.xsd");
if (resource != null) {
EntityResolver resolver = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
{
InputSource is = new InputSource(resource);
return is;
}
}
};
algorithmConfig.getXMLConfiguration().setEntityResolver(resolver);
algorithmConfig.getXMLConfiguration().setSchemaValidation(true);
} else {
log.warn("cannot find schema-xsd file (algorithm_xml_schema.xsd). try to read xml without xml-file-validation.");
}
}
try {
algorithmConfig.getXMLConfiguration().load();
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
}
public void read(String filename) {
log.debug("read algorithm-config from file " + filename);
URL url = Resource.getAsURL(filename);
read(url);
}
}

View file

@ -0,0 +1,115 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.algorithm;
import com.graphhopper.jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListeners;
import com.graphhopper.jsprit.core.algorithm.recreate.InsertionBuilder;
import com.graphhopper.jsprit.core.algorithm.recreate.InsertionStrategy;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ExecutorService;
class InsertionFactory {
private static Logger log = LoggerFactory.getLogger(InsertionFactory.class.getName());
@SuppressWarnings("deprecation")
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
VehicleFleetManager vehicleFleetManager, StateManager stateManager, List<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
if (config.containsKey("[@name]")) {
String insertionName = config.getString("[@name]");
if (!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")) {
throw new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\"");
}
InsertionBuilder iBuilder = new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager);
if (executorService != null) {
iBuilder.setConcurrentMode(executorService, nuOfThreads);
}
if (config.containsKey("level")) {
String level = config.getString("level");
if (level.equals("local")) {
iBuilder.setLocalLevel(addDefaultCostCalculators);
} else if (level.equals("route")) {
int forwardLooking = 0;
int memory = 1;
String forward = config.getString("level[@forwardLooking]");
String mem = config.getString("level[@memory]");
if (forward != null) forwardLooking = Integer.parseInt(forward);
else
log.warn("parameter route[@forwardLooking] is missing. by default it is 0 which equals to local level");
if (mem != null) memory = Integer.parseInt(mem);
else log.warn("parameter route[@memory] is missing. by default it is 1");
iBuilder.setRouteLevel(forwardLooking, memory, addDefaultCostCalculators);
} else
throw new IllegalStateException("level " + level + " is not known. currently it only knows \"local\" or \"route\"");
} else iBuilder.setLocalLevel(addDefaultCostCalculators);
if (config.containsKey("considerFixedCosts") || config.containsKey("considerFixedCost")) {
if (addDefaultCostCalculators) {
String val = config.getString("considerFixedCosts");
if (val == null) val = config.getString("considerFixedCost");
if (val.equals("true")) {
double fixedCostWeight = 0.5;
String weight = config.getString("considerFixedCosts[@weight]");
if (weight == null) weight = config.getString("considerFixedCost[@weight]");
if (weight != null) fixedCostWeight = Double.parseDouble(weight);
else
throw new IllegalStateException("fixedCostsParameter 'weight' must be set, e.g. <considerFixedCosts weight=1.0>true</considerFixedCosts>.\n" +
"this has to be changed in algorithm-config-xml-file.");
iBuilder.considerFixedCosts(fixedCostWeight);
} else if (val.equals("false")) {
} else
throw new IllegalStateException("considerFixedCosts must either be true or false, i.e. <considerFixedCosts weight=1.0>true</considerFixedCosts> or \n<considerFixedCosts weight=1.0>false</considerFixedCosts>. " +
"if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file");
}
}
String allowVehicleSwitch = config.getString("allowVehicleSwitch");
if (allowVehicleSwitch != null) {
iBuilder.setAllowVehicleSwitch(Boolean.parseBoolean(allowVehicleSwitch));
}
if (insertionName.equals("regretInsertion")) {
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
String fastRegret = config.getString("fastRegret");
if (fastRegret != null) {
iBuilder.setFastRegret(Boolean.parseBoolean(fastRegret));
}
}
return iBuilder.build();
} else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
}
}

View file

@ -0,0 +1,907 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.algorithm;
import com.graphhopper.jsprit.core.algorithm.*;
import com.graphhopper.jsprit.core.algorithm.acceptor.*;
import com.graphhopper.jsprit.core.algorithm.listener.AlgorithmEndsListener;
import com.graphhopper.jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
import com.graphhopper.jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListeners.Priority;
import com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule;
import com.graphhopper.jsprit.core.algorithm.recreate.InsertionStrategy;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionListener;
import com.graphhopper.jsprit.core.algorithm.ruin.RadialRuinStrategyFactory;
import com.graphhopper.jsprit.core.algorithm.ruin.RandomRuinStrategyFactory;
import com.graphhopper.jsprit.core.algorithm.ruin.RuinStrategy;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.AvgServiceAndShipmentDistance;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance;
import com.graphhopper.jsprit.core.algorithm.selector.SelectBest;
import com.graphhopper.jsprit.core.algorithm.selector.SelectRandomly;
import com.graphhopper.jsprit.core.algorithm.selector.SolutionSelector;
import com.graphhopper.jsprit.core.algorithm.state.*;
import com.graphhopper.jsprit.core.algorithm.termination.IterationWithoutImprovementTermination;
import com.graphhopper.jsprit.core.algorithm.termination.PrematureAlgorithmTermination;
import com.graphhopper.jsprit.core.algorithm.termination.TimeTermination;
import com.graphhopper.jsprit.core.algorithm.termination.VariationCoefficientTermination;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem.FleetSize;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.SwitchNotFeasible;
import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.ReverseActivityVisitor;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.*;
import com.graphhopper.jsprit.core.util.ActivityTimeTracker;
import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms.TypedMap.*;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VehicleRoutingAlgorithms {
static class TypedMap {
static interface AbstractKey<K> {
Class<K> getType();
}
static class AcceptorKey implements AbstractKey<SolutionAcceptor> {
private ModKey modKey;
public AcceptorKey(ModKey modKey) {
super();
this.modKey = modKey;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((modKey == null) ? 0 : modKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof AcceptorKey))
return false;
AcceptorKey other = (AcceptorKey) obj;
if (modKey == null) {
if (other.modKey != null)
return false;
} else if (!modKey.equals(other.modKey))
return false;
return true;
}
@Override
public Class<SolutionAcceptor> getType() {
return SolutionAcceptor.class;
}
}
static class SelectorKey implements AbstractKey<SolutionSelector> {
private ModKey modKey;
public SelectorKey(ModKey modKey) {
super();
this.modKey = modKey;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((modKey == null) ? 0 : modKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SelectorKey other = (SelectorKey) obj;
if (modKey == null) {
if (other.modKey != null)
return false;
} else if (!modKey.equals(other.modKey))
return false;
return true;
}
@Override
public Class<SolutionSelector> getType() {
return SolutionSelector.class;
}
}
static class StrategyModuleKey implements AbstractKey<SearchStrategyModule> {
private ModKey modKey;
public StrategyModuleKey(ModKey modKey) {
super();
this.modKey = modKey;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((modKey == null) ? 0 : modKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StrategyModuleKey other = (StrategyModuleKey) obj;
if (modKey == null) {
if (other.modKey != null)
return false;
} else if (!modKey.equals(other.modKey))
return false;
return true;
}
@Override
public Class<SearchStrategyModule> getType() {
return SearchStrategyModule.class;
}
}
static class RuinStrategyKey implements AbstractKey<RuinStrategy> {
private ModKey modKey;
public RuinStrategyKey(ModKey modKey) {
super();
this.modKey = modKey;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((modKey == null) ? 0 : modKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RuinStrategyKey other = (RuinStrategyKey) obj;
if (modKey == null) {
if (other.modKey != null)
return false;
} else if (!modKey.equals(other.modKey))
return false;
return true;
}
@Override
public Class<RuinStrategy> getType() {
return RuinStrategy.class;
}
}
static class InsertionStrategyKey implements AbstractKey<InsertionStrategy> {
private ModKey modKey;
public InsertionStrategyKey(ModKey modKey) {
super();
this.modKey = modKey;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((modKey == null) ? 0 : modKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InsertionStrategyKey other = (InsertionStrategyKey) obj;
if (modKey == null) {
if (other.modKey != null)
return false;
} else if (!modKey.equals(other.modKey))
return false;
return true;
}
@Override
public Class<InsertionStrategy> getType() {
return InsertionStrategy.class;
}
}
private Map<AbstractKey<?>, Object> map = new HashMap<AbstractKey<?>, Object>();
public <T> T get(AbstractKey<T> key) {
if (map.get(key) == null) return null;
return key.getType().cast(map.get(key));
}
public <T> T put(AbstractKey<T> key, T value) {
return key.getType().cast(map.put(key, key.getType().cast(value)));
}
public Set<AbstractKey<?>> keySet() {
return map.keySet();
}
}
static class ModKey {
private String name;
private String id;
public ModKey(String name, String id) {
super();
this.name = name;
this.id = id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ModKey other = (ModKey) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
private static Logger log = LoggerFactory.getLogger(VehicleRoutingAlgorithms.class.getName());
private VehicleRoutingAlgorithms() {
}
/**
* Creates a {@link com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm} from a AlgorithConfig based on the input vrp.
*
* @param vrp the routing problem
* @param algorithmConfig the algorithm config
* @return {@link com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm}
*/
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, final AlgorithmConfig algorithmConfig) {
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null);
}
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final AlgorithmConfig algorithmConfig) {
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), nThreads, null);
}
/**
* Read and creates a {@link VehicleRoutingAlgorithm} from an url.
*
* @param vrp the routing problem
* @param configURL config url
* @return {@link com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm}
*/
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final URL configURL) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
xmlReader.read(configURL);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null);
}
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final URL configURL) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
xmlReader.read(configURL);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), nThreads, null);
}
/**
* Read and creates {@link com.graphhopper.jsprit.core.problem.VehicleRoutingProblem} from config-file.
*
* @param vrp the routing problem
* @param configFileName the config filename (and location)
* @return {@link com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm}
*/
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final String configFileName) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
xmlReader.read(configFileName);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null);
}
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final String configFileName, StateManager stateManager) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
xmlReader.read(configFileName);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, stateManager);
}
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final String configFileName, StateManager stateManager) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
xmlReader.read(configFileName);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), nThreads, stateManager);
}
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(VehicleRoutingProblem vrp, int nThreads, String configFileName) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
xmlReader.read(configFileName);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), nThreads, null);
}
private static class OpenRouteStateVerifier implements StateUpdater, ReverseActivityVisitor {
private End end;
private boolean firstAct = true;
private Vehicle vehicle;
@Override
public void begin(VehicleRoute route) {
end = route.getEnd();
vehicle = route.getVehicle();
}
@Override
public void visit(TourActivity activity) {
if (firstAct) {
firstAct = false;
if (!vehicle.isReturnToDepot()) {
assert activity.getLocation().getId().equals(end.getLocation().getId()) : "route end and last activity are not equal even route is open. this should not be.";
}
}
}
@Override
public void finish() {
firstAct = true;
}
}
private static VehicleRoutingAlgorithm createAlgo(final VehicleRoutingProblem vrp, XMLConfiguration config, int nuOfThreads, StateManager stateMan) {
//create state-manager
final StateManager stateManager;
if (stateMan != null) {
stateManager = stateMan;
} else {
stateManager = new StateManager(vrp);
}
stateManager.updateLoadStates();
stateManager.updateTimeWindowStates();
stateManager.updateSkillStates();
stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen());
stateManager.addStateUpdater(new OpenRouteStateVerifier());
// stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts()));
// stateManager.addStateUpdater(new UpdateVariableCosts(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
/*
* define constraints
*/
//constraint manager
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
constraintManager.addTimeWindowConstraint();
constraintManager.addLoadConstraint();
constraintManager.addSkillsConstraint();
constraintManager.addConstraint(new SwitchNotFeasible(stateManager));
return readAndCreateAlgorithm(vrp, config, nuOfThreads, null, stateManager, constraintManager, true);
}
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, AlgorithmConfig config,
int nuOfThreads, SolutionCostCalculator solutionCostCalculator, final StateManager stateManager, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
return readAndCreateAlgorithm(vrp, config.getXMLConfiguration(), nuOfThreads, solutionCostCalculator, stateManager, constraintManager, addDefaultCostCalculators);
}
private static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, XMLConfiguration config,
int nuOfThreads, final SolutionCostCalculator solutionCostCalculator, final StateManager stateManager, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
// map to store constructed modules
TypedMap definedClasses = new TypedMap();
// algorithm listeners
Set<PrioritizedVRAListener> algorithmListeners = new HashSet<PrioritizedVRAListener>();
// insertion listeners
List<InsertionListener> insertionListeners = new ArrayList<InsertionListener>();
//threading
final ExecutorService executorService;
if (nuOfThreads > 0) {
log.debug("setup executor-service with " + nuOfThreads + " threads");
executorService = Executors.newFixedThreadPool(nuOfThreads);
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new AlgorithmEndsListener() {
@Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
log.debug("shutdown executor-service");
executorService.shutdown();
}
}));
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread arg0, Throwable arg1) {
System.err.println(arg1.toString());
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
if (!executorService.isShutdown()) {
System.err.println("shutdowHook shuts down executorService");
executorService.shutdown();
}
}
});
} else executorService = null;
//create fleetmanager
final VehicleFleetManager vehicleFleetManager = createFleetManager(vrp);
String switchString = config.getString("construction.insertion.allowVehicleSwitch");
final boolean switchAllowed;
if (switchString != null) {
switchAllowed = Boolean.parseBoolean(switchString);
} else switchAllowed = true;
ActivityTimeTracker.ActivityPolicy activityPolicy;
if (stateManager.timeWindowUpdateIsActivated()) {
UpdateVehicleDependentPracticalTimeWindows timeWindowUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts(), vrp.getActivityCosts());
timeWindowUpdater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
Map<VehicleTypeKey, Vehicle> uniqueTypes = new HashMap<VehicleTypeKey, Vehicle>();
@Override
public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
if (uniqueTypes.isEmpty()) {
for (Vehicle v : vrp.getVehicles()) {
if (!uniqueTypes.containsKey(v.getVehicleTypeIdentifier())) {
uniqueTypes.put(v.getVehicleTypeIdentifier(), v);
}
}
}
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
vehicles.addAll(uniqueTypes.values());
return vehicles;
}
});
stateManager.addStateUpdater(timeWindowUpdater);
activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS;
} else {
activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_ARRIVED;
}
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), activityPolicy, vrp.getActivityCosts()));
stateManager.addStateUpdater(new UpdateVariableCosts(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager, activityPolicy));
final SolutionCostCalculator costCalculator;
if (solutionCostCalculator == null) costCalculator = getDefaultCostCalculator(stateManager);
else costCalculator = solutionCostCalculator;
PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager);
//construct initial solution creator
final InsertionStrategy initialInsertionStrategy = createInitialSolution(config, vrp, vehicleFleetManager, stateManager, algorithmListeners, definedClasses, executorService, nuOfThreads, costCalculator, constraintManager, addDefaultCostCalculators);
if (initialInsertionStrategy != null)
prettyAlgorithmBuilder.constructInitialSolutionWith(initialInsertionStrategy, costCalculator);
//construct algorithm, i.e. search-strategies and its modules
int solutionMemory = config.getInt("strategy.memory");
List<HierarchicalConfiguration> strategyConfigs = config.configurationsAt("strategy.searchStrategies.searchStrategy");
for (HierarchicalConfiguration strategyConfig : strategyConfigs) {
String name = getName(strategyConfig);
SolutionAcceptor acceptor = getAcceptor(strategyConfig, vrp, algorithmListeners, definedClasses, solutionMemory);
SolutionSelector selector = getSelector(strategyConfig, vrp, algorithmListeners, definedClasses);
SearchStrategy strategy = new SearchStrategy(name, selector, acceptor, costCalculator);
strategy.setName(name);
List<HierarchicalConfiguration> modulesConfig = strategyConfig.configurationsAt("modules.module");
for (HierarchicalConfiguration moduleConfig : modulesConfig) {
SearchStrategyModule module = buildModule(moduleConfig, vrp, vehicleFleetManager, stateManager, algorithmListeners, definedClasses, executorService, nuOfThreads, constraintManager, addDefaultCostCalculators);
strategy.addModule(module);
}
prettyAlgorithmBuilder.withStrategy(strategy, strategyConfig.getDouble("probability"));
}
//construct algorithm
VehicleRoutingAlgorithm metaAlgorithm = prettyAlgorithmBuilder.build();
int maxIterations = getMaxIterations(config);
if (maxIterations > -1) metaAlgorithm.setMaxIterations(maxIterations);
//define prematureBreak
PrematureAlgorithmTermination prematureAlgorithmTermination = getPrematureTermination(config, algorithmListeners);
if (prematureAlgorithmTermination != null)
metaAlgorithm.setPrematureAlgorithmTermination(prematureAlgorithmTermination);
else {
List<HierarchicalConfiguration> terminationCriteria = config.configurationsAt("terminationCriteria.termination");
for (HierarchicalConfiguration terminationConfig : terminationCriteria) {
PrematureAlgorithmTermination termination = getTerminationCriterion(terminationConfig, algorithmListeners);
if (termination != null) metaAlgorithm.addTerminationCriterion(termination);
}
}
for (PrioritizedVRAListener l : algorithmListeners) {
metaAlgorithm.getAlgorithmListeners().add(l);
}
return metaAlgorithm;
}
private static int getMaxIterations(XMLConfiguration config) {
String maxIterationsString = config.getString("iterations");
if (maxIterationsString == null) maxIterationsString = config.getString("maxIterations");
if (maxIterationsString != null) return (Integer.parseInt(maxIterationsString));
return -1;
}
private static SolutionCostCalculator getDefaultCostCalculator(final StateManager stateManager) {
return new VariablePlusFixedSolutionCostCalculatorFactory(stateManager).createCalculator();
}
private static VehicleFleetManager createFleetManager(final VehicleRoutingProblem vrp) {
if (vrp.getFleetSize().equals(FleetSize.INFINITE)) {
return new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} else if (vrp.getFleetSize().equals(FleetSize.FINITE)) {
return new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
}
throw new IllegalStateException("fleet size can only be infinite or finite. " +
"makes sure your config file contains one of these options");
}
private static PrematureAlgorithmTermination getTerminationCriterion(HierarchicalConfiguration config, Set<PrioritizedVRAListener> algorithmListeners) {
String basedOn = config.getString("[@basedOn]");
if (basedOn == null) {
log.debug("set default prematureBreak, i.e. no premature break at all.");
return null;
}
if (basedOn.equals("iterations")) {
log.debug("set prematureBreak based on iterations");
String iter = config.getString("iterations");
if (iter == null) throw new IllegalStateException("iterations is missing");
int iterations = Integer.valueOf(iter);
return new IterationWithoutImprovementTermination(iterations);
}
if (basedOn.equals("time")) {
log.debug("set prematureBreak based on time");
String timeString = config.getString("time");
if (timeString == null) throw new IllegalStateException("time is missing");
long time = Long.parseLong(timeString);
TimeTermination timeBreaker = new TimeTermination(time);
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, timeBreaker));
return timeBreaker;
}
if (basedOn.equals("variationCoefficient")) {
log.debug("set prematureBreak based on variation coefficient");
String thresholdString = config.getString("threshold");
String iterationsString = config.getString("iterations");
if (thresholdString == null) throw new IllegalStateException("threshold is missing");
if (iterationsString == null) throw new IllegalStateException("iterations is missing");
double threshold = Double.valueOf(thresholdString);
int iterations = Integer.valueOf(iterationsString);
VariationCoefficientTermination variationCoefficientBreaker = new VariationCoefficientTermination(iterations, threshold);
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, variationCoefficientBreaker));
return variationCoefficientBreaker;
}
throw new IllegalStateException("prematureBreak basedOn " + basedOn + " is not defined");
}
private static PrematureAlgorithmTermination getPrematureTermination(XMLConfiguration config, Set<PrioritizedVRAListener> algorithmListeners) {
String basedOn = config.getString("prematureBreak[@basedOn]");
if (basedOn == null) {
log.debug("set default prematureBreak, i.e. no premature break at all.");
return null;
}
if (basedOn.equals("iterations")) {
log.debug("set prematureBreak based on iterations");
String iter = config.getString("prematureBreak.iterations");
if (iter == null) throw new IllegalStateException("prematureBreak.iterations is missing");
int iterations = Integer.valueOf(iter);
return new IterationWithoutImprovementTermination(iterations);
}
if (basedOn.equals("time")) {
log.debug("set prematureBreak based on time");
String timeString = config.getString("prematureBreak.time");
if (timeString == null) throw new IllegalStateException("prematureBreak.time is missing");
long time = Long.parseLong(timeString);
TimeTermination timeBreaker = new TimeTermination(time);
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, timeBreaker));
return timeBreaker;
}
if (basedOn.equals("variationCoefficient")) {
log.debug("set prematureBreak based on variation coefficient");
String thresholdString = config.getString("prematureBreak.threshold");
String iterationsString = config.getString("prematureBreak.iterations");
if (thresholdString == null) throw new IllegalStateException("prematureBreak.threshold is missing");
if (iterationsString == null) throw new IllegalStateException("prematureBreak.iterations is missing");
double threshold = Double.valueOf(thresholdString);
int iterations = Integer.valueOf(iterationsString);
VariationCoefficientTermination variationCoefficientBreaker = new VariationCoefficientTermination(iterations, threshold);
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, variationCoefficientBreaker));
return variationCoefficientBreaker;
}
throw new IllegalStateException("prematureBreak basedOn " + basedOn + " is not defined");
}
private static String getName(HierarchicalConfiguration strategyConfig) {
if (strategyConfig.containsKey("[@name]")) {
return strategyConfig.getString("[@name]");
}
return "";
}
private static InsertionStrategy createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, final StateManager routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, final SolutionCostCalculator solutionCostCalculator, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
List<HierarchicalConfiguration> modConfigs = config.configurationsAt("construction.insertion");
if (modConfigs == null) return null;
if (modConfigs.isEmpty()) return null;
if (modConfigs.size() != 1) throw new IllegalStateException("#construction.modules != 1. 1 expected");
HierarchicalConfiguration modConfig = modConfigs.get(0);
String insertionName = modConfig.getString("[@name]");
if (insertionName == null) throw new IllegalStateException("insertion[@name] is missing.");
String insertionId = modConfig.getString("[@id]");
if (insertionId == null) insertionId = "noId";
ModKey modKey = makeKey(insertionName, insertionId);
InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(modKey);
InsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey);
if (insertionStrategy == null) {
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads, constraintManager, addDefaultCostCalculators);
algorithmListeners.addAll(prioListeners);
definedClasses.put(insertionStrategyKey, insertionStrategy);
}
return insertionStrategy;
}
private static SolutionSelector getSelector(HierarchicalConfiguration strategyConfig, VehicleRoutingProblem vrp, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedSelectors) {
String selectorName = strategyConfig.getString("selector[@name]");
if (selectorName == null)
throw new IllegalStateException("no solutionSelector defined. define either \"selectRandomly\" or \"selectBest\"");
String selectorId = strategyConfig.getString("selector[@id]");
if (selectorId == null) selectorId = "noId";
ModKey modKey = makeKey(selectorName, selectorId);
SelectorKey selectorKey = new SelectorKey(modKey);
SolutionSelector definedSelector = definedSelectors.get(selectorKey);
if (definedSelector != null) {
return definedSelector;
}
if (selectorName.equals("selectRandomly")) {
SelectRandomly selector = SelectRandomly.getInstance();
definedSelectors.put(selectorKey, selector);
return selector;
}
if (selectorName.equals("selectBest")) {
SelectBest selector = SelectBest.getInstance();
definedSelectors.put(selectorKey, selector);
return selector;
}
throw new IllegalStateException("solutionSelector is not know. Currently, it only knows \"selectRandomly\" and \"selectBest\"");
}
private static ModKey makeKey(String name, String id) {
return new ModKey(name, id);
}
private static SolutionAcceptor getAcceptor(HierarchicalConfiguration strategyConfig, VehicleRoutingProblem vrp, Set<PrioritizedVRAListener> algorithmListeners, TypedMap typedMap, int solutionMemory) {
String acceptorName = strategyConfig.getString("acceptor[@name]");
if (acceptorName == null) throw new IllegalStateException("no solution acceptor is defined");
String acceptorId = strategyConfig.getString("acceptor[@id]");
if (acceptorId == null) acceptorId = "noId";
AcceptorKey acceptorKey = new AcceptorKey(makeKey(acceptorName, acceptorId));
SolutionAcceptor definedAcceptor = typedMap.get(acceptorKey);
if (definedAcceptor != null) return definedAcceptor;
if (acceptorName.equals("acceptNewRemoveWorst")) {
GreedyAcceptance acceptor = new GreedyAcceptance(solutionMemory);
typedMap.put(acceptorKey, acceptor);
return acceptor;
}
if (acceptorName.equals("acceptNewRemoveFirst")) {
AcceptNewRemoveFirst acceptor = new AcceptNewRemoveFirst(solutionMemory);
typedMap.put(acceptorKey, acceptor);
return acceptor;
}
if (acceptorName.equals("greedyAcceptance")) {
GreedyAcceptance acceptor = new GreedyAcceptance(solutionMemory);
typedMap.put(acceptorKey, acceptor);
return acceptor;
}
if (acceptorName.equals("schrimpfAcceptance")) {
String nuWarmupIterations = strategyConfig.getString("acceptor.warmup");
double alpha = strategyConfig.getDouble("acceptor.alpha");
SchrimpfAcceptance schrimpf = new SchrimpfAcceptance(solutionMemory, alpha);
if (nuWarmupIterations != null) {
SchrimpfInitialThresholdGenerator iniThresholdGenerator = new SchrimpfInitialThresholdGenerator(schrimpf, Integer.parseInt(nuWarmupIterations));
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, iniThresholdGenerator));
} else {
double threshold = strategyConfig.getDouble("acceptor.initialThreshold");
schrimpf.setInitialThreshold(threshold);
}
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, schrimpf));
typedMap.put(acceptorKey, schrimpf);
return schrimpf;
}
if (acceptorName.equals("experimentalSchrimpfAcceptance")) {
int iterOfSchrimpf = strategyConfig.getInt("acceptor.warmup");
double alpha = strategyConfig.getDouble("acceptor.alpha");
ExperimentalSchrimpfAcceptance schrimpf = new ExperimentalSchrimpfAcceptance(solutionMemory, alpha, iterOfSchrimpf);
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, schrimpf));
typedMap.put(acceptorKey, schrimpf);
return schrimpf;
} else {
throw new IllegalStateException("solution acceptor " + acceptorName + " is not known");
}
}
private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager,
final StateManager routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
String moduleName = moduleConfig.getString("[@name]");
if (moduleName == null) throw new IllegalStateException("module(-name) is missing.");
String moduleId = moduleConfig.getString("[@id]");
if (moduleId == null) moduleId = "noId";
ModKey modKey = makeKey(moduleName, moduleId);
StrategyModuleKey strategyModuleKey = new StrategyModuleKey(modKey);
SearchStrategyModule definedModule = definedClasses.get(strategyModuleKey);
if (definedModule != null) return definedModule;
if (moduleName.equals("ruin_and_recreate")) {
String ruin_name = moduleConfig.getString("ruin[@name]");
if (ruin_name == null) throw new IllegalStateException("module.ruin[@name] is missing.");
String ruin_id = moduleConfig.getString("ruin[@id]");
if (ruin_id == null) ruin_id = "noId";
String shareToRuinString = moduleConfig.getString("ruin.share");
if (shareToRuinString == null) throw new IllegalStateException("module.ruin.share is missing.");
double shareToRuin = Double.valueOf(shareToRuinString);
final RuinStrategy ruin;
ModKey ruinKey = makeKey(ruin_name, ruin_id);
if (ruin_name.equals("randomRuin")) {
ruin = getRandomRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin);
} else if (ruin_name.equals("radialRuin")) {
JobDistance jobDistance = new AvgServiceAndShipmentDistance(vrp.getTransportCosts());
ruin = getRadialRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin, jobDistance);
} else
throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin.");
String insertionName = moduleConfig.getString("insertion[@name]");
if (insertionName == null)
throw new IllegalStateException("module.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
String insertionId = moduleConfig.getString("insertion[@id]");
if (insertionId == null) insertionId = "noId";
ModKey insertionKey = makeKey(insertionName, insertionId);
InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(insertionKey);
InsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
if (insertion == null) {
List<HierarchicalConfiguration> insertionConfigs = moduleConfig.configurationsAt("insertion");
if (insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1");
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads, constraintManager, addDefaultCostCalculators);
algorithmListeners.addAll(prioListeners);
}
final InsertionStrategy final_insertion = insertion;
RuinAndRecreateModule rrModule = new RuinAndRecreateModule("ruin_and_recreate", final_insertion, ruin);
return rrModule;
}
throw new NullPointerException("no module found with moduleName=" + moduleName +
"\n\tcheck config whether the correct names are used" +
"\n\tcurrently there are following modules available: " +
"\n\tbestInsertion" +
"\n\trandomRuin" +
"\n\tradialRuin");
}
private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final StateManager routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) {
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
RuinStrategy ruin = definedClasses.get(stratKey);
if (ruin == null) {
ruin = new RadialRuinStrategyFactory(shareToRuin, jobDistance).createStrategy(vrp);
definedClasses.put(stratKey, ruin);
}
return ruin;
}
private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final StateManager routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) {
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
RuinStrategy ruin = definedClasses.get(stratKey);
if (ruin == null) {
ruin = new RandomRuinStrategyFactory(shareToRuin).createStrategy(vrp);
definedClasses.put(stratKey, ruin);
}
return ruin;
}
private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
return InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads, constraintManager, addDefaultCostCalculators);
}
}

View file

@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.problem;
final class Schema {
public static final String PROBLEM = "problem";
public static final String VEHICLE = "vehicle";
public static final String TYPES = "vehicleTypes";
public static final String VEHICLES = "vehicles";
public static final String SHIPMENTS = "shipments";
public static final String SHIPMENT = "shipment";
public static final String SERVICETIME = "serviceTime";
public static final String PICKUP = "pickup";
public static final String TYPE = "type";
public void dot() {
}
public static class PathBuilder {
StringBuilder stringBuilder = new StringBuilder();
boolean justCreated = true;
public PathBuilder dot(String string) {
stringBuilder.append(".").append(string);
return this;
}
public PathBuilder append(String string) {
stringBuilder.append(string);
return this;
}
public String build() {
return stringBuilder.toString();
}
}
public static PathBuilder builder() {
return new PathBuilder();
}
private Schema() {
}
}

View file

@ -0,0 +1,721 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.problem;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem.FleetSize;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.driver.DriverImpl;
import com.graphhopper.jsprit.core.problem.job.*;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl.Builder;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
import com.graphhopper.jsprit.core.util.Coordinate;
import com.graphhopper.jsprit.core.util.Resource;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public class VrpXMLReader {
public interface ServiceBuilderFactory {
Service.Builder createBuilder(String serviceType, String id, Integer size);
}
static class DefaultServiceBuilderFactory implements ServiceBuilderFactory {
@Override
public Service.Builder createBuilder(String serviceType, String id, Integer size) {
if (serviceType.equals("pickup")) {
if (size != null) return Pickup.Builder.newInstance(id).addSizeDimension(0, size);
else return Pickup.Builder.newInstance(id);
} else if (serviceType.equals("delivery")) {
if (size != null) return Delivery.Builder.newInstance(id).addSizeDimension(0, size);
else return Delivery.Builder.newInstance(id);
} else {
if (size != null) return Service.Builder.newInstance(id).addSizeDimension(0, size);
else return Service.Builder.newInstance(id);
}
}
}
private static Logger logger = LoggerFactory.getLogger(VrpXMLReader.class);
private VehicleRoutingProblem.Builder vrpBuilder;
private Map<String, Vehicle> vehicleMap;
private Map<String, Service> serviceMap;
private Map<String, Shipment> shipmentMap;
private Set<String> freezedJobIds = new HashSet<String>();
private boolean schemaValidation = true;
private Collection<VehicleRoutingProblemSolution> solutions;
private ServiceBuilderFactory serviceBuilderFactory = new DefaultServiceBuilderFactory();
/**
* @param schemaValidation the schemaValidation to set
*/
@SuppressWarnings("UnusedDeclaration")
public void setSchemaValidation(boolean schemaValidation) {
this.schemaValidation = schemaValidation;
}
public VrpXMLReader(VehicleRoutingProblem.Builder vrpBuilder, Collection<VehicleRoutingProblemSolution> solutions) {
this.vrpBuilder = vrpBuilder;
this.vehicleMap = new LinkedHashMap<String, Vehicle>();
this.serviceMap = new LinkedHashMap<String, Service>();
this.shipmentMap = new LinkedHashMap<String, Shipment>();
this.solutions = solutions;
}
public VrpXMLReader(VehicleRoutingProblem.Builder vrpBuilder) {
this.vrpBuilder = vrpBuilder;
this.vehicleMap = new LinkedHashMap<String, Vehicle>();
this.serviceMap = new LinkedHashMap<String, Service>();
this.shipmentMap = new LinkedHashMap<String, Shipment>();
this.solutions = null;
}
public void read(String filename) {
logger.debug("read vrp: {}", filename);
XMLConfiguration xmlConfig = createXMLConfiguration();
try {
xmlConfig.load(filename);
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
read(xmlConfig);
}
public void read(InputStream fileContents) {
XMLConfiguration xmlConfig = createXMLConfiguration();
try {
xmlConfig.load(fileContents);
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
read(xmlConfig);
}
private XMLConfiguration createXMLConfiguration() {
XMLConfiguration xmlConfig = new XMLConfiguration();
xmlConfig.setAttributeSplittingDisabled(true);
xmlConfig.setDelimiterParsingDisabled(true);
if (schemaValidation) {
final InputStream resource = Resource.getAsInputStream("vrp_xml_schema.xsd");
if (resource != null) {
EntityResolver resolver = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
{
InputSource is = new InputSource(resource);
return is;
}
}
};
xmlConfig.setEntityResolver(resolver);
xmlConfig.setSchemaValidation(true);
} else {
logger.debug("cannot find schema-xsd file (vrp_xml_schema.xsd). try to read xml without xml-file-validation.");
}
}
return xmlConfig;
}
private void read(XMLConfiguration xmlConfig) {
readProblemType(xmlConfig);
readVehiclesAndTheirTypes(xmlConfig);
readShipments(xmlConfig);
readServices(xmlConfig);
readInitialRoutes(xmlConfig);
readSolutions(xmlConfig);
addJobsAndTheirLocationsToVrp();
}
private void addJobsAndTheirLocationsToVrp() {
for (Service service : serviceMap.values()) {
if (!freezedJobIds.contains(service.getId())) {
vrpBuilder.addJob(service);
}
}
for (Shipment shipment : shipmentMap.values()) {
if (!freezedJobIds.contains(shipment.getId())) {
vrpBuilder.addJob(shipment);
}
}
}
private void readInitialRoutes(XMLConfiguration xmlConfig) {
List<HierarchicalConfiguration> initialRouteConfigs = xmlConfig.configurationsAt("initialRoutes.route");
for (HierarchicalConfiguration routeConfig : initialRouteConfigs) {
Driver driver = DriverImpl.noDriver();
String vehicleId = routeConfig.getString("vehicleId");
Vehicle vehicle = getVehicle(vehicleId);
if (vehicle == null) throw new IllegalArgumentException("vehicle is missing.");
String start = routeConfig.getString("start");
if (start == null) throw new IllegalArgumentException("route start-time is missing.");
double departureTime = Double.parseDouble(start);
VehicleRoute.Builder routeBuilder = VehicleRoute.Builder.newInstance(vehicle, driver);
routeBuilder.setDepartureTime(departureTime);
List<HierarchicalConfiguration> actConfigs = routeConfig.configurationsAt("act");
for (HierarchicalConfiguration actConfig : actConfigs) {
String type = actConfig.getString("[@type]");
if (type == null) throw new IllegalArgumentException("act[@type] is missing.");
double arrTime = 0.;
double endTime = 0.;
String arrTimeS = actConfig.getString("arrTime");
if (arrTimeS != null) arrTime = Double.parseDouble(arrTimeS);
String endTimeS = actConfig.getString("endTime");
if (endTimeS != null) endTime = Double.parseDouble(endTimeS);
String serviceId = actConfig.getString("serviceId");
if(type.equals("break")) {
Break currentbreak = getBreak(vehicleId);
routeBuilder.addBreak(currentbreak);
}
else {
if (serviceId != null) {
Service service = getService(serviceId);
if (service == null)
throw new IllegalArgumentException("service to serviceId " + serviceId + " is missing (reference in one of your initial routes). make sure you define the service you refer to here in <services> </services>.");
//!!!since job is part of initial route, it does not belong to jobs in problem, i.e. variable jobs that can be assigned/scheduled
freezedJobIds.add(serviceId);
routeBuilder.addService(service);
} else {
String shipmentId = actConfig.getString("shipmentId");
if (shipmentId == null)
throw new IllegalArgumentException("either serviceId or shipmentId is missing");
Shipment shipment = getShipment(shipmentId);
if (shipment == null)
throw new IllegalArgumentException("shipment to shipmentId " + shipmentId + " is missing (reference in one of your initial routes). make sure you define the shipment you refer to here in <shipments> </shipments>.");
freezedJobIds.add(shipmentId);
if (type.equals("pickupShipment")) {
routeBuilder.addPickup(shipment);
} else if (type.equals("deliverShipment")) {
routeBuilder.addDelivery(shipment);
} else
throw new IllegalArgumentException("type " + type + " is not supported. Use 'pickupShipment' or 'deliverShipment' here");
}
}
}
VehicleRoute route = routeBuilder.build();
vrpBuilder.addInitialVehicleRoute(route);
}
}
private void readSolutions(XMLConfiguration vrpProblem) {
if (solutions == null) return;
List<HierarchicalConfiguration> solutionConfigs = vrpProblem.configurationsAt("solutions.solution");
for (HierarchicalConfiguration solutionConfig : solutionConfigs) {
String totalCost = solutionConfig.getString("cost");
double cost = -1;
if (totalCost != null) cost = Double.parseDouble(totalCost);
List<HierarchicalConfiguration> routeConfigs = solutionConfig.configurationsAt("routes.route");
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
for (HierarchicalConfiguration routeConfig : routeConfigs) {
//! here, driverId is set to noDriver, no matter whats in driverId.
Driver driver = DriverImpl.noDriver();
String vehicleId = routeConfig.getString("vehicleId");
Vehicle vehicle = getVehicle(vehicleId);
if (vehicle == null) throw new IllegalArgumentException("vehicle is missing.");
String start = routeConfig.getString("start");
if (start == null) throw new IllegalArgumentException("route start-time is missing.");
double departureTime = Double.parseDouble(start);
String end = routeConfig.getString("end");
if (end == null) throw new IllegalArgumentException("route end-time is missing.");
VehicleRoute.Builder routeBuilder = VehicleRoute.Builder.newInstance(vehicle, driver);
routeBuilder.setDepartureTime(departureTime);
List<HierarchicalConfiguration> actConfigs = routeConfig.configurationsAt("act");
for (HierarchicalConfiguration actConfig : actConfigs) {
String type = actConfig.getString("[@type]");
if (type == null) throw new IllegalArgumentException("act[@type] is missing.");
double arrTime = 0.;
double endTime = 0.;
String arrTimeS = actConfig.getString("arrTime");
if (arrTimeS != null) arrTime = Double.parseDouble(arrTimeS);
String endTimeS = actConfig.getString("endTime");
if (endTimeS != null) endTime = Double.parseDouble(endTimeS);
if(type.equals("break")) {
Break currentbreak = getBreak(vehicleId);
routeBuilder.addBreak(currentbreak);
}
else {
String serviceId = actConfig.getString("serviceId");
if (serviceId != null) {
Service service = getService(serviceId);
routeBuilder.addService(service);
} else {
String shipmentId = actConfig.getString("shipmentId");
if (shipmentId == null)
throw new IllegalArgumentException("either serviceId or shipmentId is missing");
Shipment shipment = getShipment(shipmentId);
if (shipment == null)
throw new IllegalArgumentException("shipment with id " + shipmentId + " does not exist.");
if (type.equals("pickupShipment")) {
routeBuilder.addPickup(shipment);
} else if (type.equals("deliverShipment")) {
routeBuilder.addDelivery(shipment);
} else
throw new IllegalArgumentException("type " + type + " is not supported. Use 'pickupShipment' or 'deliverShipment' here");
}
}
}
routes.add(routeBuilder.build());
}
VehicleRoutingProblemSolution solution = new VehicleRoutingProblemSolution(routes, cost);
List<HierarchicalConfiguration> unassignedJobConfigs = solutionConfig.configurationsAt("unassignedJobs.job");
for (HierarchicalConfiguration unassignedJobConfig : unassignedJobConfigs) {
String jobId = unassignedJobConfig.getString("[@id]");
Job job = getShipment(jobId);
if (job == null) job = getService(jobId);
if (job == null) throw new IllegalArgumentException("cannot find unassignedJob with id " + jobId);
solution.getUnassignedJobs().add(job);
}
solutions.add(solution);
}
}
private Shipment getShipment(String shipmentId) {
return shipmentMap.get(shipmentId);
}
private Service getService(String serviceId) {
return serviceMap.get(serviceId);
}
private Vehicle getVehicle(String vehicleId) {
return vehicleMap.get(vehicleId);
}
private Break getBreak(String vehicleId) {
return vehicleMap.get(vehicleId).getBreak();
}
private void readProblemType(XMLConfiguration vrpProblem) {
String fleetSize = vrpProblem.getString("problemType.fleetSize");
if (fleetSize == null) vrpBuilder.setFleetSize(FleetSize.INFINITE);
else if (fleetSize.toUpperCase().equals(FleetSize.INFINITE.toString()))
vrpBuilder.setFleetSize(FleetSize.INFINITE);
else vrpBuilder.setFleetSize(FleetSize.FINITE);
}
private void readShipments(XMLConfiguration config) {
List<HierarchicalConfiguration> shipmentConfigs = config.configurationsAt("shipments.shipment");
for (HierarchicalConfiguration shipmentConfig : shipmentConfigs) {
String id = shipmentConfig.getString("[@id]");
if (id == null) throw new IllegalArgumentException("shipment[@id] is missing.");
String capacityString = shipmentConfig.getString("capacity-demand");
boolean capacityDimensionsExist = shipmentConfig.containsKey("capacity-dimensions.dimension(0)");
if (capacityString == null && !capacityDimensionsExist) {
throw new IllegalArgumentException("capacity of shipment is not set. use 'capacity-dimensions'");
}
if (capacityString != null && capacityDimensionsExist) {
throw new IllegalArgumentException("either use capacity or capacity-dimension, not both. prefer the use of 'capacity-dimensions' over 'capacity'.");
}
Shipment.Builder builder;
if (capacityString != null) {
builder = Shipment.Builder.newInstance(id).addSizeDimension(0, Integer.parseInt(capacityString));
} else {
builder = Shipment.Builder.newInstance(id);
List<HierarchicalConfiguration> dimensionConfigs = shipmentConfig.configurationsAt("capacity-dimensions.dimension");
for (HierarchicalConfiguration dimension : dimensionConfigs) {
Integer index = dimension.getInt("[@index]");
Integer value = dimension.getInt("");
builder.addSizeDimension(index, value);
}
}
//name
String name = shipmentConfig.getString("name");
if (name != null) builder.setName(name);
//pickup location
//pickup-locationId
Location.Builder pickupLocationBuilder = Location.Builder.newInstance();
String pickupLocationId = shipmentConfig.getString("pickup.locationId");
if (pickupLocationId == null) pickupLocationId = shipmentConfig.getString("pickup.location.id");
if (pickupLocationId != null) {
pickupLocationBuilder.setId(pickupLocationId);
}
//pickup-coord
Coordinate pickupCoord = getCoord(shipmentConfig, "pickup.");
if (pickupCoord == null) pickupCoord = getCoord(shipmentConfig, "pickup.location.");
if (pickupCoord != null) {
pickupLocationBuilder.setCoordinate(pickupCoord);
}
//pickup.location.index
String pickupLocationIndex = shipmentConfig.getString("pickup.location.index");
if (pickupLocationIndex != null) pickupLocationBuilder.setIndex(Integer.parseInt(pickupLocationIndex));
builder.setPickupLocation(pickupLocationBuilder.build());
//pickup-serviceTime
String pickupServiceTime = shipmentConfig.getString("pickup.duration");
if (pickupServiceTime != null) builder.setPickupServiceTime(Double.parseDouble(pickupServiceTime));
//pickup-tw
List<HierarchicalConfiguration> pickupTWConfigs = shipmentConfig.configurationsAt("pickup.timeWindows.timeWindow");
if (!pickupTWConfigs.isEmpty()) {
for (HierarchicalConfiguration pu_twConfig : pickupTWConfigs) {
builder.addPickupTimeWindow(TimeWindow.newInstance(pu_twConfig.getDouble("start"), pu_twConfig.getDouble("end")));
}
}
//delivery location
//delivery-locationId
Location.Builder deliveryLocationBuilder = Location.Builder.newInstance();
String deliveryLocationId = shipmentConfig.getString("delivery.locationId");
if (deliveryLocationId == null) deliveryLocationId = shipmentConfig.getString("delivery.location.id");
if (deliveryLocationId != null) {
deliveryLocationBuilder.setId(deliveryLocationId);
// builder.setDeliveryLocationId(deliveryLocationId);
}
//delivery-coord
Coordinate deliveryCoord = getCoord(shipmentConfig, "delivery.");
if (deliveryCoord == null) deliveryCoord = getCoord(shipmentConfig, "delivery.location.");
if (deliveryCoord != null) {
deliveryLocationBuilder.setCoordinate(deliveryCoord);
}
String deliveryLocationIndex = shipmentConfig.getString("delivery.location.index");
if (deliveryLocationIndex != null)
deliveryLocationBuilder.setIndex(Integer.parseInt(deliveryLocationIndex));
builder.setDeliveryLocation(deliveryLocationBuilder.build());
//delivery-serviceTime
String deliveryServiceTime = shipmentConfig.getString("delivery.duration");
if (deliveryServiceTime != null) builder.setDeliveryServiceTime(Double.parseDouble(deliveryServiceTime));
//delivery-tw
List<HierarchicalConfiguration> deliveryTWConfigs = shipmentConfig.configurationsAt("delivery.timeWindows.timeWindow");
if (!deliveryTWConfigs.isEmpty()) {
for (HierarchicalConfiguration dl_twConfig : deliveryTWConfigs) {
builder.addDeliveryTimeWindow(TimeWindow.newInstance(dl_twConfig.getDouble("start"), dl_twConfig.getDouble("end")));
}
}
//read skills
String skillString = shipmentConfig.getString("requiredSkills");
if (skillString != null) {
String cleaned = skillString.replaceAll("\\s", "");
String[] skillTokens = cleaned.split("[,;]");
for (String skill : skillTokens) builder.addRequiredSkill(skill.toLowerCase());
}
//build shipment
Shipment shipment = builder.build();
// vrpBuilder.addJob(shipment);
shipmentMap.put(shipment.getId(), shipment);
}
}
private static Coordinate getCoord(HierarchicalConfiguration serviceConfig, String prefix) {
Coordinate pickupCoord = null;
if (serviceConfig.getString(prefix + "coord[@x]") != null && serviceConfig.getString(prefix + "coord[@y]") != null) {
double x = Double.parseDouble(serviceConfig.getString(prefix + "coord[@x]"));
double y = Double.parseDouble(serviceConfig.getString(prefix + "coord[@y]"));
pickupCoord = Coordinate.newInstance(x, y);
}
return pickupCoord;
}
private void readServices(XMLConfiguration vrpProblem) {
List<HierarchicalConfiguration> serviceConfigs = vrpProblem.configurationsAt("services.service");
for (HierarchicalConfiguration serviceConfig : serviceConfigs) {
String id = serviceConfig.getString("[@id]");
if (id == null) throw new IllegalArgumentException("service[@id] is missing.");
String type = serviceConfig.getString("[@type]");
if (type == null) type = "service";
String capacityString = serviceConfig.getString("capacity-demand");
boolean capacityDimensionsExist = serviceConfig.containsKey("capacity-dimensions.dimension(0)");
if (capacityString == null && !capacityDimensionsExist) {
throw new IllegalArgumentException("capacity of service is not set. use 'capacity-dimensions'");
}
if (capacityString != null && capacityDimensionsExist) {
throw new IllegalArgumentException("either use capacity or capacity-dimension, not both. prefer the use of 'capacity-dimensions' over 'capacity'.");
}
Service.Builder builder;
if (capacityString != null) {
builder = serviceBuilderFactory.createBuilder(type, id, Integer.parseInt(capacityString));
} else {
builder = serviceBuilderFactory.createBuilder(type, id, null);
List<HierarchicalConfiguration> dimensionConfigs = serviceConfig.configurationsAt("capacity-dimensions.dimension");
for (HierarchicalConfiguration dimension : dimensionConfigs) {
Integer index = dimension.getInt("[@index]");
Integer value = dimension.getInt("");
builder.addSizeDimension(index, value);
}
}
//name
String name = serviceConfig.getString("name");
if (name != null) builder.setName(name);
//location
Location.Builder locationBuilder = Location.Builder.newInstance();
String serviceLocationId = serviceConfig.getString("locationId");
if (serviceLocationId == null) {
serviceLocationId = serviceConfig.getString("location.id");
}
if (serviceLocationId != null) locationBuilder.setId(serviceLocationId);
Coordinate serviceCoord = getCoord(serviceConfig, "");
if (serviceCoord == null) serviceCoord = getCoord(serviceConfig, "location.");
if (serviceCoord != null) {
locationBuilder.setCoordinate(serviceCoord);
}
String locationIndex = serviceConfig.getString("location.index");
if (locationIndex != null) locationBuilder.setIndex(Integer.parseInt(locationIndex));
builder.setLocation(locationBuilder.build());
if (serviceConfig.containsKey("duration")) {
builder.setServiceTime(serviceConfig.getDouble("duration"));
}
List<HierarchicalConfiguration> deliveryTWConfigs = serviceConfig.configurationsAt("timeWindows.timeWindow");
if (!deliveryTWConfigs.isEmpty()) {
for (HierarchicalConfiguration twConfig : deliveryTWConfigs) {
builder.addTimeWindow(TimeWindow.newInstance(twConfig.getDouble("start"), twConfig.getDouble("end")));
}
}
//read skills
String skillString = serviceConfig.getString("requiredSkills");
if (skillString != null) {
String cleaned = skillString.replaceAll("\\s", "");
String[] skillTokens = cleaned.split("[,;]");
for (String skill : skillTokens) builder.addRequiredSkill(skill.toLowerCase());
}
//build service
Service service = builder.build();
serviceMap.put(service.getId(), service);
// vrpBuilder.addJob(service);
}
}
private void readVehiclesAndTheirTypes(XMLConfiguration vrpProblem) {
//read vehicle-types
Map<String, VehicleType> types = new HashMap<String, VehicleType>();
List<HierarchicalConfiguration> typeConfigs = vrpProblem.configurationsAt("vehicleTypes.type");
for (HierarchicalConfiguration typeConfig : typeConfigs) {
String typeId = typeConfig.getString("id");
if (typeId == null) throw new IllegalArgumentException("typeId is missing.");
String capacityString = typeConfig.getString("capacity");
boolean capacityDimensionsExist = typeConfig.containsKey("capacity-dimensions.dimension(0)");
if (capacityString == null && !capacityDimensionsExist) {
throw new IllegalArgumentException("capacity of type is not set. use 'capacity-dimensions'");
}
if (capacityString != null && capacityDimensionsExist) {
throw new IllegalArgumentException("either use capacity or capacity-dimension, not both. prefer the use of 'capacity-dimensions' over 'capacity'.");
}
VehicleTypeImpl.Builder typeBuilder;
if (capacityString != null) {
typeBuilder = VehicleTypeImpl.Builder.newInstance(typeId).addCapacityDimension(0, Integer.parseInt(capacityString));
} else {
typeBuilder = VehicleTypeImpl.Builder.newInstance(typeId);
List<HierarchicalConfiguration> dimensionConfigs = typeConfig.configurationsAt("capacity-dimensions.dimension");
for (HierarchicalConfiguration dimension : dimensionConfigs) {
Integer index = dimension.getInt("[@index]");
Integer value = dimension.getInt("");
typeBuilder.addCapacityDimension(index, value);
}
}
Double fix = typeConfig.getDouble("costs.fixed");
Double timeC = typeConfig.getDouble("costs.time");
Double distC = typeConfig.getDouble("costs.distance");
if(typeConfig.containsKey("costs.service")){
Double serviceC = typeConfig.getDouble("costs.service");
if (serviceC != null) typeBuilder.setCostPerServiceTime(serviceC);
}
if(typeConfig.containsKey("costs.wait")){
Double waitC = typeConfig.getDouble("costs.wait");
if (waitC != null) typeBuilder.setCostPerWaitingTime(waitC);
}
if (fix != null) typeBuilder.setFixedCost(fix);
if (timeC != null) typeBuilder.setCostPerTransportTime(timeC);
if (distC != null) typeBuilder.setCostPerDistance(distC);
VehicleType type = typeBuilder.build();
String id = type.getTypeId();
types.put(id, type);
}
//read vehicles
List<HierarchicalConfiguration> vehicleConfigs = vrpProblem.configurationsAt("vehicles.vehicle");
boolean doNotWarnAgain = false;
for (HierarchicalConfiguration vehicleConfig : vehicleConfigs) {
String vehicleId = vehicleConfig.getString("id");
if (vehicleId == null) throw new IllegalArgumentException("vehicleId is missing.");
Builder builder = VehicleImpl.Builder.newInstance(vehicleId);
String typeId = vehicleConfig.getString("typeId");
if (typeId == null) throw new IllegalArgumentException("typeId is missing.");
String vType = vehicleConfig.getString("[@type]");
if (vType != null) {
if (vType.equals("penalty")) {
typeId += "_penalty";
}
}
VehicleType type = types.get(typeId);
if (type == null) throw new IllegalArgumentException("vehicleType with typeId " + typeId + " is missing.");
builder.setType(type);
//read startlocation
Location.Builder startLocationBuilder = Location.Builder.newInstance();
String locationId = vehicleConfig.getString("location.id");
if (locationId == null) {
locationId = vehicleConfig.getString("startLocation.id");
}
startLocationBuilder.setId(locationId);
String coordX = vehicleConfig.getString("location.coord[@x]");
String coordY = vehicleConfig.getString("location.coord[@y]");
if (coordX == null || coordY == null) {
coordX = vehicleConfig.getString("startLocation.coord[@x]");
coordY = vehicleConfig.getString("startLocation.coord[@y]");
}
if (coordX == null || coordY == null) {
if (!doNotWarnAgain) {
logger.debug("location.coord is missing. will not warn you again.");
doNotWarnAgain = true;
}
} else {
Coordinate coordinate = Coordinate.newInstance(Double.parseDouble(coordX), Double.parseDouble(coordY));
startLocationBuilder.setCoordinate(coordinate);
}
String index = vehicleConfig.getString("startLocation.index");
if (index == null) index = vehicleConfig.getString("location.index");
if (index != null) {
startLocationBuilder.setIndex(Integer.parseInt(index));
}
builder.setStartLocation(startLocationBuilder.build());
//read endlocation
Location.Builder endLocationBuilder = Location.Builder.newInstance();
boolean hasEndLocation = false;
String endLocationId = vehicleConfig.getString("endLocation.id");
if (endLocationId != null) {
hasEndLocation = true;
endLocationBuilder.setId(endLocationId);
}
String endCoordX = vehicleConfig.getString("endLocation.coord[@x]");
String endCoordY = vehicleConfig.getString("endLocation.coord[@y]");
if (endCoordX == null || endCoordY == null) {
if (!doNotWarnAgain) {
logger.debug("endLocation.coord is missing. will not warn you again.");
doNotWarnAgain = true;
}
} else {
Coordinate coordinate = Coordinate.newInstance(Double.parseDouble(endCoordX), Double.parseDouble(endCoordY));
hasEndLocation = true;
endLocationBuilder.setCoordinate(coordinate);
}
String endLocationIndex = vehicleConfig.getString("endLocation.index");
if (endLocationIndex != null) {
hasEndLocation = true;
endLocationBuilder.setIndex(Integer.parseInt(endLocationIndex));
}
if (hasEndLocation) builder.setEndLocation(endLocationBuilder.build());
//read timeSchedule
String start = vehicleConfig.getString("timeSchedule.start");
String end = vehicleConfig.getString("timeSchedule.end");
if (start != null) builder.setEarliestStart(Double.parseDouble(start));
if (end != null) builder.setLatestArrival(Double.parseDouble(end));
//read return2depot
String returnToDepot = vehicleConfig.getString("returnToDepot");
if (returnToDepot != null) {
builder.setReturnToDepot(vehicleConfig.getBoolean("returnToDepot"));
}
//read skills
String skillString = vehicleConfig.getString("skills");
if (skillString != null) {
String cleaned = skillString.replaceAll("\\s", "");
String[] skillTokens = cleaned.split("[,;]");
for (String skill : skillTokens) builder.addSkill(skill.toLowerCase());
}
// read break
List<HierarchicalConfiguration> breakTWConfigs = vehicleConfig.configurationsAt("breaks.timeWindows.timeWindow");
if (!breakTWConfigs.isEmpty()) {
String breakDurationString = vehicleConfig.getString("breaks.duration");
Break.Builder current_break = Break.Builder.newInstance(vehicleId);
current_break.setServiceTime(Double.parseDouble(breakDurationString));
for (HierarchicalConfiguration twConfig : breakTWConfigs) {
current_break.addTimeWindow(TimeWindow.newInstance(twConfig.getDouble("start"), twConfig.getDouble("end")));
}
builder.setBreak(current_break.build());
}
//build vehicle
VehicleImpl vehicle = builder.build();
vrpBuilder.addVehicle(vehicle);
vehicleMap.put(vehicleId, vehicle);
}
}
}

View file

@ -0,0 +1,429 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.graphhopper.jsprit.io.problem;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.Skills;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Break;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
import com.graphhopper.jsprit.core.util.Solutions;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class VrpXMLWriter {
static class XMLConf extends XMLConfiguration {
/**
*
*/
private static final long serialVersionUID = 1L;
public Document createDoc() throws ConfigurationException {
return createDocument();
}
}
private Logger log = LoggerFactory.getLogger(VrpXMLWriter.class);
private VehicleRoutingProblem vrp;
private Collection<VehicleRoutingProblemSolution> solutions;
private boolean onlyBestSolution = false;
public VrpXMLWriter(VehicleRoutingProblem vrp, Collection<VehicleRoutingProblemSolution> solutions, boolean onlyBestSolution) {
this.vrp = vrp;
this.solutions = new ArrayList<VehicleRoutingProblemSolution>(solutions);
this.onlyBestSolution = onlyBestSolution;
}
public VrpXMLWriter(VehicleRoutingProblem vrp, Collection<VehicleRoutingProblemSolution> solutions) {
this.vrp = vrp;
this.solutions = solutions;
}
public VrpXMLWriter(VehicleRoutingProblem vrp) {
this.vrp = vrp;
this.solutions = null;
}
private static Logger logger = LoggerFactory.getLogger(VrpXMLWriter.class);
public void write(String filename) {
if (!filename.endsWith(".xml")) filename += ".xml";
log.info("write vrp: " + filename);
XMLConf xmlConfig = new XMLConf();
xmlConfig.setFileName(filename);
xmlConfig.setRootElementName("problem");
xmlConfig.setAttributeSplittingDisabled(true);
xmlConfig.setDelimiterParsingDisabled(true);
writeProblemType(xmlConfig);
writeVehiclesAndTheirTypes(xmlConfig);
//might be sorted?
List<Job> jobs = new ArrayList<Job>();
jobs.addAll(vrp.getJobs().values());
for (VehicleRoute r : vrp.getInitialVehicleRoutes()) {
jobs.addAll(r.getTourActivities().getJobs());
}
writeServices(xmlConfig, jobs);
writeShipments(xmlConfig, jobs);
writeInitialRoutes(xmlConfig);
if(onlyBestSolution && solutions != null) {
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
solutions.clear();
solutions.add(solution);
}
writeSolutions(xmlConfig);
OutputFormat format = new OutputFormat();
format.setIndenting(true);
format.setIndent(5);
try {
Document document = xmlConfig.createDoc();
Element element = document.getDocumentElement();
element.setAttribute("xmlns", "http://www.w3schools.com");
element.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
element.setAttribute("xsi:schemaLocation", "http://www.w3schools.com vrp_xml_schema.xsd");
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
try {
Writer out = new FileWriter(filename);
XMLSerializer serializer = new XMLSerializer(out, format);
serializer.serialize(xmlConfig.getDocument());
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void writeInitialRoutes(XMLConf xmlConfig) {
if (vrp.getInitialVehicleRoutes().isEmpty()) return;
String path = "initialRoutes.route";
int routeCounter = 0;
for (VehicleRoute route : vrp.getInitialVehicleRoutes()) {
xmlConfig.setProperty(path + "(" + routeCounter + ").driverId", route.getDriver().getId());
xmlConfig.setProperty(path + "(" + routeCounter + ").vehicleId", route.getVehicle().getId());
xmlConfig.setProperty(path + "(" + routeCounter + ").start", route.getStart().getEndTime());
int actCounter = 0;
for (TourActivity act : route.getTourActivities().getActivities()) {
xmlConfig.setProperty(path + "(" + routeCounter + ").act(" + actCounter + ")[@type]", act.getName());
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (job instanceof Service) {
xmlConfig.setProperty(path + "(" + routeCounter + ").act(" + actCounter + ").serviceId", job.getId());
} else if (job instanceof Shipment) {
xmlConfig.setProperty(path + "(" + routeCounter + ").act(" + actCounter + ").shipmentId", job.getId());
} else if (job instanceof Break) {
xmlConfig.setProperty(path + "(" + routeCounter + ").act(" + actCounter + ").breakId", job.getId());
} else {
throw new IllegalStateException("cannot write solution correctly since job-type is not know. make sure you use either service or shipment, or another writer");
}
}
xmlConfig.setProperty(path + "(" + routeCounter + ").act(" + actCounter + ").arrTime", act.getArrTime());
xmlConfig.setProperty(path + "(" + routeCounter + ").act(" + actCounter + ").endTime", act.getEndTime());
actCounter++;
}
xmlConfig.setProperty(path + "(" + routeCounter + ").end", route.getEnd().getArrTime());
routeCounter++;
}
}
private void writeSolutions(XMLConf xmlConfig) {
if (solutions == null) return;
String solutionPath = "solutions.solution";
int counter = 0;
for (VehicleRoutingProblemSolution solution : solutions) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").cost", solution.getCost());
int routeCounter = 0;
for (VehicleRoute route : solution.getRoutes()) {
// xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").cost", route.getCost());
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").driverId", route.getDriver().getId());
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").vehicleId", route.getVehicle().getId());
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").start", route.getStart().getEndTime());
int actCounter = 0;
for (TourActivity act : route.getTourActivities().getActivities()) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ")[@type]", act.getName());
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (job instanceof Service) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").serviceId", job.getId());
} else if (job instanceof Shipment) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").shipmentId", job.getId());
} else if (job instanceof Break) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").breakId", job.getId());
} else {
throw new IllegalStateException("cannot write solution correctly since job-type is not know. make sure you use either service or shipment, or another writer");
}
}
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").arrTime", act.getArrTime());
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").endTime", act.getEndTime());
actCounter++;
}
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").end", route.getEnd().getArrTime());
routeCounter++;
}
int unassignedJobCounter = 0;
for (Job unassignedJob : solution.getUnassignedJobs()) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").unassignedJobs.job(" + unassignedJobCounter + ")[@id]", unassignedJob.getId());
unassignedJobCounter++;
}
counter++;
}
}
private void writeServices(XMLConf xmlConfig, List<Job> jobs) {
String shipmentPathString = "services.service";
int counter = 0;
for (Job j : jobs) {
if (!(j instanceof Service)) continue;
Service service = (Service) j;
xmlConfig.setProperty(shipmentPathString + "(" + counter + ")[@id]", service.getId());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ")[@type]", service.getType());
if (service.getLocation().getId() != null)
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").location.id", service.getLocation().getId());
if (service.getLocation().getCoordinate() != null) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").location.coord[@x]", service.getLocation().getCoordinate().getX());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").location.coord[@y]", service.getLocation().getCoordinate().getY());
}
if (service.getLocation().getIndex() != Location.NO_INDEX) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").location.index", service.getLocation().getIndex());
}
for (int i = 0; i < service.getSize().getNuOfDimensions(); i++) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").capacity-dimensions.dimension(" + i + ")[@index]", i);
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").capacity-dimensions.dimension(" + i + ")", service.getSize().get(i));
}
Collection<TimeWindow> tws = service.getTimeWindows();
int index = 0;
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").duration", service.getServiceDuration());
for(TimeWindow tw : tws) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").timeWindows.timeWindow(" + index + ").start", tw.getStart());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").timeWindows.timeWindow(" + index + ").end", tw.getEnd());
++index;
}
//skills
String skillString = getSkillString(service);
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").requiredSkills", skillString);
//name
if (service.getName() != null) {
if (!service.getName().equals("no-name")) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").name", service.getName());
}
}
counter++;
}
}
private void writeShipments(XMLConf xmlConfig, List<Job> jobs) {
String shipmentPathString = "shipments.shipment";
int counter = 0;
for (Job j : jobs) {
if (!(j instanceof Shipment)) continue;
Shipment shipment = (Shipment) j;
xmlConfig.setProperty(shipmentPathString + "(" + counter + ")[@id]", shipment.getId());
// xmlConfig.setProperty(shipmentPathString + "("+counter+")[@type]", service.getType());
if (shipment.getPickupLocation().getId() != null)
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.location.id", shipment.getPickupLocation().getId());
if (shipment.getPickupLocation().getCoordinate() != null) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.location.coord[@x]", shipment.getPickupLocation().getCoordinate().getX());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.location.coord[@y]", shipment.getPickupLocation().getCoordinate().getY());
}
if (shipment.getPickupLocation().getIndex() != Location.NO_INDEX) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.location.index", shipment.getPickupLocation().getIndex());
}
Collection<TimeWindow> pu_tws = shipment.getPickupTimeWindows();
int index = 0;
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.duration", shipment.getPickupServiceTime());
for(TimeWindow tw : pu_tws) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.timeWindows.timeWindow(" + index + ").start", tw.getStart());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").pickup.timeWindows.timeWindow(" + index + ").end", tw.getEnd());
++index;
}
if (shipment.getDeliveryLocation().getId() != null)
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.location.id", shipment.getDeliveryLocation().getId());
if (shipment.getDeliveryLocation().getCoordinate() != null) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.location.coord[@x]", shipment.getDeliveryLocation().getCoordinate().getX());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.location.coord[@y]", shipment.getDeliveryLocation().getCoordinate().getY());
}
if (shipment.getDeliveryLocation().getIndex() != Location.NO_INDEX) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.location.index", shipment.getDeliveryLocation().getIndex());
}
Collection<TimeWindow> del_tws = shipment.getDeliveryTimeWindows();
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.duration", shipment.getDeliveryServiceTime());
index = 0;
for(TimeWindow tw : del_tws) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.timeWindows.timeWindow(" + index + ").start", tw.getStart());
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").delivery.timeWindows.timeWindow(" + index + ").end", tw.getEnd());
++index;
}
for (int i = 0; i < shipment.getSize().getNuOfDimensions(); i++) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").capacity-dimensions.dimension(" + i + ")[@index]", i);
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").capacity-dimensions.dimension(" + i + ")", shipment.getSize().get(i));
}
//skills
String skillString = getSkillString(shipment);
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").requiredSkills", skillString);
//name
if (shipment.getName() != null) {
if (!shipment.getName().equals("no-name")) {
xmlConfig.setProperty(shipmentPathString + "(" + counter + ").name", shipment.getName());
}
}
counter++;
}
}
private void writeProblemType(XMLConfiguration xmlConfig) {
xmlConfig.setProperty("problemType.fleetSize", vrp.getFleetSize());
}
private void writeVehiclesAndTheirTypes(XMLConfiguration xmlConfig) {
//vehicles
String vehiclePathString = Schema.VEHICLES + "." + Schema.VEHICLE;
int counter = 0;
for (Vehicle vehicle : vrp.getVehicles()) {
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").id", vehicle.getId());
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").typeId", vehicle.getType().getTypeId());
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").startLocation.id", vehicle.getStartLocation().getId());
if (vehicle.getStartLocation().getCoordinate() != null) {
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").startLocation.coord[@x]", vehicle.getStartLocation().getCoordinate().getX());
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").startLocation.coord[@y]", vehicle.getStartLocation().getCoordinate().getY());
}
if (vehicle.getStartLocation().getIndex() != Location.NO_INDEX) {
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").startLocation.index", vehicle.getStartLocation().getIndex());
}
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").endLocation.id", vehicle.getEndLocation().getId());
if (vehicle.getEndLocation().getCoordinate() != null) {
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").endLocation.coord[@x]", vehicle.getEndLocation().getCoordinate().getX());
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").endLocation.coord[@y]", vehicle.getEndLocation().getCoordinate().getY());
}
if (vehicle.getEndLocation().getIndex() != Location.NO_INDEX) {
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").endLocation.index", vehicle.getEndLocation().getId());
}
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").timeSchedule.start", vehicle.getEarliestDeparture());
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").timeSchedule.end", vehicle.getLatestArrival());
if (vehicle.getBreak() != null) {
Collection<TimeWindow> tws = vehicle.getBreak().getTimeWindows();
int index = 0;
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").breaks.duration", vehicle.getBreak().getServiceDuration());
for(TimeWindow tw : tws) {
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").breaks.timeWindows.timeWindow(" + index + ").start", tw.getStart());
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").breaks.timeWindows.timeWindow(" + index + ").end", tw.getEnd());
++index;
}
}
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").returnToDepot", vehicle.isReturnToDepot());
//write skills
String skillString = getSkillString(vehicle);
xmlConfig.setProperty(vehiclePathString + "(" + counter + ").skills", skillString);
counter++;
}
//types
String typePathString = Schema.builder().append(Schema.TYPES).dot(Schema.TYPE).build();
int typeCounter = 0;
for (VehicleType type : vrp.getTypes()) {
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").id", type.getTypeId());
for (int i = 0; i < type.getCapacityDimensions().getNuOfDimensions(); i++) {
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").capacity-dimensions.dimension(" + i + ")[@index]", i);
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").capacity-dimensions.dimension(" + i + ")", type.getCapacityDimensions().get(i));
}
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").costs.fixed", type.getVehicleCostParams().fix);
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").costs.distance", type.getVehicleCostParams().perDistanceUnit);
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").costs.time", type.getVehicleCostParams().perTransportTimeUnit);
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").costs.service", type.getVehicleCostParams().perServiceTimeUnit);
xmlConfig.setProperty(typePathString + "(" + typeCounter + ").costs.wait", type.getVehicleCostParams().perWaitingTimeUnit);
typeCounter++;
}
}
private String getSkillString(Vehicle vehicle) {
return createSkillString(vehicle.getSkills());
}
private String getSkillString(Job job) {
return createSkillString(job.getRequiredSkills());
}
private String createSkillString(Skills skills) {
if (skills.values().size() == 0) return null;
String skillString = null;
for (String skill : skills.values()) {
if (skillString == null) skillString = skill;
else skillString += ", " + skill;
}
return skillString;
}
}