or-tools 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/or-tools/ext.cpp CHANGED
@@ -1,1037 +1,30 @@
1
- // or-tools
2
- #include <ortools/algorithms/knapsack_solver.h>
3
1
  #include <ortools/base/version.h>
4
- #include <ortools/constraint_solver/routing.h>
5
- #include <ortools/constraint_solver/routing_parameters.h>
6
- #include <ortools/graph/assignment.h>
7
- #include <ortools/graph/max_flow.h>
8
- #include <ortools/graph/min_cost_flow.h>
9
- #include <ortools/linear_solver/linear_solver.h>
10
- #include <ortools/sat/cp_model.h>
11
2
 
12
- // rice
13
- #include <rice/Array.hpp>
14
- #include <rice/Class.hpp>
15
- #include <rice/Constructor.hpp>
16
- #include <rice/Hash.hpp>
17
3
  #include <rice/Module.hpp>
18
- #include <rice/String.hpp>
19
- #include <rice/Symbol.hpp>
20
4
 
21
- using operations_research::ArcIndex;
22
- using operations_research::DefaultRoutingSearchParameters;
23
- using operations_research::Domain;
24
- using operations_research::FirstSolutionStrategy;
25
- using operations_research::FlowQuantity;
26
- using operations_research::KnapsackSolver;
27
- using operations_research::LinearExpr;
28
- using operations_research::LinearRange;
29
- using operations_research::LocalSearchMetaheuristic;
30
- using operations_research::MPConstraint;
31
- using operations_research::MPObjective;
32
- using operations_research::MPSolver;
33
- using operations_research::MPVariable;
34
- using operations_research::NodeIndex;
35
- using operations_research::RoutingDimension;
36
- using operations_research::RoutingIndexManager;
37
- using operations_research::RoutingModel;
38
- using operations_research::RoutingNodeIndex;
39
- using operations_research::RoutingSearchParameters;
40
- using operations_research::SimpleLinearSumAssignment;
41
- using operations_research::SimpleMaxFlow;
42
- using operations_research::SimpleMinCostFlow;
43
-
44
- using operations_research::sat::BoolVar;
45
- using operations_research::sat::CpModelBuilder;
46
- using operations_research::sat::CpSolverResponse;
47
- using operations_research::sat::CpSolverStatus;
48
- using operations_research::sat::NewFeasibleSolutionObserver;
49
- using operations_research::sat::SatParameters;
50
- using operations_research::sat::SolutionIntegerValue;
51
-
52
- using Rice::Array;
53
- using Rice::Class;
54
- using Rice::Constructor;
55
- using Rice::Hash;
56
- using Rice::Module;
57
- using Rice::Object;
58
- using Rice::String;
59
- using Rice::Symbol;
60
- using Rice::define_module;
61
- using Rice::define_class_under;
62
-
63
- template<>
64
- inline
65
- KnapsackSolver::SolverType from_ruby<KnapsackSolver::SolverType>(Object x)
66
- {
67
- std::string s = Symbol(x).str();
68
- if (s == "branch_and_bound") {
69
- return KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER;
70
- } else {
71
- throw std::runtime_error("Unknown solver type: " + s);
72
- }
73
- }
74
-
75
- template<>
76
- inline
77
- MPSolver::OptimizationProblemType from_ruby<MPSolver::OptimizationProblemType>(Object x)
78
- {
79
- std::string s = Symbol(x).str();
80
- if (s == "glop") {
81
- return MPSolver::OptimizationProblemType::GLOP_LINEAR_PROGRAMMING;
82
- } else if (s == "cbc") {
83
- return MPSolver::OptimizationProblemType::CBC_MIXED_INTEGER_PROGRAMMING;
84
- } else {
85
- throw std::runtime_error("Unknown optimization problem type: " + s);
86
- }
87
- }
88
-
89
- template<>
90
- inline
91
- RoutingNodeIndex from_ruby<RoutingNodeIndex>(Object x)
92
- {
93
- const RoutingNodeIndex index{from_ruby<int>(x)};
94
- return index;
95
- }
96
-
97
- template<>
98
- inline
99
- Object to_ruby<RoutingNodeIndex>(RoutingNodeIndex const &x)
100
- {
101
- return to_ruby<int>(x.value());
102
- }
103
-
104
- std::vector<RoutingNodeIndex> nodeIndexVector(Array x) {
105
- std::vector<RoutingNodeIndex> res;
106
- for (auto const& v : x) {
107
- res.push_back(from_ruby<RoutingNodeIndex>(v));
108
- }
109
- return res;
110
- }
111
-
112
- template<>
113
- inline
114
- operations_research::sat::LinearExpr from_ruby<operations_research::sat::LinearExpr>(Object x)
115
- {
116
- operations_research::sat::LinearExpr expr;
117
-
118
- if (x.respond_to("to_i")) {
119
- expr = from_ruby<int64>(x.call("to_i"));
120
- } else if (x.respond_to("vars")) {
121
- Array vars = x.call("vars");
122
- for(auto const& var: vars) {
123
- auto cvar = (Array) var;
124
- // TODO clean up
125
- Object o = cvar[0];
126
- std::string type = ((String) o.call("class").call("name")).str();
127
- if (type == "ORTools::BoolVar") {
128
- expr.AddTerm(from_ruby<operations_research::sat::BoolVar>(cvar[0]), from_ruby<int64>(cvar[1]));
129
- } else if (type == "Integer") {
130
- expr.AddConstant(from_ruby<int64>(cvar[0]));
131
- } else {
132
- expr.AddTerm(from_ruby<operations_research::sat::IntVar>(cvar[0]), from_ruby<int64>(cvar[1]));
133
- }
134
- }
135
- } else {
136
- std::string type = ((String) x.call("class").call("name")).str();
137
- if (type == "ORTools::BoolVar") {
138
- expr = from_ruby<operations_research::sat::BoolVar>(x);
139
- } else {
140
- expr = from_ruby<operations_research::sat::IntVar>(x);
141
- }
142
- }
143
-
144
- return expr;
145
- }
146
-
147
- // need a wrapper class due to const
148
- class Assignment {
149
- const operations_research::Assignment* self;
150
- public:
151
- Assignment(const operations_research::Assignment* v) {
152
- self = v;
153
- }
154
- int64 ObjectiveValue() {
155
- return self->ObjectiveValue();
156
- }
157
- int64 Value(const operations_research::IntVar* const var) const {
158
- return self->Value(var);
159
- }
160
- int64 Min(const operations_research::IntVar* const var) const {
161
- return self->Min(var);
162
- }
163
- int64 Max(const operations_research::IntVar* const var) const {
164
- return self->Max(var);
165
- }
166
- };
167
-
168
- Class rb_cMPVariable;
169
- Class rb_cMPConstraint;
170
- Class rb_cMPObjective;
171
- Class rb_cIntVar;
172
- Class rb_cIntervalVar;
173
- Class rb_cRoutingDimension;
174
- Class rb_cConstraint;
175
- Class rb_cSolver2;
176
-
177
- template<>
178
- inline
179
- Object to_ruby<MPVariable*>(MPVariable* const &x)
180
- {
181
- return Rice::Data_Object<MPVariable>(x, rb_cMPVariable, nullptr, nullptr);
182
- }
183
-
184
- template<>
185
- inline
186
- Object to_ruby<MPConstraint*>(MPConstraint* const &x)
187
- {
188
- return Rice::Data_Object<MPConstraint>(x, rb_cMPConstraint, nullptr, nullptr);
189
- }
190
-
191
- template<>
192
- inline
193
- Object to_ruby<MPObjective*>(MPObjective* const &x)
194
- {
195
- return Rice::Data_Object<MPObjective>(x, rb_cMPObjective, nullptr, nullptr);
196
- }
197
-
198
- template<>
199
- inline
200
- Object to_ruby<operations_research::IntVar*>(operations_research::IntVar* const &x)
201
- {
202
- return Rice::Data_Object<operations_research::IntVar>(x, rb_cIntVar, nullptr, nullptr);
203
- }
204
-
205
- template<>
206
- inline
207
- Object to_ruby<operations_research::IntervalVar*>(operations_research::IntervalVar* const &x)
208
- {
209
- return Rice::Data_Object<operations_research::IntervalVar>(x, rb_cIntervalVar, nullptr, nullptr);
210
- }
211
-
212
- template<>
213
- inline
214
- Object to_ruby<RoutingDimension*>(RoutingDimension* const &x)
215
- {
216
- return Rice::Data_Object<RoutingDimension>(x, rb_cRoutingDimension, nullptr, nullptr);
217
- }
218
-
219
- template<>
220
- inline
221
- Object to_ruby<operations_research::Constraint*>(operations_research::Constraint* const &x)
222
- {
223
- return Rice::Data_Object<operations_research::Constraint>(x, rb_cConstraint, nullptr, nullptr);
224
- }
225
-
226
- template<>
227
- inline
228
- Object to_ruby<operations_research::Solver*>(operations_research::Solver* const &x)
229
- {
230
- return Rice::Data_Object<operations_research::Solver>(x, rb_cSolver2, nullptr, nullptr);
231
- }
232
-
233
- // need a wrapper class since absl::Span doesn't own
234
- class IntVarSpan {
235
- std::vector<operations_research::sat::IntVar> vec;
236
- public:
237
- IntVarSpan(Object x) {
238
- Array a = Array(x);
239
- for (std::size_t i = 0; i < a.size(); ++i) {
240
- vec.push_back(from_ruby<operations_research::sat::IntVar>(a[i]));
241
- }
242
- }
243
- operator absl::Span<const operations_research::sat::IntVar>() {
244
- return absl::Span<const operations_research::sat::IntVar>(vec);
245
- }
246
- };
247
-
248
- template<>
249
- inline
250
- IntVarSpan from_ruby<IntVarSpan>(Object x)
251
- {
252
- return IntVarSpan(x);
253
- }
254
-
255
- // need a wrapper class since absl::Span doesn't own
256
- class IntervalVarSpan {
257
- std::vector<operations_research::sat::IntervalVar> vec;
258
- public:
259
- IntervalVarSpan(Object x) {
260
- Array a = Array(x);
261
- for (std::size_t i = 0; i < a.size(); ++i) {
262
- vec.push_back(from_ruby<operations_research::sat::IntervalVar>(a[i]));
263
- }
264
- }
265
- operator absl::Span<const operations_research::sat::IntervalVar>() {
266
- return absl::Span<const operations_research::sat::IntervalVar>(vec);
267
- }
268
- };
269
-
270
- template<>
271
- inline
272
- IntervalVarSpan from_ruby<IntervalVarSpan>(Object x)
273
- {
274
- return IntervalVarSpan(x);
275
- }
276
-
277
- // need a wrapper class since absl::Span doesn't own
278
- class BoolVarSpan {
279
- std::vector<operations_research::sat::BoolVar> vec;
280
- public:
281
- BoolVarSpan(Object x) {
282
- Array a = Array(x);
283
- for (std::size_t i = 0; i < a.size(); ++i) {
284
- vec.push_back(from_ruby<operations_research::sat::BoolVar>(a[i]));
285
- }
286
- }
287
- operator absl::Span<const operations_research::sat::BoolVar>() {
288
- return absl::Span<const operations_research::sat::BoolVar>(vec);
289
- }
290
- };
291
-
292
- template<>
293
- inline
294
- BoolVarSpan from_ruby<BoolVarSpan>(Object x)
295
- {
296
- return BoolVarSpan(x);
297
- }
5
+ void init_assignment(Rice::Module& m);
6
+ void init_bin_packing(Rice::Module& m);
7
+ void init_constraint(Rice::Module& m);
8
+ void init_linear(Rice::Module& m);
9
+ void init_network_flows(Rice::Module& m);
10
+ void init_routing(Rice::Module& m);
298
11
 
299
12
  extern "C"
300
13
  void Init_ext()
301
14
  {
302
- Module rb_mORTools = define_module("ORTools")
303
- .define_singleton_method("default_routing_search_parameters", &DefaultRoutingSearchParameters)
304
- .define_singleton_method(
305
- "lib_version",
306
- *[]() {
307
- return std::to_string(operations_research::OrToolsMajorVersion()) + "."
308
- + std::to_string(operations_research::OrToolsMinorVersion());
309
- });
310
-
311
- define_class_under<RoutingSearchParameters>(rb_mORTools, "RoutingSearchParameters")
312
- .define_method(
313
- "first_solution_strategy=",
314
- *[](RoutingSearchParameters& self, Symbol value) {
315
- std::string s = Symbol(value).str();
316
-
317
- FirstSolutionStrategy::Value v;
318
- if (s == "path_cheapest_arc") {
319
- v = FirstSolutionStrategy::PATH_CHEAPEST_ARC;
320
- } else if (s == "path_most_constrained_arc") {
321
- v = FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC;
322
- } else if (s == "evaluator_strategy") {
323
- v = FirstSolutionStrategy::EVALUATOR_STRATEGY;
324
- } else if (s == "savings") {
325
- v = FirstSolutionStrategy::SAVINGS;
326
- } else if (s == "sweep") {
327
- v = FirstSolutionStrategy::SWEEP;
328
- } else if (s == "christofides") {
329
- v = FirstSolutionStrategy::CHRISTOFIDES;
330
- } else if (s == "all_unperformed") {
331
- v = FirstSolutionStrategy::ALL_UNPERFORMED;
332
- } else if (s == "best_insertion") {
333
- v = FirstSolutionStrategy::BEST_INSERTION;
334
- } else if (s == "parallel_cheapest_insertion") {
335
- v = FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION;
336
- } else if (s == "sequential_cheapest_insertion") {
337
- v = FirstSolutionStrategy::SEQUENTIAL_CHEAPEST_INSERTION;
338
- } else if (s == "local_cheapest_insertion") {
339
- v = FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION;
340
- } else if (s == "global_cheapest_arc") {
341
- v = FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC;
342
- } else if (s == "local_cheapest_arc") {
343
- v = FirstSolutionStrategy::LOCAL_CHEAPEST_ARC;
344
- } else if (s == "first_unbound_min_value") {
345
- v = FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE;
346
- } else {
347
- throw std::runtime_error("Unknown first solution strategy: " + s);
348
- }
349
-
350
- return self.set_first_solution_strategy(v);
351
- })
352
- .define_method(
353
- "local_search_metaheuristic=",
354
- *[](RoutingSearchParameters& self, Symbol value) {
355
- std::string s = Symbol(value).str();
356
-
357
- LocalSearchMetaheuristic::Value v;
358
- if (s == "guided_local_search") {
359
- v = LocalSearchMetaheuristic::GUIDED_LOCAL_SEARCH;
360
- } else if (s == "tabu_search") {
361
- v = LocalSearchMetaheuristic::TABU_SEARCH;
362
- } else if (s == "generic_tabu_search") {
363
- v = LocalSearchMetaheuristic::GENERIC_TABU_SEARCH;
364
- } else if (s == "simulated_annealing") {
365
- v = LocalSearchMetaheuristic::SIMULATED_ANNEALING;
366
- } else {
367
- throw std::runtime_error("Unknown local search metaheuristic: " + s);
368
- }
369
-
370
- return self.set_local_search_metaheuristic(v);
371
- })
372
- .define_method(
373
- "log_search=",
374
- *[](RoutingSearchParameters& self, bool value) {
375
- self.set_log_search(value);
376
- })
377
- .define_method(
378
- "solution_limit=",
379
- *[](RoutingSearchParameters& self, int64 value) {
380
- self.set_solution_limit(value);
381
- })
382
- .define_method(
383
- "time_limit=",
384
- *[](RoutingSearchParameters& self, int64 value) {
385
- self.mutable_time_limit()->set_seconds(value);
386
- })
387
- .define_method(
388
- "lns_time_limit=",
389
- *[](RoutingSearchParameters& self, int64 value) {
390
- self.mutable_lns_time_limit()->set_seconds(value);
391
- });
392
-
393
- rb_cMPVariable = define_class_under<MPVariable>(rb_mORTools, "MPVariable")
394
- .define_method("name", &MPVariable::name)
395
- .define_method("solution_value", &MPVariable::solution_value)
396
- .define_method(
397
- "+",
398
- *[](MPVariable& self, LinearExpr& other) {
399
- LinearExpr s(&self);
400
- return s + other;
401
- })
402
- .define_method(
403
- "-",
404
- *[](MPVariable& self, LinearExpr& other) {
405
- LinearExpr s(&self);
406
- return s - other;
407
- })
408
- .define_method(
409
- "*",
410
- *[](MPVariable& self, double other) {
411
- LinearExpr s(&self);
412
- return s * other;
413
- })
414
- .define_method(
415
- "inspect",
416
- *[](MPVariable& self) {
417
- return "#<ORTools::MPVariable @name=\"" + self.name() + "\">";
418
- });
15
+ auto m = Rice::define_module("ORTools");
419
16
 
420
- define_class_under<LinearExpr>(rb_mORTools, "LinearExpr")
421
- .define_constructor(Constructor<LinearExpr>())
422
- .define_method(
423
- "_add_linear_expr",
424
- *[](LinearExpr& self, LinearExpr& other) {
425
- return self + other;
426
- })
427
- .define_method(
428
- "_add_mp_variable",
429
- *[](LinearExpr& self, MPVariable &other) {
430
- LinearExpr o(&other);
431
- return self + o;
432
- })
433
- .define_method(
434
- "_gte_double",
435
- *[](LinearExpr& self, double other) {
436
- LinearExpr o(other);
437
- return self >= o;
438
- })
439
- .define_method(
440
- "_gte_linear_expr",
441
- *[](LinearExpr& self, LinearExpr& other) {
442
- return self >= other;
443
- })
444
- .define_method(
445
- "_lte_double",
446
- *[](LinearExpr& self, double other) {
447
- LinearExpr o(other);
448
- return self <= o;
449
- })
450
- .define_method(
451
- "_lte_linear_expr",
452
- *[](LinearExpr& self, LinearExpr& other) {
453
- return self <= other;
454
- })
455
- .define_method(
456
- "==",
457
- *[](LinearExpr& self, double other) {
458
- LinearExpr o(other);
459
- return self == o;
460
- })
461
- .define_method(
462
- "to_s",
463
- *[](LinearExpr& self) {
464
- return self.ToString();
465
- })
466
- .define_method(
467
- "inspect",
468
- *[](LinearExpr& self) {
469
- return "#<ORTools::LinearExpr \"" + self.ToString() + "\">";
470
- });
471
-
472
- define_class_under<LinearRange>(rb_mORTools, "LinearRange");
473
-
474
- rb_cMPConstraint = define_class_under<MPConstraint>(rb_mORTools, "MPConstraint")
475
- .define_method("set_coefficient", &MPConstraint::SetCoefficient);
476
-
477
- rb_cMPObjective = define_class_under<MPObjective>(rb_mORTools, "MPObjective")
478
- .define_method("value", &MPObjective::Value)
479
- .define_method("set_coefficient", &MPObjective::SetCoefficient)
480
- .define_method("set_maximization", &MPObjective::SetMaximization);
481
-
482
- define_class_under<MPSolver>(rb_mORTools, "Solver")
483
- .define_constructor(Constructor<MPSolver, std::string, MPSolver::OptimizationProblemType>())
484
- .define_method("infinity", &MPSolver::infinity)
485
- .define_method(
486
- "int_var",
487
- *[](MPSolver& self, double min, double max, const std::string& name) {
488
- return self.MakeIntVar(min, max, name);
489
- })
490
- .define_method("num_var", &MPSolver::MakeNumVar)
491
- .define_method("bool_var", &MPSolver::MakeBoolVar)
492
- .define_method("num_variables", &MPSolver::NumVariables)
493
- .define_method("num_constraints", &MPSolver::NumConstraints)
494
- .define_method("wall_time", &MPSolver::wall_time)
495
- .define_method("iterations", &MPSolver::iterations)
496
- .define_method("nodes", &MPSolver::nodes)
497
- .define_method("objective", &MPSolver::MutableObjective)
498
- .define_method(
499
- "maximize",
500
- *[](MPSolver& self, LinearExpr& expr) {
501
- return self.MutableObjective()->MaximizeLinearExpr(expr);
502
- })
503
- .define_method(
504
- "minimize",
505
- *[](MPSolver& self, LinearExpr& expr) {
506
- return self.MutableObjective()->MinimizeLinearExpr(expr);
507
- })
508
- .define_method(
509
- "add",
510
- *[](MPSolver& self, const LinearRange& range) {
511
- return self.MakeRowConstraint(range);
512
- })
513
- .define_method(
514
- "constraint",
515
- *[](MPSolver& self, double lb, double ub) {
516
- return self.MakeRowConstraint(lb, ub);
517
- })
518
- .define_method(
519
- "solve",
520
- *[](MPSolver& self) {
521
- auto status = self.Solve();
522
-
523
- if (status == MPSolver::ResultStatus::OPTIMAL) {
524
- return Symbol("optimal");
525
- } else if (status == MPSolver::ResultStatus::FEASIBLE) {
526
- return Symbol("feasible");
527
- } else if (status == MPSolver::ResultStatus::INFEASIBLE) {
528
- return Symbol("infeasible");
529
- } else if (status == MPSolver::ResultStatus::UNBOUNDED) {
530
- return Symbol("unbounded");
531
- } else if (status == MPSolver::ResultStatus::ABNORMAL) {
532
- return Symbol("abnormal");
533
- } else if (status == MPSolver::ResultStatus::MODEL_INVALID) {
534
- return Symbol("model_invalid");
535
- } else if (status == MPSolver::ResultStatus::NOT_SOLVED) {
536
- return Symbol("not_solved");
537
- } else {
538
- throw std::runtime_error("Unknown status");
539
- }
540
- });
541
-
542
- define_class_under<operations_research::sat::IntVar>(rb_mORTools, "SatIntVar")
543
- .define_method("name", &operations_research::sat::IntVar::Name);
544
-
545
- define_class_under<operations_research::sat::IntervalVar>(rb_mORTools, "SatIntervalVar")
546
- .define_method("name", &operations_research::sat::IntervalVar::Name);
547
-
548
- define_class_under<operations_research::sat::Constraint>(rb_mORTools, "SatConstraint");
549
-
550
- define_class_under<BoolVar>(rb_mORTools, "BoolVar")
551
- .define_method("name", &BoolVar::Name)
552
- .define_method("index", &BoolVar::index)
553
- .define_method("not", &BoolVar::Not)
554
- .define_method(
555
- "inspect",
556
- *[](BoolVar& self) {
557
- String name(self.Name());
558
- return "#<ORTools::BoolVar @name=" + name.inspect().str() + ">";
559
- });
560
-
561
- define_class_under<CpModelBuilder>(rb_mORTools, "CpModel")
562
- .define_constructor(Constructor<CpModelBuilder>())
563
- .define_method(
564
- "new_int_var",
565
- *[](CpModelBuilder& self, int64 start, int64 end, std::string name) {
566
- const Domain domain(start, end);
567
- return self.NewIntVar(domain).WithName(name);
568
- })
569
- .define_method(
570
- "new_bool_var",
571
- *[](CpModelBuilder& self, std::string name) {
572
- return self.NewBoolVar().WithName(name);
573
- })
574
- .define_method(
575
- "new_interval_var",
576
- *[](CpModelBuilder& self, operations_research::sat::IntVar start, operations_research::sat::IntVar size, operations_research::sat::IntVar end, std::string name) {
577
- return self.NewIntervalVar(start, size, end).WithName(name);
578
- })
579
- .define_method(
580
- "add_equality",
581
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
582
- self.AddEquality(x, y);
583
- })
584
- .define_method(
585
- "add_not_equal",
586
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
587
- self.AddNotEqual(x, y);
588
- })
589
- .define_method(
590
- "add_greater_than",
591
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
592
- self.AddGreaterThan(x, y);
593
- })
594
- .define_method(
595
- "add_greater_or_equal",
596
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
597
- self.AddGreaterOrEqual(x, y);
598
- })
599
- .define_method(
600
- "add_less_than",
601
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
602
- self.AddLessThan(x, y);
603
- })
604
- .define_method(
605
- "add_less_or_equal",
606
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr x, operations_research::sat::LinearExpr y) {
607
- self.AddLessOrEqual(x, y);
608
- })
609
- .define_method(
610
- "add_all_different",
611
- *[](CpModelBuilder& self, IntVarSpan vars) {
612
- self.AddAllDifferent(vars);
613
- })
614
- .define_method(
615
- "add_max_equality",
616
- *[](CpModelBuilder& self, operations_research::sat::IntVar target, IntVarSpan vars) {
617
- self.AddMaxEquality(target, vars);
618
- })
619
- .define_method(
620
- "add_no_overlap",
621
- *[](CpModelBuilder& self, IntervalVarSpan vars) {
622
- self.AddNoOverlap(vars);
623
- })
624
- .define_method(
625
- "add_bool_or",
626
- *[](CpModelBuilder& self, BoolVarSpan literals) {
627
- self.AddBoolOr(literals);
628
- })
629
- .define_method("add_implication", &CpModelBuilder::AddImplication)
630
- .define_method(
631
- "maximize",
632
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr expr) {
633
- self.Maximize(expr);
634
- })
635
- .define_method(
636
- "minimize",
637
- *[](CpModelBuilder& self, operations_research::sat::LinearExpr expr) {
638
- self.Minimize(expr);
639
- });
640
-
641
- define_class_under<SatParameters>(rb_mORTools, "SatParameters")
642
- .define_constructor(Constructor<SatParameters>())
643
- .define_method("max_time_in_seconds=",
644
- *[](SatParameters& self, double value) {
645
- self.set_max_time_in_seconds(value);
17
+ m.define_singleton_method(
18
+ "lib_version",
19
+ *[]() {
20
+ return std::to_string(operations_research::OrToolsMajorVersion()) + "."
21
+ + std::to_string(operations_research::OrToolsMinorVersion());
646
22
  });
647
23
 
648
- define_class_under(rb_mORTools, "CpSolver")
649
- .define_method(
650
- "_solve_with_observer",
651
- *[](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback, bool all_solutions) {
652
- operations_research::sat::Model m;
653
-
654
- if (all_solutions) {
655
- // set parameters for SearchForAllSolutions
656
- parameters.set_enumerate_all_solutions(true);
657
- }
658
- m.Add(NewSatParameters(parameters));
659
-
660
- m.Add(NewFeasibleSolutionObserver(
661
- [callback](const CpSolverResponse& r) {
662
- // TODO find a better way to do this
663
- callback.call("response=", r);
664
- callback.call("on_solution_callback");
665
- })
666
- );
667
- return SolveCpModel(model.Build(), &m);
668
- })
669
- .define_method(
670
- "_solve",
671
- *[](Object self, CpModelBuilder& model, SatParameters& parameters) {
672
- operations_research::sat::Model m;
673
- m.Add(NewSatParameters(parameters));
674
- return SolveCpModel(model.Build(), &m);
675
- })
676
- .define_method(
677
- "_solution_integer_value",
678
- *[](Object self, CpSolverResponse& response, operations_research::sat::IntVar& x) {
679
- return SolutionIntegerValue(response, x);
680
- })
681
- .define_method(
682
- "_solution_boolean_value",
683
- *[](Object self, CpSolverResponse& response, operations_research::sat::BoolVar& x) {
684
- return SolutionBooleanValue(response, x);
685
- });
686
-
687
- define_class_under<CpSolverResponse>(rb_mORTools, "CpSolverResponse")
688
- .define_method("objective_value", &CpSolverResponse::objective_value)
689
- .define_method("num_conflicts", &CpSolverResponse::num_conflicts)
690
- .define_method("num_branches", &CpSolverResponse::num_branches)
691
- .define_method("wall_time", &CpSolverResponse::wall_time)
692
- .define_method(
693
- "solution_integer_value",
694
- *[](CpSolverResponse& self, operations_research::sat::IntVar& x) {
695
- operations_research::sat::LinearExpr expr(x);
696
- return SolutionIntegerValue(self, expr);
697
- })
698
- .define_method("solution_boolean_value", &operations_research::sat::SolutionBooleanValue)
699
- .define_method(
700
- "status",
701
- *[](CpSolverResponse& self) {
702
- auto status = self.status();
703
-
704
- if (status == CpSolverStatus::OPTIMAL) {
705
- return Symbol("optimal");
706
- } else if (status == CpSolverStatus::FEASIBLE) {
707
- return Symbol("feasible");
708
- } else if (status == CpSolverStatus::INFEASIBLE) {
709
- return Symbol("infeasible");
710
- } else if (status == CpSolverStatus::MODEL_INVALID) {
711
- return Symbol("model_invalid");
712
- } else if (status == CpSolverStatus::UNKNOWN) {
713
- return Symbol("unknown");
714
- } else {
715
- throw std::runtime_error("Unknown solver status");
716
- }
717
- });
718
-
719
- define_class_under<RoutingIndexManager>(rb_mORTools, "RoutingIndexManager")
720
- .define_singleton_method(
721
- "_new_depot",
722
- *[](int num_nodes, int num_vehicles, RoutingNodeIndex depot) {
723
- return RoutingIndexManager(num_nodes, num_vehicles, depot);
724
- })
725
- .define_singleton_method(
726
- "_new_starts_ends",
727
- *[](int num_nodes, int num_vehicles, Array starts, Array ends) {
728
- return RoutingIndexManager(num_nodes, num_vehicles, nodeIndexVector(starts), nodeIndexVector(ends));
729
- })
730
- .define_method("index_to_node", &RoutingIndexManager::IndexToNode)
731
- .define_method("node_to_index", &RoutingIndexManager::NodeToIndex);
732
-
733
- define_class_under<Assignment>(rb_mORTools, "Assignment")
734
- .define_method("objective_value", &Assignment::ObjectiveValue)
735
- .define_method("value", &Assignment::Value)
736
- .define_method("min", &Assignment::Min)
737
- .define_method("max", &Assignment::Max);
738
-
739
- // not to be confused with operations_research::sat::IntVar
740
- rb_cIntVar = define_class_under<operations_research::IntVar>(rb_mORTools, "IntVar")
741
- .define_method(
742
- "set_range",
743
- *[](operations_research::IntVar& self, int64 new_min, int64 new_max) {
744
- self.SetRange(new_min, new_max);
745
- });
746
-
747
- rb_cIntervalVar = define_class_under<operations_research::IntervalVar>(rb_mORTools, "IntervalVar");
748
-
749
- rb_cRoutingDimension = define_class_under<RoutingDimension>(rb_mORTools, "RoutingDimension")
750
- .define_method("global_span_cost_coefficient=", &RoutingDimension::SetGlobalSpanCostCoefficient)
751
- .define_method("cumul_var", &RoutingDimension::CumulVar);
752
-
753
- rb_cConstraint = define_class_under<operations_research::Constraint>(rb_mORTools, "Constraint");
754
-
755
- rb_cSolver2 = define_class_under<operations_research::Solver>(rb_mORTools, "Solver2")
756
- .define_method(
757
- "add",
758
- *[](operations_research::Solver& self, Object o) {
759
- operations_research::Constraint* constraint;
760
- if (o.respond_to("left")) {
761
- operations_research::IntExpr* left(from_ruby<operations_research::IntVar*>(o.call("left")));
762
- operations_research::IntExpr* right(from_ruby<operations_research::IntVar*>(o.call("right")));
763
- auto op = o.call("operator").to_s().str();
764
- if (op == "==") {
765
- constraint = self.MakeEquality(left, right);
766
- } else if (op == "<=") {
767
- constraint = self.MakeLessOrEqual(left, right);
768
- } else {
769
- throw std::runtime_error("Unknown operator");
770
- }
771
- } else {
772
- constraint = from_ruby<operations_research::Constraint*>(o);
773
- }
774
- self.AddConstraint(constraint);
775
- })
776
- .define_method(
777
- "fixed_duration_interval_var",
778
- *[](operations_research::Solver& self, operations_research::IntVar* const start_variable, int64 duration, const std::string& name) {
779
- return self.MakeFixedDurationIntervalVar(start_variable, duration, name);
780
- })
781
- .define_method(
782
- "cumulative",
783
- *[](operations_research::Solver& self, Array rb_intervals, Array rb_demands, int64 capacity, const std::string& name) {
784
- std::vector<operations_research::IntervalVar*> intervals;
785
- for (std::size_t i = 0; i < rb_intervals.size(); ++i) {
786
- intervals.push_back(from_ruby<operations_research::IntervalVar*>(rb_intervals[i]));
787
- }
788
-
789
- std::vector<int64> demands;
790
- for (std::size_t i = 0; i < rb_demands.size(); ++i) {
791
- demands.push_back(from_ruby<int64>(rb_demands[i]));
792
- }
793
-
794
- return self.MakeCumulative(intervals, demands, capacity, name);
795
- });
796
-
797
- define_class_under<RoutingModel>(rb_mORTools, "RoutingModel")
798
- .define_constructor(Constructor<RoutingModel, RoutingIndexManager>())
799
- .define_method(
800
- "register_transit_callback",
801
- *[](RoutingModel& self, Object callback) {
802
- return self.RegisterTransitCallback(
803
- [callback](int64 from_index, int64 to_index) -> int64 {
804
- return from_ruby<int64>(callback.call("call", from_index, to_index));
805
- }
806
- );
807
- })
808
- .define_method(
809
- "register_unary_transit_callback",
810
- *[](RoutingModel& self, Object callback) {
811
- return self.RegisterUnaryTransitCallback(
812
- [callback](int64 from_index) -> int64 {
813
- return from_ruby<int64>(callback.call("call", from_index));
814
- }
815
- );
816
- })
817
- .define_method("depot", &RoutingModel::GetDepot)
818
- .define_method("size", &RoutingModel::Size)
819
- .define_method("status", *[](RoutingModel& self) {
820
- auto status = self.status();
821
-
822
- if (status == RoutingModel::ROUTING_NOT_SOLVED) {
823
- return Symbol("not_solved");
824
- } else if (status == RoutingModel::ROUTING_SUCCESS) {
825
- return Symbol("success");
826
- } else if (status == RoutingModel::ROUTING_FAIL) {
827
- return Symbol("fail");
828
- } else if (status == RoutingModel::ROUTING_FAIL_TIMEOUT) {
829
- return Symbol("fail_timeout");
830
- } else if (status == RoutingModel::ROUTING_INVALID) {
831
- return Symbol("invalid");
832
- } else {
833
- throw std::runtime_error("Unknown solver status");
834
- }
835
- })
836
- .define_method("vehicle_var", &RoutingModel::VehicleVar)
837
- .define_method("set_arc_cost_evaluator_of_all_vehicles", &RoutingModel::SetArcCostEvaluatorOfAllVehicles)
838
- .define_method("set_arc_cost_evaluator_of_vehicle", &RoutingModel::SetArcCostEvaluatorOfVehicle)
839
- .define_method("set_fixed_cost_of_all_vehicles", &RoutingModel::SetFixedCostOfAllVehicles)
840
- .define_method("set_fixed_cost_of_vehicle", &RoutingModel::SetFixedCostOfVehicle)
841
- .define_method("fixed_cost_of_vehicle", &RoutingModel::GetFixedCostOfVehicle)
842
- .define_method("add_dimension", &RoutingModel::AddDimension)
843
- .define_method(
844
- "add_dimension_with_vehicle_capacity",
845
- *[](RoutingModel& self, int evaluator_index, int64 slack_max, Array vc, bool fix_start_cumul_to_zero, const std::string& name) {
846
- std::vector<int64> vehicle_capacities;
847
- for (std::size_t i = 0; i < vc.size(); ++i) {
848
- vehicle_capacities.push_back(from_ruby<int64>(vc[i]));
849
- }
850
- self.AddDimensionWithVehicleCapacity(evaluator_index, slack_max, vehicle_capacities, fix_start_cumul_to_zero, name);
851
- })
852
- .define_method(
853
- "add_dimension_with_vehicle_transits",
854
- *[](RoutingModel& self, Array rb_indices, int64 slack_max, int64 capacity, bool fix_start_cumul_to_zero, const std::string& name) {
855
- std::vector<int> evaluator_indices;
856
- for (std::size_t i = 0; i < rb_indices.size(); ++i) {
857
- evaluator_indices.push_back(from_ruby<int>(rb_indices[i]));
858
- }
859
- self.AddDimensionWithVehicleTransits(evaluator_indices, slack_max, capacity, fix_start_cumul_to_zero, name);
860
- })
861
- .define_method(
862
- "add_disjunction",
863
- *[](RoutingModel& self, Array rb_indices, int64 penalty) {
864
- std::vector<int64> indices;
865
- for (std::size_t i = 0; i < rb_indices.size(); ++i) {
866
- indices.push_back(from_ruby<int64>(rb_indices[i]));
867
- }
868
- self.AddDisjunction(indices, penalty);
869
- })
870
- .define_method("add_pickup_and_delivery", &RoutingModel::AddPickupAndDelivery)
871
- .define_method("solver", &RoutingModel::solver)
872
- .define_method("start", &RoutingModel::Start)
873
- .define_method("end", &RoutingModel::End)
874
- .define_method("start?", &RoutingModel::IsStart)
875
- .define_method("end?", &RoutingModel::IsEnd)
876
- .define_method("vehicle_index", &RoutingModel::VehicleIndex)
877
- .define_method("next", &RoutingModel::Next)
878
- .define_method("vehicle_used?", &RoutingModel::IsVehicleUsed)
879
- .define_method("next_var", &RoutingModel::NextVar)
880
- .define_method("arc_cost_for_vehicle", &RoutingModel::GetArcCostForVehicle)
881
- .define_method("mutable_dimension", &RoutingModel::GetMutableDimension)
882
- .define_method("add_variable_minimized_by_finalizer", &RoutingModel::AddVariableMinimizedByFinalizer)
883
- .define_method(
884
- "solve_with_parameters",
885
- *[](RoutingModel& self, const RoutingSearchParameters& search_parameters) {
886
- auto assignment = self.SolveWithParameters(search_parameters);
887
- // std::cout << assignment->DebugString();
888
- return (Assignment) assignment;
889
- });
890
-
891
- define_class_under<KnapsackSolver>(rb_mORTools, "KnapsackSolver")
892
- .define_constructor(Constructor<KnapsackSolver, KnapsackSolver::SolverType, std::string>())
893
- .define_method("_solve", &KnapsackSolver::Solve)
894
- .define_method("best_solution_contains?", &KnapsackSolver::BestSolutionContains)
895
- .define_method(
896
- "init",
897
- *[](KnapsackSolver& self, Array rb_values, Array rb_weights, Array rb_capacities) {
898
- std::vector<int64> values;
899
- for (std::size_t i = 0; i < rb_values.size(); ++i) {
900
- values.push_back(from_ruby<int64>(rb_values[i]));
901
- }
902
-
903
- std::vector<std::vector<int64>> weights;
904
- for (std::size_t i = 0; i < rb_weights.size(); ++i) {
905
- Array rb_w = Array(rb_weights[i]);
906
- std::vector<int64> w;
907
- for (std::size_t j = 0; j < rb_w.size(); ++j) {
908
- w.push_back(from_ruby<int64>(rb_w[j]));
909
- }
910
- weights.push_back(w);
911
- }
912
-
913
- std::vector<int64> capacities;
914
- for (std::size_t i = 0; i < rb_capacities.size(); ++i) {
915
- capacities.push_back(from_ruby<int64>(rb_capacities[i]));
916
- }
917
-
918
- self.Init(values, weights, capacities);
919
- });
920
-
921
- define_class_under<SimpleMaxFlow>(rb_mORTools, "SimpleMaxFlow")
922
- .define_constructor(Constructor<SimpleMaxFlow>())
923
- .define_method("add_arc_with_capacity", &SimpleMaxFlow::AddArcWithCapacity)
924
- .define_method("num_nodes", &SimpleMaxFlow::NumNodes)
925
- .define_method("num_arcs", &SimpleMaxFlow::NumArcs)
926
- .define_method("tail", &SimpleMaxFlow::Tail)
927
- .define_method("head", &SimpleMaxFlow::Head)
928
- .define_method("capacity", &SimpleMaxFlow::Capacity)
929
- .define_method("optimal_flow", &SimpleMaxFlow::OptimalFlow)
930
- .define_method("flow", &SimpleMaxFlow::Flow)
931
- .define_method(
932
- "solve",
933
- *[](SimpleMaxFlow& self, NodeIndex source, NodeIndex sink) {
934
- auto status = self.Solve(source, sink);
935
-
936
- if (status == SimpleMaxFlow::Status::OPTIMAL) {
937
- return Symbol("optimal");
938
- } else if (status == SimpleMaxFlow::Status::POSSIBLE_OVERFLOW) {
939
- return Symbol("possible_overflow");
940
- } else if (status == SimpleMaxFlow::Status::BAD_INPUT) {
941
- return Symbol("bad_input");
942
- } else if (status == SimpleMaxFlow::Status::BAD_RESULT) {
943
- return Symbol("bad_result");
944
- } else {
945
- throw std::runtime_error("Unknown status");
946
- }
947
- })
948
- .define_method(
949
- "source_side_min_cut",
950
- *[](SimpleMaxFlow& self) {
951
- std::vector<NodeIndex> result;
952
- self.GetSourceSideMinCut(&result);
953
-
954
- Array ret;
955
- for(auto const& it: result) {
956
- ret.push(it);
957
- }
958
- return ret;
959
- })
960
- .define_method(
961
- "sink_side_min_cut",
962
- *[](SimpleMaxFlow& self) {
963
- std::vector<NodeIndex> result;
964
- self.GetSinkSideMinCut(&result);
965
-
966
- Array ret;
967
- for(auto const& it: result) {
968
- ret.push(it);
969
- }
970
- return ret;
971
- });
972
-
973
- define_class_under<SimpleMinCostFlow>(rb_mORTools, "SimpleMinCostFlow")
974
- .define_constructor(Constructor<SimpleMinCostFlow>())
975
- .define_method("add_arc_with_capacity_and_unit_cost", &SimpleMinCostFlow::AddArcWithCapacityAndUnitCost)
976
- .define_method("set_node_supply", &SimpleMinCostFlow::SetNodeSupply)
977
- .define_method("optimal_cost", &SimpleMinCostFlow::OptimalCost)
978
- .define_method("maximum_flow", &SimpleMinCostFlow::MaximumFlow)
979
- .define_method("flow", &SimpleMinCostFlow::Flow)
980
- .define_method("num_nodes", &SimpleMinCostFlow::NumNodes)
981
- .define_method("num_arcs", &SimpleMinCostFlow::NumArcs)
982
- .define_method("tail", &SimpleMinCostFlow::Tail)
983
- .define_method("head", &SimpleMinCostFlow::Head)
984
- .define_method("capacity", &SimpleMinCostFlow::Capacity)
985
- .define_method("supply", &SimpleMinCostFlow::Supply)
986
- .define_method("unit_cost", &SimpleMinCostFlow::UnitCost)
987
- .define_method(
988
- "solve",
989
- *[](SimpleMinCostFlow& self) {
990
- auto status = self.Solve();
991
-
992
- if (status == SimpleMinCostFlow::Status::NOT_SOLVED) {
993
- return Symbol("not_solved");
994
- } else if (status == SimpleMinCostFlow::Status::OPTIMAL) {
995
- return Symbol("optimal");
996
- } else if (status == SimpleMinCostFlow::Status::FEASIBLE) {
997
- return Symbol("feasible");
998
- } else if (status == SimpleMinCostFlow::Status::INFEASIBLE) {
999
- return Symbol("infeasible");
1000
- } else if (status == SimpleMinCostFlow::Status::UNBALANCED) {
1001
- return Symbol("unbalanced");
1002
- } else if (status == SimpleMinCostFlow::Status::BAD_RESULT) {
1003
- return Symbol("bad_result");
1004
- } else if (status == SimpleMinCostFlow::Status::BAD_COST_RANGE) {
1005
- return Symbol("bad_cost_range");
1006
- } else {
1007
- throw std::runtime_error("Unknown status");
1008
- }
1009
- });
1010
-
1011
- define_class_under<SimpleLinearSumAssignment>(rb_mORTools, "LinearSumAssignment")
1012
- .define_constructor(Constructor<SimpleLinearSumAssignment>())
1013
- .define_method("add_arc_with_cost", &SimpleLinearSumAssignment::AddArcWithCost)
1014
- .define_method("num_nodes", &SimpleLinearSumAssignment::NumNodes)
1015
- .define_method("num_arcs", &SimpleLinearSumAssignment::NumArcs)
1016
- .define_method("left_node", &SimpleLinearSumAssignment::LeftNode)
1017
- .define_method("right_node", &SimpleLinearSumAssignment::RightNode)
1018
- .define_method("cost", &SimpleLinearSumAssignment::Cost)
1019
- .define_method("optimal_cost", &SimpleLinearSumAssignment::OptimalCost)
1020
- .define_method("right_mate", &SimpleLinearSumAssignment::RightMate)
1021
- .define_method("assignment_cost", &SimpleLinearSumAssignment::AssignmentCost)
1022
- .define_method(
1023
- "solve",
1024
- *[](SimpleLinearSumAssignment& self) {
1025
- auto status = self.Solve();
1026
-
1027
- if (status == SimpleLinearSumAssignment::Status::OPTIMAL) {
1028
- return Symbol("optimal");
1029
- } else if (status == SimpleLinearSumAssignment::Status::INFEASIBLE) {
1030
- return Symbol("infeasible");
1031
- } else if (status == SimpleLinearSumAssignment::Status::POSSIBLE_OVERFLOW) {
1032
- return Symbol("possible_overflow");
1033
- } else {
1034
- throw std::runtime_error("Unknown status");
1035
- }
1036
- });
24
+ init_assignment(m);
25
+ init_bin_packing(m);
26
+ init_constraint(m);
27
+ init_linear(m);
28
+ init_network_flows(m);
29
+ init_routing(m);
1037
30
  }