1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00
This commit is contained in:
oblonski 2016-05-09 22:29:48 +02:00
parent c4c7de152f
commit ee3b1589ba
73 changed files with 223 additions and 211 deletions

View file

@ -121,7 +121,7 @@ public class SearchStrategy {
/**
* Runs the search-strategy and its according modules, and returns DiscoveredSolution.
* <p/>
* <p>
* <p>This involves three basic steps: 1) Selecting a solution from solutions (input parameter) according to {@link com.graphhopper.jsprit.core.algorithm.selector.SolutionSelector}, 2) running the modules
* ({@link SearchStrategyModule}) on the selectedSolution and 3) accepting the new solution according to {@link com.graphhopper.jsprit.core.algorithm.acceptor.SolutionAcceptor}.
* <p> Note that after 1) the selected solution is copied, thus the original solution is not modified.

View file

@ -182,7 +182,7 @@ public class VehicleRoutingAlgorithm {
/**
* Runs the vehicle routing algorithm and returns a number of generated solutions.
* <p/>
* <p>
* <p>The algorithm runs as long as it is specified in nuOfIterations and prematureBreak. In each iteration it selects a searchStrategy according
* to searchStrategyManager and runs the strategy to improve solutions.
* <p>Note that clients are allowed to observe/listen the algorithm. See {@link com.graphhopper.jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListener} and its according listeners.

View file

@ -76,7 +76,7 @@ public class VehicleRoutingAlgorithmBuilder {
/**
* Sets custom objective function.
* <p/>
* <p>
* <p>If objective function is not set, a default function is applied (which basically minimizes
* fixed and variable transportation costs ({@link VariablePlusFixedSolutionCostCalculatorFactory}).
*
@ -99,7 +99,7 @@ public class VehicleRoutingAlgorithmBuilder {
/**
* Adds core constraints.
* <p/>
* <p>
* <p>Thus, it adds vehicle-capacity, time-window and skills constraints and their
* required stateUpdater.
*/
@ -113,7 +113,7 @@ public class VehicleRoutingAlgorithmBuilder {
* By default, marginal transportation costs are calculated. Thus when inserting
* act_k between act_i and act_j, marginal (additional) transportation costs
* are basically c(act_i,act_k)+c(act_k,act_j)-c(act_i,act_j).
* <p/>
* <p>
* <p>Do not use this method, if you plan to control the insertion heuristic
* entirely via hard- and soft-constraints.
*/
@ -145,7 +145,7 @@ public class VehicleRoutingAlgorithmBuilder {
/**
* Builds and returns the algorithm.
* <p/>
* <p>
* <p>If algorithmConfigFile is set, it reads the configuration.
*
* @return the algorithm

View file

@ -18,7 +18,7 @@ public class AcceptNewRemoveFirst implements SolutionAcceptor {
/**
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
* Consequently, the worst solution is removed from solutions, and the new solution added.
* <p/>
* <p>
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
*/
@Override

View file

@ -23,7 +23,7 @@ import java.util.Collection;
/**
* Acceptor that accepts solutions to be memorized only better solutions.
* <p/>
* <p>
* <p>If there is enough memory, every solution will be accepted. If there is no memory anymore and the solution
* to be evaluated is better than the worst, the worst will be replaced by the new solution.</p>
*/
@ -38,7 +38,7 @@ public class GreedyAcceptance implements SolutionAcceptor {
/**
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
* Consequently, the worst solution is removed from solutions, and the new solution added.
* <p/>
* <p>
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
*/
@Override

View file

@ -29,21 +29,21 @@ import java.util.Collection;
/**
* ThresholdAcceptance-Function defined by Schrimpf et al. (2000).
* <p/>
* <p>
* <p>The <b>idea</b> can be described as follows: Most problems do not only have one unique minimum (maximum) but
* a number of local minima (maxima). To avoid to get stuck in a local minimum at the beginning of a search
* this threshold-acceptance function accepts also worse solution at the beginning (in contrary to a greedy
* approach which only accepts better solutions), and converges to a greedy approach at the end. <br>
* The difficulty is to define (i) an appropriate initial threshold and (ii) a corresponding function describing
* how the threshold converges to zero, i.e. the greedy threshold.
* <p/>
* <p>
* <p>ad i) The initial threshold is determined by a random walk through the search space.
* The random walk currently runs with the following algorithm: src/main/resources/randomWalk.xml. It runs
* as long as it is specified in nuOfWarmupIterations. In the first iteration or walk respectively the algorithm generates a solution.
* This solution in turn is the basis of the next walk yielding to another solution value ... and so on.
* Each solution value is memorized since the initial threshold is essentially a function of the standard deviation of these solution values.
* To be more precise: initial threshold = stddev(solution values) / 2.
* <p/>
* <p>
* <p>ad ii) The threshold of iteration i is determined as follows:
* threshold(i) = initialThreshold * Math.exp(-Math.log(2) * (i / nuOfTotalIterations) / alpha)
* To get a better understanding of the threshold-function go to Wolfram Alpha and plot the following line
@ -55,7 +55,7 @@ import java.util.Collection;
* alpha = 0.1<br>
* x corresponds to i iterations and<br>
* y to the threshold(i)
* <p/>
* <p>
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck (2000).
* Record breaking optimization results using the ruin and recreate principle.
* Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.

View file

@ -31,7 +31,7 @@ public interface SolutionAcceptor {
/**
* Accepts solution or not, and returns true if a new solution has been accepted.
* <p/>
* <p>
* <p>If the solution is accepted, it is added to solutions, i.e. the solutions-collections is modified.
*
* @param solutions collection of existing solutions

View file

@ -28,18 +28,18 @@ import java.net.URL;
/**
* Factory that creates the {@link com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters:
* <p/>
* <p/>
* <p>
* <p>
* R&R_random (prob=0.5, F=0.5);
* R&R_radial (prob=0.5, F=0.3);
* threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100);
* nuOfIterations=2000
* <p/>
* <p>
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck.
* Record breaking optimization results using the ruin and recreate principle.
* Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.
* URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136
* <p/>
* <p>
* <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml.
*
* @author stefan schroeder

View file

@ -28,18 +28,18 @@ import java.net.URL;
/**
* Factory that creates the {@link com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters:
* <p/>
* <p/>
* <p>
* <p>
* R&R_random (prob=0.5, F=0.5);
* R&R_radial (prob=0.5, F=0.3);
* threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100);
* nuOfIterations=2000
* <p/>
* <p>
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck.
* Record breaking optimization results using the ruin and recreate principle.
* Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.
* URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136
* <p/>
* <p>
* <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml.
*
* @author stefan schroeder

View file

@ -25,7 +25,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
/**
* Estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location.
* <p/>
* <p>
* <p>If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero.
*
* @author schroeder
@ -36,7 +36,7 @@ class AdditionalAccessEgressCalculator {
/**
* Constructs the estimator that estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location.
* <p/>
* <p>
* <p>If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero.
*
* @author schroeder

View file

@ -95,7 +95,7 @@ public class JobInsertionCostsCalculatorBuilder {
/**
* Constructs the builder.
* <p/>
* <p>
* <p>Some calculators require information from the overall algorithm or the higher-level insertion procedure. Thus listeners inform them.
* These listeners are cached in the according list and can thus be added when its time to add them.
*
@ -143,7 +143,7 @@ public class JobInsertionCostsCalculatorBuilder {
/**
* Sets a flag to build a calculator based on local calculations.
* <p/>
* <p>
* <p>Insertion of a job and job-activity is evaluated based on the previous and next activity.
*
* @param addDefaultCostCalc

View file

@ -30,7 +30,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
* Calculates activity insertion costs locally, i.e. by comparing the additional costs of insertion the new activity k between
* activity i (prevAct) and j (nextAct).
* Additional costs are then basically calculated as delta c = c_ik + c_kj - c_ij.
* <p/>
* <p>
* <p>Note once time has an effect on costs this class requires activity endTimes.
*
* @author stefan

View file

@ -31,7 +31,7 @@ import java.util.List;
/**
* Insertion based on regret approach.
* <p/>
* <p>
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
@ -52,7 +52,7 @@ public class RegretInsertion extends AbstractInsertionStrategy {
/**
* Sets the scoring function.
* <p/>
* <p>
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction to score
@ -77,7 +77,7 @@ public class RegretInsertion extends AbstractInsertionStrategy {
/**
* Runs insertion.
* <p/>
* <p>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*/
@Override

View file

@ -32,7 +32,7 @@ import java.util.concurrent.*;
/**
* Insertion based on regret approach.
* <p/>
* <p>
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
@ -53,7 +53,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
/**
* Sets the scoring function.
* <p/>
* <p>
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction to score
@ -79,7 +79,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
/**
* Runs insertion.
* <p/>
* <p>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*
* @throws java.lang.RuntimeException if smth went wrong with thread execution

View file

@ -32,7 +32,7 @@ import java.util.concurrent.Future;
/**
* Insertion based on regret approach.
* <p/>
* <p>
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
@ -60,7 +60,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
/**
* Sets the scoring function.
* <p/>
* <p>
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction to score
@ -100,7 +100,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
/**
* Runs insertion.
* <p/>
* <p>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*
* @throws java.lang.RuntimeException if smth went wrong with thread execution

View file

@ -29,7 +29,7 @@ import java.util.*;
/**
* Insertion based on regret approach.
* <p/>
* <p>
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
@ -65,7 +65,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
/**
* Sets the scoring function.
* <p/>
* <p>
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction to score
@ -94,7 +94,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
/**
* Runs insertion.
* <p/>
* <p>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*/
@Override

View file

@ -46,7 +46,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
/**
* true if a vehicle(-type) is allowed to take over the whole route that was previously served by another vehicle
* <p/>
* <p>
* <p>vehicleSwitch allowed makes sense if fleet consists of vehicles with different capacities such that one
* can start with a small vehicle, but as the number of customers grows bigger vehicles can be operated, i.e.
* bigger vehicles can take over the route that was previously served by a small vehicle.

View file

@ -95,7 +95,7 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio
/**
* Removes a fraction of jobs from vehicleRoutes.
* <p/>
* <p>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/
@Override

View file

@ -64,7 +64,7 @@ public final class RuinRandom extends AbstractRuinStrategy {
/**
* Removes a fraction of jobs from vehicleRoutes.
* <p/>
* <p>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/
@Override

View file

@ -68,7 +68,7 @@ public final class RuinWorst extends AbstractRuinStrategy {
/**
* Removes a fraction of jobs from vehicleRoutes.
* <p/>
* <p>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/
@Override

View file

@ -26,7 +26,7 @@ import com.graphhopper.jsprit.core.util.EuclideanDistanceCalculator;
/**
* Calculator that calculates average distance between two jobs based on the input-transport costs.
* <p/>
* <p>
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
*
* @author stefan schroeder
@ -43,7 +43,7 @@ public class AvgServiceAndShipmentDistance implements JobDistance {
/**
* Calculates and returns the average distance between two jobs based on the input-transport costs.
* <p/>
* <p>
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
*/
@Override

View file

@ -23,7 +23,7 @@ import com.graphhopper.jsprit.core.problem.job.Service;
/**
* Calculator that calculates average distance between two jobs based on the input-transport costs.
* <p/>
* <p>
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
*
* @author stefan schroeder
@ -40,7 +40,7 @@ public class AvgServiceDistance implements JobDistance {
/**
* Calculates and returns the average distance between two jobs based on the input-transport costs.
* <p/>
* <p>
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
*/
@Override

View file

@ -37,7 +37,7 @@ import java.util.*;
/**
* Manages states.
* <p/>
* <p>
* <p>Some condition, rules or constraints are stateful. This StateManager manages these states, i.e. it offers
* methods to add, store and retrieve states based on the problem, vehicle-routes and tour-activities.
*
@ -95,7 +95,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
/**
* Create and returns a stateId with the specified state-name.
* <p/>
* <p>
* <p>If a stateId with the specified name has already been created, it returns the created stateId.</p>
* <p>If the specified is equal to a name that is already used internally, it throws an IllegalStateException</p>
*
@ -485,11 +485,11 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
/**
* Adds state updater.
* <p/>
* <p>
* <p>Note that a state update occurs if route and/or activity states have changed, i.e. if jobs are removed
* or inserted into a route. Thus here, it is assumed that a state updater is either of type InsertionListener,
* RuinListener, ActivityVisitor, ReverseActivityVisitor, RouteVisitor, ReverseRouteVisitor.
* <p/>
* <p>
* <p>The following rule pertain for activity/route visitors:These visitors visits all activities/route in a route subsequently in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes)
* and, second, if a job has been inserted and thus if a route has changed.
*

View file

@ -26,7 +26,7 @@ import com.graphhopper.jsprit.core.util.ActivityTimeTracker;
/**
* Updates arrival and end times of activities.
* <p/>
* <p>
* <p>Note that this modifies arrTime and endTime of each activity in a route.
*
* @author stefan
@ -39,9 +39,9 @@ public class UpdateActivityTimes implements ActivityVisitor, StateUpdater {
/**
* Updates arrival and end times of activities.
* <p/>
* <p>
* <p>Note that this modifies arrTime and endTime of each activity in a route.
* <p/>
* <p>
* <p>ArrTimes and EndTimes can be retrieved by <br>
* <code>activity.getArrTime()</code> and
* <code>activity.getEndTime()</code>

View file

@ -33,7 +33,7 @@ import java.util.Collection;
/**
* Updates load at start and end of route as well as at each activity. And update is triggered when either
* activityVisitor has been started, the insertion process has been started or a job has been inserted.
* <p/>
* <p>
* <p>Note that this only works properly if you register this class as ActivityVisitor AND InsertionStartsListener AND JobInsertedListener.
* The reason behind is that activity states are dependent on route-level states and vice versa. If this is properly registered,
* this dependency is solved automatically.

View file

@ -24,7 +24,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
/**
* A {@link com.graphhopper.jsprit.core.problem.solution.route.activity.ReverseActivityVisitor} that looks forward in the vehicle route and determines
* the maximum capacity utilization (in terms of loads) at subsequent activities.
* <p/>
* <p>
* <p>Assume a vehicle route with the following activity sequence {start,pickup(1,4),delivery(2,3),pickup(3,2),end} where
* pickup(1,2) = pickup(id,cap-demand).<br>
* Future maxLoad for each activity are calculated as follows:<br>

View file

@ -25,10 +25,10 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
/**
* Updates load at activity level.
* <p/>
* <p>
* <p>Note that this assumes that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT.
* If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot.
* <p/>
* <p>
* <p>Thus it DEPENDS on StateTypes.LOAD_AT_DEPOT
*
* @author stefan

View file

@ -27,7 +27,7 @@ import com.graphhopper.jsprit.core.util.ActivityTimeTracker;
/**
* Updates total costs (i.e. transport and activity costs) at route and activity level.
* <p/>
* <p>
* <p>Thus it modifies <code>stateManager.getRouteState(route, StateTypes.COSTS)</code> and <br>
* <code>stateManager.getActivityState(activity, StateTypes.COSTS)</code>
*/
@ -51,7 +51,7 @@ public class UpdateVariableCosts implements ActivityVisitor, StateUpdater {
/**
* Updates total costs (i.e. transport and activity costs) at route and activity level.
* <p/>
* <p>
* <p>Thus it modifies <code>stateManager.getRouteState(route, StateTypes.COSTS)</code> and <br>
* <code>stateManager.getActivityState(activity, StateTypes.COSTS)</code>
*

View file

@ -22,9 +22,9 @@ import org.apache.logging.log4j.Logger;
/**
* Terminates algorithm prematurely based on iterations without any improvement (i.e. new solution acceptance).
* <p/>
* <p>
* <p>Termination will be activated by:<br>
* <p/>
* <p>
* <code>algorithm.setPrematureAlgorithmTermination(this);</code><br>
*
* @author stefan schroeder

View file

@ -29,10 +29,10 @@ import java.util.Collection;
/**
* Terminates algorithm prematurely based on specified time.
* <p/>
* <p>
* <p>Note, TimeTermination must be registered as AlgorithmListener <br>
* TimeTermination will be activated by:<br>
* <p/>
* <p>
* <code>algorithm.setPrematureAlgorithmTermination(this);</code><br>
* <code>algorithm.addListener(this);</code>
*

View file

@ -34,10 +34,10 @@ import java.util.Collection;
/**
* Terminates algorithm prematurely based on variationCoefficient (http://en.wikipedia.org/wiki/Coefficient_of_variation).
* <p/>
* <p>
* <p>Note, that this must be registered as AlgorithmListener <br>
* It will be activated by:<br>
* <p/>
* <p>
* <code>algorithm.setPrematureAlgorithmTermination(this);</code><br>
* <code>algorithm.addListener(this);</code>
*

View file

@ -18,7 +18,7 @@ package com.graphhopper.jsprit.core.problem;
/**
* Capacity with an arbitrary number of capacity-dimension.
* <p/>
* <p>
* <p>Note that this assumes the the values of each capacity dimension can be added up and subtracted
*
* @author schroeder
@ -27,7 +27,7 @@ public class Capacity {
/**
* Adds up two capacities, i.e. sums up each and every capacity dimension, and returns the resulting Capacity.
* <p/>
* <p>
* <p>Note that this assumes that capacity dimension can be added up.
*
* @param cap1 capacity to be added up
@ -83,7 +83,7 @@ public class Capacity {
/**
* Divides every dimension of numerator capacity by the corresponding dimension of denominator capacity,
* , and averages each quotient.
* <p/>
* <p>
* <p>If both nominator.get(i) and denominator.get(i) equal to 0, dimension i is ignored.
* <p>If both capacities are have only dimensions with dimensionVal=0, it returns 0.0
*
@ -146,7 +146,7 @@ public class Capacity {
/**
* add capacity dimension
* <p/>
* <p>
* <p>Note that it automatically resizes dimensions according to index, i.e. if index=7 there are 8 dimensions.
* New dimensions then are initialized with 0
*
@ -215,7 +215,7 @@ public class Capacity {
/**
* Returns value of capacity-dimension with specified index.
* <p/>
* <p>
* <p>If capacity dimension does not exist, it returns 0 (rather than IndexOutOfBoundsException).
*
* @param index dimension index of the capacity value to be retrieved

View file

@ -41,11 +41,11 @@ import java.util.*;
/**
* Contains and defines the vehicle routing problem.
* <p/>
* <p>
* <p>A routing problem is defined as jobs, vehicles, costs and constraints.
* <p/>
* <p>
* <p> To construct the problem, use VehicleRoutingProblem.Builder. Get an instance of this by using the static method VehicleRoutingProblem.Builder.newInstance().
* <p/>
* <p>
* <p>By default, fleetSize is INFINITE, transport-costs are calculated as euclidean-distance (CrowFlyCosts),
* and activity-costs are set to zero.
*
@ -153,7 +153,7 @@ public class VehicleRoutingProblem {
/**
* Returns the locations collected SO FAR by this builder.
* <p/>
* <p>
* <p>Locations are cached when adding a shipment, service, depot, vehicle.
*
* @return locations
@ -184,7 +184,7 @@ public class VehicleRoutingProblem {
/**
* Sets the type of fleetSize.
* <p/>
* <p>
* <p>FleetSize is either FleetSize.INFINITE or FleetSize.FINITE. By default it is FleetSize.INFINITE.
*
* @param fleetSize the fleet size used in this problem. it can either be FleetSize.INFINITE or FleetSize.FINITE
@ -197,7 +197,7 @@ public class VehicleRoutingProblem {
/**
* Adds a job which is either a service or a shipment.
* <p/>
* <p>
* <p>Note that job.getId() must be unique, i.e. no job (either it is a shipment or a service) is allowed to have an already allocated id.
*
* @param job job to be added
@ -212,7 +212,7 @@ public class VehicleRoutingProblem {
/**
* Adds a job which is either a service or a shipment.
* <p/>
* <p>
* <p>Note that job.getId() must be unique, i.e. no job (either it is a shipment or a service) is allowed to have an already allocated id.
*
* @param job job to be added
@ -396,7 +396,7 @@ public class VehicleRoutingProblem {
/**
* Sets the activity-costs.
* <p/>
* <p>
* <p>By default it is set to zero.
*
* @param activityCosts activity costs of the problem
@ -410,7 +410,7 @@ public class VehicleRoutingProblem {
/**
* Builds the {@link VehicleRoutingProblem}.
* <p/>
* <p>
* <p>If {@link VehicleRoutingTransportCosts} are not set, {@link CrowFlyCosts} is used.
*
* @return {@link VehicleRoutingProblem}
@ -592,7 +592,7 @@ public class VehicleRoutingProblem {
/**
* Returns type of fleetSize, either INFINITE or FINITE.
* <p/>
* <p>
* <p>By default, it is INFINITE.
*
* @return either FleetSize.INFINITE or FleetSize.FINITE

View file

@ -35,7 +35,7 @@ class AdditionalTransportationCosts implements SoftActivityConstraint {
/**
* Constructs the calculator that calculates additional transportation costs induced by inserting new activity.
* <p/>
* <p>
* <p>It is calculated at local level, i.e. the additional costs of inserting act_new between act_i and act_j is c(act_i,act_new,newVehicle)+c(act_new,act_j,newVehicle)-c(act_i,act_j,oldVehicle)
* <p>If newVehicle.isReturnToDepot == false then the additional costs of inserting act_new between act_i and end is c(act_i,act_new) [since act_new is then the new end-of-route]
*
@ -50,7 +50,7 @@ class AdditionalTransportationCosts implements SoftActivityConstraint {
/**
* Returns additional transportation costs induced by inserting newAct.
* <p/>
* <p>
* <p>It is calculated at local level, i.e. the additional costs of inserting act_new between act_i and act_j is c(act_i,act_new,newVehicle)+c(act_new,act_j,newVehicle)-c(act_i,act_j,oldVehicle)
* <p>If newVehicle.isReturnToDepot == false then the additional costs of inserting act_new between act_i and end is c(act_i,act_new) [since act_new is then the new end-of-route]
*/

View file

@ -35,37 +35,37 @@ public interface HardActivityConstraint extends HardConstraint {
/**
* Returns whether newAct can be inserted in between prevAct and nextAct.
* <p/>
* <p/>
* <p>
* <p>
* When you check activities, you need to understand the following:
* <p/>
* <p>
* Let us assume an existing route;
* <p/>
* <p>
* start, ..., i-1, i, j, j+1, ..., end
* <p/>
* <p>
* When inserting a shipment, two activities will be inserted, pickupShipment k_pick and deliverShipment k_deliver,
* i.e. jsprit loops through this route (activity sequence) and checks hard and soft constraints and calculates (marginal) insertion costs. For
* the activity sequence above, it means:
* <p/>
* <p>
* start, k_pick, start+1 (prevAct, newAct, nextAct)<br>
* ...<br>
* i-1, k_pick, i<br>
* i, k_pick, j<br>
* ...<br>
* <p/>
* <p>
* accordingly:<br>
* start, k_pick, k_delivery (prevAct, newAct, nextAct)<br>
* ...<br>
* i-1, k_delivery, i<br>
* i, k_delivery, j<br>
* ...<br>
* <p/>
* <p>
* You specify a hard activity constraint, you to check whether for example k_pick can be inserted between prevActivity and nextActivity at all.
* If so, your hard constraint should return ConstraintsStatus.FULFILLED.<br>
* If not, you can return ConstraintsStatus.NOT_FULFILLED or ConstraintsStatus.NOT_FULFILLED_BREAK.<br>
* <p/>
* <p>
* Latter should be used, if your constraint can never be fulfilled anymore when looping further through your route.
* <p/>
* <p>
* Since constraint checking at activity level is rather time consuming (you need to do this thousand/millions times),
* you can memorize states behind activities to avoid additional loopings through your activity sequence and thus to
* check your constraint locally (only by looking at prevAct, newAct, nextAct) in constant time.

View file

@ -28,7 +28,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivity
/**
* Constraint that ensures capacity constraint at each activity.
* <p/>
* <p>
* <p>This is critical to consistently calculate pd-problems with capacity constraints. Critical means
* that is MUST be visited. It also assumes that pd-activities are visited in the order they occur in a tour.
*
@ -42,7 +42,7 @@ public class PickupAndDeliverShipmentLoadActivityLevelConstraint implements Hard
/**
* Constructs the constraint ensuring capacity constraint at each activity.
* <p/>
* <p>
* <p>This is critical to consistently calculate pd-problems with capacity constraints. Critical means
* that is MUST be visited. It also assumes that pd-activities are visited in the order they occur in a tour.
*

View file

@ -25,7 +25,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivity
/**
* Ensures load constraint for inserting ServiceActivity.
* <p/>
* <p>
* <p>When using this, you need to use<br>
*
* @author schroeder

View file

@ -27,7 +27,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivity
/**
* Ensures that capacity constraint is met, i.e. that current load plus
* new job size does not exceeds capacity of new vehicle.
* <p/>
* <p>
* <p>If job is neither Pickup, Delivery nor Service, it returns true.
*
* @author stefan

View file

@ -22,7 +22,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
/**
* Interface for overall routing and operation costs.
* <p/>
* <p>
* <p>This calculates activity and leg-based costs. If you want to consider for example costs incurred by missed time-windows, you can do it here.
*
* @author schroeder
@ -46,7 +46,7 @@ public interface VehicleRoutingActivityCosts {
/**
* Calculates and returns the activity cost at tourAct.
* <p/>
* <p>
* <p>Here waiting-times, service-times and missed time-windows can be considered.
*
* @param tourAct

View file

@ -19,7 +19,7 @@ package com.graphhopper.jsprit.core.problem.cost;
/**
* Interface for transportCost and transportTime.
* <p/>
* <p>
* <p>Transport here is what happens between two activities within the transport system, i.e. in the physical transport network. And
* must give the answer of how long does it take from A to B, and how much does this cost.
*

View file

@ -47,7 +47,7 @@ public class Break extends Service {
/**
* Builds Pickup.
* <p/>
* <p>
* <p>Pickup type is "pickup"
*
* @return pickup

View file

@ -42,7 +42,7 @@ public class Pickup extends Service {
/**
* Builds Pickup.
* <p/>
* <p>
* <p>Pickup type is "pickup"
*
* @return pickup

View file

@ -29,10 +29,10 @@ import java.util.Collection;
/**
* Service implementation of a job.
* <p/>
* <p>
* <p>A service distinguishes itself from a shipment such that it has only one location. Thus a service
* is a single point in space (where a service-activity occurs).
* <p/>
* <p>
* <p>Note that two services are equal if they have the same id.
*
* @author schroeder
@ -94,7 +94,7 @@ public class Service extends AbstractJob {
/**
* Protected method to set the type-name of the service.
* <p/>
* <p>
* <p>Currently there are {@link Service}, {@link Pickup} and {@link Delivery}.
*
* @param name the name of service
@ -118,7 +118,7 @@ public class Service extends AbstractJob {
/**
* Sets the serviceTime of this service.
* <p/>
* <p>
* <p>It is understood as time that a service or its implied activity takes at the service-location, for instance
* to unload goods.
*
@ -286,7 +286,7 @@ public class Service extends AbstractJob {
/**
* Returns a string with the service's attributes.
* <p/>
* <p>
* <p>String is built as follows: [attr1=val1][attr2=val2]...
*/
@Override

View file

@ -28,16 +28,16 @@ import java.util.Collection;
/**
* Shipment is an implementation of Job and consists of a pickup and a delivery of something.
* <p/>
* <p>
* <p>It distinguishes itself from {@link Service} as two locations are involved a pickup where usually
* something is loaded to the transport unit and a delivery where something is unloaded.
* <p/>
* <p>
* <p>By default serviceTimes of both pickup and delivery is 0.0 and timeWindows of both is [0.0, Double.MAX_VALUE],
* <p/>
* <p>
* <p>A shipment can be built with a builder. You can get an instance of the builder by coding <code>Shipment.Builder.newInstance(...)</code>.
* This way you can specify the shipment. Once you build the shipment, it is immutable, i.e. fields/attributes cannot be changed anymore and
* you can only 'get' the specified values.
* <p/>
* <p>
* <p>Note that two shipments are equal if they have the same id.
*
* @author schroeder
@ -117,7 +117,7 @@ public class Shipment extends AbstractJob {
/**
* Sets pickupServiceTime.
* <p/>
* <p>
* <p>ServiceTime is intended to be the time the implied activity takes at the pickup-location.
*
* @param serviceTime the service time / duration the pickup of the associated shipment takes
@ -133,7 +133,7 @@ public class Shipment extends AbstractJob {
/**
* Sets the timeWindow for the pickup, i.e. the time-period in which a pickup operation is
* allowed to START.
* <p/>
* <p>
* <p>By default timeWindow is [0.0, Double.MAX_VALUE}
*
* @param timeWindow the time window within the pickup operation/activity can START
@ -163,7 +163,7 @@ public class Shipment extends AbstractJob {
/**
* Sets the delivery service-time.
* <p/>
* <p>
* <p>ServiceTime is intended to be the time the implied activity takes at the delivery-location.
*
* @param deliveryServiceTime the service time / duration of shipment's delivery
@ -179,7 +179,7 @@ public class Shipment extends AbstractJob {
/**
* Sets the timeWindow for the delivery, i.e. the time-period in which a delivery operation is
* allowed to start.
* <p/>
* <p>
* <p>By default timeWindow is [0.0, Double.MAX_VALUE}
*
* @param timeWindow the time window within the associated delivery is allowed to START
@ -315,7 +315,7 @@ public class Shipment extends AbstractJob {
/**
* Returns the pickup service-time.
* <p/>
* <p>
* <p>By default service-time is 0.0.
*
* @return service-time

View file

@ -48,14 +48,14 @@ public class ActivityContext {
/**
* Returns the insertion index of the associated vehicle.
* <p/>
* <p>
* <p>The associated activity is not inserted yet. The actual insertion position is still to be evaluated.
* Thus this insertion index is related to the potential insertion index which is the position before
* the activity at this index in the existing route.
* <p/>
* <p>
* if insertionIndex == 0, the associated activity will be inserted between start of vehicle and the first
* activity in activity sequence.
* <p/>
* <p>
* if insertionIndex == relatedRoute.getActivities().size(), the associated activity will be inserted between
* the last activity in the activity sequence and the end of vehicle.
*

View file

@ -75,7 +75,7 @@ public class JobInsertionContext {
/**
* Returns the driver that should operate the new route, i.e. route <code>this.getRoute()</code> + new job <code>this.getJob()</code>.
* <p/>
* <p>
* <p>Currently the driver is just a mock, it has no functions</p>
*
* @return the newDriver

View file

@ -18,7 +18,7 @@ package com.graphhopper.jsprit.core.problem.solution;
/**
* Interface for all solutionCostCalculators which should be the objective-functions of the problem.
* <p/>
* <p>
* <p>It evaluates VehicleRoutingProblemSolution and returns its costs.
*
* @author schroeder

View file

@ -48,7 +48,7 @@ public class VehicleRoute {
/**
* Returns an empty route.
* <p/>
* <p>
* <p>An empty route has an empty list of tour-activities, no driver (DriverImpl.noDriver()) and no vehicle (VehicleImpl.createNoVehicle()).
*
* @return empty route
@ -68,7 +68,7 @@ public class VehicleRoute {
/**
* Returns new instance of this builder.
* <p/>
* <p>
* <p><b>Construction-settings of vehicleRoute:</b>
* <p>startLocation == vehicle.getStartLocationId()
* <p>endLocation == vehicle.getEndLocationId()
@ -88,7 +88,7 @@ public class VehicleRoute {
/**
* Returns new instance of this builder.
* <p/>
* <p>
* <p><b>Construction-settings of vehicleRoute:</b>
* <p>startLocation == vehicle.getStartLocationId()
* <p>endLocation == vehicle.getEndLocationId()
@ -155,7 +155,7 @@ public class VehicleRoute {
/**
* Sets the departure-time of the route, i.e. which is the time the vehicle departs from start-location.
* <p/>
* <p>
* <p><b>Note</b> that departureTime cannot be lower than earliestDepartureTime of vehicle.
*
* @param departureTime departure time of vehicle being employed for this route
@ -172,9 +172,9 @@ public class VehicleRoute {
/**
* Adds a service to this route. Activity is initialized with .getTimeWindow(). If you want to explicitly set another time window
* use .addService(Service service, TimeWindow timeWindow)
* <p/>
* <p>
* <p>This implies that for this service a serviceActivity is created with {@link TourActivityFactory} and added to the sequence of tourActivities.
* <p/>
* <p>
* <p>The resulting activity occurs in the activity-sequence in the order adding/inserting.
*
* @param service to be added
@ -370,7 +370,7 @@ public class VehicleRoute {
/**
* Sets the vehicle and its departureTime from <code>vehicle.getStartLocationId()</code>.
* <p/>
* <p>
* <p>This implies the following:<br>
* if start and end are null, new start and end activities are created.<br>
* <p>startActivity is initialized with the start-location of the specified vehicle (<code>vehicle.getStartLocationId()</code>). the time-window of this activity is initialized

View file

@ -23,7 +23,7 @@ import com.graphhopper.jsprit.core.problem.job.Job;
/**
* Basic interface for tour-activities.
* <p/>
* <p>
* <p>A tour activity is the basic element of a tour, which is consequently a sequence of tour-activities.
*
* @author schroeder
@ -36,7 +36,7 @@ public interface TourActivity extends HasIndex {
/**
* Basic interface of job-activies.
* <p/>
* <p>
* <p>A job activity is related to a {@link Job}.
*
* @author schroeder
@ -84,7 +84,7 @@ public interface TourActivity extends HasIndex {
/**
* Returns the operation-time this activity takes.
* <p/>
* <p>
* <p>Note that this is not necessarily the duration of this activity, but the
* service time a pickup/delivery actually takes, that is for example <code>service.getServiceTime()</code>.
*

View file

@ -23,7 +23,7 @@ public interface VehicleFleetManager {
/**
* Locks vehicle.
* <p/>
* <p>
* <p>This indicates that this vehicle is being used. Thus it is not in list of available vehicles.
*
* @param vehicle
@ -32,7 +32,7 @@ public interface VehicleFleetManager {
/**
* Unlocks vehicle.
* <p/>
* <p>
* <p>This indicates that this vehicle is not being used anymore. Thus it is in list of available vehicles.
*
* @param vehicle
@ -54,7 +54,7 @@ public interface VehicleFleetManager {
/**
* Returns a collection of available vehicles.
* <p/>
* <p>
* <p>Note that this does not return ALL available vehicles that were added to the fleetmanager. Vehicles are clustered according
* to {@link VehicleTypeKey}. If there are two unlocked vehicle with the same VehicleTypeKey then only one of them will be returned.
* This is to avoid returning too many vehicles that are basically equal.

View file

@ -129,7 +129,7 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
/**
* Returns a collection of available vehicles.
* <p/>
* <p>
* <p>If there is no vehicle with a certain type and location anymore, it looks up whether a penalty vehicle has been specified with
* this type and location. If so, it returns this penalty vehicle. If not, no vehicle with this type and location is returned.
*/

View file

@ -98,7 +98,7 @@ public class VehicleImpl extends AbstractVehicle {
/**
* Builder that builds the vehicle.
* <p/>
* <p>
* <p>By default, earliestDepartureTime is 0.0, latestDepartureTime is Double.MAX_VALUE,
* it returns to the depot and its {@link VehicleType} is the DefaultType with typeId equal to 'default'
* and a capacity of 0.
@ -149,11 +149,11 @@ public class VehicleImpl extends AbstractVehicle {
/**
* Sets the flag whether the vehicle must return to depot or not.
* <p/>
* <p>
* <p>If returnToDepot is true, the vehicle must return to specified end-location. If you
* omit specifying the end-location, vehicle returns to start-location (that must to be set). If
* you specify it, it returns to specified end-location.
* <p/>
* <p>
* <p>If returnToDepot is false, the end-location of the vehicle is endogenous.
*
* @param returnToDepot true if vehicle need to return to depot, otherwise false
@ -213,10 +213,10 @@ public class VehicleImpl extends AbstractVehicle {
/**
* Builds and returns the vehicle.
* <p/>
* <p>
* <p>if {@link VehicleType} is not set, default vehicle-type is set with id="default" and
* capacity=0
* <p/>
* <p>
* <p>if startLocationId || locationId is null (=> startLocationCoordinate || locationCoordinate must be set) then startLocationId=startLocationCoordinate.toString()
* and locationId=locationCoordinate.toString() [coord.toString() --> [x=x_val][y=y_val])
* <p>if endLocationId is null and endLocationCoordinate is set then endLocationId=endLocationCoordinate.toString()
@ -268,7 +268,7 @@ public class VehicleImpl extends AbstractVehicle {
/**
* Returns empty/noVehicle which is a vehicle having no capacity, no type and no reasonable id.
* <p/>
* <p>
* <p>NoVehicle has id="noVehicle" and extends {@link VehicleImpl}
*
* @return emptyVehicle
@ -311,7 +311,7 @@ public class VehicleImpl extends AbstractVehicle {
/**
* Returns String with attributes of this vehicle
* <p/>
* <p>
* <p>String has the following format [attr1=val1][attr2=val2]...[attrn=valn]
*/
@Override

View file

@ -21,7 +21,7 @@ import com.graphhopper.jsprit.core.problem.Capacity;
/**
* Implementation of {@link VehicleType}.
* <p/>
* <p>
* <p>Two vehicle-types are equal if they have the same typeId.
*
* @author schroeder
@ -134,7 +134,7 @@ public class VehicleTypeImpl implements VehicleType {
/**
* Sets the fixed costs of the vehicle-type.
* <p/>
* <p>
* <p>by default it is 0.
*
* @param fixedCost
@ -149,7 +149,7 @@ public class VehicleTypeImpl implements VehicleType {
/**
* Sets the cost per distance unit, for instance per meter.
* <p/>
* <p>
* <p>by default it is 1.0
*
* @param perDistance
@ -164,7 +164,7 @@ public class VehicleTypeImpl implements VehicleType {
/**
* Sets cost per time unit, for instance per second.
* <p/>
* <p>
* <p>by default it is 0.0
*
* @param perTime
@ -181,7 +181,7 @@ public class VehicleTypeImpl implements VehicleType {
/**
* Sets cost per time unit, for instance per second.
* <p/>
* <p>
* <p>by default it is 0.0
*
* @param perTime
@ -196,7 +196,7 @@ public class VehicleTypeImpl implements VehicleType {
/**
* Sets cost per waiting time unit, for instance per second.
* <p/>
* <p>
* <p>by default it is 0.0
*
* @param perWaitingTime
@ -248,7 +248,7 @@ public class VehicleTypeImpl implements VehicleType {
/**
* Sets capacity dimensions.
* <p/>
* <p>
* <p>Note if you use this you cannot use <code>addCapacityDimension(int dimIndex, int dimVal)</code> anymore. Thus either build
* your dimensions with <code>addCapacityDimension(int dimIndex, int dimVal)</code> or set the already built dimensions with
* this method.

View file

@ -23,7 +23,7 @@ import com.graphhopper.jsprit.core.problem.Skills;
/**
* Key to identify similar vehicles
* <p/>
* <p>
* <p>Two vehicles are equal if they share the same type, the same start and end-location and the same earliestStart and latestStart.
*
* @author stefan

View file

@ -39,8 +39,8 @@ public class SolutionPrinter {
/**
* Enum to indicate verbose-level.
* <p/>
* <p/>
* <p>
* <p>
* Print.CONCISE and Print.VERBOSE are available.
*
* @author stefan schroeder

View file

@ -26,7 +26,7 @@ public class GreatCircleDistanceCalculator {
/**
* Harversine method.
* <p/>
* <p>
* double lon1 = coord1.getX();
* double lon2 = coord2.getX();
* double lat1 = coord1.getY();

View file

@ -44,9 +44,9 @@ public class Time {
/**
* Parse time to seconds.
* <p/>
* <p>
* <p>If you add PM or AM to timeString, it considers english-time, otherwise not.
* <p/>
* <p>
* <p>timeString can be 6AM, 06AM, 6 am, 6:01AM, 6:1 pM, 6:12:1 pm, 6:12:01 am, 06:12:01 Pm etc. - but not more precise than seconds.
* <p>example: 12 AM returns 12*3600. sec
* 6:30 AM --> 6*3600. + 30*60.

View file

@ -24,7 +24,7 @@ public class CostFactory {
/**
* Return manhattanCosts.
* <p/>
* <p>
* This retrieves coordinates from locationIds. LocationId has to be locId="{x},{y}". For example,
* locId="10,10" is interpreted such that x=10 and y=10.
*
@ -47,7 +47,7 @@ public class CostFactory {
/**
* Return euclideanCosts.
* <p/>
* <p>
* This retrieves coordinates from locationIds. LocationId has to be locId="{x},{y}". For example,
* locId="10,10" is interpreted such that x=10 and y=10.
*

View file

@ -6,15 +6,15 @@
</problemType>
<vehicles>
<vehicle>
<id>v3</id>
<typeId>vehType2</typeId>
<id>v1</id>
<typeId>vehType</typeId>
<startLocation>
<id>startLoc</id>
<coord x="10.0" y="100.0"/>
<id>depotLoc2</id>
<coord x="100.0" y="100.0"/>
</startLocation>
<endLocation>
<id>endLoc</id>
<coord x="1000.0" y="2000.0"/>
<id>depotLoc2</id>
<coord x="100.0" y="100.0"/>
</endLocation>
<timeSchedule>
<start>0.0</start>
@ -39,6 +39,23 @@
</timeSchedule>
<returnToDepot>false</returnToDepot>
</vehicle>
<vehicle>
<id>v3</id>
<typeId>vehType2</typeId>
<startLocation>
<id>startLoc</id>
<coord x="10.0" y="100.0"/>
</startLocation>
<endLocation>
<id>endLoc</id>
<coord x="1000.0" y="2000.0"/>
</endLocation>
<timeSchedule>
<start>0.0</start>
<end>1000.0</end>
</timeSchedule>
<returnToDepot>true</returnToDepot>
</vehicle>
<vehicle>
<id>v4</id>
<typeId>vehType2</typeId>
@ -73,23 +90,6 @@
</timeSchedule>
<returnToDepot>true</returnToDepot>
</vehicle>
<vehicle>
<id>v1</id>
<typeId>vehType</typeId>
<startLocation>
<id>depotLoc2</id>
<coord x="100.0" y="100.0"/>
</startLocation>
<endLocation>
<id>depotLoc2</id>
<coord x="100.0" y="100.0"/>
</endLocation>
<timeSchedule>
<start>0.0</start>
<end>1000.0</end>
</timeSchedule>
<returnToDepot>true</returnToDepot>
</vehicle>
</vehicles>
<vehicleTypes>
<type>

View file

@ -6,8 +6,8 @@
</problemType>
<vehicles>
<vehicle>
<id>v2</id>
<typeId>vehType2</typeId>
<id>v1</id>
<typeId>vehType</typeId>
<startLocation>
<id>loc</id>
</startLocation>
@ -21,8 +21,8 @@
<returnToDepot>true</returnToDepot>
</vehicle>
<vehicle>
<id>v1</id>
<typeId>vehType</typeId>
<id>v2</id>
<typeId>vehType2</typeId>
<startLocation>
<id>loc</id>
</startLocation>