or-tools 0.3.1 → 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: 116cfa149eef398630f24b3776c9db8e0a1dddb2b17c8e4b04f347f064231c72
4
- data.tar.gz: 9930c7e37bc26fd88a6c59eac718eb057d82990bc3ccb3bee3f395456baa9318
3
+ metadata.gz: 7ce5b035a9a0f52391ef97cd12d32ec7632101940fde4e2f19de4887900a4dc1
4
+ data.tar.gz: c63b37906fb5337cd805c627266422ccfc698d3759456327e2414f5e31e4ab52
5
5
  SHA512:
6
- metadata.gz: eab3682edbfa9d3a90eb54ffe1697abd9f9e4dcb75ae6e08b08dfea1dcaedce4d773d3d53490d4c9de258d4d0e3b92e38bcb1cb4c5f4f50225e829c566b2c74b
7
- data.tar.gz: '0514577229f62526c914a52b7164a2dc49b17515cbe798cd177f3a9dadc1da4a9026c45cec77830b08ac2bce44831f072ee18c6e3bdb9db66d958b6ed407d7b2'
6
+ metadata.gz: 5eda4c29a50790d7c569e67b9538ac2c13a6cd20af1580cd679a68d386244b5cd1bbafa311c52fe9cad519652bbfb6666aed09e6a5ae1f7c71cc666491644d4f
7
+ data.tar.gz: 5241d2788f6883ca0349967e4f953382cd03564fe4856e853888518427a2ed5ec8a8cf948aac34a02b39f413c787eeb98ff22284f59359f7cf9a9aa73b449188
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
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
+
7
+ ## 0.4.0 (2021-01-14)
8
+
9
+ - Updated OR-Tools to 8.1
10
+
11
+ ## 0.3.4 (2021-01-14)
12
+
13
+ - Added support for time limit for `CpSolver`
14
+ - Added `add_dimension_with_vehicle_transits` and `status` methods to `RoutingModel`
15
+
16
+ ## 0.3.3 (2020-10-12)
17
+
18
+ - Added support for start and end points for routing
19
+
20
+ ## 0.3.2 (2020-08-04)
21
+
22
+ - Updated OR-Tools to 7.8
23
+ - Added binary installation for Ubuntu 20.04
24
+
1
25
  ## 0.3.1 (2020-07-21)
2
26
 
3
27
  - Reduced gem size
data/NOTICE.txt CHANGED
@@ -1,4 +1,5 @@
1
- Copyright 2020 Andrew Kane
1
+ Copyright 2010-2018 Google LLC
2
+ Copyright 2020-2021 Andrew Kane
2
3
 
3
4
  Licensed under the Apache License, Version 2.0 (the "License");
4
5
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [OR-Tools](https://github.com/google/or-tools) - operations research tools - for Ruby
4
4
 
5
- [![Build Status](https://travis-ci.org/ankane/or-tools.svg?branch=master)](https://travis-ci.org/ankane/or-tools)
5
+ [![Build Status](https://github.com/ankane/or-tools/workflows/build/badge.svg?branch=master)](https://github.com/ankane/or-tools/actions)
6
6
 
7
7
  ## Installation
8
8
 
@@ -267,6 +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)
270
271
 
271
272
  Assignment
272
273
 
@@ -578,6 +579,39 @@ puts
578
579
  puts "Solutions found : %i" % solution_printer.solution_count
579
580
  ```
580
581
 
582
+ ### Setting Solver Limits
583
+
584
+ [Guide](https://developers.google.com/optimization/cp/cp_tasks)
585
+
586
+ ```ruby
587
+ # create the model
588
+ model = ORTools::CpModel.new
589
+
590
+ # create the variables
591
+ num_vals = 3
592
+ x = model.new_int_var(0, num_vals - 1, "x")
593
+ y = model.new_int_var(0, num_vals - 1, "y")
594
+ z = model.new_int_var(0, num_vals - 1, "z")
595
+
596
+ # add an all-different constraint
597
+ model.add(x != y)
598
+
599
+ # create the solver
600
+ solver = ORTools::CpSolver.new
601
+
602
+ # set a time limit of 10 seconds.
603
+ solver.parameters.max_time_in_seconds = 10
604
+
605
+ # solve the model
606
+ status = solver.solve(model)
607
+
608
+ # display the first solution
609
+ if status == :optimal
610
+ puts "x = #{solver.value(x)}"
611
+ puts "y = #{solver.value(y)}"
612
+ puts "z = #{solver.value(z)}"
613
+ end
614
+ ```
581
615
 
582
616
  ### Assignment
583
617
 
@@ -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
+ }