or-tools 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e557f98fc061c46799334f589a41f1592da361bce8a6e199120d3425efe67c0a
4
- data.tar.gz: be6fa049625b6d9aae8134b34a4731053b1e3b12c7481dd041bdb98e40648c1d
3
+ metadata.gz: 7ce5b035a9a0f52391ef97cd12d32ec7632101940fde4e2f19de4887900a4dc1
4
+ data.tar.gz: c63b37906fb5337cd805c627266422ccfc698d3759456327e2414f5e31e4ab52
5
5
  SHA512:
6
- metadata.gz: 5f5542b967fc7fd25afa4598bcfa99c17978e8020ced4af449ca00e8e7e20f2aeb1e5de2b6d562a60cd880afa14f9ea383c12a3d3fe7434dc2f4837d98e18d24
7
- data.tar.gz: 69506b406afe60200592f5b526ce617fba45d8581e253ca12b143d243aa1d9fdda5c2e122e24d5dd516e9e141a542ed5eaef834861ccfa3917693d8f1971ffca
6
+ metadata.gz: 5eda4c29a50790d7c569e67b9538ac2c13a6cd20af1580cd679a68d386244b5cd1bbafa311c52fe9cad519652bbfb6666aed09e6a5ae1f7c71cc666491644d4f
7
+ data.tar.gz: 5241d2788f6883ca0349967e4f953382cd03564fe4856e853888518427a2ed5ec8a8cf948aac34a02b39f413c787eeb98ff22284f59359f7cf9a9aa73b449188
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.4.1 (2021-02-23)
2
+
3
+ - Added solution printers
4
+ - Improved `inspect` and `to_s` for `CpModel`
5
+ - Improved constraint construction
6
+
1
7
  ## 0.4.0 (2021-01-14)
2
8
 
3
9
  - Updated OR-Tools to 8.1
data/README.md CHANGED
@@ -267,7 +267,7 @@ Constraint Optimization
267
267
  - [Solving an Optimization Problem](#solving-an-optimization-problem)
268
268
  - [Cryptarithmetic](#cryptarithmetic)
269
269
  - [The N-queens Problem](#the-n-queens-problem)
270
- - [Setting Solver Limits](#setting-solver-limits) [master]
270
+ - [Setting Solver Limits](#setting-solver-limits)
271
271
 
272
272
  Assignment
273
273
 
@@ -0,0 +1,39 @@
1
+ #include <ortools/graph/assignment.h>
2
+
3
+ #include <rice/Array.hpp>
4
+ #include <rice/Constructor.hpp>
5
+ #include <rice/Module.hpp>
6
+
7
+ using operations_research::SimpleLinearSumAssignment;
8
+
9
+ using Rice::Array;
10
+ using Rice::Symbol;
11
+
12
+ void init_assignment(Rice::Module& m) {
13
+ Rice::define_class_under<SimpleLinearSumAssignment>(m, "LinearSumAssignment")
14
+ .define_constructor(Rice::Constructor<SimpleLinearSumAssignment>())
15
+ .define_method("add_arc_with_cost", &SimpleLinearSumAssignment::AddArcWithCost)
16
+ .define_method("num_nodes", &SimpleLinearSumAssignment::NumNodes)
17
+ .define_method("num_arcs", &SimpleLinearSumAssignment::NumArcs)
18
+ .define_method("left_node", &SimpleLinearSumAssignment::LeftNode)
19
+ .define_method("right_node", &SimpleLinearSumAssignment::RightNode)
20
+ .define_method("cost", &SimpleLinearSumAssignment::Cost)
21
+ .define_method("optimal_cost", &SimpleLinearSumAssignment::OptimalCost)
22
+ .define_method("right_mate", &SimpleLinearSumAssignment::RightMate)
23
+ .define_method("assignment_cost", &SimpleLinearSumAssignment::AssignmentCost)
24
+ .define_method(
25
+ "solve",
26
+ *[](SimpleLinearSumAssignment& self) {
27
+ auto status = self.Solve();
28
+
29
+ if (status == SimpleLinearSumAssignment::Status::OPTIMAL) {
30
+ return Symbol("optimal");
31
+ } else if (status == SimpleLinearSumAssignment::Status::INFEASIBLE) {
32
+ return Symbol("infeasible");
33
+ } else if (status == SimpleLinearSumAssignment::Status::POSSIBLE_OVERFLOW) {
34
+ return Symbol("possible_overflow");
35
+ } else {
36
+ throw std::runtime_error("Unknown status");
37
+ }
38
+ });
39
+ }
@@ -0,0 +1,55 @@
1
+ #include <ortools/algorithms/knapsack_solver.h>
2
+
3
+ #include <rice/Array.hpp>
4
+ #include <rice/Constructor.hpp>
5
+ #include <rice/Module.hpp>
6
+
7
+ using operations_research::KnapsackSolver;
8
+
9
+ using Rice::Array;
10
+ using Rice::Object;
11
+ using Rice::Symbol;
12
+
13
+ template<>
14
+ inline
15
+ KnapsackSolver::SolverType from_ruby<KnapsackSolver::SolverType>(Object x)
16
+ {
17
+ std::string s = Symbol(x).str();
18
+ if (s == "branch_and_bound") {
19
+ return KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER;
20
+ } else {
21
+ throw std::runtime_error("Unknown solver type: " + s);
22
+ }
23
+ }
24
+
25
+ void init_bin_packing(Rice::Module& m) {
26
+ Rice::define_class_under<KnapsackSolver>(m, "KnapsackSolver")
27
+ .define_constructor(Rice::Constructor<KnapsackSolver, KnapsackSolver::SolverType, std::string>())
28
+ .define_method("_solve", &KnapsackSolver::Solve)
29
+ .define_method("best_solution_contains?", &KnapsackSolver::BestSolutionContains)
30
+ .define_method(
31
+ "init",
32
+ *[](KnapsackSolver& self, Array rb_values, Array rb_weights, Array rb_capacities) {
33
+ std::vector<int64> values;
34
+ for (std::size_t i = 0; i < rb_values.size(); ++i) {
35
+ values.push_back(from_ruby<int64>(rb_values[i]));
36
+ }
37
+
38
+ std::vector<std::vector<int64>> weights;
39
+ for (std::size_t i = 0; i < rb_weights.size(); ++i) {
40
+ Array rb_w = Array(rb_weights[i]);
41
+ std::vector<int64> w;
42
+ for (std::size_t j = 0; j < rb_w.size(); ++j) {
43
+ w.push_back(from_ruby<int64>(rb_w[j]));
44
+ }
45
+ weights.push_back(w);
46
+ }
47
+
48
+ std::vector<int64> capacities;
49
+ for (std::size_t i = 0; i < rb_capacities.size(); ++i) {
50
+ capacities.push_back(from_ruby<int64>(rb_capacities[i]));
51
+ }
52
+
53
+ self.Init(values, weights, capacities);
54
+ });
55
+ }
@@ -0,0 +1,423 @@
1
+ #include <google/protobuf/text_format.h>
2
+ #include <ortools/sat/cp_model.h>
3
+
4
+ #include <rice/Array.hpp>
5
+ #include <rice/Constructor.hpp>
6
+ #include <rice/Module.hpp>
7
+
8
+ using operations_research::sat::BoolVar;
9
+ using operations_research::sat::Constraint;
10
+ using operations_research::sat::CpModelBuilder;
11
+ using operations_research::sat::CpSolverResponse;
12
+ using operations_research::sat::CpSolverStatus;
13
+ using operations_research::sat::LinearExpr;
14
+ using operations_research::sat::IntVar;
15
+ using operations_research::sat::IntervalVar;
16
+ using operations_research::sat::Model;
17
+ using operations_research::sat::NewFeasibleSolutionObserver;
18
+ using operations_research::sat::SatParameters;
19
+ using operations_research::sat::SolutionBooleanValue;
20
+ using operations_research::sat::SolutionIntegerValue;
21
+
22
+ using Rice::Array;
23
+ using Rice::Object;
24
+ using Rice::String;
25
+ using Rice::Symbol;
26
+
27
+ template<>
28
+ inline
29
+ LinearExpr from_ruby<LinearExpr>(Object x)
30
+ {
31
+ LinearExpr expr;
32
+
33
+ if (x.respond_to("to_i")) {
34
+ expr = from_ruby<int64>(x.call("to_i"));
35
+ } else if (x.respond_to("vars")) {
36
+ Array vars = x.call("vars");
37
+ for(auto const& var: vars) {
38
+ auto cvar = (Array) var;
39
+ // TODO clean up
40
+ Object o = cvar[0];
41
+ std::string type = ((String) o.call("class").call("name")).str();
42
+ if (type == "ORTools::BoolVar") {
43
+ expr.AddTerm(from_ruby<BoolVar>(cvar[0]), from_ruby<int64>(cvar[1]));
44
+ } else if (type == "Integer") {
45
+ expr.AddConstant(from_ruby<int64>(cvar[0]) * from_ruby<int64>(cvar[1]));
46
+ } else {
47
+ expr.AddTerm(from_ruby<IntVar>(cvar[0]), from_ruby<int64>(cvar[1]));
48
+ }
49
+ }
50
+ } else {
51
+ std::string type = ((String) x.call("class").call("name")).str();
52
+ if (type == "ORTools::BoolVar") {
53
+ expr = from_ruby<BoolVar>(x);
54
+ } else {
55
+ expr = from_ruby<IntVar>(x);
56
+ }
57
+ }
58
+
59
+ return expr;
60
+ }
61
+
62
+ // need a wrapper class since absl::Span doesn't own
63
+ class IntVarSpan {
64
+ std::vector<IntVar> vec;
65
+ public:
66
+ IntVarSpan(Object x) {
67
+ Array a = Array(x);
68
+ vec.reserve(a.size());
69
+ for (std::size_t i = 0; i < a.size(); ++i) {
70
+ vec.push_back(from_ruby<IntVar>(a[i]));
71
+ }
72
+ }
73
+ operator absl::Span<const IntVar>() {
74
+ return absl::Span<const IntVar>(vec);
75
+ }
76
+ };
77
+
78
+ template<>
79
+ inline
80
+ IntVarSpan from_ruby<IntVarSpan>(Object x)
81
+ {
82
+ return IntVarSpan(x);
83
+ }
84
+
85
+ // need a wrapper class since absl::Span doesn't own
86
+ class IntervalVarSpan {
87
+ std::vector<IntervalVar> vec;
88
+ public:
89
+ IntervalVarSpan(Object x) {
90
+ Array a = Array(x);
91
+ vec.reserve(a.size());
92
+ for (std::size_t i = 0; i < a.size(); ++i) {
93
+ vec.push_back(from_ruby<IntervalVar>(a[i]));
94
+ }
95
+ }
96
+ operator absl::Span<const IntervalVar>() {
97
+ return absl::Span<const IntervalVar>(vec);
98
+ }
99
+ };
100
+
101
+ template<>
102
+ inline
103
+ IntervalVarSpan from_ruby<IntervalVarSpan>(Object x)
104
+ {
105
+ return IntervalVarSpan(x);
106
+ }
107
+
108
+ // need a wrapper class since absl::Span doesn't own
109
+ class LinearExprSpan {
110
+ std::vector<LinearExpr> vec;
111
+ public:
112
+ LinearExprSpan(Object x) {
113
+ Array a = Array(x);
114
+ vec.reserve(a.size());
115
+ for (std::size_t i = 0; i < a.size(); ++i) {
116
+ vec.push_back(from_ruby<LinearExpr>(a[i]));
117
+ }
118
+ }
119
+ operator absl::Span<const LinearExpr>() {
120
+ return absl::Span<const LinearExpr>(vec);
121
+ }
122
+ };
123
+
124
+ template<>
125
+ inline
126
+ LinearExprSpan from_ruby<LinearExprSpan>(Object x)
127
+ {
128
+ return LinearExprSpan(x);
129
+ }
130
+
131
+ // need a wrapper class since absl::Span doesn't own
132
+ class BoolVarSpan {
133
+ std::vector<BoolVar> vec;
134
+ public:
135
+ BoolVarSpan(Object x) {
136
+ Array a = Array(x);
137
+ vec.reserve(a.size());
138
+ for (std::size_t i = 0; i < a.size(); ++i) {
139
+ vec.push_back(from_ruby<BoolVar>(a[i]));
140
+ }
141
+ }
142
+ operator absl::Span<const BoolVar>() {
143
+ return absl::Span<const BoolVar>(vec);
144
+ }
145
+ };
146
+
147
+ template<>
148
+ inline
149
+ BoolVarSpan from_ruby<BoolVarSpan>(Object x)
150
+ {
151
+ return BoolVarSpan(x);
152
+ }
153
+
154
+ void init_constraint(Rice::Module& m) {
155
+ Rice::define_class_under<IntVar>(m, "SatIntVar")
156
+ .define_method("name", &IntVar::Name);
157
+
158
+ Rice::define_class_under<IntervalVar>(m, "SatIntervalVar")
159
+ .define_method("name", &IntervalVar::Name);
160
+
161
+ Rice::define_class_under<Constraint>(m, "SatConstraint");
162
+
163
+ Rice::define_class_under<BoolVar>(m, "BoolVar")
164
+ .define_method("name", &BoolVar::Name)
165
+ .define_method("index", &BoolVar::index)
166
+ .define_method("not", &BoolVar::Not)
167
+ .define_method(
168
+ "inspect",
169
+ *[](BoolVar& self) {
170
+ String name(self.Name());
171
+ return "#<ORTools::BoolVar @name=" + name.inspect().str() + ">";
172
+ });
173
+
174
+ Rice::define_class_under<SatParameters>(m, "SatParameters")
175
+ .define_constructor(Rice::Constructor<SatParameters>())
176
+ .define_method("max_time_in_seconds=",
177
+ *[](SatParameters& self, double value) {
178
+ self.set_max_time_in_seconds(value);
179
+ });
180
+
181
+ Rice::define_class_under<CpModelBuilder>(m, "CpModel")
182
+ .define_constructor(Rice::Constructor<CpModelBuilder>())
183
+ .define_method(
184
+ "new_int_var",
185
+ *[](CpModelBuilder& self, int64 start, int64 end, std::string name) {
186
+ const operations_research::Domain domain(start, end);
187
+ return self.NewIntVar(domain).WithName(name);
188
+ })
189
+ .define_method(
190
+ "new_bool_var",
191
+ *[](CpModelBuilder& self, std::string name) {
192
+ return self.NewBoolVar().WithName(name);
193
+ })
194
+ .define_method(
195
+ "new_constant",
196
+ *[](CpModelBuilder& self, int64 value) {
197
+ return self.NewConstant(value);
198
+ })
199
+ .define_method(
200
+ "true_var",
201
+ *[](CpModelBuilder& self) {
202
+ return self.TrueVar();
203
+ })
204
+ .define_method(
205
+ "false_var",
206
+ *[](CpModelBuilder& self) {
207
+ return self.FalseVar();
208
+ })
209
+ .define_method(
210
+ "new_interval_var",
211
+ *[](CpModelBuilder& self, IntVar start, IntVar size, IntVar end, std::string name) {
212
+ return self.NewIntervalVar(start, size, end).WithName(name);
213
+ })
214
+ .define_method(
215
+ "new_optional_interval_var",
216
+ *[](CpModelBuilder& self, IntVar start, IntVar size, IntVar end, BoolVar presence, std::string name) {
217
+ return self.NewOptionalIntervalVar(start, size, end, presence).WithName(name);
218
+ })
219
+ .define_method(
220
+ "add_bool_or",
221
+ *[](CpModelBuilder& self, BoolVarSpan literals) {
222
+ self.AddBoolOr(literals);
223
+ })
224
+ .define_method(
225
+ "add_bool_and",
226
+ *[](CpModelBuilder& self, BoolVarSpan literals) {
227
+ self.AddBoolAnd(literals);
228
+ })
229
+ .define_method(
230
+ "add_bool_xor",
231
+ *[](CpModelBuilder& self, BoolVarSpan literals) {
232
+ self.AddBoolXor(literals);
233
+ })
234
+ .define_method(
235
+ "add_implication",
236
+ *[](CpModelBuilder& self, BoolVar a, BoolVar b) {
237
+ self.AddImplication(a, b);
238
+ })
239
+ .define_method(
240
+ "add_equality",
241
+ *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
242
+ self.AddEquality(x, y);
243
+ })
244
+ .define_method(
245
+ "add_greater_or_equal",
246
+ *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
247
+ self.AddGreaterOrEqual(x, y);
248
+ })
249
+ .define_method(
250
+ "add_greater_than",
251
+ *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
252
+ self.AddGreaterThan(x, y);
253
+ })
254
+ .define_method(
255
+ "add_less_or_equal",
256
+ *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
257
+ self.AddLessOrEqual(x, y);
258
+ })
259
+ .define_method(
260
+ "add_less_than",
261
+ *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
262
+ self.AddLessThan(x, y);
263
+ })
264
+ // TODO add domain
265
+ // .define_method(
266
+ // "add_linear_constraint",
267
+ // *[](CpModelBuilder& self, LinearExpr expr, Domain domain) {
268
+ // self.AddLinearConstraint(expr, domain);
269
+ // })
270
+ .define_method(
271
+ "add_not_equal",
272
+ *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
273
+ self.AddNotEqual(x, y);
274
+ })
275
+ .define_method(
276
+ "add_all_different",
277
+ *[](CpModelBuilder& self, IntVarSpan vars) {
278
+ self.AddAllDifferent(vars);
279
+ })
280
+ .define_method(
281
+ "add_inverse_constraint",
282
+ *[](CpModelBuilder& self, IntVarSpan variables, IntVarSpan inverse_variables) {
283
+ self.AddInverseConstraint(variables, inverse_variables);
284
+ })
285
+ .define_method(
286
+ "add_min_equality",
287
+ *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
288
+ self.AddMinEquality(target, vars);
289
+ })
290
+ .define_method(
291
+ "add_lin_min_equality",
292
+ *[](CpModelBuilder& self, LinearExpr target, LinearExprSpan exprs) {
293
+ self.AddLinMinEquality(target, exprs);
294
+ })
295
+ .define_method(
296
+ "add_max_equality",
297
+ *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
298
+ self.AddMaxEquality(target, vars);
299
+ })
300
+ .define_method(
301
+ "add_lin_max_equality",
302
+ *[](CpModelBuilder& self, LinearExpr target, LinearExprSpan exprs) {
303
+ self.AddLinMaxEquality(target, exprs);
304
+ })
305
+ .define_method(
306
+ "add_division_equality",
307
+ *[](CpModelBuilder& self, IntVar target, IntVar numerator, IntVar denominator) {
308
+ self.AddDivisionEquality(target, numerator, denominator);
309
+ })
310
+ .define_method(
311
+ "add_abs_equality",
312
+ *[](CpModelBuilder& self, IntVar target, IntVar var) {
313
+ self.AddAbsEquality(target, var);
314
+ })
315
+ .define_method(
316
+ "add_modulo_equality",
317
+ *[](CpModelBuilder& self, IntVar target, IntVar var, IntVar mod) {
318
+ self.AddModuloEquality(target, var, mod);
319
+ })
320
+ .define_method(
321
+ "add_product_equality",
322
+ *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
323
+ self.AddProductEquality(target, vars);
324
+ })
325
+ .define_method(
326
+ "add_no_overlap",
327
+ *[](CpModelBuilder& self, IntervalVarSpan vars) {
328
+ self.AddNoOverlap(vars);
329
+ })
330
+ .define_method(
331
+ "maximize",
332
+ *[](CpModelBuilder& self, LinearExpr expr) {
333
+ self.Maximize(expr);
334
+ })
335
+ .define_method(
336
+ "minimize",
337
+ *[](CpModelBuilder& self, LinearExpr expr) {
338
+ self.Minimize(expr);
339
+ })
340
+ .define_method(
341
+ "scale_objective_by",
342
+ *[](CpModelBuilder& self, double scaling) {
343
+ self.ScaleObjectiveBy(scaling);
344
+ })
345
+ .define_method(
346
+ "to_s",
347
+ *[](CpModelBuilder& self) {
348
+ std::string proto_string;
349
+ google::protobuf::TextFormat::PrintToString(self.Proto(), &proto_string);
350
+ return proto_string;
351
+ });
352
+
353
+ Rice::define_class_under(m, "CpSolver")
354
+ .define_method(
355
+ "_solve_with_observer",
356
+ *[](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback, bool all_solutions) {
357
+ Model m;
358
+
359
+ if (all_solutions) {
360
+ // set parameters for SearchForAllSolutions
361
+ parameters.set_enumerate_all_solutions(true);
362
+ }
363
+ m.Add(NewSatParameters(parameters));
364
+
365
+ m.Add(NewFeasibleSolutionObserver(
366
+ [callback](const CpSolverResponse& r) {
367
+ // TODO find a better way to do this
368
+ callback.call("response=", r);
369
+ callback.call("on_solution_callback");
370
+ })
371
+ );
372
+ return SolveCpModel(model.Build(), &m);
373
+ })
374
+ .define_method(
375
+ "_solve",
376
+ *[](Object self, CpModelBuilder& model, SatParameters& parameters) {
377
+ Model m;
378
+ m.Add(NewSatParameters(parameters));
379
+ return SolveCpModel(model.Build(), &m);
380
+ })
381
+ .define_method(
382
+ "_solution_integer_value",
383
+ *[](Object self, CpSolverResponse& response, IntVar& x) {
384
+ return SolutionIntegerValue(response, x);
385
+ })
386
+ .define_method(
387
+ "_solution_boolean_value",
388
+ *[](Object self, CpSolverResponse& response, BoolVar& x) {
389
+ return SolutionBooleanValue(response, x);
390
+ });
391
+
392
+ Rice::define_class_under<CpSolverResponse>(m, "CpSolverResponse")
393
+ .define_method("objective_value", &CpSolverResponse::objective_value)
394
+ .define_method("num_conflicts", &CpSolverResponse::num_conflicts)
395
+ .define_method("num_branches", &CpSolverResponse::num_branches)
396
+ .define_method("wall_time", &CpSolverResponse::wall_time)
397
+ .define_method(
398
+ "solution_integer_value",
399
+ *[](CpSolverResponse& self, IntVar& x) {
400
+ LinearExpr expr(x);
401
+ return SolutionIntegerValue(self, expr);
402
+ })
403
+ .define_method("solution_boolean_value", &SolutionBooleanValue)
404
+ .define_method(
405
+ "status",
406
+ *[](CpSolverResponse& self) {
407
+ auto status = self.status();
408
+
409
+ if (status == CpSolverStatus::OPTIMAL) {
410
+ return Symbol("optimal");
411
+ } else if (status == CpSolverStatus::FEASIBLE) {
412
+ return Symbol("feasible");
413
+ } else if (status == CpSolverStatus::INFEASIBLE) {
414
+ return Symbol("infeasible");
415
+ } else if (status == CpSolverStatus::MODEL_INVALID) {
416
+ return Symbol("model_invalid");
417
+ } else if (status == CpSolverStatus::UNKNOWN) {
418
+ return Symbol("unknown");
419
+ } else {
420
+ throw std::runtime_error("Unknown solver status");
421
+ }
422
+ });
423
+ }