or-tools 0.13.1 → 0.14.0

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: 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