or-tools 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +748 -2
- data/ext/or-tools/ext.cpp +465 -7
- data/ext/or-tools/extconf.rb +60 -1
- data/lib/or-tools.rb +8 -0
- data/lib/or_tools/comparison.rb +11 -0
- data/lib/or_tools/comparison_operators.rb +9 -0
- data/lib/or_tools/cp_model.rb +29 -0
- data/lib/or_tools/cp_solver.rb +4 -0
- data/lib/or_tools/ext.bundle +0 -0
- data/lib/or_tools/linear_expr.rb +19 -0
- data/lib/or_tools/routing_model.rb +17 -0
- data/lib/or_tools/sat_int_var.rb +9 -0
- data/lib/or_tools/sat_linear_expr.rb +35 -0
- data/lib/or_tools/solver.rb +7 -0
- data/lib/or_tools/version.rb +1 -1
- metadata +10 -2
data/ext/or-tools/ext.cpp
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
// or-tools
|
2
|
-
#include <ortools/sat/cp_model.h>
|
3
2
|
#include <ortools/algorithms/knapsack_solver.h>
|
3
|
+
#include <ortools/constraint_solver/routing.h>
|
4
|
+
#include <ortools/constraint_solver/routing_parameters.h>
|
5
|
+
#include <ortools/graph/assignment.h>
|
4
6
|
#include <ortools/graph/max_flow.h>
|
5
7
|
#include <ortools/graph/min_cost_flow.h>
|
8
|
+
#include <ortools/linear_solver/linear_solver.h>
|
9
|
+
#include <ortools/sat/cp_model.h>
|
6
10
|
|
7
11
|
// rice
|
8
12
|
#include <rice/Array.hpp>
|
@@ -13,20 +17,36 @@
|
|
13
17
|
#include <rice/Symbol.hpp>
|
14
18
|
|
15
19
|
using operations_research::ArcIndex;
|
20
|
+
using operations_research::DefaultRoutingSearchParameters;
|
16
21
|
using operations_research::Domain;
|
22
|
+
using operations_research::FirstSolutionStrategy;
|
17
23
|
using operations_research::FlowQuantity;
|
18
24
|
using operations_research::KnapsackSolver;
|
25
|
+
using operations_research::LinearExpr;
|
26
|
+
using operations_research::LinearRange;
|
27
|
+
using operations_research::LocalSearchMetaheuristic;
|
28
|
+
using operations_research::MPConstraint;
|
29
|
+
using operations_research::MPObjective;
|
30
|
+
using operations_research::MPSolver;
|
31
|
+
using operations_research::MPVariable;
|
19
32
|
using operations_research::NodeIndex;
|
33
|
+
using operations_research::RoutingDimension;
|
34
|
+
using operations_research::RoutingIndexManager;
|
35
|
+
using operations_research::RoutingModel;
|
36
|
+
using operations_research::RoutingNodeIndex;
|
37
|
+
using operations_research::RoutingSearchParameters;
|
38
|
+
using operations_research::SimpleLinearSumAssignment;
|
20
39
|
using operations_research::SimpleMaxFlow;
|
21
40
|
using operations_research::SimpleMinCostFlow;
|
22
41
|
|
42
|
+
using operations_research::sat::BoolVar;
|
23
43
|
using operations_research::sat::CpModelBuilder;
|
24
44
|
using operations_research::sat::CpSolverResponse;
|
25
45
|
using operations_research::sat::CpSolverStatus;
|
26
|
-
using operations_research::sat::IntVar;
|
27
46
|
using operations_research::sat::SolutionIntegerValue;
|
28
47
|
|
29
48
|
using Rice::Array;
|
49
|
+
using Rice::Class;
|
30
50
|
using Rice::Constructor;
|
31
51
|
using Rice::Hash;
|
32
52
|
using Rice::Module;
|
@@ -47,12 +67,332 @@ KnapsackSolver::SolverType from_ruby<KnapsackSolver::SolverType>(Object x)
|
|
47
67
|
}
|
48
68
|
}
|
49
69
|
|
70
|
+
template<>
|
71
|
+
inline
|
72
|
+
MPSolver::OptimizationProblemType from_ruby<MPSolver::OptimizationProblemType>(Object x)
|
73
|
+
{
|
74
|
+
std::string s = Symbol(x).str();
|
75
|
+
if (s == "glop") {
|
76
|
+
return MPSolver::OptimizationProblemType::GLOP_LINEAR_PROGRAMMING;
|
77
|
+
} else if (s == "cbc") {
|
78
|
+
return MPSolver::OptimizationProblemType::CBC_MIXED_INTEGER_PROGRAMMING;
|
79
|
+
} else {
|
80
|
+
throw std::runtime_error("Unknown optimization problem type: " + s);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
template<>
|
85
|
+
inline
|
86
|
+
RoutingNodeIndex from_ruby<RoutingNodeIndex>(Object x)
|
87
|
+
{
|
88
|
+
const RoutingNodeIndex index{from_ruby<int>(x)};
|
89
|
+
return index;
|
90
|
+
}
|
91
|
+
|
92
|
+
template<>
|
93
|
+
inline
|
94
|
+
Object to_ruby<RoutingNodeIndex>(RoutingNodeIndex const &x)
|
95
|
+
{
|
96
|
+
return to_ruby<int>(x.value());
|
97
|
+
}
|
98
|
+
|
99
|
+
template<>
|
100
|
+
inline
|
101
|
+
operations_research::sat::LinearExpr from_ruby<operations_research::sat::LinearExpr>(Object x)
|
102
|
+
{
|
103
|
+
operations_research::sat::LinearExpr expr;
|
104
|
+
|
105
|
+
if (x.respond_to("to_i")) {
|
106
|
+
expr = from_ruby<int64>(x.call("to_i"));
|
107
|
+
} else if (x.respond_to("vars")) {
|
108
|
+
Array vars = x.call("vars");
|
109
|
+
for(auto const& var: vars) {
|
110
|
+
auto cvar = (Array) var;
|
111
|
+
// TODO clean up
|
112
|
+
Object o = cvar[0];
|
113
|
+
if (((Rice::String) o.call("class").call("name")).str() == "ORTools::BoolVar") {
|
114
|
+
expr.AddTerm(from_ruby<operations_research::sat::BoolVar>(cvar[0]), from_ruby<int64>(cvar[1]));
|
115
|
+
} else {
|
116
|
+
expr.AddTerm(from_ruby<operations_research::sat::IntVar>(cvar[0]), from_ruby<int64>(cvar[1]));
|
117
|
+
}
|
118
|
+
}
|
119
|
+
} else {
|
120
|
+
expr = from_ruby<operations_research::sat::IntVar>(x);
|
121
|
+
}
|
122
|
+
|
123
|
+
return expr;
|
124
|
+
}
|
125
|
+
|
126
|
+
// need a wrapper class due to const
|
127
|
+
class Assignment {
|
128
|
+
const operations_research::Assignment* self;
|
129
|
+
public:
|
130
|
+
Assignment(const operations_research::Assignment* v) {
|
131
|
+
self = v;
|
132
|
+
}
|
133
|
+
int64 ObjectiveValue() {
|
134
|
+
return self->ObjectiveValue();
|
135
|
+
}
|
136
|
+
int64 Value(const operations_research::IntVar* const var) const {
|
137
|
+
return self->Value(var);
|
138
|
+
}
|
139
|
+
};
|
140
|
+
|
141
|
+
Class rb_cMPVariable;
|
142
|
+
Class rb_cMPConstraint;
|
143
|
+
Class rb_cMPObjective;
|
144
|
+
Class rb_cIntVar;
|
145
|
+
Class rb_cRoutingDimension;
|
146
|
+
|
147
|
+
template<>
|
148
|
+
inline
|
149
|
+
Object to_ruby<MPVariable*>(MPVariable* const &x)
|
150
|
+
{
|
151
|
+
return Rice::Data_Object<MPVariable>(x, rb_cMPVariable, nullptr, nullptr);
|
152
|
+
}
|
153
|
+
|
154
|
+
template<>
|
155
|
+
inline
|
156
|
+
Object to_ruby<MPConstraint*>(MPConstraint* const &x)
|
157
|
+
{
|
158
|
+
return Rice::Data_Object<MPConstraint>(x, rb_cMPConstraint, nullptr, nullptr);
|
159
|
+
}
|
160
|
+
|
161
|
+
template<>
|
162
|
+
inline
|
163
|
+
Object to_ruby<MPObjective*>(MPObjective* const &x)
|
164
|
+
{
|
165
|
+
return Rice::Data_Object<MPObjective>(x, rb_cMPObjective, nullptr, nullptr);
|
166
|
+
}
|
167
|
+
|
168
|
+
template<>
|
169
|
+
inline
|
170
|
+
Object to_ruby<operations_research::IntVar*>(operations_research::IntVar* const &x)
|
171
|
+
{
|
172
|
+
return Rice::Data_Object<operations_research::IntVar>(x, rb_cIntVar, nullptr, nullptr);
|
173
|
+
}
|
174
|
+
|
175
|
+
template<>
|
176
|
+
inline
|
177
|
+
Object to_ruby<RoutingDimension*>(RoutingDimension* const &x)
|
178
|
+
{
|
179
|
+
return Rice::Data_Object<RoutingDimension>(x, rb_cRoutingDimension, nullptr, nullptr);
|
180
|
+
}
|
181
|
+
|
50
182
|
extern "C"
|
51
183
|
void Init_ext()
|
52
184
|
{
|
53
|
-
Module rb_mORTools = define_module("ORTools")
|
185
|
+
Module rb_mORTools = define_module("ORTools")
|
186
|
+
.define_singleton_method("default_routing_search_parameters", &DefaultRoutingSearchParameters);
|
187
|
+
|
188
|
+
define_class_under<RoutingSearchParameters>(rb_mORTools, "RoutingSearchParameters")
|
189
|
+
.define_method(
|
190
|
+
"first_solution_strategy=",
|
191
|
+
*[](RoutingSearchParameters& self, Symbol value) {
|
192
|
+
std::string s = Symbol(value).str();
|
193
|
+
|
194
|
+
FirstSolutionStrategy::Value v;
|
195
|
+
if (s == "path_cheapest_arc") {
|
196
|
+
v = FirstSolutionStrategy::PATH_CHEAPEST_ARC;
|
197
|
+
} else if (s == "path_most_constrained_arc") {
|
198
|
+
v = FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC;
|
199
|
+
} else if (s == "evaluator_strategy") {
|
200
|
+
v = FirstSolutionStrategy::EVALUATOR_STRATEGY;
|
201
|
+
} else if (s == "savings") {
|
202
|
+
v = FirstSolutionStrategy::SAVINGS;
|
203
|
+
} else if (s == "sweep") {
|
204
|
+
v = FirstSolutionStrategy::SWEEP;
|
205
|
+
} else if (s == "christofides") {
|
206
|
+
v = FirstSolutionStrategy::CHRISTOFIDES;
|
207
|
+
} else if (s == "all_unperformed") {
|
208
|
+
v = FirstSolutionStrategy::ALL_UNPERFORMED;
|
209
|
+
} else if (s == "best_insertion") {
|
210
|
+
v = FirstSolutionStrategy::BEST_INSERTION;
|
211
|
+
} else if (s == "parallel_cheapest_insertion") {
|
212
|
+
v = FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION;
|
213
|
+
} else if (s == "sequential_cheapest_insertion") {
|
214
|
+
v = FirstSolutionStrategy::SEQUENTIAL_CHEAPEST_INSERTION;
|
215
|
+
} else if (s == "local_cheapest_insertion") {
|
216
|
+
v = FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION;
|
217
|
+
} else if (s == "global_cheapest_arc") {
|
218
|
+
v = FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC;
|
219
|
+
} else if (s == "local_cheapest_arc") {
|
220
|
+
v = FirstSolutionStrategy::LOCAL_CHEAPEST_ARC;
|
221
|
+
} else if (s == "first_unbound_min_value") {
|
222
|
+
v = FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE;
|
223
|
+
} else {
|
224
|
+
throw std::runtime_error("Unknown first solution strategy: " + s);
|
225
|
+
}
|
54
226
|
|
55
|
-
|
227
|
+
return self.set_first_solution_strategy(v);
|
228
|
+
})
|
229
|
+
.define_method(
|
230
|
+
"local_search_metaheuristic=",
|
231
|
+
*[](RoutingSearchParameters& self, Symbol value) {
|
232
|
+
std::string s = Symbol(value).str();
|
233
|
+
|
234
|
+
LocalSearchMetaheuristic::Value v;
|
235
|
+
if (s == "guided_local_search") {
|
236
|
+
v = LocalSearchMetaheuristic::GUIDED_LOCAL_SEARCH;
|
237
|
+
} else if (s == "tabu_search") {
|
238
|
+
v = LocalSearchMetaheuristic::TABU_SEARCH;
|
239
|
+
} else if (s == "generic_tabu_search") {
|
240
|
+
v = LocalSearchMetaheuristic::GENERIC_TABU_SEARCH;
|
241
|
+
} else if (s == "simulated_annealing") {
|
242
|
+
v = LocalSearchMetaheuristic::SIMULATED_ANNEALING;
|
243
|
+
} else {
|
244
|
+
throw std::runtime_error("Unknown local search metaheuristic: " + s);
|
245
|
+
}
|
246
|
+
|
247
|
+
return self.set_local_search_metaheuristic(v);
|
248
|
+
})
|
249
|
+
.define_method(
|
250
|
+
"log_search=",
|
251
|
+
*[](RoutingSearchParameters& self, bool value) {
|
252
|
+
self.set_log_search(value);
|
253
|
+
})
|
254
|
+
.define_method(
|
255
|
+
"solution_limit=",
|
256
|
+
*[](RoutingSearchParameters& self, int64 value) {
|
257
|
+
self.set_solution_limit(value);
|
258
|
+
})
|
259
|
+
.define_method(
|
260
|
+
"time_limit=",
|
261
|
+
*[](RoutingSearchParameters& self, int64 value) {
|
262
|
+
self.mutable_time_limit()->set_seconds(value);
|
263
|
+
})
|
264
|
+
.define_method(
|
265
|
+
"lns_time_limit=",
|
266
|
+
*[](RoutingSearchParameters& self, int64 value) {
|
267
|
+
self.mutable_lns_time_limit()->set_seconds(value);
|
268
|
+
});
|
269
|
+
|
270
|
+
rb_cMPVariable = define_class_under<MPVariable>(rb_mORTools, "MPVariable")
|
271
|
+
.define_method("name", &MPVariable::name)
|
272
|
+
.define_method("solution_value", &MPVariable::solution_value)
|
273
|
+
.define_method(
|
274
|
+
"+",
|
275
|
+
*[](MPVariable& self, MPVariable& other) {
|
276
|
+
LinearExpr s(&self);
|
277
|
+
LinearExpr o(&other);
|
278
|
+
return s + o;
|
279
|
+
})
|
280
|
+
.define_method(
|
281
|
+
"*",
|
282
|
+
*[](MPVariable& self, double other) {
|
283
|
+
LinearExpr s(&self);
|
284
|
+
return s * other;
|
285
|
+
});
|
286
|
+
|
287
|
+
define_class_under<LinearExpr>(rb_mORTools, "LinearExpr")
|
288
|
+
.define_constructor(Constructor<LinearExpr>())
|
289
|
+
.define_method(
|
290
|
+
"_add_linear_expr",
|
291
|
+
*[](LinearExpr& self, LinearExpr& other) {
|
292
|
+
return self + other;
|
293
|
+
})
|
294
|
+
.define_method(
|
295
|
+
"_add_mp_variable",
|
296
|
+
*[](LinearExpr& self, MPVariable &other) {
|
297
|
+
LinearExpr o(&other);
|
298
|
+
return self + o;
|
299
|
+
})
|
300
|
+
.define_method(
|
301
|
+
"_lte_double",
|
302
|
+
*[](LinearExpr& self, double other) {
|
303
|
+
LinearExpr o(other);
|
304
|
+
return self <= o;
|
305
|
+
})
|
306
|
+
.define_method(
|
307
|
+
"_lte_linear_expr",
|
308
|
+
*[](LinearExpr& self, LinearExpr& other) {
|
309
|
+
return self <= other;
|
310
|
+
})
|
311
|
+
.define_method(
|
312
|
+
"==",
|
313
|
+
*[](LinearExpr& self, double other) {
|
314
|
+
LinearExpr o(other);
|
315
|
+
return self == o;
|
316
|
+
})
|
317
|
+
.define_method(
|
318
|
+
"to_s",
|
319
|
+
*[](LinearExpr& self) {
|
320
|
+
return self.ToString();
|
321
|
+
})
|
322
|
+
.define_method(
|
323
|
+
"inspect",
|
324
|
+
*[](LinearExpr& self) {
|
325
|
+
return "#<ORTools::LinearExpr \"" + self.ToString() + "\">";
|
326
|
+
});
|
327
|
+
|
328
|
+
define_class_under<LinearRange>(rb_mORTools, "LinearRange");
|
329
|
+
|
330
|
+
rb_cMPConstraint = define_class_under<MPConstraint>(rb_mORTools, "MPConstraint")
|
331
|
+
.define_method("set_coefficient", &MPConstraint::SetCoefficient);
|
332
|
+
|
333
|
+
rb_cMPObjective = define_class_under<MPObjective>(rb_mORTools, "MPObjective")
|
334
|
+
.define_method("value", &MPObjective::Value)
|
335
|
+
.define_method("set_coefficient", &MPObjective::SetCoefficient)
|
336
|
+
.define_method("set_maximization", &MPObjective::SetMaximization);
|
337
|
+
|
338
|
+
define_class_under<MPSolver>(rb_mORTools, "Solver")
|
339
|
+
.define_constructor(Constructor<MPSolver, std::string, MPSolver::OptimizationProblemType>())
|
340
|
+
.define_method("infinity", &MPSolver::infinity)
|
341
|
+
.define_method(
|
342
|
+
"int_var",
|
343
|
+
*[](MPSolver& self, double min, double max, const std::string& name) {
|
344
|
+
return self.MakeIntVar(min, max, name);
|
345
|
+
})
|
346
|
+
.define_method("num_var", &MPSolver::MakeNumVar)
|
347
|
+
.define_method("bool_var", &MPSolver::MakeBoolVar)
|
348
|
+
.define_method("num_variables", &MPSolver::NumVariables)
|
349
|
+
.define_method("num_constraints", &MPSolver::NumConstraints)
|
350
|
+
.define_method("wall_time", &MPSolver::wall_time)
|
351
|
+
.define_method("iterations", &MPSolver::iterations)
|
352
|
+
.define_method("nodes", &MPSolver::nodes)
|
353
|
+
.define_method("objective", &MPSolver::MutableObjective)
|
354
|
+
.define_method(
|
355
|
+
"minimize",
|
356
|
+
*[](MPSolver& self, LinearExpr& expr) {
|
357
|
+
return self.MutableObjective()->MinimizeLinearExpr(expr);
|
358
|
+
})
|
359
|
+
.define_method(
|
360
|
+
"add",
|
361
|
+
*[](MPSolver& self, const LinearRange& range) {
|
362
|
+
return self.MakeRowConstraint(range);
|
363
|
+
})
|
364
|
+
.define_method(
|
365
|
+
"constraint",
|
366
|
+
*[](MPSolver& self, double lb, double ub) {
|
367
|
+
return self.MakeRowConstraint(lb, ub);
|
368
|
+
})
|
369
|
+
.define_method(
|
370
|
+
"solve",
|
371
|
+
*[](MPSolver& self) {
|
372
|
+
auto status = self.Solve();
|
373
|
+
|
374
|
+
if (status == MPSolver::ResultStatus::OPTIMAL) {
|
375
|
+
return Symbol("optimal");
|
376
|
+
} else if (status == MPSolver::ResultStatus::FEASIBLE) {
|
377
|
+
return Symbol("feasible");
|
378
|
+
} else if (status == MPSolver::ResultStatus::INFEASIBLE) {
|
379
|
+
return Symbol("infeasible");
|
380
|
+
} else if (status == MPSolver::ResultStatus::UNBOUNDED) {
|
381
|
+
return Symbol("unbounded");
|
382
|
+
} else if (status == MPSolver::ResultStatus::ABNORMAL) {
|
383
|
+
return Symbol("abnormal");
|
384
|
+
} else if (status == MPSolver::ResultStatus::MODEL_INVALID) {
|
385
|
+
return Symbol("model_invalid");
|
386
|
+
} else if (status == MPSolver::ResultStatus::NOT_SOLVED) {
|
387
|
+
return Symbol("not_solved");
|
388
|
+
} else {
|
389
|
+
throw std::runtime_error("Unknown status");
|
390
|
+
}
|
391
|
+
});
|
392
|
+
|
393
|
+
// not to be confused with operations_research::IntVar
|
394
|
+
define_class_under<operations_research::sat::IntVar>(rb_mORTools, "SatIntVar");
|
395
|
+
define_class_under<BoolVar>(rb_mORTools, "BoolVar");
|
56
396
|
|
57
397
|
define_class_under<CpModelBuilder>(rb_mORTools, "CpModel")
|
58
398
|
.define_constructor(Constructor<CpModelBuilder>())
|
@@ -62,11 +402,50 @@ void Init_ext()
|
|
62
402
|
const Domain domain(start, end);
|
63
403
|
return self.NewIntVar(domain).WithName(name);
|
64
404
|
})
|
405
|
+
.define_method(
|
406
|
+
"new_bool_var",
|
407
|
+
*[](CpModelBuilder& self, std::string name) {
|
408
|
+
return self.NewBoolVar().WithName(name);
|
409
|
+
})
|
410
|
+
.define_method(
|
411
|
+
"add_equality",
|
412
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
|
413
|
+
self.AddEquality(x, y);
|
414
|
+
})
|
65
415
|
.define_method(
|
66
416
|
"add_not_equal",
|
67
|
-
*[](CpModelBuilder& self,
|
68
|
-
// TODO return value
|
417
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
|
69
418
|
self.AddNotEqual(x, y);
|
419
|
+
})
|
420
|
+
.define_method(
|
421
|
+
"add_greater_than",
|
422
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
|
423
|
+
self.AddGreaterThan(x, y);
|
424
|
+
})
|
425
|
+
.define_method(
|
426
|
+
"add_greater_or_equal",
|
427
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
|
428
|
+
self.AddGreaterOrEqual(x, y);
|
429
|
+
})
|
430
|
+
.define_method(
|
431
|
+
"add_less_than",
|
432
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
|
433
|
+
self.AddLessThan(x, y);
|
434
|
+
})
|
435
|
+
.define_method(
|
436
|
+
"add_less_or_equal",
|
437
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
|
438
|
+
self.AddLessOrEqual(x, y);
|
439
|
+
})
|
440
|
+
.define_method(
|
441
|
+
"maximize",
|
442
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr expr) {
|
443
|
+
self.Maximize(expr);
|
444
|
+
})
|
445
|
+
.define_method(
|
446
|
+
"minimize",
|
447
|
+
*[](CpModelBuilder& self, operations_research::sat::LinearExpr expr) {
|
448
|
+
self.Minimize(expr);
|
70
449
|
});
|
71
450
|
|
72
451
|
define_class_under(rb_mORTools, "CpSolver")
|
@@ -77,15 +456,17 @@ void Init_ext()
|
|
77
456
|
})
|
78
457
|
.define_method(
|
79
458
|
"_solution_integer_value",
|
80
|
-
*[](Object self, CpSolverResponse& response, IntVar& x) {
|
459
|
+
*[](Object self, CpSolverResponse& response, operations_research::sat::IntVar& x) {
|
81
460
|
return SolutionIntegerValue(response, x);
|
82
461
|
});
|
83
462
|
|
84
463
|
define_class_under<CpSolverResponse>(rb_mORTools, "CpSolverResponse")
|
464
|
+
.define_method("objective_value", &CpSolverResponse::objective_value)
|
85
465
|
.define_method(
|
86
466
|
"status",
|
87
467
|
*[](CpSolverResponse& self) {
|
88
468
|
auto status = self.status();
|
469
|
+
|
89
470
|
if (status == CpSolverStatus::OPTIMAL) {
|
90
471
|
return Symbol("optimal");
|
91
472
|
} else if (status == CpSolverStatus::FEASIBLE) {
|
@@ -99,6 +480,56 @@ void Init_ext()
|
|
99
480
|
}
|
100
481
|
});
|
101
482
|
|
483
|
+
define_class_under<RoutingIndexManager>(rb_mORTools, "RoutingIndexManager")
|
484
|
+
.define_constructor(Constructor<RoutingIndexManager, int, int, RoutingNodeIndex>())
|
485
|
+
.define_method("index_to_node", &RoutingIndexManager::IndexToNode);
|
486
|
+
|
487
|
+
define_class_under<Assignment>(rb_mORTools, "Assignment")
|
488
|
+
.define_method("objective_value", &Assignment::ObjectiveValue)
|
489
|
+
.define_method("value", &Assignment::Value);
|
490
|
+
|
491
|
+
// not to be confused with operations_research::sat::IntVar
|
492
|
+
rb_cIntVar = define_class_under<operations_research::IntVar>(rb_mORTools, "IntVar");
|
493
|
+
|
494
|
+
rb_cRoutingDimension = define_class_under<RoutingDimension>(rb_mORTools, "RoutingDimension")
|
495
|
+
.define_method("global_span_cost_coefficient=", &RoutingDimension::SetGlobalSpanCostCoefficient);
|
496
|
+
|
497
|
+
define_class_under<RoutingModel>(rb_mORTools, "RoutingModel")
|
498
|
+
.define_constructor(Constructor<RoutingModel, RoutingIndexManager>())
|
499
|
+
.define_method(
|
500
|
+
"register_transit_callback",
|
501
|
+
*[](RoutingModel& self, Object callback) {
|
502
|
+
return self.RegisterTransitCallback(
|
503
|
+
[callback](int64 from_index, int64 to_index) -> int64 {
|
504
|
+
return from_ruby<int64>(callback.call("call", from_index, to_index));
|
505
|
+
}
|
506
|
+
);
|
507
|
+
})
|
508
|
+
.define_method("depot", &RoutingModel::GetDepot)
|
509
|
+
.define_method("set_arc_cost_evaluator_of_all_vehicles", &RoutingModel::SetArcCostEvaluatorOfAllVehicles)
|
510
|
+
.define_method("set_arc_cost_evaluator_of_vehicle", &RoutingModel::SetArcCostEvaluatorOfVehicle)
|
511
|
+
.define_method("set_fixed_cost_of_all_vehicles", &RoutingModel::SetFixedCostOfAllVehicles)
|
512
|
+
.define_method("set_fixed_cost_of_vehicle", &RoutingModel::SetFixedCostOfVehicle)
|
513
|
+
.define_method("fixed_cost_of_vehicle", &RoutingModel::GetFixedCostOfVehicle)
|
514
|
+
.define_method("add_dimension", &RoutingModel::AddDimension)
|
515
|
+
.define_method("start", &RoutingModel::Start)
|
516
|
+
.define_method("end", &RoutingModel::End)
|
517
|
+
.define_method("start?", &RoutingModel::IsStart)
|
518
|
+
.define_method("end?", &RoutingModel::IsEnd)
|
519
|
+
.define_method("vehicle_index", &RoutingModel::VehicleIndex)
|
520
|
+
.define_method("next", &RoutingModel::Next)
|
521
|
+
.define_method("vehicle_used?", &RoutingModel::IsVehicleUsed)
|
522
|
+
.define_method("next_var", &RoutingModel::NextVar)
|
523
|
+
.define_method("arc_cost_for_vehicle", &RoutingModel::GetArcCostForVehicle)
|
524
|
+
.define_method("mutable_dimension", &RoutingModel::GetMutableDimension)
|
525
|
+
.define_method(
|
526
|
+
"solve_with_parameters",
|
527
|
+
*[](RoutingModel& self, const RoutingSearchParameters& search_parameters) {
|
528
|
+
auto assignment = self.SolveWithParameters(search_parameters);
|
529
|
+
// std::cout << assignment->DebugString();
|
530
|
+
return (Assignment) assignment;
|
531
|
+
});
|
532
|
+
|
102
533
|
define_class_under<KnapsackSolver>(rb_mORTools, "KnapsackSolver")
|
103
534
|
.define_constructor(Constructor<KnapsackSolver, KnapsackSolver::SolverType, std::string>())
|
104
535
|
.define_method("_solve", &KnapsackSolver::Solve)
|
@@ -218,4 +649,31 @@ void Init_ext()
|
|
218
649
|
throw std::runtime_error("Unknown status");
|
219
650
|
}
|
220
651
|
});
|
652
|
+
|
653
|
+
define_class_under<SimpleLinearSumAssignment>(rb_mORTools, "LinearSumAssignment")
|
654
|
+
.define_constructor(Constructor<SimpleLinearSumAssignment>())
|
655
|
+
.define_method("add_arc_with_cost", &SimpleLinearSumAssignment::AddArcWithCost)
|
656
|
+
.define_method("num_nodes", &SimpleLinearSumAssignment::NumNodes)
|
657
|
+
.define_method("num_arcs", &SimpleLinearSumAssignment::NumArcs)
|
658
|
+
.define_method("left_node", &SimpleLinearSumAssignment::LeftNode)
|
659
|
+
.define_method("right_node", &SimpleLinearSumAssignment::RightNode)
|
660
|
+
.define_method("cost", &SimpleLinearSumAssignment::Cost)
|
661
|
+
.define_method("optimal_cost", &SimpleLinearSumAssignment::OptimalCost)
|
662
|
+
.define_method("right_mate", &SimpleLinearSumAssignment::RightMate)
|
663
|
+
.define_method("assignment_cost", &SimpleLinearSumAssignment::AssignmentCost)
|
664
|
+
.define_method(
|
665
|
+
"solve",
|
666
|
+
*[](SimpleLinearSumAssignment& self) {
|
667
|
+
auto status = self.Solve();
|
668
|
+
|
669
|
+
if (status == SimpleLinearSumAssignment::Status::OPTIMAL) {
|
670
|
+
return Symbol("optimal");
|
671
|
+
} else if (status == SimpleLinearSumAssignment::Status::INFEASIBLE) {
|
672
|
+
return Symbol("infeasible");
|
673
|
+
} else if (status == SimpleLinearSumAssignment::Status::POSSIBLE_OVERFLOW) {
|
674
|
+
return Symbol("possible_overflow");
|
675
|
+
} else {
|
676
|
+
throw std::runtime_error("Unknown status");
|
677
|
+
}
|
678
|
+
});
|
221
679
|
}
|
data/ext/or-tools/extconf.rb
CHANGED
@@ -2,7 +2,7 @@ require "mkmf-rice"
|
|
2
2
|
|
3
3
|
abort "Missing stdc++" unless have_library("stdc++")
|
4
4
|
|
5
|
-
$CXXFLAGS << " -std=c++11"
|
5
|
+
$CXXFLAGS << " -std=c++11 -DUSE_CBC"
|
6
6
|
|
7
7
|
# or-tools warnings
|
8
8
|
$CXXFLAGS << " -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-ignored-qualifiers"
|
@@ -18,4 +18,63 @@ $LDFLAGS << " -Wl,-rpath,#{lib}"
|
|
18
18
|
$LDFLAGS << " -L#{lib}"
|
19
19
|
$LDFLAGS << " -lortools"
|
20
20
|
|
21
|
+
%w(
|
22
|
+
absl_city
|
23
|
+
absl_time_zone
|
24
|
+
absl_spinlock_wait
|
25
|
+
absl_log_severity
|
26
|
+
absl_failure_signal_handler
|
27
|
+
absl_bad_optional_access
|
28
|
+
absl_hash
|
29
|
+
absl_raw_logging_internal
|
30
|
+
absl_random_internal_pool_urbg
|
31
|
+
absl_base
|
32
|
+
absl_bad_any_cast_impl
|
33
|
+
absl_periodic_sampler
|
34
|
+
absl_random_distributions
|
35
|
+
absl_flags_usage_internal
|
36
|
+
absl_random_seed_sequences
|
37
|
+
absl_throw_delegate
|
38
|
+
absl_flags_handle
|
39
|
+
absl_dynamic_annotations
|
40
|
+
absl_debugging_internal
|
41
|
+
absl_strings
|
42
|
+
absl_flags
|
43
|
+
absl_malloc_internal
|
44
|
+
absl_str_format_internal
|
45
|
+
absl_flags_usage
|
46
|
+
absl_strings_internal
|
47
|
+
absl_flags_program_name
|
48
|
+
absl_flags_registry
|
49
|
+
absl_int128
|
50
|
+
absl_scoped_set_env
|
51
|
+
absl_raw_hash_set
|
52
|
+
absl_random_internal_seed_material
|
53
|
+
absl_symbolize
|
54
|
+
absl_random_internal_randen_slow
|
55
|
+
absl_graphcycles_internal
|
56
|
+
absl_exponential_biased
|
57
|
+
absl_random_internal_randen_hwaes_impl
|
58
|
+
absl_bad_variant_access
|
59
|
+
absl_stacktrace
|
60
|
+
absl_random_internal_randen_hwaes
|
61
|
+
absl_flags_parse
|
62
|
+
absl_random_internal_randen
|
63
|
+
absl_random_internal_distribution_test_util
|
64
|
+
absl_time
|
65
|
+
absl_flags_config
|
66
|
+
absl_synchronization
|
67
|
+
absl_hashtablez_sampler
|
68
|
+
absl_demangle_internal
|
69
|
+
absl_leak_check
|
70
|
+
absl_flags_marshalling
|
71
|
+
absl_leak_check_disable
|
72
|
+
absl_examine_stack
|
73
|
+
absl_flags_internal
|
74
|
+
absl_random_seed_gen_exception
|
75
|
+
absl_civil_time
|
76
|
+
).each do |lib|
|
77
|
+
$LDFLAGS << " -l#{lib}"
|
78
|
+
end
|
79
|
+
|
21
80
|
create_makefile("or_tools/ext")
|
data/lib/or-tools.rb
CHANGED
@@ -2,8 +2,16 @@
|
|
2
2
|
require "or_tools/ext"
|
3
3
|
|
4
4
|
# modules
|
5
|
+
require "or_tools/comparison"
|
6
|
+
require "or_tools/comparison_operators"
|
7
|
+
require "or_tools/cp_model"
|
5
8
|
require "or_tools/cp_solver"
|
6
9
|
require "or_tools/knapsack_solver"
|
10
|
+
require "or_tools/linear_expr"
|
11
|
+
require "or_tools/routing_model"
|
12
|
+
require "or_tools/sat_linear_expr"
|
13
|
+
require "or_tools/sat_int_var"
|
14
|
+
require "or_tools/solver"
|
7
15
|
require "or_tools/version"
|
8
16
|
|
9
17
|
module ORTools
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ORTools
|
2
|
+
class CpModel
|
3
|
+
def add(comparison)
|
4
|
+
method_name =
|
5
|
+
case comparison.operator
|
6
|
+
when "=="
|
7
|
+
:add_equality
|
8
|
+
when "!="
|
9
|
+
:add_not_equal
|
10
|
+
when ">"
|
11
|
+
:add_greater_than
|
12
|
+
when ">="
|
13
|
+
:add_greater_or_equal
|
14
|
+
when "<"
|
15
|
+
:add_less_than
|
16
|
+
when "<="
|
17
|
+
:add_less_or_equal
|
18
|
+
else
|
19
|
+
raise ArgumentError, "Unknown operator: #{comparison.operator}"
|
20
|
+
end
|
21
|
+
|
22
|
+
send(method_name, comparison.left, comparison.right)
|
23
|
+
end
|
24
|
+
|
25
|
+
def sum(arr)
|
26
|
+
arr.sum(SatLinearExpr.new)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/or_tools/cp_solver.rb
CHANGED
data/lib/or_tools/ext.bundle
CHANGED
Binary file
|