Skip to content

Commit

Permalink
feat: allow custom rejection penalties through an interface (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebhoerl authored Feb 12, 2024
1 parent 61f58d0 commit 2d2fc34
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.matsim.alonso_mora.algorithm.DefaultAlonsoMoraRequestFactory;
import org.matsim.alonso_mora.algorithm.DefaultAlonsoMoraVehicle;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.DefaultRejectionPenalty;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.RejectionPenalty;
import org.matsim.alonso_mora.algorithm.assignment.CbcMpsAssignmentSolver;
import org.matsim.alonso_mora.algorithm.assignment.GlpkMpsAssignmentSolver;
import org.matsim.alonso_mora.algorithm.assignment.GreedyTripFirstSolver;
Expand Down Expand Up @@ -122,6 +124,9 @@ protected void configureQSim() {
return new GreedyVehicleFirstSolver();
})).in(Singleton.class);

bindModal(RejectionPenalty.class)
.toInstance(new DefaultRejectionPenalty(amConfig.unassignmentPenalty, amConfig.rejectionPenalty));

bindModal(CbcMpsAssignmentSolver.class).toProvider(modalProvider(getter -> {
if (!CbcMpsAssignmentSolver.checkAvailability()) {
throw new IllegalStateException("Cbc solver is not available on this system!");
Expand All @@ -133,9 +138,8 @@ protected void configureQSim() {

CbcMpsAssignmentParameters solverParameters = (CbcMpsAssignmentParameters) amConfig.assignmentSolver;

return new CbcMpsAssignmentSolver(amConfig.unassignmentPenalty, amConfig.rejectionPenalty,
solverParameters.timeLimit, solverParameters.optimalityGap, problemPath, solutionPath,
getConfig().global().getRandomSeed());
return new CbcMpsAssignmentSolver(getter.getModal(RejectionPenalty.class), solverParameters.timeLimit,
solverParameters.optimalityGap, problemPath, solutionPath, getConfig().global().getRandomSeed());
})).in(Singleton.class);

bindModal(GlpkMpsAssignmentSolver.class).toProvider(modalProvider(getter -> {
Expand All @@ -149,8 +153,8 @@ protected void configureQSim() {

GlpkMpsAssignmentParameters solverParameters = (GlpkMpsAssignmentParameters) amConfig.assignmentSolver;

return new GlpkMpsAssignmentSolver(amConfig.unassignmentPenalty, amConfig.rejectionPenalty,
solverParameters.timeLimit, solverParameters.optimalityGap, problemPath, solutionPath);
return new GlpkMpsAssignmentSolver(getter.getModal(RejectionPenalty.class), solverParameters.timeLimit,
solverParameters.optimalityGap, problemPath, solutionPath);
})).in(Singleton.class);

switch (amConfig.assignmentSolver.getSolverType()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Collection;
import java.util.stream.Stream;

import org.matsim.alonso_mora.algorithm.AlonsoMoraRequest;
import org.matsim.alonso_mora.algorithm.AlonsoMoraTrip;

/**
Expand All @@ -26,4 +27,23 @@ public Solution(Status status, Collection<AlonsoMoraTrip> trips) {
this.trips = trips;
}
}

static public interface RejectionPenalty {
double getPenalty(AlonsoMoraRequest request);
}

static public class DefaultRejectionPenalty implements RejectionPenalty {
private final double unassignmentPenalty;
private final double rejectionPenalty;

public DefaultRejectionPenalty(double unassignmentPenalty, double rejectionPenalty) {
this.unassignmentPenalty = unassignmentPenalty;
this.rejectionPenalty = rejectionPenalty;
}

@Override
public double getPenalty(AlonsoMoraRequest request) {
return request.isAssigned() ? unassignmentPenalty : rejectionPenalty;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ public class CbcMpsAssignmentSolver implements AssignmentSolver {

private final static Logger logger = LogManager.getLogger(CbcMpsAssignmentSolver.class);

private final double rejectionPenalty;
private final double unassignmentPenalty;
private final RejectionPenalty rejectionPenalty;

private final File problemPath;
private final File solutionPath;
Expand All @@ -40,9 +39,8 @@ public class CbcMpsAssignmentSolver implements AssignmentSolver {
private final double optimalityGap;
private final long randomSeed;

public CbcMpsAssignmentSolver(double unassignmentPenalty, double rejectionPenalty, double timeLimit,
double optimalityGap, File problemPath, File solutionPath, long randomSeed) {
this.unassignmentPenalty = unassignmentPenalty;
public CbcMpsAssignmentSolver(RejectionPenalty rejectionPenalty, double timeLimit, double optimalityGap,
File problemPath, File solutionPath, long randomSeed) {
this.rejectionPenalty = rejectionPenalty;

this.problemPath = problemPath;
Expand All @@ -58,7 +56,7 @@ public CbcMpsAssignmentSolver(double unassignmentPenalty, double rejectionPenalt
public Solution solve(Stream<AlonsoMoraTrip> candidates) {
try {
List<AlonsoMoraTrip> tripList = candidates.collect(Collectors.toList());
new MpsAssignmentWriter(tripList, unassignmentPenalty, rejectionPenalty).write(problemPath);
new MpsAssignmentWriter(tripList, rejectionPenalty).write(problemPath);

new ProcessBuilder("cbc", problemPath.toString(), "-randomSeed", String.valueOf(randomSeed),
"-randomCbcSeed", String.valueOf(randomSeed), "-ratio", String.valueOf(optimalityGap), "-seconds",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,16 @@ public class GlpkMpsAssignmentSolver implements AssignmentSolver {

private static final Logger logger = LogManager.getLogger(GlpkMpsAssignmentSolver.class);

private final double unassignmentPenalty;
private final double rejectionPenalty;
private final RejectionPenalty rejectionPenalty;

private final File problemPath;
private final File solutionPath;

private final double timeLimit;
private final double optimalityGap;

public GlpkMpsAssignmentSolver(double unassignmentPenalty, double rejectionPenalty, double timeLimit,
double optimalityGap, File problemPath, File solutionPath) {
this.unassignmentPenalty = unassignmentPenalty;
public GlpkMpsAssignmentSolver(RejectionPenalty rejectionPenalty, double timeLimit, double optimalityGap,
File problemPath, File solutionPath) {
this.rejectionPenalty = rejectionPenalty;

this.problemPath = problemPath;
Expand All @@ -55,11 +53,11 @@ public GlpkMpsAssignmentSolver(double unassignmentPenalty, double rejectionPenal
public Solution solve(Stream<AlonsoMoraTrip> candidates) {
try {
List<AlonsoMoraTrip> tripList = candidates.collect(Collectors.toList());
new MpsAssignmentWriter(tripList, unassignmentPenalty, rejectionPenalty).write(problemPath);
new MpsAssignmentWriter(tripList, rejectionPenalty).write(problemPath);

new ProcessBuilder("glpsol", "--mipgap", String.valueOf(optimalityGap), "--tmlim",
String.valueOf((int) (timeLimit * 1e3)), "-w", solutionPath.toString(), problemPath.toString())
.start().waitFor();
.start().waitFor();

BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(solutionPath)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.matsim.alonso_mora.algorithm.AlonsoMoraRequest;
import org.matsim.alonso_mora.algorithm.AlonsoMoraTrip;
import org.matsim.alonso_mora.algorithm.AlonsoMoraVehicle;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.RejectionPenalty;

/**
* Writes the assignment problem from Alonso-Mora et al. in MPS format which can
Expand All @@ -23,13 +24,11 @@
public class MpsAssignmentWriter {
private final List<AlonsoMoraTrip> tripList;

private final double unassignmentPenalty;
private final double rejectionPenalty;
private final RejectionPenalty rejectionPenalty;

public MpsAssignmentWriter(List<AlonsoMoraTrip> tripList, double unassignmentPenalty, double rejectionPenalty) {
public MpsAssignmentWriter(List<AlonsoMoraTrip> tripList, RejectionPenalty rejectionPenalty) {
this.tripList = tripList;
this.rejectionPenalty = rejectionPenalty;
this.unassignmentPenalty = unassignmentPenalty;
}

public void write(File path) throws IOException {
Expand Down Expand Up @@ -83,7 +82,7 @@ public void write(File path) throws IOException {

// Request influences
for (int i = 0; i < numberOfRequests; i++) {
double penalty = requestList.get(i).isAssigned() ? unassignmentPenalty : rejectionPenalty;
double penalty = rejectionPenalty.getPenalty(requestList.get(i));
writer.write(String.format(Locale.US, " x%d R%07d %f R%07d 1\n", i, 0, penalty, i + numberOfVehicles + 1));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.matsim.alonso_mora.algorithm.AlonsoMoraRequest;
import org.matsim.alonso_mora.algorithm.AlonsoMoraTrip;
import org.matsim.alonso_mora.algorithm.AlonsoMoraVehicle;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.DefaultRejectionPenalty;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.RejectionPenalty;
import org.matsim.alonso_mora.algorithm.function.AlonsoMoraFunction.Result;
import org.mockito.Mockito;

Expand Down Expand Up @@ -50,7 +52,8 @@ public void testOneVehicleOneRequestExample(@TempDir File temporaryFolder) throw
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "problem");

AssignmentSolver solver = new CbcMpsAssignmentSolver(9000.0, 9000.0, 1000, 0.1, problemFile, solutionFile, 0);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new CbcMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile, 0);

AlonsoMoraVehicle vehicle = mockVehicle();
AlonsoMoraRequest request = mockRequest();
Expand All @@ -68,7 +71,8 @@ public void testTwoIndependentRequests(@TempDir File temporaryFolder) throws IOE
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "problem");

AssignmentSolver solver = new CbcMpsAssignmentSolver(9000.0, 9000.0, 1000, 0.1, problemFile, solutionFile, 0);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new CbcMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile, 0);

AlonsoMoraVehicle vehicle1 = mockVehicle();
AlonsoMoraRequest request1 = mockRequest();
Expand All @@ -91,7 +95,8 @@ public void testTwoRequestsWithOneVehicle(@TempDir File temporaryFolder) throws
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "problem");

AssignmentSolver solver = new CbcMpsAssignmentSolver(9000.0, 9000.0, 1000, 0.1, problemFile, solutionFile, 0);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new CbcMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile, 0);

AlonsoMoraVehicle vehicle = mockVehicle();
AlonsoMoraRequest request1 = mockRequest();
Expand All @@ -118,7 +123,8 @@ public void testTwoRequestsWithOneVehicleLowPenalty(@TempDir File temporaryFolde
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "problem");

AssignmentSolver solver = new CbcMpsAssignmentSolver(250.0, 250.0, 1000, 0.1, problemFile, solutionFile, 0);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(250.0, 250.0);
AssignmentSolver solver = new CbcMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile, 0);

AlonsoMoraVehicle vehicle = mockVehicle();
AlonsoMoraRequest request1 = mockRequest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.matsim.alonso_mora.algorithm.AlonsoMoraRequest;
import org.matsim.alonso_mora.algorithm.AlonsoMoraTrip;
import org.matsim.alonso_mora.algorithm.AlonsoMoraVehicle;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.DefaultRejectionPenalty;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.RejectionPenalty;
import org.matsim.alonso_mora.algorithm.function.AlonsoMoraFunction.Result;
import org.mockito.Mockito;

Expand Down Expand Up @@ -49,9 +51,9 @@ private AlonsoMoraTrip mockTrip(AlonsoMoraVehicle vehicle, double cost, AlonsoMo
public void testOneVehicleOneRequestExample(@TempDir File temporaryFolder) throws IOException {
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "solution");
AssignmentSolver solver = new GlpkMpsAssignmentSolver(9000.0, 9000.0, 1000, 0.1,
problemFile, solutionFile);

RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new GlpkMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile);

AlonsoMoraVehicle vehicle = mockVehicle();
AlonsoMoraRequest request = mockRequest();
Expand All @@ -68,9 +70,9 @@ public void testOneVehicleOneRequestExample(@TempDir File temporaryFolder) throw
public void testTwoIndependentRequests(@TempDir File temporaryFolder) throws IOException {
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "solution");
AssignmentSolver solver = new GlpkMpsAssignmentSolver(9000.0, 9000.0, 1000, 0.1,
problemFile, solutionFile);

RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new GlpkMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile);

AlonsoMoraVehicle vehicle1 = mockVehicle();
AlonsoMoraRequest request1 = mockRequest();
Expand All @@ -92,9 +94,9 @@ public void testTwoIndependentRequests(@TempDir File temporaryFolder) throws IOE
public void testTwoRequestsWithOneVehicle(@TempDir File temporaryFolder) throws IOException {
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "solution");
AssignmentSolver solver = new GlpkMpsAssignmentSolver(9000.0, 9000.0, 1000, 0.1,
problemFile, solutionFile);

RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new GlpkMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile);

AlonsoMoraVehicle vehicle = mockVehicle();
AlonsoMoraRequest request1 = mockRequest();
Expand All @@ -120,9 +122,9 @@ public void testTwoRequestsWithOneVehicle(@TempDir File temporaryFolder) throws
public void testTwoRequestsWithOneVehicleLowPenalty(@TempDir File temporaryFolder) throws IOException {
File problemFile = new File(temporaryFolder, "problem");
File solutionFile = new File(temporaryFolder, "solution");
AssignmentSolver solver = new GlpkMpsAssignmentSolver(250.0, 250.0, 1000, 0.1,
problemFile, solutionFile);

RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(250.0, 250.0);
AssignmentSolver solver = new GlpkMpsAssignmentSolver(rejectionPenalty, 1000, 0.1, problemFile, solutionFile);

AlonsoMoraVehicle vehicle = mockVehicle();
AlonsoMoraRequest request1 = mockRequest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,14 @@ public class CplexAssignmentSolver implements AssignmentSolver {

private static final Logger logger = LogManager.getLogger(CplexAssignmentSolver.class);

private final double unassignmentPenalty;
private final double rejectionPenalty;
private final RejectionPenalty rejectionPenalty;

private final int numberOfThreads;
private final double timeLimit;
private final double optimalityGap;

public CplexAssignmentSolver(double unassignmentPenalty, double rejectionPenalty, int numberOfThreads,
double timeLimit, double optimalityGap) {
this.unassignmentPenalty = unassignmentPenalty;
public CplexAssignmentSolver(RejectionPenalty rejectionPenalty, int numberOfThreads, double timeLimit,
double optimalityGap) {
this.rejectionPenalty = rejectionPenalty;
this.numberOfThreads = numberOfThreads;
this.timeLimit = timeLimit;
Expand Down Expand Up @@ -129,7 +127,7 @@ public Solution solve(Stream<AlonsoMoraTrip> candidates) {

for (int k = 0; k < requestVariables.size(); k++) {
AlonsoMoraRequest request = requestList.get(k);
double penalty = request.isAssigned() ? unassignmentPenalty : rejectionPenalty;
double penalty = rejectionPenalty.getPenalty(request);
objective.addTerm(penalty, requestVariables.get(k));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.matsim.alonso_mora.AlonsoMoraConfigGroup;
import org.matsim.alonso_mora.MultiModeAlonsoMoraConfigGroup;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.RejectionPenalty;
import org.matsim.alonso_mora.algorithm.relocation.RelocationSolver;
import org.matsim.contrib.drt.run.DrtConfigGroup;
import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule;
Expand Down Expand Up @@ -37,8 +38,8 @@ protected void configureQSim() {

CplexAssignmentParameters solverParameters = (CplexAssignmentParameters) amConfig.assignmentSolver;

return new CplexAssignmentSolver(amConfig.unassignmentPenalty, amConfig.rejectionPenalty,
globalConfig.getNumberOfThreads(), solverParameters.timeLimit, solverParameters.optimalityGap);
return new CplexAssignmentSolver(getter.getModal(RejectionPenalty.class), globalConfig.getNumberOfThreads(),
solverParameters.timeLimit, solverParameters.optimalityGap);
})).in(Singleton.class);

if (amConfig.assignmentSolver.getSolverType().equals(CplexAssignmentSolver.TYPE)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.matsim.alonso_mora.algorithm.AlonsoMoraTrip;
import org.matsim.alonso_mora.algorithm.AlonsoMoraVehicle;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.DefaultRejectionPenalty;
import org.matsim.alonso_mora.algorithm.assignment.AssignmentSolver.RejectionPenalty;
import org.matsim.alonso_mora.algorithm.function.AlonsoMoraFunction.Result;
import org.matsim.api.core.v01.Id;
import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
Expand Down Expand Up @@ -52,7 +54,8 @@ private AlonsoMoraTrip mockTrip(AlonsoMoraVehicle vehicle, double cost, AlonsoMo

@Test
public void testOneVehicleOneRequestExample() {
AssignmentSolver solver = new CplexAssignmentSolver(9000.0, 9000.0, 1000, 10.0, 0.1);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new CplexAssignmentSolver(rejectionPenalty, 1000, 10.0, 0.1);

AlonsoMoraVehicle vehicle = mockVehicle(0);
AlonsoMoraRequest request = mockRequest();
Expand All @@ -67,7 +70,8 @@ public void testOneVehicleOneRequestExample() {

@Test
public void testTwoIndependentRequests() {
AssignmentSolver solver = new CplexAssignmentSolver(9000.0, 9000.0, 1000, 10.0, 0.1);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new CplexAssignmentSolver(rejectionPenalty, 1000, 10.0, 0.1);

AlonsoMoraVehicle vehicle1 = mockVehicle(1);
AlonsoMoraRequest request1 = mockRequest();
Expand All @@ -87,7 +91,8 @@ public void testTwoIndependentRequests() {

@Test
public void testTwoRequestsWithOneVehicle() {
AssignmentSolver solver = new CplexAssignmentSolver(9000.0, 9000.0, 1000, 10.0, 0.1);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(9000.0, 9000.0);
AssignmentSolver solver = new CplexAssignmentSolver(rejectionPenalty, 1000, 10.0, 0.1);

AlonsoMoraVehicle vehicle = mockVehicle(0);
AlonsoMoraRequest request1 = mockRequest();
Expand All @@ -111,7 +116,8 @@ public void testTwoRequestsWithOneVehicle() {

@Test
public void testTwoRequestsWithOneVehicleLowPenalty() {
AssignmentSolver solver = new CplexAssignmentSolver(250.0, 250.0, 1000, 10.0, 0.1);
RejectionPenalty rejectionPenalty = new DefaultRejectionPenalty(250.0, 250.0);
AssignmentSolver solver = new CplexAssignmentSolver(rejectionPenalty, 1000, 10.0, 0.1);

AlonsoMoraVehicle vehicle = mockVehicle(0);
AlonsoMoraRequest request1 = mockRequest();
Expand Down
Loading

0 comments on commit 2d2fc34

Please sign in to comment.