@@ -27,6 +27,7 @@ Rulp is inspired by the ruby wrapper for the GLPK toolkit and the python LP libr
27
27
28
28
## Sample Code
29
29
30
+ ``` ruby
30
31
# maximize
31
32
# z = 10 * x + 6 * y + 4 * z
32
33
#
@@ -62,12 +63,13 @@ Rulp is inspired by the ruby wrapper for the GLPK toolkit and the python LP libr
62
63
# Y_i.value == 67
63
64
# Z_i.value == 0
64
65
# #
65
-
66
+ ```
66
67
67
68
## Usage
68
69
69
70
#### Variables
70
71
72
+ ``` ruby
71
73
# Rulp variables are initialized as soon as they are needed so there is no
72
74
# need to initialize them.
73
75
# They follow a naming convention that defines their type.
@@ -110,7 +112,7 @@ Rulp is inspired by the ruby wrapper for the GLPK toolkit and the python LP libr
110
112
# <LV:0x007ffc4cc0d460 @name="Unit8">,
111
113
# <LV:0x007ffc4cc0cee8 @name="Unit9">,
112
114
# <LV:0x007ffc4cc0c970 @name="Unit10">]
113
-
115
+ ```
114
116
115
117
### Variable Constraints
116
118
@@ -119,6 +121,7 @@ Be careful to use '==' and not '=' when expressing equality.
119
121
Constraints on a variable can only use numeric literals and not other variables.
120
122
Inter-variable constraints should be expressed as problem constrants. (Explained below.)
121
123
124
+ ``` ruby
122
125
X_i < 5
123
126
X_i .bounds
124
127
=> " X <= 5"
@@ -130,11 +133,13 @@ Inter-variable constraints should be expressed as problem constrants. (Explained
130
133
Y_f == 10
131
134
Y_f .bounds
132
135
=> " y = 10"
136
+ ```
133
137
134
138
### Problem constraints
135
139
136
140
Constraints are added to a problem using the :[ ] syntax.
137
141
142
+ ``` ruby
138
143
problem = Rulp ::Cbc Rulp ::Max ( 10 * X_i + 6 * Y_i + 4 * Z_i )
139
144
140
145
problem[
@@ -146,14 +151,17 @@ Constraints are added to a problem using the :[] syntax.
146
151
]
147
152
...
148
153
problem.solve
154
+ ```
149
155
150
156
You can add multiple constraints at once by comma separating them as seen in the earlier examples:
151
157
158
+ ``` ruby
152
159
Rulp ::Cbc Rulp ::Max ( 10 * X_i + 6 * Y_i + 4 * Z_i ) [
153
160
X_i + Y_i + Z_i <= 100 ,
154
161
10 * X_i + 4 * Y_i + 5 * Z_i <= 600 ,
155
162
2 * X_i + 2 * Y_i + 6 * Z_i <= 300
156
163
]
164
+ ```
157
165
158
166
### Solving or saving 'lp' files
159
167
@@ -165,61 +173,76 @@ such that the command `which [exec_name]` returns a path. (I.e they must be on y
165
173
166
174
Given a problem there are multiple ways to initiate a solver.
167
175
176
+ ``` ruby
168
177
@problem = Rulp ::Cbc Rulp ::Max ( 10 * X_i + 6 * Y_i + 4 * Z_i ) [
169
178
X_i + Y_i + Z_i <= 100 ,
170
179
10 * X_i + 4 * Y_i + 5 * Z_i <= 600 ,
171
180
2 * X_i + 2 * Y_i + 6 * Z_i <= 300
172
181
]
182
+ ```
173
183
174
184
Default solver:
175
185
186
+ ``` ruby
176
187
@problem .solve
177
188
# this will use the solver specified in the environment variable 'SOLVER' by default.
178
189
# This can be 'scip', 'cbc', or 'glpk'. If no variable is given it uses scip as a default.
190
+ ```
179
191
180
192
If you had a linear equation in a file named 'problem.rb' from the command line you could specify an alternate solver by executing:
181
193
194
+ ``` ruby
182
195
SOLVER = cbc ruby problem.rb
196
+ ```
183
197
184
198
Explicit solver:
185
199
200
+ ``` ruby
186
201
@problem .scip
187
202
# Or
188
203
@problem .cbc
189
204
# Or
190
205
@problem .glpk
206
+ ```
191
207
192
208
Or
193
209
210
+ ``` ruby
194
211
Rulp ::Scip (@problem )
195
212
Rulp ::Glpk (@problem )
196
213
Rulp ::Cbc (@problem )
197
-
214
+ ```
198
215
199
216
For debugging purposes you may wish to see the input and output files generated and consumed by Rulp.
200
217
To do this you can use the following extended syntax:
201
218
219
+ ``` ruby
202
220
def solve_with (type , open_definition = false , open_solution = false )...
221
+ ` ` `
203
222
204
223
The optional booleans will optionally call the 'open' utility to open the problem definition or the solution. (This utility is installed by default on a mac and will not work if the utility is not on your PATH)
205
224
206
-
225
+ ` ` ` ruby
207
226
@problem .solve_with(SCIP , true , true )
227
+ ```
208
228
209
229
#### Saving LP files.
210
230
211
231
You may not wish to use one of the RULP compatible but another solver that is able to read .lp files. (E.g CPLEX or Gurobi) but still want to use Rulp to generate your LP file. In this case you should use Rulp to output your lp problem description to a file of your choice. To do this simply use the following call
212
232
233
+ ``` ruby
213
234
@problem .save(" /Users/johndoe/Desktop/myproblem.lp" )
235
+ ```
214
236
215
237
OR
216
-
238
+ ``` ruby
217
239
@problem .output(" /Users/johndoe/Desktop/myproblem.lp" )
240
+ ```
218
241
219
242
You should also be able to call
220
-
243
+ ``` ruby
221
244
@problem .save
222
-
245
+ ```
223
246
Without parameters to be prompted for a save location.
224
247
225
248
### Examples.
@@ -230,6 +253,8 @@ Rulp comes bundled with a 'rulp' executable which by default loads the rulp envi
230
253
(Preference for PRY). Once installed you should be able to simply execute 'rulp' to launch this rulp enabled REPL.
231
254
You can then play with and attempt LP and MIP problems straight from the command line.
232
255
256
+ ``` ruby
257
+
233
258
[1 ] pry(main)> 13 <= X_i <= 45 # Declare integer variable
234
259
=> X (i)[undefined]
235
260
@@ -286,7 +311,7 @@ You can then play with and attempt LP and MIP problems straight from the command
286
311
287
312
[10 ] pry(main)> (2 * X_i + 15 * Y_f ).evaluate
288
313
=> 251.0
289
-
314
+ ```
290
315
291
316
### A larger example
292
317
Here is a basic example of how Rulp can help you model problems with a large number of variables.
@@ -298,18 +323,28 @@ of how we could use Rulp to formulate this problem.
298
323
We decide to model each of these possible purchases as a binary variable (as we either purchase them or
299
324
we don't. We can't partially purchase one.)
300
325
301
- # Generate the data randomly for this example.
302
- costs, points = [*0..1000].map do |i|
303
- [Purchase_b(i) * Random.rand(1.0..3.0), Purchase_b(i) * Random.rand(5.0..10.0)]
304
- end.transpose.map(&:sum) #We sum the array of points and array of costs to create a Rulp expression
305
-
306
- # And this is where the magic happens!. We ask rulp to maximise the number of points given
307
- # the constraint that costs must be less than $55
308
-
309
- Rulp::Max(points)[
310
- costs < 55
311
- ].solve
312
- => 538.2125623353652 (# You will get a different value as data was generated randomly)
313
-
314
- # Now how do we check which purchases were selected?
315
- selected_purchases = [*0..1000].select{|i| Purchase_b(i).value }
326
+ ``` ruby
327
+ # Generate the data randomly for this example.
328
+ costs, points = [* 0 ..1000 ].map do |i |
329
+ [Purchase_b (i) * Random .rand (1.0 ..3.0 ), Purchase_b (i) * Random .rand (5.0 ..10.0 )]
330
+ end .transpose.map(& :sum ) # We sum the array of points and array of costs to create a Rulp expression
331
+
332
+ # And this is where the magic happens!. We ask rulp to maximise the number of points given
333
+ # the constraint that costs must be less than $55
334
+
335
+ Rulp ::Max (points)[
336
+ costs < 55
337
+ ].solve
338
+ => 538.2125623353652 (# You will get a different value as data was generated randomly)
339
+
340
+ # Now how do we check which purchases were selected?
341
+ selected_purchases = [* 0 ..1000 ].select do |i |
342
+ Purchase_b (i).value
343
+ end .map(& Purchase_b )
344
+ => [Purchase27 (b)[true ],
345
+ Purchase86 (b)[true ],
346
+ Purchase120 (b)[true ],
347
+ Purchase141 (b)[true ],
348
+ Purchase154 (b)[true ],
349
+ ...
350
+ ```
0 commit comments