or-tools 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }