or-tools 0.3.2 → 0.4.2

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