mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
Merge branch 'master' into driver-breaks
This commit is contained in:
commit
4925231e03
45 changed files with 152 additions and 175 deletions
|
|
@ -0,0 +1,61 @@
|
|||
package jsprit.core.algorithm.box;
|
||||
|
||||
import jsprit.core.algorithm.listener.IterationStartsListener;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.constraint.SoftActivityConstraint;
|
||||
import jsprit.core.problem.misc.JobInsertionContext;
|
||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.util.RandomNumberGeneration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 16/01/15.
|
||||
*/
|
||||
class ConcurrentInsertionNoiseMaker implements SoftActivityConstraint, IterationStartsListener {
|
||||
|
||||
private final double noiseProbability;
|
||||
|
||||
private boolean makeNoise = false;
|
||||
|
||||
private double noiseLevel = 0.1;
|
||||
|
||||
private Random random = RandomNumberGeneration.newInstance();
|
||||
|
||||
private Random[] randomArray;
|
||||
|
||||
private double maxCosts;
|
||||
|
||||
ConcurrentInsertionNoiseMaker(VehicleRoutingProblem vrp, double maxCosts, double noiseLevel, double noiseProbability) {
|
||||
this.noiseLevel = noiseLevel;
|
||||
this.noiseProbability = noiseProbability;
|
||||
this.maxCosts = maxCosts;
|
||||
randomArray = new Random[vrp.getNuActivities() + 2];
|
||||
for (int i = 0; i < randomArray.length; i++) {
|
||||
Random r = new Random();
|
||||
r.setSeed(random.nextLong());
|
||||
randomArray[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||
if (random.nextDouble() < noiseProbability) {
|
||||
makeNoise = true;
|
||||
} else makeNoise = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||
if (makeNoise) {
|
||||
return noiseLevel * maxCosts * randomArray[newAct.getIndex()].nextDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setRandom(Random random) {
|
||||
this.random = random;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
package jsprit.core.algorithm.box;
|
||||
|
||||
import jsprit.core.algorithm.listener.IterationStartsListener;
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.constraint.SoftActivityConstraint;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.job.Service;
|
||||
import jsprit.core.problem.job.Shipment;
|
||||
import jsprit.core.problem.misc.JobInsertionContext;
|
||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.util.RandomNumberGeneration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 16/01/15.
|
||||
*/
|
||||
class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsListener {
|
||||
|
||||
private final double noiseProbability;
|
||||
|
||||
private boolean makeNoise = false;
|
||||
|
||||
private VehicleRoutingProblem vrp;
|
||||
|
||||
double maxCosts = 0.;
|
||||
|
||||
private double noiseLevel = 0.1;
|
||||
|
||||
private Random random = RandomNumberGeneration.getRandom();
|
||||
|
||||
public InsertionNoiseMaker(VehicleRoutingProblem vrp, double noiseLevel, double noiseProbability) {
|
||||
this.vrp = vrp;
|
||||
this.noiseLevel = noiseLevel;
|
||||
this.noiseProbability = noiseProbability;
|
||||
determineMaxCosts(vrp);
|
||||
}
|
||||
|
||||
//@ToDo refactor determining max costs to allow skipping this
|
||||
private void determineMaxCosts(VehicleRoutingProblem vrp) {
|
||||
double max = 0.;
|
||||
for (Job i : vrp.getJobs().values()) {
|
||||
List<Location> fromLocations = getLocations(i);
|
||||
for (Job j : vrp.getJobs().values()) {
|
||||
List<Location> toLocations = getLocations(j);
|
||||
for (Location iLoc : fromLocations) {
|
||||
for (Location jLoc : toLocations) {
|
||||
max = Math.max(max, vrp.getTransportCosts().getTransportCost(iLoc, jLoc, 0, null, vrp.getVehicles().iterator().next()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
maxCosts = max;
|
||||
}
|
||||
|
||||
private List<Location> getLocations(Job j) {
|
||||
List<Location> locs = new ArrayList<Location>();
|
||||
if (j instanceof Service) {
|
||||
locs.add(((Service) j).getLocation());
|
||||
} else if (j instanceof Shipment) {
|
||||
locs.add(((Shipment) j).getPickupLocation());
|
||||
locs.add(((Shipment) j).getDeliveryLocation());
|
||||
}
|
||||
return locs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||
if (random.nextDouble() < noiseProbability) {
|
||||
makeNoise = true;
|
||||
} else makeNoise = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||
if (makeNoise) {
|
||||
return noiseLevel * maxCosts * random.nextDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public void setRandom(Random random) {
|
||||
this.random = random;
|
||||
}
|
||||
}
|
||||
|
|
@ -309,14 +309,29 @@ public class Jsprit {
|
|||
constraintManager = new ConstraintManager(vrp, stateManager);
|
||||
}
|
||||
|
||||
if (noThreads == null) {
|
||||
noThreads = toInteger(getProperty(Parameter.THREADS.toString()));
|
||||
}
|
||||
if (noThreads > 1) {
|
||||
if (es == null) {
|
||||
setupExecutorInternally = true;
|
||||
es = Executors.newFixedThreadPool(noThreads);
|
||||
}
|
||||
}
|
||||
|
||||
double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString()));
|
||||
double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString()));
|
||||
final InsertionNoiseMaker noiseMaker = new InsertionNoiseMaker(vrp, noiseLevel, noiseProbability);
|
||||
noiseMaker.setRandom(random);
|
||||
constraintManager.addConstraint(noiseMaker);
|
||||
|
||||
JobNeighborhoods jobNeighborhoods = new JobNeighborhoodsFactory().createNeighborhoods(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts()), (int) (vrp.getJobs().values().size() * 0.5));
|
||||
jobNeighborhoods.initialise();
|
||||
final double maxCosts = jobNeighborhoods.getMaxDistance();
|
||||
|
||||
IterationStartsListener noiseConfigurator;
|
||||
|
||||
ConcurrentInsertionNoiseMaker noiseMaker = new ConcurrentInsertionNoiseMaker(vrp, maxCosts, noiseLevel, noiseProbability);
|
||||
noiseMaker.setRandom(random);
|
||||
constraintManager.addConstraint(noiseMaker);
|
||||
noiseConfigurator = noiseMaker;
|
||||
|
||||
RuinRadial radial = new RuinRadial(vrp, vrp.getJobs().size(), jobNeighborhoods);
|
||||
radial.setRandom(random);
|
||||
|
|
@ -357,7 +372,7 @@ public class Jsprit {
|
|||
public double makeNoise() {
|
||||
if (random.nextDouble() < toDouble(getProperty(Parameter.RUIN_WORST_NOISE_PROB.toString()))) {
|
||||
return toDouble(getProperty(Parameter.RUIN_WORST_NOISE_LEVEL.toString()))
|
||||
* noiseMaker.maxCosts * random.nextDouble();
|
||||
* maxCosts * random.nextDouble();
|
||||
} else return 0.;
|
||||
}
|
||||
});
|
||||
|
|
@ -374,15 +389,7 @@ public class Jsprit {
|
|||
|
||||
AbstractInsertionStrategy regret;
|
||||
final RegretInsertion.DefaultScorer scorer;
|
||||
if (noThreads == null) {
|
||||
noThreads = toInteger(getProperty(Parameter.THREADS.toString()));
|
||||
}
|
||||
if (noThreads > 1) {
|
||||
if (es == null) {
|
||||
setupExecutorInternally = true;
|
||||
es = Executors.newFixedThreadPool(noThreads);
|
||||
}
|
||||
}
|
||||
|
||||
if (es != null) {
|
||||
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
|
|
@ -435,7 +442,7 @@ public class Jsprit {
|
|||
}
|
||||
};
|
||||
|
||||
SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, noiseMaker.maxCosts);
|
||||
SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, maxCosts);
|
||||
SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||
radial_regret.addModule(new RuinAndRecreateModule(Strategy.RADIAL_REGRET.toString(), regret, radial));
|
||||
|
||||
|
|
@ -483,7 +490,7 @@ public class Jsprit {
|
|||
|
||||
VehicleRoutingAlgorithm vra = prettyBuilder.build();
|
||||
vra.addListener(schrimpfThreshold);
|
||||
vra.addListener(noiseMaker);
|
||||
vra.addListener(noiseConfigurator);
|
||||
vra.addListener(noise);
|
||||
vra.addListener(clusters);
|
||||
vra.addListener(new RuinBreaks());
|
||||
|
|
|
|||
|
|
@ -13,4 +13,6 @@ public interface JobNeighborhoods {
|
|||
|
||||
public void initialise();
|
||||
|
||||
public double getMaxDistance();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
|
|||
|
||||
private JobDistance jobDistance;
|
||||
|
||||
private double maxDistance = 0.;
|
||||
|
||||
public JobNeighborhoodsImpl(VehicleRoutingProblem vrp, JobDistance jobDistance) {
|
||||
super();
|
||||
this.vrp = vrp;
|
||||
|
|
@ -58,6 +60,11 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
|
|||
calculateDistancesFromJob2Job();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaxDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void calculateDistancesFromJob2Job() {
|
||||
logger.debug("preprocess distances between locations ...");
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
|
|
@ -79,6 +86,7 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
|
|||
for (Job j : vrp.getJobs().values()) {
|
||||
if (i == j) continue;
|
||||
double distance = jobDistance.getDistance(i, j);
|
||||
if (distance > maxDistance) maxDistance = distance;
|
||||
ReferencedJob refNode = new ReferencedJob(j, distance);
|
||||
treeSet.add(refNode);
|
||||
nuOfDistancesStored++;
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
|
|||
|
||||
private int capacity;
|
||||
|
||||
private double maxDistance = 0.;
|
||||
|
||||
public JobNeighborhoodsImplWithCapRestriction(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) {
|
||||
super();
|
||||
this.vrp = vrp;
|
||||
this.jobDistance = jobDistance;
|
||||
this.capacity = capacity;
|
||||
logger.debug("intialise {}", this);
|
||||
logger.debug("initialize {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -64,6 +66,11 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
|
|||
calculateDistancesFromJob2Job();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaxDistance() {
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
private void calculateDistancesFromJob2Job() {
|
||||
logger.debug("preprocess distances between locations ...");
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
|
|
@ -85,6 +92,7 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
|
|||
for (Job j : vrp.getJobs().values()) {
|
||||
if (i == j) continue;
|
||||
double distance = jobDistance.getDistance(i, j);
|
||||
if (distance > maxDistance) maxDistance = distance;
|
||||
ReferencedJob refNode = new ReferencedJob(j, distance);
|
||||
if (treeSet.size() < capacity) {
|
||||
treeSet.add(refNode);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ public class SwitchNotFeasible implements HardRouteConstraint{
|
|||
@Override
|
||||
public boolean fulfilled(JobInsertionContext insertionContext) {
|
||||
Boolean notFeasible = stateManager.getRouteState(insertionContext.getRoute(), insertionContext.getNewVehicle(), InternalStates.SWITCH_NOT_FEASIBLE, Boolean.class);
|
||||
if(notFeasible == null || insertionContext.getRoute().getVehicle().getVehicleTypeIdentifier().equals(insertionContext.getNewVehicle().getVehicleTypeIdentifier())) return true;
|
||||
if (notFeasible == null || insertionContext.getRoute().getVehicle().getVehicleTypeIdentifier().equals(insertionContext.getNewVehicle().getVehicleTypeIdentifier()))
|
||||
return true;
|
||||
else return !notFeasible;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,36 +66,20 @@ public class TourActivities {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static TourActivities emptyTour() {
|
||||
return new TourActivities();
|
||||
}
|
||||
|
||||
private final ArrayList<TourActivity> tourActivities = new ArrayList<TourActivity>();
|
||||
|
||||
private final Set<Job> jobs = new HashSet<Job>();
|
||||
|
||||
private final Set<TourActivity> activities = new HashSet<TourActivity>();
|
||||
|
||||
private ReverseActivityIterator backward;
|
||||
|
||||
private TourActivities(TourActivities tour2copy) {
|
||||
for (TourActivity tourAct : tour2copy.getActivities()) {
|
||||
TourActivity newAct = tourAct.duplicate();
|
||||
this.tourActivities.add(newAct);
|
||||
addToActivitySet(newAct);
|
||||
addJob(newAct);
|
||||
}
|
||||
}
|
||||
|
||||
private void addToActivitySet(TourActivity newAct) {
|
||||
activities.add(newAct);
|
||||
}
|
||||
|
||||
private void removeFromActivitySet(TourActivity act) {
|
||||
activities.remove(act);
|
||||
}
|
||||
|
||||
public TourActivities() {
|
||||
|
||||
}
|
||||
|
|
@ -148,7 +132,6 @@ public class TourActivities {
|
|||
if (c instanceof JobActivity) {
|
||||
if (job.equals(((JobActivity) c).getJob())) {
|
||||
tourActivities.remove(c);
|
||||
removeFromActivitySet(c);
|
||||
activityRemoved = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -163,8 +146,9 @@ public class TourActivities {
|
|||
* @param activity to be looked up
|
||||
* @return true if this contains specified activity, false otherwise
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean hasActivity(TourActivity activity) {
|
||||
return activities.contains(activity);
|
||||
return tourActivities.contains(activity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -185,7 +169,6 @@ public class TourActivities {
|
|||
for (TourActivity act : acts) {
|
||||
if (act == activity) {
|
||||
tourActivities.remove(act);
|
||||
removeFromActivitySet(act);
|
||||
actRemoved = true;
|
||||
} else {
|
||||
if (act instanceof JobActivity && job != null) {
|
||||
|
|
@ -228,7 +211,6 @@ public class TourActivities {
|
|||
} else if (insertionIndex >= tourActivities.size()) {
|
||||
tourActivities.add(act);
|
||||
}
|
||||
addToActivitySet(act);
|
||||
addJob(act);
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +225,6 @@ public class TourActivities {
|
|||
if (tourActivities.contains(act))
|
||||
throw new IllegalStateException("act " + act + " already in tour. cannot add act twice.");
|
||||
tourActivities.add(act);
|
||||
addToActivitySet(act);
|
||||
addJob(act);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue