Skip to content

Commit b73d5aa

Browse files
committed
Encapsulate arc and vertex variables in Vars class
1 parent 40a3b30 commit b73d5aa

File tree

2 files changed

+107
-57
lines changed

2 files changed

+107
-57
lines changed

src/main/java/io/github/plastix/Main.java

Lines changed: 18 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
import com.graphhopper.util.EdgeIterator;
1414
import gurobi.*;
1515

16-
import java.util.Arrays;
17-
1816
public class Main {
1917

2018
private static Params params;
@@ -27,33 +25,14 @@ public class Main {
2725
private static Weighting score;
2826
private static FlagEncoder flagEncoder;
2927

28+
// Solver variables
3029
private static GRBEnv env;
3130
private static GRBModel model;
32-
private static GRBVar[] arcsFwd;
33-
private static GRBVar[] arcsBwd;
34-
private static int[] arcBaseIds;
3531

3632
private static void setupSolver() throws GRBException {
3733
env = new GRBEnv("osm.log");
3834
model = new GRBModel(env);
39-
40-
AllEdgesIterator edges = graph.getAllEdges();
41-
int numEdges = edges.getMaxId();
42-
int numNodes = graph.getNodes();
43-
44-
// Make a decision variable "x_i" for every arc in our graph
45-
// x_i: =1 if arc is travelled, 0 otherwise
46-
// Since every edge can be 2 arcs (forward + backward), we keep two lists
47-
arcsFwd = model.addVars(numEdges, GRB.BINARY);
48-
arcsBwd = model.addVars(numEdges, GRB.BINARY);
49-
arcBaseIds = new int[numEdges];
50-
51-
// Make a variable for every node in the graph
52-
// verts[i]: = the number of times vertex i is visited
53-
char[] types = new char[numNodes];
54-
Arrays.fill(types, GRB.INTEGER);
55-
GRBVar[] verts = model.addVars(null, null, null, types,
56-
null, 0, numNodes);
35+
Vars vars = new Vars(graph, model, flagEncoder);
5736

5837
// (1a)
5938
// Objective maximizes total collected score of all roads
@@ -63,51 +42,43 @@ private static void setupSolver() throws GRBException {
6342
// Limit length of path
6443
GRBLinExpr maxCost = new GRBLinExpr();
6544

45+
AllEdgesIterator edges = graph.getAllEdges();
6646
while(edges.next()) {
67-
int edgeId = edges.getEdge();
68-
arcBaseIds[edgeId] = edges.getBaseNode(); // Record the original base ID to keep direction
69-
GRBVar fwd = arcsFwd[edgeId];
70-
GRBVar bwd = arcsBwd[edgeId];
71-
double edgeScore = score.calcWeight(edges, false, edgeId);
47+
double edgeScore = score.calcWeight(edges, false, edges.getEdge());
7248
double edgeDist = edges.getDistance();
7349

74-
if(edges.isForward(flagEncoder)) {
75-
objective.addTerm(edgeScore, fwd);
76-
maxCost.addTerm(edgeDist, fwd);
77-
} else {
78-
fwd.set(GRB.DoubleAttr.UB, 0);
79-
}
50+
GRBVar forward = vars.getArc(edges);
51+
GRBVar backward = vars.getComplementArc(edges);
8052

81-
if(edges.isBackward(flagEncoder)) {
82-
objective.addTerm(edgeScore, bwd);
83-
maxCost.addTerm(edgeDist, bwd);
84-
} else {
85-
bwd.set(GRB.DoubleAttr.UB, 0);
86-
}
53+
objective.addTerm(edgeScore, forward);
54+
objective.addTerm(edgeScore, backward);
55+
maxCost.addTerm(edgeDist, forward);
56+
maxCost.addTerm(edgeDist, backward);
8757

8858
// (1j)
8959
GRBLinExpr arcConstraint = new GRBLinExpr();
90-
arcConstraint.addTerm(1, fwd);
91-
arcConstraint.addTerm(1, bwd);
60+
arcConstraint.addTerm(1, forward);
61+
arcConstraint.addTerm(1, backward);
9262
model.addConstr(arcConstraint, GRB.LESS_EQUAL, 1, "arc_constraint");
9363
}
9464

9565
model.setObjective(objective, GRB.MAXIMIZE);
9666
model.addConstr(maxCost, GRB.LESS_EQUAL, params.getMaxCost(), "max_cost");
9767

68+
int numNodes = graph.getNodes();
9869
for(int i = 0; i < numNodes; i++) {
9970
// (1d)
10071
GRBLinExpr edgeCounts = new GRBLinExpr();
10172
IntHashSet incomingIds = new IntHashSet();
10273
EdgeIterator incoming = graphUtils.incomingEdges(i);
10374
while(incoming.next()) {
10475
incomingIds.add(incoming.getEdge());
105-
edgeCounts.addTerm(1, getArc(incoming));
76+
edgeCounts.addTerm(1, vars.getArc(incoming));
10677
}
10778

10879
EdgeIterator outgoing = graphUtils.outgoingEdges(i);
10980
while(outgoing.next()) {
110-
GRBVar arc = getArc(outgoing);
81+
GRBVar arc = vars.getArc(outgoing);
11182
// Check if we already recorded it as an incoming edge
11283
if(incomingIds.contains(outgoing.getEdge())) {
11384
edgeCounts.remove(arc);
@@ -122,29 +93,19 @@ private static void setupSolver() throws GRBException {
12293
GRBLinExpr vertexVisits = new GRBLinExpr();
12394
outgoing = graphUtils.outgoingEdges(i);
12495
while(outgoing.next()) {
125-
vertexVisits.addTerm(1, getArc(outgoing));
96+
vertexVisits.addTerm(1, vars.getArc(outgoing));
12697
}
127-
vertexVisits.addTerm(-1, verts[i]);
98+
vertexVisits.addTerm(-1, vars.getVertex(i));
12899
model.addConstr(vertexVisits, GRB.EQUAL, 0, "vertex_visits");
129100
}
130101

131102
// (1h)/(1i)
132103
// Start vertex can only be visited once
133-
GRBVar startNode = verts[START_NODE_ID];
104+
GRBVar startNode = vars.getVertex(START_NODE_ID);
134105
startNode.set(GRB.DoubleAttr.LB, 1);
135106
startNode.set(GRB.DoubleAttr.UB, 1);
136107
}
137108

138-
private static GRBVar getArc(EdgeIterator edge) {
139-
int edgeId = edge.getEdge();
140-
int baseNode = edge.getBaseNode();
141-
if(baseNode == arcBaseIds[edgeId]) {
142-
return arcsFwd[edgeId];
143-
} else {
144-
return arcsBwd[edgeId];
145-
}
146-
}
147-
148109
private static void runSolver() throws GRBException {
149110
System.out.println("Max cost: " + params.getMaxCost());
150111
System.out.println("Start position: " + params.getStartLat() + ", " + params.getStartLon() +
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package io.github.plastix;
2+
3+
import com.graphhopper.routing.util.AllEdgesIterator;
4+
import com.graphhopper.routing.util.FlagEncoder;
5+
import com.graphhopper.storage.Graph;
6+
import com.graphhopper.util.EdgeIterator;
7+
import gurobi.GRB;
8+
import gurobi.GRBException;
9+
import gurobi.GRBModel;
10+
import gurobi.GRBVar;
11+
12+
import java.util.Arrays;
13+
14+
public class Vars {
15+
16+
private Graph graph;
17+
private FlagEncoder flagEncoder;
18+
private GRBModel model;
19+
20+
// arcs[arcId][0] = forwardArc
21+
// arcs[arcId][1] = backwardArc
22+
private GRBVar[][] arcs;
23+
private GRBVar[] verts;
24+
private int[] arcBaseIds;
25+
26+
Vars(Graph graph, GRBModel model, FlagEncoder flagEncoder) throws GRBException {
27+
this.graph = graph;
28+
this.model = model;
29+
this.flagEncoder = flagEncoder;
30+
addVarsToModel();
31+
}
32+
33+
private void addVarsToModel() throws GRBException {
34+
AllEdgesIterator edges = graph.getAllEdges();
35+
int numEdges = edges.getMaxId();
36+
int numNodes = graph.getNodes();
37+
arcBaseIds = new int[numEdges];
38+
39+
// Make a decision variable for every arc in our graph
40+
// arcs[i] = 1 if arc is travelled, 0 otherwise
41+
GRBVar[] arcVars = model.addVars(2 * numEdges, GRB.BINARY);
42+
arcs = new GRBVar[numEdges][2];
43+
44+
// Make a variable for every node in the graph
45+
// verts[i] = n the number of times vertex i is visited
46+
char[] types = new char[numNodes];
47+
Arrays.fill(types, GRB.INTEGER);
48+
verts = model.addVars(null, null, null, types,
49+
null, 0, numNodes);
50+
51+
int i = 0;
52+
while(edges.next()) {
53+
int edgeId = edges.getEdge();
54+
int baseNode = edges.getBaseNode();
55+
arcBaseIds[edgeId] = baseNode;
56+
57+
GRBVar forward = arcVars[i++];
58+
GRBVar backward = arcVars[i++];
59+
60+
arcs[edgeId][0] = forward;
61+
arcs[edgeId][1] = backward;
62+
63+
if(!edges.isForward(flagEncoder)) {
64+
forward.set(GRB.DoubleAttr.UB, 0);
65+
}
66+
67+
if(!edges.isBackward(flagEncoder)) {
68+
backward.set(GRB.DoubleAttr.UB, 0);
69+
}
70+
}
71+
}
72+
73+
private int getIndex(EdgeIterator edge) {
74+
return arcBaseIds[edge.getEdge()] == edge.getBaseNode() ? 0 : 1;
75+
}
76+
77+
public GRBVar getArc(EdgeIterator edge) {
78+
return arcs[edge.getEdge()][getIndex(edge)];
79+
}
80+
81+
public GRBVar getComplementArc(EdgeIterator edge) {
82+
return arcs[edge.getEdge()][getIndex(edge) ^ 1];
83+
}
84+
85+
public GRBVar getVertex(int id) {
86+
return verts[id];
87+
}
88+
89+
}

0 commit comments

Comments
 (0)