Skip to content

Commit

Permalink
refactor regret scorer
Browse files Browse the repository at this point in the history
  • Loading branch information
oblonski committed Nov 14, 2024
1 parent f01fbe8 commit 6ff58a4
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.graphhopper.jsprit.core.algorithm.recreate;

import com.graphhopper.jsprit.core.problem.job.Job;

public class DefaultRegretScoringFunction implements RegretScoringFunction {

private final ScoringFunction scoringFunction;

public DefaultRegretScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
}

@Override
public double score(InsertionData best, InsertionData secondBest, Job job) {
if (best == null) {
throw new IllegalStateException("cannot score job " + job.getId());
}
double score;
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
//if only one vehicle, I want the job to be inserted with min iCosts
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
score = (11 - job.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, job);
} else {
score = (11 - job.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, job);
}
return score;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,16 @@ static Comparator<VersionedInsertionData> getComparator(){
};
}

static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<ScoredJob> badJobs) {
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, RegretScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<ScoredJob> badJobs) {
ScoredJob bestScoredJob = null;
for(Job j : unassignedJobList){
for (Job j : unassignedJobList) {
VehicleRoute bestRoute = null;
InsertionData best = null;
InsertionData secondBest = null;
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
List<String> failedConstraintNames = new ArrayList<>();
while(iterator.hasNext()){
while (iterator.hasNext()) {
VersionedInsertionData versionedIData = iterator.next();
if(bestRoute != null){
if(versionedIData.getRoute() == bestRoute){
Expand Down Expand Up @@ -142,7 +142,7 @@ static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, V
badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames));
continue;
}
double score = score(j, best, secondBest, scoringFunction);
double score = scoringFunction.score(best, secondBest, j);
ScoredJob scoredJob;
if (bestRoute == emptyRoute) {
scoredJob = new ScoredJob(j, score, best, bestRoute, true);
Expand All @@ -158,8 +158,5 @@ else if(scoredJob.getScore() > bestScoredJob.getScore()){
return bestScoredJob;
}

private static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
return Scorer.score(unassignedJob,best,secondBest,scoringFunction);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@
public class RegretInsertion extends AbstractInsertionStrategy {


private static final Logger logger = LoggerFactory.getLogger(RegretInsertionFast.class);

private static Logger logger = LoggerFactory.getLogger(RegretInsertionFast.class);
private final JobInsertionCostsCalculator insertionCostsCalculator;

private ScoringFunction scoringFunction;
private RegretScoringFunction regretScoringFunction;

private JobInsertionCostsCalculator insertionCostsCalculator;

public void setRegretScoringFunction(RegretScoringFunction regretScoringFunction) {
this.regretScoringFunction = regretScoringFunction;
}

/**
* Sets the scoring function.
Expand All @@ -59,20 +62,20 @@ public class RegretInsertion extends AbstractInsertionStrategy {
* @param scoringFunction to score
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
this.regretScoringFunction = new DefaultRegretScoringFunction(scoringFunction);
}

public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
super(vehicleRoutingProblem);
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.regretScoringFunction = new DefaultRegretScoringFunction(new DefaultScorer(vehicleRoutingProblem));
this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem;
logger.debug("initialise {}", this);
}

@Override
public String toString() {
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
return "[name=regretInsertion][additionalScorer=" + regretScoringFunction + "]";
}


Expand All @@ -83,7 +86,7 @@ public String toString() {
*/
@Override
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> badJobs = new ArrayList<>(unassignedJobs.size());

Iterator<Job> jobIterator = unassignedJobs.iterator();
while (jobIterator.hasNext()){
Expand All @@ -109,7 +112,7 @@ public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Col
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
ScoredJob bestScoredJob = getBestScoredUnassignedJob(routes, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
routes.add(bestScoredJob.getRoute());
Expand All @@ -134,10 +137,10 @@ private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
return null;
}

private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<ScoredJob> badJobs) {
private ScoredJob getBestScoredUnassignedJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<ScoredJob> badJobs) {
ScoredJob bestScoredJob = null;
for (Job unassignedJob : unassignedJobList) {
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
ScoredJob scoredJob = Scorer.scoreUnassignedJob(routes, unassignedJob, insertionCostsCalculator, regretScoringFunction);
if (scoredJob instanceof ScoredJob.BadJob) {
badJobs.add(scoredJob);
continue;
Expand All @@ -156,63 +159,5 @@ private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unass
return bestScoredJob;
}

static ScoredJob getScoredJob(Collection<VehicleRoute> routes, Job unassignedJob, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction) {
InsertionData best = null;
InsertionData secondBest = null;
VehicleRoute bestRoute = null;
List<String> failedConstraintNames = new ArrayList<>();
double benchmark = Double.MAX_VALUE;
for (VehicleRoute route : routes) {
if (secondBest != null) {
benchmark = secondBest.getInsertionCost();
}
InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark);
if (iData instanceof InsertionData.NoInsertionFound) {
failedConstraintNames.addAll(iData.getFailedConstraintNames());
continue;
}
if (best == null) {
best = iData;
bestRoute = route;
} else if (iData.getInsertionCost() < best.getInsertionCost()) {
secondBest = best;
best = iData;
bestRoute = route;
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
}

VehicleRoute emptyRoute = VehicleRoute.emptyRoute();
InsertionData iData = insertionCostsCalculator.getInsertionData(emptyRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark);
if (!(iData instanceof InsertionData.NoInsertionFound)) {
if (best == null) {
best = iData;
bestRoute = emptyRoute;
} else if (iData.getInsertionCost() < best.getInsertionCost()) {
secondBest = best;
best = iData;
bestRoute = emptyRoute;
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
if (best == null) {
ScoredJob.BadJob badJob = new ScoredJob.BadJob(unassignedJob, failedConstraintNames);
return badJob;
}
double score = score(unassignedJob, best, secondBest, scoringFunction);
ScoredJob scoredJob;
if (bestRoute == emptyRoute) {
scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true);
} else scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false);
return scoredJob;
}


static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
return Scorer.score(unassignedJob,best,secondBest,scoringFunction);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {

private final ExecutorService executorService;

private ScoringFunction scoringFunction;
private RegretScoringFunction regretScoringFunction;

private final JobInsertionCostsCalculator insertionCostsCalculator;

Expand All @@ -62,12 +62,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
* @param scoringFunction to score
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
this.regretScoringFunction = new DefaultRegretScoringFunction(scoringFunction);
}

public void setRegretScoringFunction(RegretScoringFunction regretScoringFunction) {
this.regretScoringFunction = regretScoringFunction;
}

public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService) {
super(vehicleRoutingProblem);
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
// this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.regretScoringFunction = new DefaultRegretScoringFunction(new DefaultScorer(vehicleRoutingProblem));
this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem;
this.executorService = executorService;
Expand All @@ -76,7 +81,7 @@ public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalcula

@Override
public String toString() {
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
return "[name=regretInsertion][additionalScorer=" + regretScoringFunction + "]";
}


Expand Down Expand Up @@ -137,7 +142,7 @@ private ScoredJob calculateBestJob(final Collection<VehicleRoute> routes, List<J
ScoredJob bestScoredJob = null;
List<Callable<ScoredJob>> tasks = new ArrayList<>(unassignedJobList.size());
for (final Job unassignedJob : unassignedJobList) {
tasks.add(() -> RegretInsertion.getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction));
tasks.add(() -> Scorer.scoreUnassignedJob(routes, unassignedJob, insertionCostsCalculator, regretScoringFunction));
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {

private static Logger logger = LoggerFactory.getLogger(RegretInsertionConcurrentFast.class);

private ScoringFunction scoringFunction;
private RegretScoringFunction regretScoringFunction;

private final JobInsertionCostsCalculator insertionCostsCalculator;

Expand All @@ -69,12 +69,16 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
* @param scoringFunction to score
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
this.regretScoringFunction = new DefaultRegretScoringFunction(scoringFunction);
}

public void setRegretScoringFunction(RegretScoringFunction regretScoringFunction) {
this.regretScoringFunction = regretScoringFunction;
}

public RegretInsertionConcurrentFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService, VehicleFleetManager fleetManager) {
super(vehicleRoutingProblem);
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.regretScoringFunction = new DefaultRegretScoringFunction(new DefaultScorer(vehicleRoutingProblem));
this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem;
this.executor = executorService;
Expand All @@ -85,7 +89,7 @@ public RegretInsertionConcurrentFast(JobInsertionCostsCalculator jobInsertionCal

@Override
public String toString() {
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
return "[name=regretInsertion][additionalScorer=" + regretScoringFunction + "]";
}

public void setSwitchAllowed(boolean switchAllowed) {
Expand Down Expand Up @@ -149,7 +153,7 @@ public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Col
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
if(firstRun) firstRun = false;
updateRound++;
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, regretScoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
routes.add(bestScoredJob.getRoute());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {

private static Logger logger = LoggerFactory.getLogger(RegretInsertionFast.class);

private ScoringFunction scoringFunction;
private RegretScoringFunction regretScoringFunction;

private JobInsertionCostsCalculator insertionCostsCalculator;

Expand All @@ -56,7 +56,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {

public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) {
super(vehicleRoutingProblem);
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.regretScoringFunction = new DefaultRegretScoringFunction(new DefaultScorer(vehicleRoutingProblem));
this.insertionCostsCalculator = jobInsertionCalculator;
this.fleetManager = fleetManager;
this.vrp = vehicleRoutingProblem;
Expand All @@ -72,14 +72,18 @@ public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, V
* @param scoringFunction to score
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
this.regretScoringFunction = new DefaultRegretScoringFunction(scoringFunction);
}

public void setRegretScoringFunction(RegretScoringFunction regretScoringFunction) {
this.regretScoringFunction = regretScoringFunction;
}

public void setSwitchAllowed(boolean switchAllowed) {
this.switchAllowed = switchAllowed;
}

public void setDependencyTypes(DependencyType[] dependencyTypes){
public void setDependencyTypes(DependencyType[] dependencyTypes) {
this.dependencyTypes = dependencyTypes;
}

Expand All @@ -93,7 +97,7 @@ private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingPro

@Override
public String toString() {
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
return "[name=regretInsertion][additionalScorer=" + regretScoringFunction + "]";
}


Expand Down Expand Up @@ -146,7 +150,7 @@ public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Col
// updates.put(lastModified,updateRound);
}
updateRound++;
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList);
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, regretScoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
routes.add(bestScoredJob.getRoute());
Expand Down
Loading

0 comments on commit 6ff58a4

Please sign in to comment.