1
1
package io .github .plastix ;
2
2
3
- import com .google .ortools .linearsolver .MPConstraint ;
4
- import com .google .ortools .linearsolver .MPObjective ;
5
- import com .google .ortools .linearsolver .MPSolver ;
6
- import com .google .ortools .linearsolver .MPVariable ;
3
+ import com .carrotsearch .hppc .IntHashSet ;
7
4
import com .graphhopper .GraphHopper ;
8
5
import com .graphhopper .reader .osm .GraphHopperOSM ;
9
6
import com .graphhopper .routing .util .AllEdgesIterator ;
15
12
import com .graphhopper .storage .index .QueryResult ;
16
13
import com .graphhopper .util .EdgeIterator ;
17
14
import com .graphhopper .util .shapes .GHPoint ;
15
+ import gurobi .*;
16
+
17
+ import java .util .Arrays ;
18
18
19
19
public class Main {
20
20
21
- private static final String SOLVER_TYPE = "GLPK_MIXED_INTEGER_PROGRAMMING" ;
22
21
// TODO (Aidan) Read these params from file
23
22
private static final int MAX_COST = 40_000 ; // In meters
24
23
private static final int MIN_COST = 20_000 ; // In meters
@@ -33,34 +32,14 @@ public class Main {
33
32
private static Weighting score ;
34
33
private static FlagEncoder flagEncoder ;
35
34
36
- // Optimization variables
37
- private static MPSolver solver ;
38
- private static MPVariable [] arcsFwd ;
39
- private static MPVariable [] arcsBwd ;
35
+ private static GRBModel model ;
36
+ private static GRBVar [] arcsFwd ;
37
+ private static GRBVar [] arcsBwd ;
40
38
private static int [] arcBaseIds ;
41
39
42
- static {
43
- // Load Google Optimization tools native libs
44
- System .loadLibrary ("jniortools" );
45
- }
46
-
47
- private static MPSolver createSolver (String solverType ) {
48
- try {
49
- return new MPSolver ("osm-integer-programming" ,
50
- MPSolver .OptimizationProblemType .valueOf (solverType ));
51
- } catch (java .lang .IllegalArgumentException e ) {
52
- return null ;
53
- }
54
- }
55
-
56
- private static void setupSolver () {
57
- solver = createSolver (SOLVER_TYPE );
58
- if (solver == null ) {
59
- System .out .println ("Could not create solver " + SOLVER_TYPE );
60
- System .exit (1 );
61
- }
62
-
63
- double infinity = MPSolver .infinity ();
40
+ private static void setupSolver () throws GRBException {
41
+ GRBEnv env = new GRBEnv ("osm.log" );
42
+ model = new GRBModel (env );
64
43
65
44
AllEdgesIterator edges = graph .getAllEdges ();
66
45
int numEdges = edges .getMaxId ();
@@ -69,87 +48,98 @@ private static void setupSolver() {
69
48
// Make a decision variable "x_i" for every arc in our graph
70
49
// x_i: =1 if arc is travelled, 0 otherwise
71
50
// Since every edge can be 2 arcs (forward + backward), we keep two lists
72
- arcsFwd = solver . makeBoolVarArray (numEdges );
73
- arcsBwd = solver . makeBoolVarArray (numEdges );
51
+ arcsFwd = model . addVars (numEdges , GRB . BINARY );
52
+ arcsBwd = model . addVars (numEdges , GRB . BINARY );
74
53
arcBaseIds = new int [numEdges ];
75
54
76
55
// Make a variable for every node in the graph
77
56
// verts[i]: = the number of times vertex i is visited
78
- MPVariable [] verts = solver .makeIntVarArray (numNodes , 0 , infinity );
57
+ char [] types = new char [numNodes ];
58
+ Arrays .fill (types , GRB .INTEGER );
59
+ GRBVar [] verts = model .addVars (null , null , null , types ,
60
+ null , 0 , numNodes );
79
61
80
62
// (1a)
81
63
// Objective maximizes total collected score of all roads
82
- MPObjective objective = solver .objective ();
83
- objective .setMaximization ();
64
+ GRBLinExpr objective = new GRBLinExpr ();
84
65
85
66
// (1b)
86
67
// Limit length of path
87
- MPConstraint maxCost = solver . makeConstraint (- infinity , MAX_COST );
68
+ GRBLinExpr maxCost = new GRBLinExpr ( );
88
69
89
70
while (edges .next ()) {
90
71
int edgeId = edges .getEdge ();
91
72
arcBaseIds [edgeId ] = edges .getBaseNode (); // Record the original base ID to keep direction
92
- MPVariable fwd = arcsFwd [edgeId ];
93
- MPVariable bwd = arcsBwd [edgeId ];
73
+ GRBVar fwd = arcsFwd [edgeId ];
74
+ GRBVar bwd = arcsBwd [edgeId ];
94
75
double edgeScore = score .calcWeight (edges , false , edgeId );
95
76
double edgeDist = edges .getDistance ();
96
77
97
-
98
78
if (edges .isForward (flagEncoder )) {
99
- objective .setCoefficient ( fwd , edgeScore );
100
- maxCost .setCoefficient ( fwd , edgeDist );
79
+ objective .addTerm ( edgeScore , fwd );
80
+ maxCost .addTerm ( edgeDist , fwd );
101
81
} else {
102
- fwd .setInteger ( false );
82
+ fwd .set ( GRB . DoubleAttr . UB , 0 );
103
83
}
104
84
105
85
if (edges .isBackward (flagEncoder )) {
106
- objective .setCoefficient ( bwd , edgeScore );
107
- maxCost .setCoefficient ( bwd , edgeDist );
86
+ objective .addTerm ( edgeScore , bwd );
87
+ maxCost .addTerm ( edgeDist , bwd );
108
88
} else {
109
- bwd .setInteger ( false );
89
+ bwd .set ( GRB . DoubleAttr . UB , 0 );
110
90
}
111
91
112
92
// (1j)
113
- MPConstraint arcConstraint = solver .makeConstraint (-infinity , 1 );
114
- arcConstraint .setCoefficient (fwd , 1 );
115
- arcConstraint .setCoefficient (bwd , 1 );
93
+ GRBLinExpr arcConstraint = new GRBLinExpr ();
94
+ arcConstraint .addTerm (1 , fwd );
95
+ arcConstraint .addTerm (1 , bwd );
96
+ model .addConstr (arcConstraint , GRB .LESS_EQUAL , 1 , "arc_constraint" );
116
97
}
117
98
99
+ model .setObjective (objective , GRB .MAXIMIZE );
100
+ model .addConstr (maxCost , GRB .LESS_EQUAL , MAX_COST , "max_cost" );
101
+
118
102
for (int i = 0 ; i < numNodes ; i ++) {
119
103
// (1d)
120
- MPConstraint edgeCounts = solver .makeConstraint (0 , 0 );
104
+ GRBLinExpr edgeCounts = new GRBLinExpr ();
105
+ IntHashSet incomingIds = new IntHashSet ();
121
106
EdgeIterator incoming = graphUtils .incomingEdges (i );
122
107
while (incoming .next ()) {
123
- edgeCounts .setCoefficient (getArc (incoming ), 1 );
108
+ incomingIds .add (incoming .getEdge ());
109
+ edgeCounts .addTerm (1 , getArc (incoming ));
124
110
}
125
111
126
112
EdgeIterator outgoing = graphUtils .outgoingEdges (i );
127
113
while (outgoing .next ()) {
128
- MPVariable arc = getArc (outgoing );
114
+ GRBVar arc = getArc (outgoing );
129
115
// Check if we already recorded it as an incoming edge
130
- if (edgeCounts . getCoefficient ( arc ) == 1 ) {
131
- edgeCounts .setCoefficient (arc , 0 );
116
+ if (incomingIds . contains ( outgoing . getEdge ()) ) {
117
+ edgeCounts .remove (arc );
132
118
} else {
133
- edgeCounts .setCoefficient ( arc , - 1 );
119
+ edgeCounts .addTerm (- 1 , arc );
134
120
}
135
121
}
136
122
123
+ model .addConstr (edgeCounts , GRB .EQUAL , 0 , "edge_counts" );
124
+
137
125
// (1e)
138
- MPConstraint vertexVisits = solver . makeConstraint ( 0 , 0 );
126
+ GRBLinExpr vertexVisits = new GRBLinExpr ( );
139
127
outgoing = graphUtils .outgoingEdges (i );
140
128
while (outgoing .next ()) {
141
- vertexVisits .setCoefficient ( getArc (outgoing ), 1 );
129
+ vertexVisits .addTerm ( 1 , getArc (outgoing ));
142
130
}
143
- vertexVisits .setCoefficient (verts [i ], -1 );
131
+ vertexVisits .addTerm (-1 , verts [i ]);
132
+ model .addConstr (vertexVisits , GRB .EQUAL , 0 , "vertex_visits" );
144
133
}
145
134
146
135
// (1h)/(1i)
147
136
// Start vertex can only be visited once
148
- MPVariable startNode = verts [START_NODE_ID ];
149
- startNode .setBounds (1 , 1 );
137
+ GRBVar startNode = verts [START_NODE_ID ];
138
+ startNode .set (GRB .DoubleAttr .LB , 1 );
139
+ startNode .set (GRB .DoubleAttr .UB , 1 );
150
140
}
151
141
152
- private static MPVariable getArc (EdgeIterator edge ) {
142
+ private static GRBVar getArc (EdgeIterator edge ) {
153
143
int edgeId = edge .getEdge ();
154
144
int baseNode = edge .getBaseNode ();
155
145
if (baseNode == arcBaseIds [edgeId ]) {
@@ -159,32 +149,11 @@ private static MPVariable getArc(EdgeIterator edge) {
159
149
}
160
150
}
161
151
162
- private static void runSolver () {
152
+ private static void runSolver () throws GRBException {
163
153
System .out .println ("Max cost: " + MAX_COST );
164
154
System .out .println ("Start position: " + START_POSITION + " (Node " + START_NODE_ID + ")" );
165
- System .out .println ("Number of constraints: " + solver .numConstraints ());
166
- System .out .println ("Number of variables: " + solver .numVariables ());
167
-
168
- final MPSolver .ResultStatus resultStatus = solver .solve ();
169
-
170
- // Check that the problem has an optimal solution.
171
- if (resultStatus != MPSolver .ResultStatus .OPTIMAL ) {
172
- System .err .println ("The problem does not have an optimal solution!" );
173
- return ;
174
- }
175
155
176
- // Verify that the solution satisfies all constraints (when using solvers
177
- // others than GLOP_LINEAR_PROGRAMMING, this is highly recommended!).
178
- if (!solver .verifySolution (/*tolerance=*/ 1e-7 , /*logErrors=*/ true )) {
179
- System .err .println ("The solution returned by the solver violated the"
180
- + " problem constraints by at least 1e-7" );
181
- return ;
182
- }
183
-
184
- System .out .println ("Problem solved in " + solver .wallTime () + " milliseconds" );
185
-
186
- // The objective value of the solution.
187
- System .out .println ("Optimal objective value = " + solver .objective ().value ());
156
+ model .optimize ();
188
157
}
189
158
190
159
private static void loadOSM () {
@@ -233,8 +202,13 @@ public static void main(String[] args) {
233
202
234
203
// Solve integer programming problem
235
204
System .out .println ("---- Running integer programming optimizer ----" );
236
- setupSolver ();
237
- runSolver ();
205
+ try {
206
+ setupSolver ();
207
+ runSolver ();
208
+ } catch (GRBException e ) {
209
+ System .out .println ("Error code: " + e .getErrorCode () + ". " +
210
+ e .getMessage ());
211
+ }
238
212
}
239
213
240
214
}
0 commit comments