Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow custom rejection penalties through an interface #36

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading