or-tools 0.17.1 → 0.18.0
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +14 -10
- data/ext/or-tools/assignment.cpp +1 -1
- data/ext/or-tools/bin_packing.cpp +3 -3
- data/ext/or-tools/channel.hpp +37 -0
- data/ext/or-tools/constraint.cpp +120 -61
- data/ext/or-tools/ext.cpp +1 -1
- data/ext/or-tools/linear.cpp +8 -8
- data/ext/or-tools/math_opt.cpp +8 -8
- data/ext/or-tools/network_flows.cpp +2 -2
- data/ext/or-tools/routing.cpp +44 -24
- data/ext/or-tools/vendor.rb +22 -53
- data/lib/or_tools/cp_solver.rb +1 -16
- data/lib/or_tools/cp_solver_solution_callback.rb +4 -0
- data/lib/or_tools/routing_model.rb +18 -0
- data/lib/or_tools/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c2d774f3459e19c0fc640d1c60c05cb896edec872fafb765b1162e08c79e921b
|
|
4
|
+
data.tar.gz: 40199c012d102d861fe405d7e93e51bf5232bcb402fa563ee63de6fe00db5ec8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac775e43751213a80c29ac82f38487e287891243d96b26e622474c034c44683135e412b5caa86e47232c36b32f1bfafec4b7152cab9fc652c1384a399e002072
|
|
7
|
+
data.tar.gz: f3a47294fd32b8464e33e566b277936c9ed687b79dfd3fece814cd9d5247252395131ddaf79b05cc2db8c8a76ad1e19610e9a151d8aaa5ea72d5d8cbd76135bb
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.18.0 (2026-07-06)
|
|
2
|
+
|
|
3
|
+
- Added support for releasing GVL
|
|
4
|
+
- Added `stop_search` method to `CpSolverSolutionCallback`
|
|
5
|
+
- Fixed error with `apply_locks` and `set_allowed_vehicles_for_index` methods
|
|
6
|
+
- Removed `solve_with_solution_callback` and `search_for_all_solutions` methods
|
|
7
|
+
- Dropped support for Ruby < 3.3
|
|
8
|
+
|
|
1
9
|
## 0.17.1 (2026-02-19)
|
|
2
10
|
|
|
3
11
|
- Fixed error with Rice 4.11
|
data/README.md
CHANGED
|
@@ -93,15 +93,15 @@ Specify people and their availabililty
|
|
|
93
93
|
people = [
|
|
94
94
|
{
|
|
95
95
|
availability: [
|
|
96
|
-
{starts_at: Time.parse("
|
|
97
|
-
{starts_at: Time.parse("
|
|
96
|
+
{starts_at: Time.parse("2026-01-01 08:00:00"), ends_at: Time.parse("2026-01-01 16:00:00")},
|
|
97
|
+
{starts_at: Time.parse("2026-01-02 08:00:00"), ends_at: Time.parse("2026-01-02 16:00:00")}
|
|
98
98
|
],
|
|
99
99
|
max_hours: 40 # optional, applies to entire scheduling period
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
availability: [
|
|
103
|
-
{starts_at: Time.parse("
|
|
104
|
-
{starts_at: Time.parse("
|
|
103
|
+
{starts_at: Time.parse("2026-01-01 08:00:00"), ends_at: Time.parse("2026-01-01 16:00:00")},
|
|
104
|
+
{starts_at: Time.parse("2026-01-03 08:00:00"), ends_at: Time.parse("2026-01-03 16:00:00")}
|
|
105
105
|
],
|
|
106
106
|
max_hours: 20
|
|
107
107
|
}
|
|
@@ -112,9 +112,9 @@ Specify shifts
|
|
|
112
112
|
|
|
113
113
|
```ruby
|
|
114
114
|
shifts = [
|
|
115
|
-
{starts_at: Time.parse("
|
|
116
|
-
{starts_at: Time.parse("
|
|
117
|
-
{starts_at: Time.parse("
|
|
115
|
+
{starts_at: Time.parse("2026-01-01 08:00:00"), ends_at: Time.parse("2026-01-01 16:00:00")},
|
|
116
|
+
{starts_at: Time.parse("2026-01-02 08:00:00"), ends_at: Time.parse("2026-01-02 16:00:00")},
|
|
117
|
+
{starts_at: Time.parse("2026-01-03 08:00:00"), ends_at: Time.parse("2026-01-03 16:00:00")}
|
|
118
118
|
]
|
|
119
119
|
```
|
|
120
120
|
|
|
@@ -537,7 +537,8 @@ end
|
|
|
537
537
|
# invoke the solver
|
|
538
538
|
solver = ORTools::CpSolver.new
|
|
539
539
|
solution_printer = VarArraySolutionPrinter.new(letters)
|
|
540
|
-
|
|
540
|
+
solver.parameters.enumerate_all_solutions = true
|
|
541
|
+
status = solver.solve(model, solution_printer)
|
|
541
542
|
|
|
542
543
|
puts
|
|
543
544
|
puts "Statistics"
|
|
@@ -598,7 +599,8 @@ end
|
|
|
598
599
|
# call the solver and display the results
|
|
599
600
|
solver = ORTools::CpSolver.new
|
|
600
601
|
solution_printer = SolutionPrinter.new(queens)
|
|
601
|
-
|
|
602
|
+
solver.parameters.enumerate_all_solutions = true
|
|
603
|
+
status = solver.solve(model, solution_printer)
|
|
602
604
|
puts
|
|
603
605
|
puts "Solutions found : %i" % solution_printer.solution_count
|
|
604
606
|
```
|
|
@@ -1887,11 +1889,13 @@ end
|
|
|
1887
1889
|
|
|
1888
1890
|
# call the solver and display the results
|
|
1889
1891
|
solver = ORTools::CpSolver.new
|
|
1892
|
+
solver.parameters.linearization_level = 0
|
|
1893
|
+
solver.parameters.enumerate_all_solutions = true
|
|
1890
1894
|
a_few_solutions = 5.times.to_a
|
|
1891
1895
|
solution_printer = NursesPartialSolutionPrinter.new(
|
|
1892
1896
|
shifts, num_nurses, num_days, num_shifts, a_few_solutions
|
|
1893
1897
|
)
|
|
1894
|
-
solver.
|
|
1898
|
+
solver.solve(model, solution_printer)
|
|
1895
1899
|
|
|
1896
1900
|
puts
|
|
1897
1901
|
puts "Statistics"
|
data/ext/or-tools/assignment.cpp
CHANGED
|
@@ -30,7 +30,7 @@ void init_assignment(Rice::Module& m) {
|
|
|
30
30
|
} else if (status == SimpleLinearSumAssignment::Status::POSSIBLE_OVERFLOW) {
|
|
31
31
|
return Symbol("possible_overflow");
|
|
32
32
|
} else {
|
|
33
|
-
throw std::runtime_error
|
|
33
|
+
throw std::runtime_error{"Unknown status"};
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
}
|
|
@@ -27,11 +27,11 @@ namespace Rice::detail {
|
|
|
27
27
|
double is_convertible(VALUE value) { return Convertible::Exact; }
|
|
28
28
|
|
|
29
29
|
KnapsackSolver::SolverType convert(VALUE x) {
|
|
30
|
-
|
|
30
|
+
std::string s = Symbol(x).str();
|
|
31
31
|
if (s == "branch_and_bound") {
|
|
32
32
|
return KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER;
|
|
33
33
|
} else {
|
|
34
|
-
throw std::runtime_error
|
|
34
|
+
throw std::runtime_error{"Unknown solver type: " + s};
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -47,7 +47,7 @@ void init_bin_packing(Rice::Module& m) {
|
|
|
47
47
|
.define_method("best_solution_contains?", &KnapsackSolver::BestSolutionContains)
|
|
48
48
|
.define_method(
|
|
49
49
|
"init",
|
|
50
|
-
[](KnapsackSolver& self, std::vector<int64_t
|
|
50
|
+
[](KnapsackSolver& self, const std::vector<int64_t>& values, const std::vector<std::vector<int64_t>>& weights, const std::vector<int64_t>& capacities) {
|
|
51
51
|
self.Init(values, weights, capacities);
|
|
52
52
|
});
|
|
53
53
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <chrono>
|
|
4
|
+
#include <condition_variable>
|
|
5
|
+
#include <mutex>
|
|
6
|
+
#include <optional>
|
|
7
|
+
#include <queue>
|
|
8
|
+
|
|
9
|
+
template<typename T>
|
|
10
|
+
class Channel {
|
|
11
|
+
std::queue<T> queue;
|
|
12
|
+
std::mutex mutex;
|
|
13
|
+
std::condition_variable cv;
|
|
14
|
+
|
|
15
|
+
public:
|
|
16
|
+
void send(T message) {
|
|
17
|
+
std::lock_guard<std::mutex> guard(mutex);
|
|
18
|
+
queue.push(std::move(message));
|
|
19
|
+
cv.notify_one();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
template<typename U, typename V>
|
|
23
|
+
std::optional<T> recv_timeout(const std::chrono::duration<U, V>& duration) {
|
|
24
|
+
std::unique_lock<std::mutex> lock(mutex);
|
|
25
|
+
if (!cv.wait_for(lock, duration, [&] { return !queue.empty(); })) {
|
|
26
|
+
return std::nullopt;
|
|
27
|
+
}
|
|
28
|
+
T message = std::move(queue.front());
|
|
29
|
+
queue.pop();
|
|
30
|
+
return message;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
bool empty() {
|
|
34
|
+
std::lock_guard<std::mutex> guard(mutex);
|
|
35
|
+
return queue.empty();
|
|
36
|
+
}
|
|
37
|
+
};
|
data/ext/or-tools/constraint.cpp
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
#include <atomic>
|
|
2
|
+
#include <chrono>
|
|
3
|
+
#include <optional>
|
|
1
4
|
#include <string>
|
|
2
5
|
#include <vector>
|
|
3
6
|
|
|
@@ -6,21 +9,23 @@
|
|
|
6
9
|
#include <rice/rice.hpp>
|
|
7
10
|
#include <rice/stl.hpp>
|
|
8
11
|
|
|
12
|
+
#include "channel.hpp"
|
|
13
|
+
|
|
9
14
|
using operations_research::Domain;
|
|
10
15
|
using operations_research::sat::BoolVar;
|
|
11
16
|
using operations_research::sat::Constraint;
|
|
12
|
-
using operations_research::sat::TableConstraint;
|
|
13
17
|
using operations_research::sat::CpModelBuilder;
|
|
14
18
|
using operations_research::sat::CpSolverResponse;
|
|
15
19
|
using operations_research::sat::CpSolverStatus;
|
|
16
|
-
using operations_research::sat::LinearExpr;
|
|
17
|
-
using operations_research::sat::IntVar;
|
|
18
20
|
using operations_research::sat::IntervalVar;
|
|
21
|
+
using operations_research::sat::IntVar;
|
|
22
|
+
using operations_research::sat::LinearExpr;
|
|
19
23
|
using operations_research::sat::Model;
|
|
20
24
|
using operations_research::sat::NewFeasibleSolutionObserver;
|
|
21
25
|
using operations_research::sat::SatParameters;
|
|
22
26
|
using operations_research::sat::SolutionBooleanValue;
|
|
23
27
|
using operations_research::sat::SolutionIntegerValue;
|
|
28
|
+
using operations_research::sat::TableConstraint;
|
|
24
29
|
|
|
25
30
|
using Rice::Array;
|
|
26
31
|
using Rice::Class;
|
|
@@ -131,37 +136,18 @@ void init_constraint(Rice::Module& m) {
|
|
|
131
136
|
|
|
132
137
|
Rice::define_class_under<SatParameters>(m, "SatParameters")
|
|
133
138
|
.define_constructor(Rice::Constructor<SatParameters>())
|
|
134
|
-
.define_method(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
.define_method(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
.define_method(
|
|
145
|
-
|
|
146
|
-
[](SatParameters& self) {
|
|
147
|
-
return self.enumerate_all_solutions();
|
|
148
|
-
})
|
|
149
|
-
.define_method("num_workers=",
|
|
150
|
-
[](SatParameters& self, int32_t value){
|
|
151
|
-
self.set_num_workers(value);
|
|
152
|
-
})
|
|
153
|
-
.define_method("cp_model_presolve=",
|
|
154
|
-
[](SatParameters& self, bool value) {
|
|
155
|
-
self.set_cp_model_presolve(value);
|
|
156
|
-
})
|
|
157
|
-
.define_method("random_seed",
|
|
158
|
-
[](SatParameters& self) {
|
|
159
|
-
return self.random_seed();
|
|
160
|
-
})
|
|
161
|
-
.define_method("random_seed=",
|
|
162
|
-
[](SatParameters& self, int32_t value) {
|
|
163
|
-
self.set_random_seed(value);
|
|
164
|
-
});
|
|
139
|
+
.define_method("cp_model_presolve", &SatParameters::cp_model_presolve)
|
|
140
|
+
.define_method("cp_model_presolve=", &SatParameters::set_cp_model_presolve)
|
|
141
|
+
.define_method("enumerate_all_solutions", &SatParameters::enumerate_all_solutions)
|
|
142
|
+
.define_method("enumerate_all_solutions=", &SatParameters::set_enumerate_all_solutions)
|
|
143
|
+
.define_method("linearization_level", &SatParameters::linearization_level)
|
|
144
|
+
.define_method("linearization_level=", &SatParameters::set_linearization_level)
|
|
145
|
+
.define_method("max_time_in_seconds", &SatParameters::max_time_in_seconds)
|
|
146
|
+
.define_method("max_time_in_seconds=", &SatParameters::set_max_time_in_seconds)
|
|
147
|
+
.define_method("num_workers", &SatParameters::num_workers)
|
|
148
|
+
.define_method("num_workers=", &SatParameters::set_num_workers)
|
|
149
|
+
.define_method("random_seed", &SatParameters::random_seed)
|
|
150
|
+
.define_method("random_seed=", &SatParameters::set_random_seed);
|
|
165
151
|
|
|
166
152
|
Rice::define_class_under<CpModelBuilder>(m, "CpModel")
|
|
167
153
|
.define_constructor(Rice::Constructor<CpModelBuilder>())
|
|
@@ -193,32 +179,32 @@ void init_constraint(Rice::Module& m) {
|
|
|
193
179
|
})
|
|
194
180
|
.define_method(
|
|
195
181
|
"new_interval_var",
|
|
196
|
-
[](CpModelBuilder& self, IntVar start, IntVar size, IntVar end, const std::string& name) {
|
|
182
|
+
[](CpModelBuilder& self, const IntVar& start, const IntVar& size, const IntVar& end, const std::string& name) {
|
|
197
183
|
return self.NewIntervalVar(start, size, end).WithName(name);
|
|
198
184
|
})
|
|
199
185
|
.define_method(
|
|
200
186
|
"new_optional_interval_var",
|
|
201
|
-
[](CpModelBuilder& self, IntVar start, IntVar size, IntVar end, BoolVar presence, const std::string& name) {
|
|
187
|
+
[](CpModelBuilder& self, const IntVar& start, const IntVar& size, const IntVar& end, const BoolVar& presence, const std::string& name) {
|
|
202
188
|
return self.NewOptionalIntervalVar(start, size, end, presence).WithName(name);
|
|
203
189
|
})
|
|
204
190
|
.define_method(
|
|
205
191
|
"add_bool_or",
|
|
206
|
-
[](CpModelBuilder& self, std::vector<BoolVar
|
|
192
|
+
[](CpModelBuilder& self, const std::vector<BoolVar>& literals) {
|
|
207
193
|
return self.AddBoolOr(literals);
|
|
208
194
|
})
|
|
209
195
|
.define_method(
|
|
210
196
|
"add_bool_and",
|
|
211
|
-
[](CpModelBuilder& self, std::vector<BoolVar
|
|
197
|
+
[](CpModelBuilder& self, const std::vector<BoolVar>& literals) {
|
|
212
198
|
return self.AddBoolAnd(literals);
|
|
213
199
|
})
|
|
214
200
|
.define_method(
|
|
215
201
|
"add_bool_xor",
|
|
216
|
-
[](CpModelBuilder& self, std::vector<BoolVar
|
|
202
|
+
[](CpModelBuilder& self, const std::vector<BoolVar>& literals) {
|
|
217
203
|
return self.AddBoolXor(literals);
|
|
218
204
|
})
|
|
219
205
|
.define_method(
|
|
220
206
|
"add_implication",
|
|
221
|
-
[](CpModelBuilder& self, BoolVar a, BoolVar b) {
|
|
207
|
+
[](CpModelBuilder& self, const BoolVar& a, const BoolVar& b) {
|
|
222
208
|
return self.AddImplication(a, b);
|
|
223
209
|
})
|
|
224
210
|
.define_method(
|
|
@@ -253,7 +239,7 @@ void init_constraint(Rice::Module& m) {
|
|
|
253
239
|
})
|
|
254
240
|
.define_method(
|
|
255
241
|
"add_linear_expression_in_domain",
|
|
256
|
-
[](CpModelBuilder& self, LinearExpr expr, Domain domain) {
|
|
242
|
+
[](CpModelBuilder& self, LinearExpr expr, const Domain& domain) {
|
|
257
243
|
return self.AddLinearConstraint(expr, domain);
|
|
258
244
|
})
|
|
259
245
|
.define_method(
|
|
@@ -263,7 +249,7 @@ void init_constraint(Rice::Module& m) {
|
|
|
263
249
|
})
|
|
264
250
|
.define_method(
|
|
265
251
|
"add_all_different",
|
|
266
|
-
[](CpModelBuilder& self, std::vector<IntVar
|
|
252
|
+
[](CpModelBuilder& self, const std::vector<IntVar>& vars) {
|
|
267
253
|
return self.AddAllDifferent(vars);
|
|
268
254
|
})
|
|
269
255
|
.define_method(
|
|
@@ -278,7 +264,7 @@ void init_constraint(Rice::Module& m) {
|
|
|
278
264
|
})
|
|
279
265
|
.define_method(
|
|
280
266
|
"add_inverse_constraint",
|
|
281
|
-
[](CpModelBuilder& self, std::vector<IntVar
|
|
267
|
+
[](CpModelBuilder& self, const std::vector<IntVar>& variables, const std::vector<IntVar>& inverse_variables) {
|
|
282
268
|
return self.AddInverseConstraint(variables, inverse_variables);
|
|
283
269
|
})
|
|
284
270
|
.define_method(
|
|
@@ -313,7 +299,7 @@ void init_constraint(Rice::Module& m) {
|
|
|
313
299
|
})
|
|
314
300
|
.define_method(
|
|
315
301
|
"add_no_overlap",
|
|
316
|
-
[](CpModelBuilder& self, std::vector<IntervalVar
|
|
302
|
+
[](CpModelBuilder& self, const std::vector<IntervalVar>& vars) {
|
|
317
303
|
return self.AddNoOverlap(vars);
|
|
318
304
|
})
|
|
319
305
|
.define_method(
|
|
@@ -348,12 +334,12 @@ void init_constraint(Rice::Module& m) {
|
|
|
348
334
|
})
|
|
349
335
|
.define_method(
|
|
350
336
|
"add_assumption",
|
|
351
|
-
[](CpModelBuilder& self, BoolVar lit) {
|
|
337
|
+
[](CpModelBuilder& self, const BoolVar& lit) {
|
|
352
338
|
self.AddAssumption(lit);
|
|
353
339
|
})
|
|
354
340
|
.define_method(
|
|
355
341
|
"add_assumptions",
|
|
356
|
-
[](CpModelBuilder& self, std::vector<BoolVar
|
|
342
|
+
[](CpModelBuilder& self, const std::vector<BoolVar>& literals) {
|
|
357
343
|
self.AddAssumptions(literals);
|
|
358
344
|
})
|
|
359
345
|
.define_method(
|
|
@@ -370,7 +356,9 @@ void init_constraint(Rice::Module& m) {
|
|
|
370
356
|
"to_s",
|
|
371
357
|
[](CpModelBuilder& self) {
|
|
372
358
|
std::string proto_string;
|
|
373
|
-
google::protobuf::TextFormat::PrintToString(self.Proto(), &proto_string)
|
|
359
|
+
if (!google::protobuf::TextFormat::PrintToString(self.Proto(), &proto_string)) {
|
|
360
|
+
throw Rice::Exception(rb_eRuntimeError, "PrintToString failed");
|
|
361
|
+
}
|
|
374
362
|
return proto_string;
|
|
375
363
|
});
|
|
376
364
|
|
|
@@ -402,7 +390,7 @@ void init_constraint(Rice::Module& m) {
|
|
|
402
390
|
} else if (status == CpSolverStatus::UNKNOWN) {
|
|
403
391
|
return Symbol("unknown");
|
|
404
392
|
} else {
|
|
405
|
-
throw std::runtime_error
|
|
393
|
+
throw std::runtime_error{"Unknown solver status"};
|
|
406
394
|
}
|
|
407
395
|
})
|
|
408
396
|
.define_method(
|
|
@@ -426,34 +414,105 @@ void init_constraint(Rice::Module& m) {
|
|
|
426
414
|
"_solve",
|
|
427
415
|
[](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback) {
|
|
428
416
|
Model m;
|
|
417
|
+
m.Add(NewSatParameters(parameters));
|
|
429
418
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
419
|
+
std::atomic<bool> done{false};
|
|
420
|
+
Channel<CpSolverResponse> channel;
|
|
421
|
+
Rice::Object ruby_thread;
|
|
422
|
+
std::optional<Rice::Exception> exception;
|
|
433
423
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
424
|
+
auto with_gvl = [](std::function<void()> f) {
|
|
425
|
+
auto ruby_wrapper = [](void* arg) -> void* {
|
|
426
|
+
(*static_cast<decltype(f)*>(arg))();
|
|
427
|
+
return nullptr;
|
|
428
|
+
};
|
|
429
|
+
rb_thread_call_with_gvl(ruby_wrapper, &f);
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
auto ruby_observer = [&]() {
|
|
433
|
+
return Rice::detail::no_gvl([&]() {
|
|
434
|
+
while (true) {
|
|
435
|
+
if (done.load() && channel.empty()) {
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
while (true) {
|
|
440
|
+
std::optional<CpSolverResponse> response = channel.recv_timeout(std::chrono::milliseconds(10));
|
|
441
|
+
if (!response) {
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
bool stop = false;
|
|
446
|
+
with_gvl([&]() {
|
|
447
|
+
try {
|
|
448
|
+
try {
|
|
449
|
+
callback.call("response=", response.value());
|
|
450
|
+
callback.call("on_solution_callback");
|
|
451
|
+
stop = static_cast<bool>(callback.attr_get("@stopped"));
|
|
452
|
+
} catch (const Rice::Exception& e) {
|
|
453
|
+
exception = e;
|
|
454
|
+
stop = true;
|
|
455
|
+
}
|
|
456
|
+
callback.call("response=", Object(Qnil));
|
|
457
|
+
} catch (const Rice::Exception& e) {
|
|
458
|
+
exception = e;
|
|
459
|
+
stop = true;
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
if (stop) {
|
|
464
|
+
StopSearch(&m);
|
|
465
|
+
return Qnil;
|
|
466
|
+
}
|
|
438
467
|
}
|
|
439
468
|
|
|
440
|
-
|
|
441
|
-
|
|
469
|
+
with_gvl([]() {
|
|
470
|
+
Rice::detail::protect(rb_thread_schedule);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
return Qnil;
|
|
474
|
+
});
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
auto ruby_wrapper = [](void* arg) {
|
|
478
|
+
return (*static_cast<decltype(ruby_observer)*>(arg))();
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
if (!callback.is_nil()) {
|
|
482
|
+
ruby_thread = Rice::detail::protect([&]() {
|
|
483
|
+
return rb_thread_create(ruby_wrapper, &ruby_observer);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
m.Add(NewFeasibleSolutionObserver(
|
|
487
|
+
[&](const CpSolverResponse& response) {
|
|
488
|
+
channel.send(response);
|
|
442
489
|
})
|
|
443
490
|
);
|
|
444
491
|
}
|
|
445
492
|
|
|
446
|
-
|
|
447
|
-
|
|
493
|
+
CpSolverResponse response = Rice::detail::no_gvl([&]() {
|
|
494
|
+
return SolveCpModel(model.Build(), &m);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
if (!callback.is_nil()) {
|
|
498
|
+
done = true;
|
|
499
|
+
ruby_thread.call("value");
|
|
500
|
+
|
|
501
|
+
if (exception.has_value()) {
|
|
502
|
+
throw exception.value();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return response;
|
|
448
507
|
})
|
|
449
508
|
.define_method(
|
|
450
509
|
"_solution_integer_value",
|
|
451
|
-
[](Object self, const CpSolverResponse& response, IntVar x) {
|
|
510
|
+
[](Object self, const CpSolverResponse& response, const IntVar& x) {
|
|
452
511
|
return SolutionIntegerValue(response, x);
|
|
453
512
|
})
|
|
454
513
|
.define_method(
|
|
455
514
|
"_solution_boolean_value",
|
|
456
|
-
[](Object self, const CpSolverResponse& response, BoolVar x) {
|
|
515
|
+
[](Object self, const CpSolverResponse& response, const BoolVar& x) {
|
|
457
516
|
return SolutionBooleanValue(response, x);
|
|
458
517
|
});
|
|
459
518
|
}
|
data/ext/or-tools/ext.cpp
CHANGED
|
@@ -16,7 +16,7 @@ void init_routing(Rice::Module& m);
|
|
|
16
16
|
|
|
17
17
|
extern "C"
|
|
18
18
|
void Init_ext() {
|
|
19
|
-
|
|
19
|
+
Rice::Module m = Rice::define_module("ORTools");
|
|
20
20
|
|
|
21
21
|
m.define_singleton_function("lib_version", &operations_research::OrToolsVersionString);
|
|
22
22
|
|
data/ext/or-tools/linear.cpp
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
using operations_research::MPConstraint;
|
|
10
10
|
using operations_research::MPObjective;
|
|
11
|
-
using operations_research::MPSolverParameters;
|
|
12
11
|
using operations_research::MPSolver;
|
|
12
|
+
using operations_research::MPSolverParameters;
|
|
13
13
|
using operations_research::MPVariable;
|
|
14
14
|
|
|
15
15
|
using Rice::Array;
|
|
@@ -34,13 +34,13 @@ namespace Rice::detail {
|
|
|
34
34
|
double is_convertible(VALUE value) { return Convertible::Exact; }
|
|
35
35
|
|
|
36
36
|
static MPSolver::OptimizationProblemType convert(VALUE x) {
|
|
37
|
-
|
|
37
|
+
std::string s = Symbol(x).str();
|
|
38
38
|
if (s == "glop") {
|
|
39
39
|
return MPSolver::OptimizationProblemType::GLOP_LINEAR_PROGRAMMING;
|
|
40
40
|
} else if (s == "cbc") {
|
|
41
41
|
return MPSolver::OptimizationProblemType::CBC_MIXED_INTEGER_PROGRAMMING;
|
|
42
42
|
} else {
|
|
43
|
-
throw std::runtime_error
|
|
43
|
+
throw std::runtime_error{"Unknown optimization problem type: " + s};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -175,7 +175,7 @@ void init_linear(Rice::Module& m) {
|
|
|
175
175
|
[](const std::string& name, MPSolver::OptimizationProblemType problem_type) {
|
|
176
176
|
MPSolver* solver = new MPSolver(name, problem_type);
|
|
177
177
|
if (!solver) {
|
|
178
|
-
throw std::runtime_error
|
|
178
|
+
throw std::runtime_error{"Unrecognized solver type"};
|
|
179
179
|
}
|
|
180
180
|
return solver;
|
|
181
181
|
}, Rice::Return().takeOwnership())
|
|
@@ -184,7 +184,7 @@ void init_linear(Rice::Module& m) {
|
|
|
184
184
|
[](const std::string& solver_id) {
|
|
185
185
|
MPSolver* solver = MPSolver::CreateSolver(solver_id);
|
|
186
186
|
if (!solver) {
|
|
187
|
-
throw std::runtime_error
|
|
187
|
+
throw std::runtime_error{"Unrecognized solver type"};
|
|
188
188
|
}
|
|
189
189
|
return solver;
|
|
190
190
|
}, Rice::Return().takeOwnership())
|
|
@@ -239,7 +239,7 @@ void init_linear(Rice::Module& m) {
|
|
|
239
239
|
} else if (status == MPSolver::ResultStatus::NOT_SOLVED) {
|
|
240
240
|
return Symbol("not_solved");
|
|
241
241
|
} else {
|
|
242
|
-
throw std::runtime_error
|
|
242
|
+
throw std::runtime_error{"Unknown status"};
|
|
243
243
|
}
|
|
244
244
|
})
|
|
245
245
|
.define_method(
|
|
@@ -247,7 +247,7 @@ void init_linear(Rice::Module& m) {
|
|
|
247
247
|
[](MPSolver& self, bool obfuscate) {
|
|
248
248
|
std::string model_str;
|
|
249
249
|
if (!self.ExportModelAsLpFormat(obfuscate, &model_str)) {
|
|
250
|
-
throw std::runtime_error
|
|
250
|
+
throw std::runtime_error{"Export failed"};
|
|
251
251
|
}
|
|
252
252
|
return model_str;
|
|
253
253
|
})
|
|
@@ -256,7 +256,7 @@ void init_linear(Rice::Module& m) {
|
|
|
256
256
|
[](MPSolver& self, bool fixed_format, bool obfuscate) {
|
|
257
257
|
std::string model_str;
|
|
258
258
|
if (!self.ExportModelAsMpsFormat(fixed_format, obfuscate, &model_str)) {
|
|
259
|
-
throw std::runtime_error
|
|
259
|
+
throw std::runtime_error{"Export failed"};
|
|
260
260
|
}
|
|
261
261
|
return model_str;
|
|
262
262
|
});
|
data/ext/or-tools/math_opt.cpp
CHANGED
|
@@ -32,7 +32,7 @@ namespace Rice::detail {
|
|
|
32
32
|
double is_convertible(VALUE value) { return Convertible::Exact; }
|
|
33
33
|
|
|
34
34
|
static SolverType convert(VALUE x) {
|
|
35
|
-
|
|
35
|
+
std::string s = Symbol(x).str();
|
|
36
36
|
if (s == "gscip") {
|
|
37
37
|
return SolverType::kGscip;
|
|
38
38
|
} else if (s == "gurobi") {
|
|
@@ -54,7 +54,7 @@ namespace Rice::detail {
|
|
|
54
54
|
} else if (s == "santorini") {
|
|
55
55
|
return SolverType::kSantorini;
|
|
56
56
|
} else {
|
|
57
|
-
throw std::runtime_error
|
|
57
|
+
throw std::runtime_error{"Unknown solver type: " + s};
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -71,11 +71,11 @@ void init_math_opt(Rice::Module& m) {
|
|
|
71
71
|
.define_method(
|
|
72
72
|
"name",
|
|
73
73
|
[](Variable& self) {
|
|
74
|
-
return std::string
|
|
74
|
+
return std::string{self.name()};
|
|
75
75
|
})
|
|
76
76
|
.define_method(
|
|
77
77
|
"_eql?",
|
|
78
|
-
[](Variable& self, Variable
|
|
78
|
+
[](Variable& self, Variable& other) {
|
|
79
79
|
return static_cast<bool>(self == other);
|
|
80
80
|
});
|
|
81
81
|
|
|
@@ -106,7 +106,7 @@ void init_math_opt(Rice::Module& m) {
|
|
|
106
106
|
} else if (reason == TerminationReason::kOtherError) {
|
|
107
107
|
return Rice::Symbol("other");
|
|
108
108
|
} else {
|
|
109
|
-
throw std::runtime_error
|
|
109
|
+
throw std::runtime_error{"Unknown termination reason"};
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
|
|
@@ -143,18 +143,18 @@ void init_math_opt(Rice::Module& m) {
|
|
|
143
143
|
})
|
|
144
144
|
.define_method(
|
|
145
145
|
"_set_upper_bound",
|
|
146
|
-
[](Model& self, LinearConstraint constraint, double upper_bound) {
|
|
146
|
+
[](Model& self, const LinearConstraint& constraint, double upper_bound) {
|
|
147
147
|
self.set_upper_bound(constraint, upper_bound);
|
|
148
148
|
})
|
|
149
149
|
.define_method(
|
|
150
150
|
"_set_lower_bound",
|
|
151
|
-
[](Model& self, LinearConstraint constraint, double upper_bound) {
|
|
151
|
+
[](Model& self, const LinearConstraint& constraint, double upper_bound) {
|
|
152
152
|
self.set_lower_bound(constraint, upper_bound);
|
|
153
153
|
})
|
|
154
154
|
.define_method("_set_coefficient", &Model::set_coefficient)
|
|
155
155
|
.define_method(
|
|
156
156
|
"_set_objective_coefficient",
|
|
157
|
-
[](Model& self, Variable variable, double value) {
|
|
157
|
+
[](Model& self, const Variable& variable, double value) {
|
|
158
158
|
self.set_objective_coefficient(variable, value);
|
|
159
159
|
})
|
|
160
160
|
.define_method("_clear_objective", &Model::clear_objective)
|
|
@@ -36,7 +36,7 @@ void init_network_flows(Rice::Module& m) {
|
|
|
36
36
|
} else if (status == SimpleMaxFlow::Status::BAD_RESULT) {
|
|
37
37
|
return Symbol("bad_result");
|
|
38
38
|
} else {
|
|
39
|
-
throw std::runtime_error
|
|
39
|
+
throw std::runtime_error{"Unknown status"};
|
|
40
40
|
}
|
|
41
41
|
})
|
|
42
42
|
.define_method(
|
|
@@ -98,7 +98,7 @@ void init_network_flows(Rice::Module& m) {
|
|
|
98
98
|
} else if (status == SimpleMinCostFlow::Status::BAD_COST_RANGE) {
|
|
99
99
|
return Symbol("bad_cost_range");
|
|
100
100
|
} else {
|
|
101
|
-
throw std::runtime_error
|
|
101
|
+
throw std::runtime_error{"Unknown status"};
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
}
|
data/ext/or-tools/routing.cpp
CHANGED
|
@@ -58,7 +58,7 @@ namespace Rice::detail {
|
|
|
58
58
|
|
|
59
59
|
explicit To_Ruby(Arg* arg) : arg_(arg) { }
|
|
60
60
|
|
|
61
|
-
VALUE convert(
|
|
61
|
+
VALUE convert(const RoutingNodeIndex& x) {
|
|
62
62
|
return To_Ruby<int>().convert(x.value());
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -81,13 +81,13 @@ namespace Rice::detail {
|
|
|
81
81
|
double is_convertible(VALUE value) { return Convertible::Exact; }
|
|
82
82
|
|
|
83
83
|
RoutingModel::PenaltyCostBehavior convert(VALUE x) {
|
|
84
|
-
|
|
84
|
+
std::string s = Symbol(x).str();
|
|
85
85
|
if (s == "penalize_once") {
|
|
86
86
|
return RoutingModel::PenaltyCostBehavior::PENALIZE_ONCE;
|
|
87
87
|
} else if (s == "penalize_per_inactive") {
|
|
88
88
|
return RoutingModel::PenaltyCostBehavior::PENALIZE_PER_INACTIVE;
|
|
89
89
|
} else {
|
|
90
|
-
throw std::runtime_error
|
|
90
|
+
throw std::runtime_error{"Unknown penalty cost behavior: " + s};
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -138,7 +138,7 @@ void init_routing(Rice::Module& m) {
|
|
|
138
138
|
} else if (s == "first_unbound_min_value") {
|
|
139
139
|
v = FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE;
|
|
140
140
|
} else {
|
|
141
|
-
throw std::runtime_error
|
|
141
|
+
throw std::runtime_error{"Unknown first solution strategy: " + s};
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
return self.set_first_solution_strategy(v);
|
|
@@ -158,7 +158,7 @@ void init_routing(Rice::Module& m) {
|
|
|
158
158
|
} else if (s == "simulated_annealing") {
|
|
159
159
|
v = LocalSearchMetaheuristic::SIMULATED_ANNEALING;
|
|
160
160
|
} else {
|
|
161
|
-
throw std::runtime_error
|
|
161
|
+
throw std::runtime_error{"Unknown local search metaheuristic: " + s};
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
return self.set_local_search_metaheuristic(v);
|
|
@@ -192,7 +192,7 @@ void init_routing(Rice::Module& m) {
|
|
|
192
192
|
})
|
|
193
193
|
.define_singleton_function(
|
|
194
194
|
"_new_starts_ends",
|
|
195
|
-
[](int num_nodes, int num_vehicles, std::vector<RoutingNodeIndex
|
|
195
|
+
[](int num_nodes, int num_vehicles, const std::vector<RoutingNodeIndex>& starts, const std::vector<RoutingNodeIndex>& ends) {
|
|
196
196
|
return RoutingIndexManager(num_nodes, num_vehicles, starts, ends);
|
|
197
197
|
})
|
|
198
198
|
.define_method("index_to_node", &RoutingIndexManager::IndexToNode)
|
|
@@ -273,13 +273,13 @@ void init_routing(Rice::Module& m) {
|
|
|
273
273
|
if (o.respond_to("left")) {
|
|
274
274
|
operations_research::IntExpr* left(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(o.call("left")));
|
|
275
275
|
operations_research::IntExpr* right(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(o.call("right")));
|
|
276
|
-
|
|
276
|
+
std::string op = o.call("op").to_s().str();
|
|
277
277
|
if (op == "==") {
|
|
278
278
|
constraint = self.MakeEquality(left, right);
|
|
279
279
|
} else if (op == "<=") {
|
|
280
280
|
constraint = self.MakeLessOrEqual(left, right);
|
|
281
281
|
} else {
|
|
282
|
-
throw std::runtime_error
|
|
282
|
+
throw std::runtime_error{"Unknown operator"};
|
|
283
283
|
}
|
|
284
284
|
} else {
|
|
285
285
|
constraint = Rice::detail::From_Ruby<operations_research::Constraint*>().convert(o);
|
|
@@ -288,12 +288,12 @@ void init_routing(Rice::Module& m) {
|
|
|
288
288
|
})
|
|
289
289
|
.define_method(
|
|
290
290
|
"fixed_duration_interval_var",
|
|
291
|
-
[](operations_research::Solver& self, operations_research::IntVar
|
|
292
|
-
return self.MakeFixedDurationIntervalVar(start_variable, duration, name);
|
|
291
|
+
[](operations_research::Solver& self, operations_research::IntVar& start_variable, int64_t duration, const std::string& name) {
|
|
292
|
+
return self.MakeFixedDurationIntervalVar(&start_variable, duration, name);
|
|
293
293
|
})
|
|
294
294
|
.define_method(
|
|
295
295
|
"cumulative",
|
|
296
|
-
[](operations_research::Solver& self, Array rb_intervals, std::vector<int64_t
|
|
296
|
+
[](operations_research::Solver& self, Array rb_intervals, const std::vector<int64_t>& demands, int64_t capacity, const std::string& name) {
|
|
297
297
|
std::vector<operations_research::IntervalVar*> intervals;
|
|
298
298
|
for (const auto& v : rb_intervals) {
|
|
299
299
|
intervals.push_back(Rice::detail::From_Ruby<operations_research::IntervalVar*>().convert(v.value()));
|
|
@@ -332,13 +332,13 @@ void init_routing(Rice::Module& m) {
|
|
|
332
332
|
.define_constructor(Rice::Constructor<RoutingModel, RoutingIndexManager, RoutingModelParameters>(), Rice::Arg("_index_manager"), Rice::Arg("_parameters") = operations_research::DefaultRoutingModelParameters())
|
|
333
333
|
.define_method("register_unary_transit_vector", &RoutingModel::RegisterUnaryTransitVector)
|
|
334
334
|
.define_method(
|
|
335
|
-
"
|
|
335
|
+
"_register_unary_transit_callback",
|
|
336
336
|
[](RoutingModel& self, Object callback) {
|
|
337
337
|
// TODO guard callback?
|
|
338
338
|
return self.RegisterUnaryTransitCallback(
|
|
339
339
|
[callback](int64_t from_index) -> int64_t {
|
|
340
340
|
if (!ruby_native_thread_p()) {
|
|
341
|
-
throw std::runtime_error
|
|
341
|
+
throw std::runtime_error{"Non-Ruby thread"};
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
return Rice::detail::From_Ruby<int64_t>().convert(callback.call("call", from_index));
|
|
@@ -347,13 +347,13 @@ void init_routing(Rice::Module& m) {
|
|
|
347
347
|
}, Rice::Arg("_callback").keepAlive())
|
|
348
348
|
.define_method("register_transit_matrix", &RoutingModel::RegisterTransitMatrix)
|
|
349
349
|
.define_method(
|
|
350
|
-
"
|
|
350
|
+
"_register_transit_callback",
|
|
351
351
|
[](RoutingModel& self, Object callback) {
|
|
352
352
|
// TODO guard callback?
|
|
353
353
|
return self.RegisterTransitCallback(
|
|
354
354
|
[callback](int64_t from_index, int64_t to_index) -> int64_t {
|
|
355
355
|
if (!ruby_native_thread_p()) {
|
|
356
|
-
throw std::runtime_error
|
|
356
|
+
throw std::runtime_error{"Non-Ruby thread"};
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
return Rice::detail::From_Ruby<int64_t>().convert(callback.call("call", from_index, to_index));
|
|
@@ -386,7 +386,11 @@ void init_routing(Rice::Module& m) {
|
|
|
386
386
|
.define_method("perfect_binary_disjunctions", &RoutingModel::GetPerfectBinaryDisjunctions)
|
|
387
387
|
.define_method("ignore_disjunctions_already_forced_to_zero", &RoutingModel::IgnoreDisjunctionsAlreadyForcedToZero)
|
|
388
388
|
.define_method("add_soft_same_vehicle_constraint", &RoutingModel::AddSoftSameVehicleConstraint)
|
|
389
|
-
.define_method(
|
|
389
|
+
.define_method(
|
|
390
|
+
"set_allowed_vehicles_for_index",
|
|
391
|
+
[](RoutingModel& self, const std::vector<int>& vehicles, int64_t index) {
|
|
392
|
+
self.SetAllowedVehiclesForIndex(vehicles, index);
|
|
393
|
+
})
|
|
390
394
|
.define_method("vehicle_allowed_for_index?", &RoutingModel::IsVehicleAllowedForIndex)
|
|
391
395
|
.define_method("add_pickup_and_delivery", &RoutingModel::AddPickupAndDelivery)
|
|
392
396
|
.define_method("add_pickup_and_delivery_sets", &RoutingModel::AddPickupAndDeliverySets)
|
|
@@ -426,14 +430,26 @@ void init_routing(Rice::Module& m) {
|
|
|
426
430
|
.define_method("close_model", &RoutingModel::CloseModel)
|
|
427
431
|
// solve defined in Ruby
|
|
428
432
|
.define_method(
|
|
429
|
-
"
|
|
430
|
-
[](RoutingModel& self, const RoutingSearchParameters& search_parameters) {
|
|
431
|
-
|
|
433
|
+
"_solve_with_parameters",
|
|
434
|
+
[](RoutingModel& self, const RoutingSearchParameters& search_parameters, bool release_gvl) {
|
|
435
|
+
if (release_gvl) {
|
|
436
|
+
return Rice::detail::no_gvl([&]() {
|
|
437
|
+
return self.SolveWithParameters(search_parameters);
|
|
438
|
+
});
|
|
439
|
+
} else {
|
|
440
|
+
return self.SolveWithParameters(search_parameters);
|
|
441
|
+
}
|
|
432
442
|
})
|
|
433
443
|
.define_method(
|
|
434
|
-
"
|
|
435
|
-
[](RoutingModel& self, const Assignment
|
|
436
|
-
|
|
444
|
+
"_solve_from_assignment_with_parameters",
|
|
445
|
+
[](RoutingModel& self, const Assignment& assignment, const RoutingSearchParameters& search_parameters, bool release_gvl) {
|
|
446
|
+
if (release_gvl) {
|
|
447
|
+
return Rice::detail::no_gvl([&]() {
|
|
448
|
+
return self.SolveFromAssignmentWithParameters(&assignment, search_parameters);
|
|
449
|
+
});
|
|
450
|
+
} else {
|
|
451
|
+
return self.SolveFromAssignmentWithParameters(&assignment, search_parameters);
|
|
452
|
+
}
|
|
437
453
|
})
|
|
438
454
|
.define_method("compute_lower_bound", &RoutingModel::ComputeLowerBound)
|
|
439
455
|
.define_method("status",
|
|
@@ -451,10 +467,14 @@ void init_routing(Rice::Module& m) {
|
|
|
451
467
|
} else if (status == RoutingSearchStatus::ROUTING_INVALID) {
|
|
452
468
|
return Symbol("invalid");
|
|
453
469
|
} else {
|
|
454
|
-
throw std::runtime_error
|
|
470
|
+
throw std::runtime_error{"Unknown solver status"};
|
|
455
471
|
}
|
|
456
472
|
})
|
|
457
|
-
.define_method(
|
|
473
|
+
.define_method(
|
|
474
|
+
"apply_locks",
|
|
475
|
+
[](RoutingModel& self, const std::vector<int64_t>& locks) {
|
|
476
|
+
return self.ApplyLocks(locks);
|
|
477
|
+
})
|
|
458
478
|
.define_method("apply_locks_to_all_vehicles", &RoutingModel::ApplyLocksToAllVehicles)
|
|
459
479
|
.define_method("pre_assignment", &RoutingModel::PreAssignment)
|
|
460
480
|
.define_method("mutable_pre_assignment", &RoutingModel::MutablePreAssignment)
|
data/ext/or-tools/vendor.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "digest"
|
|
2
2
|
require "fileutils"
|
|
3
|
-
require "
|
|
3
|
+
require "open-uri"
|
|
4
4
|
require "tmpdir"
|
|
5
5
|
|
|
6
6
|
version = "9.15.6755"
|
|
@@ -70,62 +70,31 @@ end
|
|
|
70
70
|
short_version = version.split(".").first(2).join(".")
|
|
71
71
|
url = "https://github.com/google/or-tools/releases/download/v#{short_version}/#{filename}"
|
|
72
72
|
|
|
73
|
-
$stdout.sync = true
|
|
74
|
-
|
|
75
|
-
def download_file(url, download_path, redirects = 0)
|
|
76
|
-
raise "Too many redirects" if redirects > 10
|
|
77
|
-
|
|
78
|
-
uri = URI(url)
|
|
79
|
-
location = nil
|
|
80
|
-
|
|
81
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
|
82
|
-
request = Net::HTTP::Get.new(uri)
|
|
83
|
-
http.request(request) do |response|
|
|
84
|
-
case response
|
|
85
|
-
when Net::HTTPRedirection
|
|
86
|
-
location = response["location"]
|
|
87
|
-
when Net::HTTPSuccess
|
|
88
|
-
i = 0
|
|
89
|
-
File.open(download_path, "wb") do |f|
|
|
90
|
-
response.read_body do |chunk|
|
|
91
|
-
f.write(chunk)
|
|
92
|
-
|
|
93
|
-
# print progress
|
|
94
|
-
putc "." if i % 50 == 0
|
|
95
|
-
i += 1
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
puts # newline
|
|
99
|
-
else
|
|
100
|
-
raise "Bad response"
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# outside of Net::HTTP block to close previous connection
|
|
106
|
-
download_file(location, download_path, redirects + 1) if location
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# download
|
|
110
|
-
download_path = "#{Dir.tmpdir}/#{filename}"
|
|
111
|
-
unless File.exist?(download_path)
|
|
112
|
-
puts "Downloading #{url}..."
|
|
113
|
-
download_file(url, download_path)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# check integrity - do this regardless of if just downloaded
|
|
117
|
-
download_checksum = Digest::SHA256.file(download_path).hexdigest
|
|
118
|
-
raise "Bad checksum: #{download_checksum}" if download_checksum != checksum
|
|
119
|
-
|
|
120
73
|
path = File.expand_path("../../tmp/or-tools", __dir__)
|
|
121
74
|
FileUtils.mkdir_p(path)
|
|
122
75
|
|
|
123
|
-
# extract - can't use Gem::Package#extract_tar_gz from RubyGems
|
|
124
|
-
# since it limits filenames to 100 characters (doesn't support UStar format)
|
|
125
|
-
# for space, only keep licenses, include, and shared library
|
|
126
76
|
Dir.mktmpdir do |extract_path|
|
|
127
|
-
|
|
128
|
-
|
|
77
|
+
# download
|
|
78
|
+
puts "Downloading #{url}..."
|
|
79
|
+
URI.parse(url).open(max_redirects: 10) do |download|
|
|
80
|
+
download_checksum =
|
|
81
|
+
if download.respond_to?(:path)
|
|
82
|
+
download.flush
|
|
83
|
+
Digest::SHA256.file(download.path).hexdigest
|
|
84
|
+
else
|
|
85
|
+
Digest::SHA256.hexdigest(download.string)
|
|
86
|
+
end
|
|
87
|
+
raise "Bad checksum: #{download_checksum}" if download_checksum != checksum
|
|
88
|
+
|
|
89
|
+
# should never happen
|
|
90
|
+
raise "Expected file" if !download.respond_to?(:path)
|
|
91
|
+
|
|
92
|
+
# extract - can't use Gem::Package#extract_tar_gz from RubyGems
|
|
93
|
+
# since it limits filenames to 100 characters (doesn't support UStar format)
|
|
94
|
+
# for space, only keep licenses, include, and shared library
|
|
95
|
+
tar_args = Gem.win_platform? ? ["--force-local"] : []
|
|
96
|
+
system "tar", "zxf", download.path, "-C", extract_path, "--strip-components=1", *tar_args
|
|
97
|
+
end
|
|
129
98
|
|
|
130
99
|
# include
|
|
131
100
|
FileUtils.mv(File.join(extract_path, "include"), File.join(path, "include"))
|
data/lib/or_tools/cp_solver.rb
CHANGED
|
@@ -8,6 +8,7 @@ module ORTools
|
|
|
8
8
|
|
|
9
9
|
def solve(model, observer = nil)
|
|
10
10
|
@response = _solve(model, parameters, observer)
|
|
11
|
+
observer.response = @response if observer
|
|
11
12
|
@response.status
|
|
12
13
|
end
|
|
13
14
|
|
|
@@ -25,22 +26,6 @@ module ORTools
|
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
28
|
|
|
28
|
-
def solve_with_solution_callback(model, observer)
|
|
29
|
-
warn "[or-tools] solve_with_solution_callback is deprecated; use solve(model, callback)"
|
|
30
|
-
solve(model, observer)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def search_for_all_solutions(model, observer)
|
|
34
|
-
warn "[or-tools] search_for_all_solutions is deprecated; use solve() with solver.parameters.enumerate_all_solutions = true"
|
|
35
|
-
previous_value = parameters.enumerate_all_solutions
|
|
36
|
-
begin
|
|
37
|
-
parameters.enumerate_all_solutions = true
|
|
38
|
-
solve(model, observer)
|
|
39
|
-
ensure
|
|
40
|
-
parameters.enumerate_all_solutions = previous_value
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
29
|
def solution_info
|
|
45
30
|
@response.solution_info
|
|
46
31
|
end
|
|
@@ -21,5 +21,23 @@ module ORTools
|
|
|
21
21
|
def add_disjunction(indices, penalty, max_cardinality = 1, penalty_cost_behavior = :penalize_once)
|
|
22
22
|
_add_disjunction(indices, penalty, max_cardinality, penalty_cost_behavior)
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
def solve_with_parameters(search_parameters)
|
|
26
|
+
_solve_with_parameters(search_parameters, !@ruby_callback)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def solve_from_assignment_with_parameters(assignment, search_parameters)
|
|
30
|
+
_solve_from_assignment_with_parameters(assignment, search_parameters, !@ruby_callback)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def register_unary_transit_callback(callback)
|
|
34
|
+
@ruby_callback = true
|
|
35
|
+
_register_unary_transit_callback(callback)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def register_transit_callback(callback)
|
|
39
|
+
@ruby_callback = true
|
|
40
|
+
_register_transit_callback(callback)
|
|
41
|
+
end
|
|
24
42
|
end
|
|
25
43
|
end
|
data/lib/or_tools/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: or-tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.18.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
@@ -35,6 +35,7 @@ files:
|
|
|
35
35
|
- README.md
|
|
36
36
|
- ext/or-tools/assignment.cpp
|
|
37
37
|
- ext/or-tools/bin_packing.cpp
|
|
38
|
+
- ext/or-tools/channel.hpp
|
|
38
39
|
- ext/or-tools/constraint.cpp
|
|
39
40
|
- ext/or-tools/ext.cpp
|
|
40
41
|
- ext/or-tools/extconf.rb
|
|
@@ -78,14 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
78
79
|
requirements:
|
|
79
80
|
- - ">="
|
|
80
81
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '3.
|
|
82
|
+
version: '3.3'
|
|
82
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
84
|
requirements:
|
|
84
85
|
- - ">="
|
|
85
86
|
- !ruby/object:Gem::Version
|
|
86
87
|
version: '0'
|
|
87
88
|
requirements: []
|
|
88
|
-
rubygems_version: 4.0.
|
|
89
|
+
rubygems_version: 4.0.14
|
|
89
90
|
specification_version: 4
|
|
90
91
|
summary: Operations research tools for Ruby
|
|
91
92
|
test_files: []
|