or-tools 0.13.1 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4863311462c6b8ec192b18548667397398e2b7f183c01922fdfe3d464157a9fc
4
- data.tar.gz: 2e0ad658ab77b7c18aa449fad095d0dfa6c098b8bae80fd7d1ea1dbcae4b292f
3
+ metadata.gz: 29ccd0801b240802b1a4c5b3344aeb33feff36381aa3bc714c369ae1ea4912ea
4
+ data.tar.gz: 3d64b0da4320c77545b75d4830ee23040c5bb3d4eab568db23ab425e9ec0a3dd
5
5
  SHA512:
6
- metadata.gz: 6135045892abd2f572bd40603d36024e3984f7dfec10b1c40cc49dbc21c381d4b81c3e2cbe795f51fe52ecc88b579fa15b99cb8455872459649865be14031d4b
7
- data.tar.gz: e0df2a74200821b3d55f78cdf764d2720724449931298a2bb902c395587cd0b7117094b629e226273c65f5492b4846f2d7a26f753eb1d126088905a8ecad6354
6
+ metadata.gz: 660915a87810919150acf5c5e5a67ae51c775a4df66a99293f3f58b6520615fd5519b7298a8d0f1d1127488faffaba8f326c7cd1740ff6d3ea2636a5e5e16062
7
+ data.tar.gz: 760fc1cf72fe774787b2ae0a28f6b1f3a7f8a954af855a86d7061945e112f88408cbf160117832568878f01bcbac86d8a6078b6c174778be8e51b025d04d6f8f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.14.0 (2024-10-22)
2
+
3
+ - Added experimental support for `MathOpt`
4
+ - Unified model building across solvers
5
+
1
6
  ## 0.13.1 (2024-10-05)
2
7
 
3
8
  - Added binary installation for Debian 12
data/README.md CHANGED
@@ -23,6 +23,10 @@ Higher Level Interfaces
23
23
  - [Traveling Salesperson Problem (TSP)](#traveling-salesperson-problem-tsp)
24
24
  - [Sudoku](#sudoku)
25
25
 
26
+ MathOpt
27
+
28
+ - [Basic example](#basic-example)
29
+
26
30
  Linear Optimization
27
31
 
28
32
  - [Solving an LP Problem](#solving-an-lp-problem)
@@ -311,6 +315,29 @@ sudoku = ORTools::Sudoku.new(grid, x: true, anti_knight: true, magic_square: tru
311
315
  sudoku.solution
312
316
  ```
313
317
 
318
+ ## MathOpt
319
+
320
+ ### Basic Example
321
+
322
+ [Guide](https://developers.google.com/optimization/math_opt/basic_example)
323
+
324
+ ```ruby
325
+ # build the model
326
+ model = ORTools::MathOpt::Model.new("getting_started_lp")
327
+ x = model.add_variable(-1.0, 1.5, "x")
328
+ y = model.add_variable(0.0, 1.0, "y")
329
+ model.add_linear_constraint(x + y <= 1.5)
330
+ model.maximize(x + 2 * y)
331
+
332
+ # solve
333
+ result = model.solve
334
+
335
+ # inspect the solution
336
+ puts "Objective value: #{result.objective_value}"
337
+ puts "x: #{result.variable_values[x]}"
338
+ puts "y: #{result.variable_values[y]}"
339
+ ```
340
+
314
341
  ## Linear Optimization
315
342
 
316
343
  ### Solving an LP Problem
@@ -44,58 +44,27 @@ namespace Rice::detail
44
44
  public:
45
45
  LinearExpr convert(VALUE v)
46
46
  {
47
- Object x(v);
48
47
  LinearExpr expr;
49
48
 
50
- if (x.respond_to("to_i")) {
51
- expr = From_Ruby<int64_t>().convert(x.call("to_i").value());
52
- } else if (x.respond_to("vars")) {
53
- Array vars = x.call("vars");
54
- for (const auto& v : vars) {
55
- // TODO clean up
56
- auto cvar = (Array) v;
57
- Object var = cvar[0];
58
- auto coeff = From_Ruby<int64_t>().convert(cvar[1].value());
49
+ Rice::Object utils = Rice::define_module("ORTools").const_get("Utils");
50
+ Rice::Hash coeffs = utils.call("index_expression", Object(v));
59
51
 
60
- if (var.is_a(rb_cBoolVar)) {
61
- expr += From_Ruby<BoolVar>().convert(var.value()) * coeff;
62
- } else if (var.is_a(rb_cInteger)) {
63
- expr += From_Ruby<int64_t>().convert(var.value()) * coeff;
64
- } else {
65
- expr += From_Ruby<IntVar>().convert(var.value()) * coeff;
66
- }
67
- }
68
- } else {
69
- if (x.is_a(rb_cBoolVar)) {
70
- expr = From_Ruby<BoolVar>().convert(x.value());
52
+ for (const auto& entry : coeffs) {
53
+ Object var = entry.key;
54
+ auto coeff = From_Ruby<int64_t>().convert(entry.value.value());
55
+
56
+ if (var.is_nil()) {
57
+ expr += coeff;
58
+ } else if (var.is_a(rb_cBoolVar)) {
59
+ expr += From_Ruby<BoolVar>().convert(var.value()) * coeff;
71
60
  } else {
72
- expr = From_Ruby<IntVar>().convert(x.value());
61
+ expr += From_Ruby<IntVar>().convert(var.value()) * coeff;
73
62
  }
74
63
  }
75
64
 
76
65
  return expr;
77
66
  }
78
67
  };
79
-
80
- template<>
81
- class From_Ruby<std::vector<BoolVar>>
82
- {
83
- public:
84
- std::vector<BoolVar> convert(VALUE v)
85
- {
86
- auto a = Array(v);
87
- std::vector<BoolVar> vec;
88
- vec.reserve(a.size());
89
- for (const Object v : a) {
90
- if (v.is_a(rb_cSatIntVar)) {
91
- vec.push_back(From_Ruby<IntVar>().convert(v.value()).ToBoolVar());
92
- } else {
93
- vec.push_back(From_Ruby<BoolVar>().convert(v.value()));
94
- }
95
- }
96
- return vec;
97
- }
98
- };
99
68
  }
100
69
 
101
70
  void init_constraint(Rice::Module& m) {
@@ -119,13 +88,23 @@ void init_constraint(Rice::Module& m) {
119
88
  return self.OnlyEnforceIf(Rice::detail::From_Ruby<IntVar>().convert(literal).ToBoolVar());
120
89
  } else if (literal.is_a(rb_cArray)) {
121
90
  // TODO support IntVarSpan
122
- return self.OnlyEnforceIf(Rice::detail::From_Ruby<std::vector<BoolVar>>().convert(literal));
91
+ auto a = Array(literal);
92
+ std::vector<BoolVar> vec;
93
+ vec.reserve(a.size());
94
+ for (const Object v : a) {
95
+ if (v.is_a(rb_cSatIntVar)) {
96
+ vec.push_back(Rice::detail::From_Ruby<IntVar>().convert(v.value()).ToBoolVar());
97
+ } else {
98
+ vec.push_back(Rice::detail::From_Ruby<BoolVar>().convert(v.value()));
99
+ }
100
+ }
101
+ return self.OnlyEnforceIf(vec);
123
102
  } else {
124
103
  return self.OnlyEnforceIf(Rice::detail::From_Ruby<BoolVar>().convert(literal));
125
104
  }
126
105
  });
127
106
 
128
- rb_cBoolVar = Rice::define_class_under<BoolVar>(m, "BoolVar")
107
+ rb_cBoolVar = Rice::define_class_under<BoolVar>(m, "SatBoolVar")
129
108
  .define_method("name", &BoolVar::Name)
130
109
  .define_method("index", &BoolVar::index)
131
110
  .define_method("not", &BoolVar::Not)
@@ -425,17 +404,17 @@ void init_constraint(Rice::Module& m) {
425
404
  Model m;
426
405
 
427
406
  if (!callback.is_nil()) {
428
- // TODO figure out how to use callback with multiple cores
407
+ // use a single worker since Ruby code cannot be run in a non-Ruby thread
429
408
  parameters.set_num_search_workers(1);
430
409
 
431
410
  m.Add(NewFeasibleSolutionObserver(
432
411
  [&callback](const CpSolverResponse& r) {
433
- // ensure Ruby thread
434
- if (ruby_native_thread_p()) {
435
- // TODO find a better way to do this
436
- callback.call("response=", r);
437
- callback.call("on_solution_callback");
412
+ if (!ruby_native_thread_p()) {
413
+ throw std::runtime_error("Non-Ruby thread");
438
414
  }
415
+
416
+ callback.call("response=", r);
417
+ callback.call("on_solution_callback");
439
418
  })
440
419
  );
441
420
  }
data/ext/or-tools/ext.cpp CHANGED
@@ -10,6 +10,7 @@ void init_assignment(Rice::Module& m);
10
10
  void init_bin_packing(Rice::Module& m);
11
11
  void init_constraint(Rice::Module& m);
12
12
  void init_linear(Rice::Module& m);
13
+ void init_math_opt(Rice::Module& m);
13
14
  void init_network_flows(Rice::Module& m);
14
15
  void init_routing(Rice::Module& m);
15
16
 
@@ -24,6 +25,7 @@ void Init_ext()
24
25
  init_bin_packing(m);
25
26
  init_constraint(m);
26
27
  init_linear(m);
28
+ init_math_opt(m);
27
29
  init_network_flows(m);
28
30
  init_routing(m);
29
31
 
@@ -2,8 +2,14 @@ require "mkmf-rice"
2
2
 
3
3
  $CXXFLAGS << " -std=c++17 $(optflags) -DUSE_CBC"
4
4
 
5
- # or-tools warnings
6
- $CXXFLAGS << " -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-ignored-qualifiers"
5
+ # show warnings
6
+ $CXXFLAGS << " -Wall -Wextra"
7
+
8
+ # hide or-tools warnings
9
+ $CXXFLAGS << " -Wno-sign-compare -Wno-ignored-qualifiers -Wno-unused-parameter -Wno-missing-field-initializers"
10
+
11
+ # hide Rice warnings
12
+ $CXXFLAGS << " -Wno-implicit-fallthrough"
7
13
 
8
14
  inc, lib = dir_config("or-tools")
9
15
  if inc || lib
@@ -2,8 +2,6 @@
2
2
 
3
3
  #include "ext.h"
4
4
 
5
- using operations_research::LinearExpr;
6
- using operations_research::LinearRange;
7
5
  using operations_research::MPConstraint;
8
6
  using operations_research::MPObjective;
9
7
  using operations_research::MPSolver;
@@ -45,12 +43,7 @@ namespace Rice::detail
45
43
  }
46
44
 
47
45
  void init_linear(Rice::Module& m) {
48
- Rice::define_class_under<LinearRange>(m, "LinearRange");
49
-
50
- auto rb_cLinearExpr = Rice::define_class_under<LinearExpr>(m, "LinearExpr");
51
- rb_cLinearExpr.define_constructor(Rice::Constructor<LinearExpr>());
52
-
53
- Rice::define_class_under<MPVariable, LinearExpr>(m, "MPVariable")
46
+ Rice::define_class_under<MPVariable>(m, "MPVariable")
54
47
  .define_method("name", &MPVariable::name)
55
48
  .define_method("solution_value", &MPVariable::solution_value);
56
49
 
@@ -66,7 +59,15 @@ void init_linear(Rice::Module& m) {
66
59
  .define_method("set_minimization", &MPObjective::SetMinimization);
67
60
 
68
61
  Rice::define_class_under<MPSolver>(m, "Solver")
69
- .define_constructor(Rice::Constructor<MPSolver, std::string, MPSolver::OptimizationProblemType>())
62
+ .define_singleton_function(
63
+ "_new",
64
+ [](const std::string& name, MPSolver::OptimizationProblemType problem_type) {
65
+ std::unique_ptr<MPSolver> solver(new MPSolver(name, problem_type));
66
+ if (!solver) {
67
+ throw std::runtime_error("Unrecognized solver type");
68
+ }
69
+ return solver;
70
+ })
70
71
  .define_singleton_function(
71
72
  "_create",
72
73
  [](const std::string& solver_id) {
@@ -0,0 +1,179 @@
1
+ #include "absl/log/check.h"
2
+ #include "absl/status/statusor.h"
3
+ #include "ortools/base/init_google.h"
4
+ #include "ortools/math_opt/cpp/math_opt.h"
5
+
6
+ #include "ext.h"
7
+
8
+ using operations_research::math_opt::LinearConstraint;
9
+ using operations_research::math_opt::Model;
10
+ using operations_research::math_opt::Solve;
11
+ using operations_research::math_opt::SolveArguments;
12
+ using operations_research::math_opt::SolveResult;
13
+ using operations_research::math_opt::SolverType;
14
+ using operations_research::math_opt::Termination;
15
+ using operations_research::math_opt::TerminationReason;
16
+ using operations_research::math_opt::Variable;
17
+
18
+ namespace Rice::detail
19
+ {
20
+ template<>
21
+ struct Type<SolverType>
22
+ {
23
+ static bool verify()
24
+ {
25
+ return true;
26
+ }
27
+ };
28
+
29
+ template<>
30
+ struct From_Ruby<SolverType>
31
+ {
32
+ static SolverType convert(VALUE x)
33
+ {
34
+ auto s = Symbol(x).str();
35
+ if (s == "gscip") {
36
+ return SolverType::kGscip;
37
+ } else if (s == "gurobi") {
38
+ return SolverType::kGurobi;
39
+ } else if (s == "glop") {
40
+ return SolverType::kGlop;
41
+ } else if (s == "cpsat") {
42
+ return SolverType::kCpSat;
43
+ } else if (s == "pdlp") {
44
+ return SolverType::kPdlp;
45
+ } else if (s == "glpk") {
46
+ return SolverType::kGlpk;
47
+ } else if (s == "ecos") {
48
+ return SolverType::kEcos;
49
+ } else if (s == "scs") {
50
+ return SolverType::kScs;
51
+ } else if (s == "highs") {
52
+ return SolverType::kHighs;
53
+ } else if (s == "santorini") {
54
+ return SolverType::kSantorini;
55
+ } else {
56
+ throw std::runtime_error("Unknown solver type: " + s);
57
+ }
58
+ }
59
+ };
60
+ }
61
+
62
+ void init_math_opt(Rice::Module& m) {
63
+ auto mathopt = Rice::define_module_under(m, "MathOpt");
64
+
65
+ Rice::define_class_under<Variable>(mathopt, "Variable")
66
+ .define_method("id", &Variable::id)
67
+ .define_method(
68
+ "_eql?",
69
+ [](Variable& self, Variable &other) {
70
+ return (bool) (self == other);
71
+ });
72
+
73
+ Rice::define_class_under<LinearConstraint>(mathopt, "LinearConstraint");
74
+
75
+ Rice::define_class_under<Termination>(mathopt, "Termination")
76
+ .define_method(
77
+ "reason",
78
+ [](Termination& self) {
79
+ auto reason = self.reason;
80
+
81
+ if (reason == TerminationReason::kOptimal) {
82
+ return Rice::Symbol("optimal");
83
+ } else if (reason == TerminationReason::kInfeasible) {
84
+ return Rice::Symbol("infeasible");
85
+ } else if (reason == TerminationReason::kUnbounded) {
86
+ return Rice::Symbol("unbounded");
87
+ } else if (reason == TerminationReason::kInfeasibleOrUnbounded) {
88
+ return Rice::Symbol("infeasible_or_unbounded");
89
+ } else if (reason == TerminationReason::kImprecise) {
90
+ return Rice::Symbol("imprecise");
91
+ } else if (reason == TerminationReason::kFeasible) {
92
+ return Rice::Symbol("feasible");
93
+ } else if (reason == TerminationReason::kNoSolutionFound) {
94
+ return Rice::Symbol("no_solution_found");
95
+ } else if (reason == TerminationReason::kNumericalError) {
96
+ return Rice::Symbol("numerical_error");
97
+ } else if (reason == TerminationReason::kOtherError) {
98
+ return Rice::Symbol("other");
99
+ } else {
100
+ throw std::runtime_error("Unknown termination reason");
101
+ }
102
+ });
103
+
104
+ Rice::define_class_under<SolveResult>(mathopt, "SolveResult")
105
+ .define_method(
106
+ "termination",
107
+ [](SolveResult& self) {
108
+ return self.termination;
109
+ })
110
+ .define_method(
111
+ "objective_value",
112
+ [](SolveResult& self) {
113
+ return self.objective_value();
114
+ })
115
+ .define_method(
116
+ "variable_values",
117
+ [](SolveResult& self) {
118
+ Rice::Hash map;
119
+ for (auto& [k, v] : self.variable_values()) {
120
+ map[k] = v;
121
+ }
122
+ return map;
123
+ });
124
+
125
+ Rice::define_class_under<Model>(mathopt, "Model")
126
+ .define_constructor(Rice::Constructor<Model, std::string>())
127
+ .define_method("add_variable", &Model::AddContinuousVariable)
128
+ .define_method("add_integer_variable", &Model::AddIntegerVariable)
129
+ .define_method("add_binary_variable", &Model::AddBinaryVariable)
130
+ .define_method(
131
+ "_add_linear_constraint",
132
+ [](Model& self) {
133
+ return self.AddLinearConstraint();
134
+ })
135
+ .define_method(
136
+ "_set_upper_bound",
137
+ [](Model& self, LinearConstraint constraint, double upper_bound) {
138
+ self.set_upper_bound(constraint, upper_bound);
139
+ })
140
+ .define_method(
141
+ "_set_lower_bound",
142
+ [](Model& self, LinearConstraint constraint, double upper_bound) {
143
+ self.set_lower_bound(constraint, upper_bound);
144
+ })
145
+ .define_method("_set_coefficient", &Model::set_coefficient)
146
+ .define_method(
147
+ "_set_objective_coefficient",
148
+ [](Model& self, Variable variable, double value) {
149
+ self.set_objective_coefficient(variable, value);
150
+ })
151
+ .define_method("_clear_objective", &Model::clear_objective)
152
+ .define_method(
153
+ "_set_objective_offset",
154
+ [](Model& self, double value) {
155
+ self.set_objective_offset(value);
156
+ })
157
+ .define_method(
158
+ "_set_maximize",
159
+ [](Model& self) {
160
+ self.set_maximize();
161
+ })
162
+ .define_method(
163
+ "_set_minimize",
164
+ [](Model& self) {
165
+ self.set_minimize();
166
+ })
167
+ .define_method(
168
+ "_solve",
169
+ [](Model& self, SolverType solver_type) {
170
+ SolveArguments args;
171
+ auto result = Solve(self, solver_type, args);
172
+
173
+ if (!result.ok()) {
174
+ throw std::invalid_argument(std::string{result.status().message()});
175
+ }
176
+
177
+ return *result;
178
+ });
179
+ }
@@ -56,22 +56,9 @@ namespace Rice::detail
56
56
  };
57
57
  }
58
58
 
59
- namespace Rice::detail
60
- {
61
- template<class T, class U>
62
- class To_Ruby<std::pair<T, U>>
63
- {
64
- public:
65
- VALUE convert(std::pair<T, U> const & x)
66
- {
67
- return rb_ary_new3(2, To_Ruby<T>().convert(x.first), To_Ruby<U>().convert(x.second));
68
- }
69
- };
70
- }
71
-
72
59
  void init_routing(Rice::Module& m) {
73
60
  auto rb_cRoutingSearchParameters = Rice::define_class_under<RoutingSearchParameters>(m, "RoutingSearchParameters");
74
- auto rb_cIntVar = Rice::define_class_under<operations_research::IntVar>(m, "IntVar");
61
+ auto rb_cIntVar = Rice::define_class_under<operations_research::IntVar>(m, "RoutingIntVar");
75
62
 
76
63
  m.define_singleton_function("default_routing_search_parameters", &DefaultRoutingSearchParameters);
77
64
 
@@ -213,7 +200,6 @@ void init_routing(Rice::Module& m) {
213
200
 
214
201
  Rice::define_class_under<RoutingDimension>(m, "RoutingDimension")
215
202
  .define_method("transit_value", &RoutingDimension::GetTransitValue)
216
- // TODO GetTransitValueFromClass
217
203
  .define_method("cumul_var", &RoutingDimension::CumulVar)
218
204
  .define_method("transit_var", &RoutingDimension::TransitVar)
219
205
  .define_method("fixed_transit_var", &RoutingDimension::FixedTransitVar)
@@ -239,7 +225,7 @@ void init_routing(Rice::Module& m) {
239
225
  .define_method("post", &operations_research::Constraint::Post)
240
226
  .define_method("debug_string", &operations_research::Constraint::DebugString);
241
227
 
242
- Rice::define_class_under<operations_research::Solver>(m, "Solver2")
228
+ Rice::define_class_under<operations_research::Solver>(m, "RoutingSolver")
243
229
  .define_method(
244
230
  "add",
245
231
  [](operations_research::Solver& self, Object o) {
@@ -247,7 +233,7 @@ void init_routing(Rice::Module& m) {
247
233
  if (o.respond_to("left")) {
248
234
  operations_research::IntExpr* left(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(o.call("left")));
249
235
  operations_research::IntExpr* right(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(o.call("right")));
250
- auto op = o.call("operator").to_s().str();
236
+ auto op = o.call("op").to_s().str();
251
237
  if (op == "==") {
252
238
  constraint = self.MakeEquality(left, right);
253
239
  } else if (op == "<=") {
@@ -304,8 +290,13 @@ void init_routing(Rice::Module& m) {
304
290
  .define_method(
305
291
  "register_unary_transit_callback",
306
292
  [](RoutingModel& self, Object callback) {
293
+ // TODO guard callback?
307
294
  return self.RegisterUnaryTransitCallback(
308
295
  [callback](int64_t from_index) -> int64_t {
296
+ if (!ruby_native_thread_p()) {
297
+ throw std::runtime_error("Non-Ruby thread");
298
+ }
299
+
309
300
  return Rice::detail::From_Ruby<int64_t>().convert(callback.call("call", from_index));
310
301
  }
311
302
  );
@@ -314,8 +305,13 @@ void init_routing(Rice::Module& m) {
314
305
  .define_method(
315
306
  "register_transit_callback",
316
307
  [](RoutingModel& self, Object callback) {
308
+ // TODO guard callback?
317
309
  return self.RegisterTransitCallback(
318
310
  [callback](int64_t from_index, int64_t to_index) -> int64_t {
311
+ if (!ruby_native_thread_p()) {
312
+ throw std::runtime_error("Non-Ruby thread");
313
+ }
314
+
319
315
  return Rice::detail::From_Ruby<int64_t>().convert(callback.call("call", from_index, to_index));
320
316
  }
321
317
  );
@@ -328,13 +324,8 @@ void init_routing(Rice::Module& m) {
328
324
  .define_method("add_constant_dimension", &RoutingModel::AddConstantDimension)
329
325
  .define_method("add_vector_dimension", &RoutingModel::AddVectorDimension)
330
326
  .define_method("add_matrix_dimension", &RoutingModel::AddMatrixDimension)
331
- // TODO AddDimensionDependentDimensionWithVehicleCapacity
332
- // .define_method("make_path_spans_and_total_slacks", &RoutingModel::MakePathSpansAndTotalSlacks)
333
327
  .define_method("all_dimension_names", &RoutingModel::GetAllDimensionNames)
334
- // .define_method("dimensions", &RoutingModel::GetDimensions)
335
- // .define_method("dimensions_with_soft_or_span_costs", &RoutingModel::GetDimensionsWithSoftOrSpanCosts)
336
328
  .define_method("dimension?", &RoutingModel::HasDimension)
337
- // .define_method("dimension_or_die", &RoutingModel::GetDimensionOrDie)
338
329
  .define_method("mutable_dimension", &RoutingModel::GetMutableDimension)
339
330
  .define_method("set_primary_constrained_dimension", &RoutingModel::SetPrimaryConstrainedDimension)
340
331
  .define_method("primary_constrained_dimension", &RoutingModel::GetPrimaryConstrainedDimension)
@@ -373,9 +364,6 @@ void init_routing(Rice::Module& m) {
373
364
  }
374
365
  return positions;
375
366
  })
376
- // TODO SetPickupAndDeliveryPolicyOfAllVehicles
377
- // TODO SetPickupAndDeliveryPolicyOfVehicle
378
- // TODO GetPickupAndDeliveryPolicyOfVehicle
379
367
  .define_method("num_of_singleton_nodes", &RoutingModel::GetNumOfSingletonNodes)
380
368
  .define_method("unperformed_penalty", &RoutingModel::UnperformedPenalty)
381
369
  .define_method("unperformed_penalty_or_value", &RoutingModel::UnperformedPenaltyOrValue)
@@ -444,8 +432,6 @@ void init_routing(Rice::Module& m) {
444
432
  .define_method("compact_and_check_assignment", &RoutingModel::CompactAndCheckAssignment)
445
433
  .define_method("add_to_assignment", &RoutingModel::AddToAssignment)
446
434
  .define_method("add_interval_to_assignment", &RoutingModel::AddIntervalToAssignment)
447
- // TODO PackCumulsOfOptimizerDimensionsFromAssignment
448
- // TODO AddLocalSearchFilter
449
435
  .define_method("start", &RoutingModel::Start)
450
436
  .define_method("end", &RoutingModel::End)
451
437
  .define_method("start?", &RoutingModel::IsStart)
data/lib/or-tools.rb CHANGED
@@ -1,39 +1,50 @@
1
1
  # ext
2
2
  require "or_tools/ext"
3
3
 
4
- # modules
4
+ # expressions
5
+ require_relative "or_tools/expression"
5
6
  require_relative "or_tools/comparison"
6
- require_relative "or_tools/comparison_operators"
7
- require_relative "or_tools/bool_var"
8
7
  require_relative "or_tools/constant"
8
+ require_relative "or_tools/product"
9
+ require_relative "or_tools/variable"
10
+
11
+ # bin packing
12
+ require_relative "or_tools/knapsack_solver"
13
+
14
+ # constraint
9
15
  require_relative "or_tools/cp_model"
10
16
  require_relative "or_tools/cp_solver"
11
17
  require_relative "or_tools/cp_solver_solution_callback"
12
- require_relative "or_tools/int_var"
13
- require_relative "or_tools/knapsack_solver"
14
- require_relative "or_tools/linear_constraint"
15
- require_relative "or_tools/linear_expr"
16
- require_relative "or_tools/mp_variable"
17
- require_relative "or_tools/product_cst"
18
- require_relative "or_tools/routing_index_manager"
19
- require_relative "or_tools/routing_model"
20
- require_relative "or_tools/sat_linear_expr"
21
- require_relative "or_tools/sat_int_var"
22
- require_relative "or_tools/solver"
23
- require_relative "or_tools/sum_array"
24
- require_relative "or_tools/version"
25
-
26
- # solution printers
27
18
  require_relative "or_tools/objective_solution_printer"
28
19
  require_relative "or_tools/var_array_solution_printer"
29
20
  require_relative "or_tools/var_array_and_objective_solution_printer"
30
21
 
22
+ # linear
23
+ require_relative "or_tools/solver"
24
+
25
+ # math opt
26
+ require_relative "or_tools/math_opt/model"
27
+ require_relative "or_tools/math_opt/variable"
28
+
29
+ # routing
30
+ require_relative "or_tools/routing_index_manager"
31
+ require_relative "or_tools/routing_model"
32
+
31
33
  # higher level interfaces
32
34
  require_relative "or_tools/basic_scheduler"
33
35
  require_relative "or_tools/seating"
34
36
  require_relative "or_tools/sudoku"
35
37
  require_relative "or_tools/tsp"
36
38
 
39
+ # modules
40
+ require_relative "or_tools/utils"
41
+ require_relative "or_tools/version"
42
+
37
43
  module ORTools
38
44
  class Error < StandardError; end
45
+
46
+ # previous names
47
+ Solver2 = RoutingSolver
48
+ IntVar = RoutingIntVar
49
+ BoolVar = SatBoolVar
39
50
  end
@@ -1,19 +1,16 @@
1
1
  module ORTools
2
2
  class Comparison
3
- attr_reader :operator, :left, :right
3
+ attr_reader :left, :op, :right
4
4
 
5
- def initialize(operator, left, right)
6
- @operator = operator
7
- @left = left
8
- @right = right
9
- end
10
-
11
- def to_s
12
- "#{left} #{operator} #{right}"
5
+ def initialize(left, op, right)
6
+ @left = Expression.to_expression(left)
7
+ @op = op
8
+ @right = Expression.to_expression(right)
13
9
  end
14
10
 
15
11
  def inspect
16
- "#<#{self.class.name} #{to_s}>"
12
+ "#{@left.inspect} #{@op} #{@right.inspect}"
17
13
  end
14
+ alias_method :to_s, :inspect
18
15
  end
19
16
  end
@@ -1,23 +1,26 @@
1
1
  module ORTools
2
- class Constant < LinearExpr
3
- def initialize(val)
4
- @val = val
2
+ class Constant < Expression
3
+ attr_reader :value
4
+
5
+ def initialize(value)
6
+ @value = value
5
7
  end
6
8
 
7
- def to_s
8
- @val.to_s
9
+ # simplify Ruby sum
10
+ def +(other)
11
+ @value == 0 ? other : super
9
12
  end
10
13
 
11
- def add_self_to_coeff_map_or_stack(coeffs, multiplier, stack)
12
- coeffs[OFFSET_KEY] += @val * multiplier
14
+ def inspect
15
+ @value.to_s
13
16
  end
14
- end
15
17
 
16
- class FakeMPVariableRepresentingTheConstantOffset
17
- def solution_value
18
- 1
18
+ def -@
19
+ Constant.new(-value)
19
20
  end
20
- end
21
21
 
22
- OFFSET_KEY = FakeMPVariableRepresentingTheConstantOffset.new
22
+ def vars
23
+ @vars ||= []
24
+ end
25
+ end
23
26
  end