or-tools 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|