or-tools 0.4.0 → 0.5.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.
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
- #include <rice/Module.hpp>
18
- #include <rice/String.hpp>
19
- #include <rice/Symbol.hpp>
3
+ #include "ext.h"
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_function(
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
  }