Skip to content

Commit

Permalink
Add extra options specific to a solver
Browse files Browse the repository at this point in the history
'--extra <filepath>' option is introduced.
This gives the path to a json file containing a dictionary.
This dictionary sets values for options that are specific to a
particular solver.

For instance, one extra option is introduced for defoCP and SRLS.
This argument controls the maximum number of intermediate segments
that these solvers can use.

This fixes Issue #7
  • Loading branch information
jadinm committed Mar 11, 2019
1 parent 45e889a commit 7898aef
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 35 deletions.
2 changes: 2 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ lazy val root = (project in file(".")).
libraryDependencies += "net.sf.jung" % "jung-visualization" % "2.1.1",
libraryDependencies += "net.sf.jung" % "jung-graph-impl" % "2.1.1",
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "1.0.4",
libraryDependencies += "com.fasterxml.jackson.core" % "jackson-core" % "2.9.8",
libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.8",
javaOptions in run += "-Xmx4G"
)

Expand Down
31 changes: 25 additions & 6 deletions src/main/java/edu/repetita/core/Setting.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package edu.repetita.core;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.*;

import edu.repetita.io.RepetitaParser;
import edu.repetita.paths.ExplicitPaths;
Expand Down Expand Up @@ -42,19 +41,19 @@ public void setDemandsFilename(String demandsFilename) {
public String getTopologyFilename() {
return this.topologyFilename;
}

public Topology getTopology() {
return this.topology;
}

public void setTopology(Topology topology) {
this.topology = topology;
}

public String getDemandsFilename() {
return this.demandsFilename;
}

public Demands getDemands() { return this.demands; }

public void setDemands(Demands newDemands) {
Expand Down Expand Up @@ -113,13 +112,33 @@ public ExplicitPaths getExplicitPaths() {
return this.config.getExplicitPaths();
}

/**
* Fills the args map with each extra argument name as key and its description as value
*/
public void help(HashMap<String, String> args) { }

protected void setExtra(String key, Object value) throws IllegalArgumentException {
throw new IllegalArgumentException("This solver does not take option '" + key + "'");
}

public void setExtras(Map<String, Object> extras) throws IllegalArgumentException {
for (String key : extras.keySet()) {
Object value = extras.get(key);
setExtra(key, value);
}
}

public Setting clone(){
Setting copy = new Setting();
this.init(copy);
return copy;
}

protected void init(Setting copy) {
copy.setTopology(this.topology.clone());
copy.setDemands(this.demands);
copy.setDemandChanges(this.demandChanges);
copy.setNumberReoptimizations(this.numberReoptimizations);
copy.setRoutingConfiguration(this.getRoutingConfiguration().clone());
return copy;
}
}
7 changes: 7 additions & 0 deletions src/main/java/edu/repetita/core/Solver.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,11 @@ public Solver(){
* @return the time needed by the last call to solve(), in nanoseconds
*/
public abstract long solveTime(Setting setting);

/**
* @return a Setting object to store and parse all the specific arguments of this solver
*/
public Setting getSetting() {
return new Setting();
}
}
67 changes: 56 additions & 11 deletions src/main/java/edu/repetita/main/Main.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package edu.repetita.main;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.repetita.core.Scenario;
import edu.repetita.core.Setting;
import edu.repetita.core.Solver;
Expand All @@ -11,9 +13,11 @@
import edu.repetita.scenarios.ScenarioFactory;
import edu.repetita.solvers.SolverFactory;

import java.net.URISyntaxException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Main {
Expand All @@ -33,7 +37,7 @@ private static String getUsageOptions(){
ArrayList<String> descriptions = new ArrayList<>();

options.addAll(Arrays.asList("h","doc","graph","demands","demandchanges","solver",
"scenario","t","outpaths","out","verbose"));
"scenario","t","outpaths","out","verbose","extra"));

descriptions.addAll(Arrays.asList(
"only prints this help message",
Expand All @@ -46,12 +50,36 @@ private static String getUsageOptions(){
"maximum time in seconds allowed to the solver",
"name of the file collecting information of paths",
"name of the file collecting all the information (standard output by default)",
"level of debugging (default 0, only results reported)"
"level of debugging (default 0, only results reported)",
"A path to a json file containing a JSON dictionary of extra options." +
" These options are specific to a solver."
));

return "All options:\n" + RepetitaWriter.formatAsListTwoColumns(options, descriptions, " -");
}

private static String getUsageExtraOptions() {
StringBuilder sb = new StringBuilder();

for (String solverID: storage.getSolverIDs()) {
Setting setting = storage.getSolver(solverID).getSetting();
HashMap<String, String> extras = new HashMap<>();
setting.help(extras);

if (extras.size() > 0) {
ArrayList<String> options = new ArrayList<>(extras.keySet());
ArrayList<String> descriptions = new ArrayList<>();
for (String option: options) {
descriptions.add(extras.get(option));
}
sb.append("\n").append(solverID).append(" extra options:\n")
.append(RepetitaWriter.formatAsListTwoColumns(options, descriptions, " "));
}
}

return sb.toString();
}


private static void printHelp(String additional) {
if (additional != null && !additional.equals("")) {
Expand All @@ -60,6 +88,7 @@ private static void printHelp(String additional) {

System.out.println(getUsage());
System.out.println(getUsageOptions());
System.out.println(getUsageExtraOptions());

System.exit(1);
}
Expand Down Expand Up @@ -123,6 +152,10 @@ public static void main(String[] args) throws Exception {

String solverChoice = "tabuLS";
String scenarioChoice = "SingleSolverRun";
HashMap<String, Object> extras = new HashMap<>();

// create storage
storage = RepetitaStorage.getInstance();

// parse command line arguments
int i = 0;
Expand Down Expand Up @@ -178,15 +211,21 @@ public static void main(String[] args) throws Exception {
RepetitaWriter.setVerbose(verboseLevel);
break;

default:
case "-extra":
try {
ObjectMapper mapper = new ObjectMapper();
extras = mapper.readValue(new File(args[++i]), new TypeReference<Map<String, Object>>(){});
} catch (IOException e) {
printHelp("IOException when reading extra options: " + e.getMessage());
}
break;

default:
printHelp("Unknown option " + args[i]);
}
}
i++;
}

// create storage (after having set the verbose level)
storage = RepetitaStorage.getInstance();

// check that the strictly necessary information has been provided in input (after having creating the storage)
if (args.length < 1 || help) printHelp("");
if (graphFilename == null) printHelp("Needs an input topology file");
Expand All @@ -196,12 +235,18 @@ public static void main(String[] args) throws Exception {
if (! storage.getSolverIDs().contains(solverChoice)) printHelp("Unknown solver: " + solverChoice);
if (! storage.getScenarioIDs().contains(scenarioChoice)) printHelp("Unknown scenario: " + scenarioChoice);

// run an experiment according to command line parameters
Setting setting = storage.newSetting(graphFilename, demandsFilename, demandChangesFilenames);

Solver solver = storage.getSolver(solverChoice);
solver.setVerbose(verboseLevel);

// run an experiment according to command line parameters
Setting setting = null;
try {
setting = storage.newSetting(solver, graphFilename, demandsFilename,
demandChangesFilenames, extras);
} catch (IllegalArgumentException e) {
printHelp(e.getMessage());
}

Scenario scenario = storage.newScenario(scenarioChoice, setting, solver);
scenario.run((long) timeLimit * 1000);
}
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/edu/repetita/main/RepetitaStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,18 @@ public Scenario newScenario(String scenarioName, Setting setting, Solver solver)
return scenario;
}

public Setting newSetting(String graphFilename, String demandsFilename){
Setting setting = new Setting();
public Setting newSetting(Solver solver, String graphFilename, String demandsFilename){
Setting setting = solver.getSetting();
setting.setTopologyFilename(graphFilename);
setting.setDemandsFilename(demandsFilename);
return setting;
}

public Setting newSetting(String graphFilename, String demandsFilename, List<String> otherDemandsFilenames){
Setting setting = this.newSetting(graphFilename,demandsFilename);
public Setting newSetting(Solver solver, String graphFilename, String demandsFilename,
List<String> otherDemandsFilenames, Map<String, Object> extras){
Setting setting = this.newSetting(solver, graphFilename,demandsFilename);
setting.setDemandChangesFilenames(otherDemandsFilenames);
setting.setExtras(extras);
return setting;
}

Expand Down
55 changes: 55 additions & 0 deletions src/main/java/edu/repetita/settings/SRSetting.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package edu.repetita.settings;

import edu.repetita.core.Setting;

import java.util.*;

public class SRSetting extends Setting {

private int maxSeg = 1;

public int getMaxSeg() {
return maxSeg;
}

public void setMaxSeg(int maxSeg) {
this.maxSeg = maxSeg;
}

@Override
public void help(HashMap<String, String> args) {
args.put("maxseg", "The maximum number of intermediate segments (i.e., source and destination nodes are not counted)");
}

@Override
protected void setExtra(String key, Object value) throws IllegalArgumentException {
switch (key) {
case "maxseg":
if (!(value instanceof Integer)) {
throw new IllegalArgumentException("The maximum number of intermediate segments should be an integer.");
}
int maxSeg = (Integer) value;
if (maxSeg < 0) {
throw new IllegalArgumentException("'" + value + "' is not a valid number of segment." +
" It should be positive.");
}
this.maxSeg = maxSeg;
break;
default:
super.setExtra(key, value);
}
}

@Override
public Setting clone() {
Setting copy = new SRSetting();
this.init(copy);
return copy;
}

@Override
protected void init(Setting copy) {
super.init(copy);
((SRSetting) copy).setMaxSeg(maxSeg);
}
}
7 changes: 7 additions & 0 deletions src/main/java/edu/repetita/solvers/SRSolver.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package edu.repetita.solvers;

import edu.repetita.core.Setting;
import edu.repetita.core.Solver;
import edu.repetita.settings.SRSetting;

/**
* Abstract class implementing methods common to all segment-routing based solvers.
Expand All @@ -12,4 +14,9 @@ public abstract class SRSolver extends Solver {
public double getTargetObjectiveValue() { return this.targetObjectiveValue; }

public void setTargetObjectiveValue(double value) { this.targetObjectiveValue = value; }

@Override
public Setting getSetting() {
return new SRSetting();
}
}
12 changes: 7 additions & 5 deletions src/main/java/edu/repetita/solvers/sr/DefoCP.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import edu.repetita.core.Setting;
import edu.repetita.core.Topology;
import edu.repetita.paths.SRPaths;
import edu.repetita.settings.SRSetting;
import edu.repetita.solvers.SRSolver;

import java.io.PrintWriter;
Expand Down Expand Up @@ -41,10 +42,11 @@ public long solveTime(Setting setting) {

@Override
public void solve(Setting setting, long timeMillis) {
SRSetting srSetting = (SRSetting) setting;
// extract information from setting
Topology topology = setting.getTopology();
Topology topology = srSetting.getTopology();
int nEdges = topology.nEdges;
Demands demands = setting.getDemands();
Demands demands = srSetting.getDemands();

// translate in scala data structures
be.ac.ucl.ingi.defo.core.Topology defoTopology = be.ac.ucl.ingi.defo.core.Topology.apply(topology.edgeSrc, topology.edgeDest);
Expand All @@ -57,7 +59,7 @@ public void solve(Setting setting, long timeMillis) {
DEFOConstraint[][] demandConstraints = new DEFOConstraint[demands.nDemands][0];
DEFOConstraint[] topologyConstraints = new DEFOConstraint[0];

DEFOInstance instance = new DEFOInstance(defoTopology, topology.edgeWeight, demandTraffic, demands.source, demands.dest, demandConstraints, topologyConstraints, edgeCapacities, topology.edgeLatency);
DEFOInstance instance = new DEFOInstance(defoTopology, topology.edgeWeight, demandTraffic, demands.source, demands.dest, demandConstraints, topologyConstraints, edgeCapacities, topology.edgeLatency, srSetting.getMaxSeg());
DEFOptimizer optimizer = new DEFOptimizer(instance, this.verbose > 0, scala.Option.apply((PrintWriter) null));

TimeUnit timeLimit = new TimeUnit((int) timeMillis, timeMillis + "ms");
Expand All @@ -72,11 +74,11 @@ public void solve(Setting setting, long timeMillis) {

// write results back
int[][] bestPaths = optimizer.core().bestPaths();
SRPaths paths = new SRPaths(setting.getDemands(),setting.getTopology().nNodes);
SRPaths paths = new SRPaths(srSetting.getDemands(),srSetting.getTopology().nNodes);
for (int demand = 0; demand < demands.nDemands; demand++) {
paths.setPath(demand, bestPaths[demand]);
}
setting.setSRPaths(paths);
srSetting.setSRPaths(paths);
}

}
5 changes: 5 additions & 0 deletions src/main/java/edu/repetita/solvers/sr/MIPTwoSRNoSplit.java
Original file line number Diff line number Diff line change
Expand Up @@ -278,4 +278,9 @@ public void computeSegments(Setting setting, long timeMillis) {
}
}

@Override
public Setting getSetting() {
return new Setting();
}

}
Loading

0 comments on commit 7898aef

Please sign in to comment.