or-tools 0.17.1 → 0.18.1

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.
@@ -10,6 +10,7 @@ using operations_research::Assignment;
10
10
  using operations_research::ConstraintSolverParameters;
11
11
  using operations_research::DefaultRoutingSearchParameters;
12
12
  using operations_research::FirstSolutionStrategy;
13
+ using operations_research::IntervalVarElement;
13
14
  using operations_research::LocalSearchMetaheuristic;
14
15
  using operations_research::RoutingDimension;
15
16
  using operations_research::RoutingDisjunctionIndex;
@@ -22,6 +23,7 @@ using operations_research::RoutingSearchStatus;
22
23
 
23
24
  using Rice::Array;
24
25
  using Rice::Class;
26
+ using Rice::Hash;
25
27
  using Rice::Module;
26
28
  using Rice::Object;
27
29
  using Rice::String;
@@ -58,7 +60,7 @@ namespace Rice::detail {
58
60
 
59
61
  explicit To_Ruby(Arg* arg) : arg_(arg) { }
60
62
 
61
- VALUE convert(RoutingNodeIndex const & x) {
63
+ VALUE convert(const RoutingNodeIndex& x) {
62
64
  return To_Ruby<int>().convert(x.value());
63
65
  }
64
66
 
@@ -81,13 +83,13 @@ namespace Rice::detail {
81
83
  double is_convertible(VALUE value) { return Convertible::Exact; }
82
84
 
83
85
  RoutingModel::PenaltyCostBehavior convert(VALUE x) {
84
- auto s = Symbol(x).str();
86
+ std::string s = Symbol(x).str();
85
87
  if (s == "penalize_once") {
86
88
  return RoutingModel::PenaltyCostBehavior::PENALIZE_ONCE;
87
89
  } else if (s == "penalize_per_inactive") {
88
90
  return RoutingModel::PenaltyCostBehavior::PENALIZE_PER_INACTIVE;
89
91
  } else {
90
- throw std::runtime_error("Unknown penalty cost behavior: " + s);
92
+ throw std::runtime_error{"Unknown penalty cost behavior: " + s};
91
93
  }
92
94
  }
93
95
 
@@ -96,13 +98,111 @@ namespace Rice::detail {
96
98
  };
97
99
  } // namespace Rice::detail
98
100
 
101
+ int64_t int64_strict(VALUE v) {
102
+ if (!Object(v).is_a(rb_cInteger)) {
103
+ throw std::invalid_argument{"Coefficient must be integer"};
104
+ }
105
+ return Rice::detail::From_Ruby<int64_t>().convert(v);
106
+ }
107
+
108
+ operations_research::IntExpr* int_expr(operations_research::Solver& solver, Object o) {
109
+ Object utils = Rice::define_module("ORTools").const_get("Utils");
110
+ Hash rb_coeffs = utils.call("index_expression", o);
111
+
112
+ std::vector<operations_research::IntVar*> vars;
113
+ std::vector<int64_t> coeffs;
114
+ int64_t constant = 0;
115
+
116
+ for (const auto& entry : rb_coeffs) {
117
+ auto coeff = int64_strict(entry.value.value());
118
+ if (Object(entry.key).is_nil()) {
119
+ constant = coeff;
120
+ } else {
121
+ vars.push_back(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(entry.key.value()));
122
+ coeffs.push_back(coeff);
123
+ }
124
+ }
125
+
126
+ operations_research::IntExpr* expr = solver.MakeScalProd(vars, coeffs);
127
+ if (constant != 0) {
128
+ expr = solver.MakeSum(expr, constant);
129
+ }
130
+ return expr;
131
+ }
132
+
99
133
  void init_routing(Rice::Module& m) {
100
134
  auto rb_cRoutingSearchParameters = Rice::define_class_under<RoutingSearchParameters>(m, "RoutingSearchParameters");
101
135
  auto rb_cIntVar = Rice::define_class_under<operations_research::IntVar>(m, "RoutingIntVar");
102
136
 
103
137
  m.define_singleton_function("default_routing_search_parameters", &DefaultRoutingSearchParameters);
104
138
 
139
+ Rice::define_class_under<RoutingSearchParameters::ImprovementSearchLimitParameters>(rb_cRoutingSearchParameters, "ImprovementSearchLimitParameters")
140
+ .define_method("improvement_rate_coefficient", &RoutingSearchParameters::ImprovementSearchLimitParameters::improvement_rate_coefficient)
141
+ .define_method("improvement_rate_coefficient=", &RoutingSearchParameters::ImprovementSearchLimitParameters::set_improvement_rate_coefficient)
142
+ .define_method("improvement_rate_solutions_distance", &RoutingSearchParameters::ImprovementSearchLimitParameters::improvement_rate_solutions_distance)
143
+ .define_method("improvement_rate_solutions_distance=", &RoutingSearchParameters::ImprovementSearchLimitParameters::set_improvement_rate_solutions_distance);
144
+
105
145
  rb_cRoutingSearchParameters
146
+ .define_method("christofides_use_minimum_matching", &RoutingSearchParameters::christofides_use_minimum_matching)
147
+ .define_method("christofides_use_minimum_matching=", &RoutingSearchParameters::set_christofides_use_minimum_matching)
148
+ .define_method("fallback_to_cp_sat_size_threshold", &RoutingSearchParameters::fallback_to_cp_sat_size_threshold)
149
+ .define_method("fallback_to_cp_sat_size_threshold=", &RoutingSearchParameters::set_fallback_to_cp_sat_size_threshold)
150
+ .define_method("first_solution_optimization_period", &RoutingSearchParameters::first_solution_optimization_period)
151
+ .define_method("first_solution_optimization_period=", &RoutingSearchParameters::set_first_solution_optimization_period)
152
+ .define_method("guided_local_search_lambda_coefficient", &RoutingSearchParameters::guided_local_search_lambda_coefficient)
153
+ .define_method("guided_local_search_lambda_coefficient=", &RoutingSearchParameters::set_guided_local_search_lambda_coefficient)
154
+ .define_method("guided_local_search_penalize_with_vehicle_classes", &RoutingSearchParameters::guided_local_search_penalize_with_vehicle_classes)
155
+ .define_method("guided_local_search_penalize_with_vehicle_classes=", &RoutingSearchParameters::set_guided_local_search_penalize_with_vehicle_classes)
156
+ .define_method("guided_local_search_reset_penalties_on_new_best_solution", &RoutingSearchParameters::guided_local_search_reset_penalties_on_new_best_solution)
157
+ .define_method("guided_local_search_reset_penalties_on_new_best_solution=", &RoutingSearchParameters::set_guided_local_search_reset_penalties_on_new_best_solution)
158
+ .define_method("heuristic_close_nodes_lns_num_nodes", &RoutingSearchParameters::heuristic_close_nodes_lns_num_nodes)
159
+ .define_method("heuristic_close_nodes_lns_num_nodes=", &RoutingSearchParameters::set_heuristic_close_nodes_lns_num_nodes)
160
+ .define_method("heuristic_expensive_chain_lns_num_arcs_to_consider", &RoutingSearchParameters::heuristic_expensive_chain_lns_num_arcs_to_consider)
161
+ .define_method("heuristic_expensive_chain_lns_num_arcs_to_consider=", &RoutingSearchParameters::set_heuristic_expensive_chain_lns_num_arcs_to_consider)
162
+ .define_method("log_cost_offset", &RoutingSearchParameters::log_cost_offset)
163
+ .define_method("log_cost_offset=", &RoutingSearchParameters::set_log_cost_offset)
164
+ .define_method("log_cost_scaling_factor", &RoutingSearchParameters::log_cost_scaling_factor)
165
+ .define_method("log_cost_scaling_factor=", &RoutingSearchParameters::set_log_cost_scaling_factor)
166
+ .define_method("log_search", &RoutingSearchParameters::log_search)
167
+ .define_method("log_search=", &RoutingSearchParameters::set_log_search)
168
+ .define_method("log_tag", &RoutingSearchParameters::log_tag)
169
+ // .define_method("log_tag=", &RoutingSearchParameters::set_log_tag)
170
+ .define_method("ls_operator_min_neighbors", &RoutingSearchParameters::ls_operator_min_neighbors)
171
+ .define_method("ls_operator_min_neighbors=", &RoutingSearchParameters::set_ls_operator_min_neighbors)
172
+ .define_method("ls_operator_neighbors_ratio", &RoutingSearchParameters::ls_operator_neighbors_ratio)
173
+ .define_method("ls_operator_neighbors_ratio=", &RoutingSearchParameters::set_ls_operator_neighbors_ratio)
174
+ .define_method("max_swap_active_chain_size", &RoutingSearchParameters::max_swap_active_chain_size)
175
+ .define_method("max_swap_active_chain_size=", &RoutingSearchParameters::set_max_swap_active_chain_size)
176
+ .define_method("multi_armed_bandit_compound_operator_exploration_coefficient", &RoutingSearchParameters::multi_armed_bandit_compound_operator_exploration_coefficient)
177
+ .define_method("multi_armed_bandit_compound_operator_exploration_coefficient=", &RoutingSearchParameters::set_multi_armed_bandit_compound_operator_exploration_coefficient)
178
+ .define_method("multi_armed_bandit_compound_operator_memory_coefficient", &RoutingSearchParameters::multi_armed_bandit_compound_operator_memory_coefficient)
179
+ .define_method("multi_armed_bandit_compound_operator_memory_coefficient=", &RoutingSearchParameters::set_multi_armed_bandit_compound_operator_memory_coefficient)
180
+ .define_method("num_max_local_optima_before_metaheuristic_switch", &RoutingSearchParameters::num_max_local_optima_before_metaheuristic_switch)
181
+ .define_method("num_max_local_optima_before_metaheuristic_switch=", &RoutingSearchParameters::set_num_max_local_optima_before_metaheuristic_switch)
182
+ .define_method("number_of_solutions_to_collect", &RoutingSearchParameters::number_of_solutions_to_collect)
183
+ .define_method("number_of_solutions_to_collect=", &RoutingSearchParameters::set_number_of_solutions_to_collect)
184
+ .define_method("optimization_step", &RoutingSearchParameters::optimization_step)
185
+ .define_method("optimization_step=", &RoutingSearchParameters::set_optimization_step)
186
+ .define_method("relocate_expensive_chain_num_arcs_to_consider", &RoutingSearchParameters::relocate_expensive_chain_num_arcs_to_consider)
187
+ .define_method("relocate_expensive_chain_num_arcs_to_consider=", &RoutingSearchParameters::set_relocate_expensive_chain_num_arcs_to_consider)
188
+ .define_method("report_intermediate_cp_sat_solutions", &RoutingSearchParameters::report_intermediate_cp_sat_solutions)
189
+ .define_method("report_intermediate_cp_sat_solutions=", &RoutingSearchParameters::set_report_intermediate_cp_sat_solutions)
190
+ .define_method("secondary_ls_time_limit_ratio", &RoutingSearchParameters::secondary_ls_time_limit_ratio)
191
+ .define_method("secondary_ls_time_limit_ratio=", &RoutingSearchParameters::set_secondary_ls_time_limit_ratio)
192
+ .define_method("solution_limit", &RoutingSearchParameters::solution_limit)
193
+ .define_method("solution_limit=", &RoutingSearchParameters::set_solution_limit)
194
+ .define_method("use_depth_first_search", &RoutingSearchParameters::use_depth_first_search)
195
+ .define_method("use_depth_first_search=", &RoutingSearchParameters::set_use_depth_first_search)
196
+ .define_method("use_full_propagation", &RoutingSearchParameters::use_full_propagation)
197
+ .define_method("use_full_propagation=", &RoutingSearchParameters::set_use_full_propagation)
198
+ .define_method("use_guided_local_search_penalties_in_local_search_operators", &RoutingSearchParameters::use_guided_local_search_penalties_in_local_search_operators)
199
+ .define_method("use_guided_local_search_penalties_in_local_search_operators=", &RoutingSearchParameters::set_use_guided_local_search_penalties_in_local_search_operators)
200
+ .define_method("use_iterated_local_search", &RoutingSearchParameters::use_iterated_local_search)
201
+ .define_method("use_iterated_local_search=", &RoutingSearchParameters::set_use_iterated_local_search)
202
+ .define_method("use_multi_armed_bandit_concatenate_operators", &RoutingSearchParameters::use_multi_armed_bandit_concatenate_operators)
203
+ .define_method("use_multi_armed_bandit_concatenate_operators=", &RoutingSearchParameters::set_use_multi_armed_bandit_concatenate_operators)
204
+ .define_method("use_unfiltered_first_solution_strategy", &RoutingSearchParameters::use_unfiltered_first_solution_strategy)
205
+ .define_method("use_unfiltered_first_solution_strategy=", &RoutingSearchParameters::set_use_unfiltered_first_solution_strategy)
106
206
  .define_method(
107
207
  "first_solution_strategy=",
108
208
  [](RoutingSearchParameters& self, Object value) {
@@ -138,7 +238,7 @@ void init_routing(Rice::Module& m) {
138
238
  } else if (s == "first_unbound_min_value") {
139
239
  v = FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE;
140
240
  } else {
141
- throw std::runtime_error("Unknown first solution strategy: " + s);
241
+ throw std::runtime_error{"Unknown first solution strategy: " + s};
142
242
  }
143
243
 
144
244
  return self.set_first_solution_strategy(v);
@@ -158,21 +258,12 @@ void init_routing(Rice::Module& m) {
158
258
  } else if (s == "simulated_annealing") {
159
259
  v = LocalSearchMetaheuristic::SIMULATED_ANNEALING;
160
260
  } else {
161
- throw std::runtime_error("Unknown local search metaheuristic: " + s);
261
+ throw std::runtime_error{"Unknown local search metaheuristic: " + s};
162
262
  }
163
263
 
164
264
  return self.set_local_search_metaheuristic(v);
165
265
  })
166
- .define_method(
167
- "log_search=",
168
- [](RoutingSearchParameters& self, bool value) {
169
- self.set_log_search(value);
170
- })
171
- .define_method(
172
- "solution_limit=",
173
- [](RoutingSearchParameters& self, int64_t value) {
174
- self.set_solution_limit(value);
175
- })
266
+ .define_method("improvement_limit_parameters", &RoutingSearchParameters::mutable_improvement_limit_parameters)
176
267
  .define_method(
177
268
  "time_limit=",
178
269
  [](RoutingSearchParameters& self, int64_t value) {
@@ -192,20 +283,38 @@ void init_routing(Rice::Module& m) {
192
283
  })
193
284
  .define_singleton_function(
194
285
  "_new_starts_ends",
195
- [](int num_nodes, int num_vehicles, std::vector<RoutingNodeIndex> starts, std::vector<RoutingNodeIndex> ends) {
286
+ [](int num_nodes, int num_vehicles, const std::vector<RoutingNodeIndex>& starts, const std::vector<RoutingNodeIndex>& ends) {
196
287
  return RoutingIndexManager(num_nodes, num_vehicles, starts, ends);
197
288
  })
198
289
  .define_method("index_to_node", &RoutingIndexManager::IndexToNode)
199
290
  .define_method("node_to_index", &RoutingIndexManager::NodeToIndex);
200
291
 
292
+
293
+ Rice::define_class_under<IntervalVarElement>(m, "IntervalVarElement")
294
+ .define_method("var", &IntervalVarElement::Var)
295
+ .define_method("start_value", &IntervalVarElement::StartValue)
296
+ .define_method("duration_value", &IntervalVarElement::DurationValue)
297
+ .define_method("end_value", &IntervalVarElement::EndValue)
298
+ .define_method("performed_value", &IntervalVarElement::PerformedValue);
299
+
300
+ Rice::define_class_under<Assignment::IntervalContainer>(m, "IntervalContainer")
301
+ .define_method("size", &Assignment::IntervalContainer::Size)
302
+ .define_method(
303
+ "element",
304
+ [](Assignment::IntervalContainer& self, int index) {
305
+ return self.Element(index);
306
+ });
307
+
201
308
  Rice::define_class_under<Assignment>(m, "Assignment")
202
309
  .define_method("objective_value", &Assignment::ObjectiveValue)
203
310
  .define_method("value", &Assignment::Value)
204
311
  .define_method("min", &Assignment::Min)
205
- .define_method("max", &Assignment::Max);
312
+ .define_method("max", &Assignment::Max)
313
+ .define_method("interval_var_container", &Assignment::IntervalVarContainer);
206
314
 
207
315
  // not to be confused with operations_research::sat::IntVar
208
316
  rb_cIntVar
317
+ .define_method("name", &operations_research::IntVar::name)
209
318
  .define_method("var?", &operations_research::IntVar::IsVar)
210
319
  .define_method("value", &operations_research::IntVar::Value)
211
320
  .define_method("remove_value", &operations_research::IntVar::RemoveValue)
@@ -223,6 +332,7 @@ void init_routing(Rice::Module& m) {
223
332
  });
224
333
 
225
334
  Rice::define_class_under<operations_research::IntervalVar>(m, "IntervalVar")
335
+ .define_method("name", &operations_research::IntervalVar::name)
226
336
  .define_method("start_min", &operations_research::IntervalVar::StartMin)
227
337
  .define_method("start_max", &operations_research::IntervalVar::StartMax)
228
338
  .define_method("set_start_min", &operations_research::IntervalVar::SetStartMin)
@@ -250,6 +360,8 @@ void init_routing(Rice::Module& m) {
250
360
  .define_method("set_global_span_cost_coefficient", &RoutingDimension::SetGlobalSpanCostCoefficient)
251
361
  // alias
252
362
  .define_method("global_span_cost_coefficient=", &RoutingDimension::SetGlobalSpanCostCoefficient)
363
+ .define_method("set_slack_cost_coefficient_for_vehicle", &RoutingDimension::SetSlackCostCoefficientForVehicle)
364
+ .define_method("set_slack_cost_coefficient_for_all_vehicles", &RoutingDimension::SetSlackCostCoefficientForAllVehicles)
253
365
  .define_method("set_cumul_var_soft_upper_bound", &RoutingDimension::SetCumulVarSoftUpperBound)
254
366
  .define_method("cumul_var_soft_upper_bound?", &RoutingDimension::HasCumulVarSoftUpperBound)
255
367
  .define_method("cumul_var_soft_upper_bound", &RoutingDimension::GetCumulVarSoftUpperBound)
@@ -257,7 +369,12 @@ void init_routing(Rice::Module& m) {
257
369
  .define_method("set_cumul_var_soft_lower_bound", &RoutingDimension::SetCumulVarSoftLowerBound)
258
370
  .define_method("cumul_var_soft_lower_bound?", &RoutingDimension::HasCumulVarSoftLowerBound)
259
371
  .define_method("cumul_var_soft_lower_bound", &RoutingDimension::GetCumulVarSoftLowerBound)
260
- .define_method("cumul_var_soft_lower_bound_coefficient", &RoutingDimension::GetCumulVarSoftLowerBoundCoefficient);
372
+ .define_method("cumul_var_soft_lower_bound_coefficient", &RoutingDimension::GetCumulVarSoftLowerBoundCoefficient)
373
+ .define_method(
374
+ "set_break_intervals_of_vehicle",
375
+ [](RoutingDimension& self, std::vector<operations_research::IntervalVar*> breaks, int vehicle, std::vector<int64_t> node_visit_transits) {
376
+ self.SetBreakIntervalsOfVehicle(breaks, vehicle, node_visit_transits);
377
+ });
261
378
 
262
379
  Rice::define_class_under<RoutingDisjunctionIndex>(m, "RoutingDisjunctionIndex");
263
380
 
@@ -271,15 +388,24 @@ void init_routing(Rice::Module& m) {
271
388
  [](operations_research::Solver& self, Object o) {
272
389
  operations_research::Constraint* constraint;
273
390
  if (o.respond_to("left")) {
274
- operations_research::IntExpr* left(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(o.call("left")));
275
- operations_research::IntExpr* right(Rice::detail::From_Ruby<operations_research::IntVar*>().convert(o.call("right")));
276
- auto op = o.call("op").to_s().str();
391
+ auto left = int_expr(self, o.call("left"));
392
+ auto right = int_expr(self, o.call("right"));
393
+ std::string op = o.call("op").to_s().str();
394
+
277
395
  if (op == "==") {
278
396
  constraint = self.MakeEquality(left, right);
397
+ } else if (op == "!=") {
398
+ constraint = self.MakeNonEquality(left, right);
399
+ } else if (op == ">") {
400
+ constraint = self.MakeGreater(left, right);
401
+ } else if (op == ">=") {
402
+ constraint = self.MakeGreaterOrEqual(left, right);
403
+ } else if (op == "<") {
404
+ constraint = self.MakeLess(left, right);
279
405
  } else if (op == "<=") {
280
406
  constraint = self.MakeLessOrEqual(left, right);
281
407
  } else {
282
- throw std::runtime_error("Unknown operator");
408
+ throw std::runtime_error{"Unknown operator"};
283
409
  }
284
410
  } else {
285
411
  constraint = Rice::detail::From_Ruby<operations_research::Constraint*>().convert(o);
@@ -288,12 +414,17 @@ void init_routing(Rice::Module& m) {
288
414
  })
289
415
  .define_method(
290
416
  "fixed_duration_interval_var",
291
- [](operations_research::Solver& self, operations_research::IntVar* const start_variable, int64_t duration, const std::string& name) {
292
- return self.MakeFixedDurationIntervalVar(start_variable, duration, name);
417
+ [](operations_research::Solver& self, operations_research::IntVar& start_variable, int64_t duration, const std::string& name) {
418
+ return self.MakeFixedDurationIntervalVar(&start_variable, duration, name);
419
+ })
420
+ .define_method(
421
+ "fixed_duration_interval_var",
422
+ [](operations_research::Solver& self, int64_t start_min, int64_t start_max, int64_t duration, bool optional, const std::string& name) {
423
+ return self.MakeFixedDurationIntervalVar(start_min, start_max, duration, optional, name);
293
424
  })
294
425
  .define_method(
295
426
  "cumulative",
296
- [](operations_research::Solver& self, Array rb_intervals, std::vector<int64_t> demands, int64_t capacity, const std::string& name) {
427
+ [](operations_research::Solver& self, Array rb_intervals, const std::vector<int64_t>& demands, int64_t capacity, const std::string& name) {
297
428
  std::vector<operations_research::IntervalVar*> intervals;
298
429
  for (const auto& v : rb_intervals) {
299
430
  intervals.push_back(Rice::detail::From_Ruby<operations_research::IntervalVar*>().convert(v.value()));
@@ -302,18 +433,64 @@ void init_routing(Rice::Module& m) {
302
433
  });
303
434
 
304
435
  Rice::define_class_under<ConstraintSolverParameters>(m, "ConstraintSolverParameters")
305
- .define_method(
306
- "trace_propagation=",
307
- [](ConstraintSolverParameters& self, bool value) {
308
- self.set_trace_propagation(value);
309
- })
310
- .define_method(
311
- "trace_search=",
312
- [](ConstraintSolverParameters& self, bool value) {
313
- self.set_trace_search(value);
314
- });
436
+ .define_method("array_split_size", &ConstraintSolverParameters::array_split_size)
437
+ .define_method("array_split_size=", &ConstraintSolverParameters::set_array_split_size)
438
+ .define_method("check_solution_period", &ConstraintSolverParameters::check_solution_period)
439
+ .define_method("check_solution_period=", &ConstraintSolverParameters::set_check_solution_period)
440
+ .define_method("diffn_use_cumulative", &ConstraintSolverParameters::diffn_use_cumulative)
441
+ .define_method("diffn_use_cumulative=", &ConstraintSolverParameters::set_diffn_use_cumulative)
442
+ .define_method("disable_solve", &ConstraintSolverParameters::disable_solve)
443
+ .define_method("disable_solve=", &ConstraintSolverParameters::set_disable_solve)
444
+ .define_method("max_edge_finder_size", &ConstraintSolverParameters::max_edge_finder_size)
445
+ .define_method("max_edge_finder_size=", &ConstraintSolverParameters::set_max_edge_finder_size)
446
+ .define_method("name_all_variables", &ConstraintSolverParameters::name_all_variables)
447
+ .define_method("name_all_variables=", &ConstraintSolverParameters::set_name_all_variables)
448
+ .define_method("name_cast_variables", &ConstraintSolverParameters::name_cast_variables)
449
+ .define_method("name_cast_variables=", &ConstraintSolverParameters::set_name_cast_variables)
450
+ .define_method("print_added_constraints", &ConstraintSolverParameters::print_added_constraints)
451
+ .define_method("print_added_constraints=", &ConstraintSolverParameters::set_print_added_constraints)
452
+ .define_method("print_local_search_profile", &ConstraintSolverParameters::print_local_search_profile)
453
+ .define_method("print_local_search_profile=", &ConstraintSolverParameters::set_print_local_search_profile)
454
+ .define_method("print_model", &ConstraintSolverParameters::print_model)
455
+ .define_method("print_model=", &ConstraintSolverParameters::set_print_model)
456
+ .define_method("print_model_stats", &ConstraintSolverParameters::print_model_stats)
457
+ .define_method("print_model_stats=", &ConstraintSolverParameters::set_print_model_stats)
458
+ .define_method("profile_file", &ConstraintSolverParameters::profile_file)
459
+ // .define_method("profile_file=", &ConstraintSolverParameters::set_profile_file)
460
+ .define_method("profile_local_search", &ConstraintSolverParameters::profile_local_search)
461
+ .define_method("profile_local_search=", &ConstraintSolverParameters::set_profile_local_search)
462
+ .define_method("profile_propagation", &ConstraintSolverParameters::profile_propagation)
463
+ .define_method("profile_propagation=", &ConstraintSolverParameters::set_profile_propagation)
464
+ .define_method("skip_locally_optimal_paths", &ConstraintSolverParameters::skip_locally_optimal_paths)
465
+ .define_method("skip_locally_optimal_paths=", &ConstraintSolverParameters::set_skip_locally_optimal_paths)
466
+ .define_method("store_names", &ConstraintSolverParameters::store_names)
467
+ .define_method("store_names=", &ConstraintSolverParameters::set_store_names)
468
+ .define_method("trace_propagation", &ConstraintSolverParameters::trace_propagation)
469
+ .define_method("trace_propagation=", &ConstraintSolverParameters::set_trace_propagation)
470
+ .define_method("trace_search", &ConstraintSolverParameters::trace_search)
471
+ .define_method("trace_search=", &ConstraintSolverParameters::set_trace_search)
472
+ .define_method("trail_block_size", &ConstraintSolverParameters::trail_block_size)
473
+ .define_method("trail_block_size=", &ConstraintSolverParameters::set_trail_block_size)
474
+ .define_method("use_all_possible_disjunctions", &ConstraintSolverParameters::use_all_possible_disjunctions)
475
+ .define_method("use_all_possible_disjunctions=", &ConstraintSolverParameters::set_use_all_possible_disjunctions)
476
+ .define_method("use_cumulative_edge_finder", &ConstraintSolverParameters::use_cumulative_edge_finder)
477
+ .define_method("use_cumulative_edge_finder=", &ConstraintSolverParameters::set_use_cumulative_edge_finder)
478
+ .define_method("use_cumulative_time_table", &ConstraintSolverParameters::use_cumulative_time_table)
479
+ .define_method("use_cumulative_time_table=", &ConstraintSolverParameters::set_use_cumulative_time_table)
480
+ .define_method("use_cumulative_time_table_sync", &ConstraintSolverParameters::use_cumulative_time_table_sync)
481
+ .define_method("use_cumulative_time_table_sync=", &ConstraintSolverParameters::set_use_cumulative_time_table_sync)
482
+ .define_method("use_element_rmq", &ConstraintSolverParameters::use_element_rmq)
483
+ .define_method("use_element_rmq=", &ConstraintSolverParameters::set_use_element_rmq)
484
+ .define_method("use_sequence_high_demand_tasks", &ConstraintSolverParameters::use_sequence_high_demand_tasks)
485
+ .define_method("use_sequence_high_demand_tasks=", &ConstraintSolverParameters::set_use_sequence_high_demand_tasks)
486
+ .define_method("use_small_table", &ConstraintSolverParameters::use_small_table)
487
+ .define_method("use_small_table=", &ConstraintSolverParameters::set_use_small_table);
315
488
 
316
489
  Rice::define_class_under<RoutingModelParameters>(m, "RoutingModelParameters")
490
+ .define_method("reduce_vehicle_cost_model", &RoutingModelParameters::reduce_vehicle_cost_model)
491
+ .define_method("reduce_vehicle_cost_model=", &RoutingModelParameters::set_reduce_vehicle_cost_model)
492
+ .define_method("max_callback_cache_size", &RoutingModelParameters::max_callback_cache_size)
493
+ .define_method("max_callback_cache_size=", &RoutingModelParameters::set_max_callback_cache_size)
317
494
  .define_method(
318
495
  "solver_parameters",
319
496
  [](RoutingModelParameters& self) {
@@ -332,13 +509,13 @@ void init_routing(Rice::Module& m) {
332
509
  .define_constructor(Rice::Constructor<RoutingModel, RoutingIndexManager, RoutingModelParameters>(), Rice::Arg("_index_manager"), Rice::Arg("_parameters") = operations_research::DefaultRoutingModelParameters())
333
510
  .define_method("register_unary_transit_vector", &RoutingModel::RegisterUnaryTransitVector)
334
511
  .define_method(
335
- "register_unary_transit_callback",
512
+ "_register_unary_transit_callback",
336
513
  [](RoutingModel& self, Object callback) {
337
514
  // TODO guard callback?
338
515
  return self.RegisterUnaryTransitCallback(
339
516
  [callback](int64_t from_index) -> int64_t {
340
517
  if (!ruby_native_thread_p()) {
341
- throw std::runtime_error("Non-Ruby thread");
518
+ throw std::runtime_error{"Non-Ruby thread"};
342
519
  }
343
520
 
344
521
  return Rice::detail::From_Ruby<int64_t>().convert(callback.call("call", from_index));
@@ -347,13 +524,13 @@ void init_routing(Rice::Module& m) {
347
524
  }, Rice::Arg("_callback").keepAlive())
348
525
  .define_method("register_transit_matrix", &RoutingModel::RegisterTransitMatrix)
349
526
  .define_method(
350
- "register_transit_callback",
527
+ "_register_transit_callback",
351
528
  [](RoutingModel& self, Object callback) {
352
529
  // TODO guard callback?
353
530
  return self.RegisterTransitCallback(
354
531
  [callback](int64_t from_index, int64_t to_index) -> int64_t {
355
532
  if (!ruby_native_thread_p()) {
356
- throw std::runtime_error("Non-Ruby thread");
533
+ throw std::runtime_error{"Non-Ruby thread"};
357
534
  }
358
535
 
359
536
  return Rice::detail::From_Ruby<int64_t>().convert(callback.call("call", from_index, to_index));
@@ -386,7 +563,11 @@ void init_routing(Rice::Module& m) {
386
563
  .define_method("perfect_binary_disjunctions", &RoutingModel::GetPerfectBinaryDisjunctions)
387
564
  .define_method("ignore_disjunctions_already_forced_to_zero", &RoutingModel::IgnoreDisjunctionsAlreadyForcedToZero)
388
565
  .define_method("add_soft_same_vehicle_constraint", &RoutingModel::AddSoftSameVehicleConstraint)
389
- .define_method("set_allowed_vehicles_for_index", &RoutingModel::SetAllowedVehiclesForIndex)
566
+ .define_method(
567
+ "set_allowed_vehicles_for_index",
568
+ [](RoutingModel& self, const std::vector<int>& vehicles, int64_t index) {
569
+ self.SetAllowedVehiclesForIndex(vehicles, index);
570
+ })
390
571
  .define_method("vehicle_allowed_for_index?", &RoutingModel::IsVehicleAllowedForIndex)
391
572
  .define_method("add_pickup_and_delivery", &RoutingModel::AddPickupAndDelivery)
392
573
  .define_method("add_pickup_and_delivery_sets", &RoutingModel::AddPickupAndDeliverySets)
@@ -426,14 +607,26 @@ void init_routing(Rice::Module& m) {
426
607
  .define_method("close_model", &RoutingModel::CloseModel)
427
608
  // solve defined in Ruby
428
609
  .define_method(
429
- "solve_with_parameters",
430
- [](RoutingModel& self, const RoutingSearchParameters& search_parameters) {
431
- return self.SolveWithParameters(search_parameters);
610
+ "_solve_with_parameters",
611
+ [](RoutingModel& self, const RoutingSearchParameters& search_parameters, bool release_gvl) {
612
+ if (release_gvl) {
613
+ return Rice::detail::no_gvl([&]() {
614
+ return self.SolveWithParameters(search_parameters);
615
+ });
616
+ } else {
617
+ return self.SolveWithParameters(search_parameters);
618
+ }
432
619
  })
433
620
  .define_method(
434
- "solve_from_assignment_with_parameters",
435
- [](RoutingModel& self, const Assignment* assignment, const RoutingSearchParameters& search_parameters) {
436
- return self.SolveFromAssignmentWithParameters(assignment, search_parameters);
621
+ "_solve_from_assignment_with_parameters",
622
+ [](RoutingModel& self, const Assignment& assignment, const RoutingSearchParameters& search_parameters, bool release_gvl) {
623
+ if (release_gvl) {
624
+ return Rice::detail::no_gvl([&]() {
625
+ return self.SolveFromAssignmentWithParameters(&assignment, search_parameters);
626
+ });
627
+ } else {
628
+ return self.SolveFromAssignmentWithParameters(&assignment, search_parameters);
629
+ }
437
630
  })
438
631
  .define_method("compute_lower_bound", &RoutingModel::ComputeLowerBound)
439
632
  .define_method("status",
@@ -451,17 +644,31 @@ void init_routing(Rice::Module& m) {
451
644
  } else if (status == RoutingSearchStatus::ROUTING_INVALID) {
452
645
  return Symbol("invalid");
453
646
  } else {
454
- throw std::runtime_error("Unknown solver status");
647
+ throw std::runtime_error{"Unknown solver status"};
455
648
  }
456
649
  })
457
- .define_method("apply_locks", &RoutingModel::ApplyLocks)
650
+ .define_method(
651
+ "apply_locks",
652
+ [](RoutingModel& self, const std::vector<int64_t>& locks) {
653
+ return self.ApplyLocks(locks);
654
+ })
458
655
  .define_method("apply_locks_to_all_vehicles", &RoutingModel::ApplyLocksToAllVehicles)
459
656
  .define_method("pre_assignment", &RoutingModel::PreAssignment)
460
657
  .define_method("mutable_pre_assignment", &RoutingModel::MutablePreAssignment)
461
658
  .define_method("write_assignment", &RoutingModel::WriteAssignment)
462
659
  .define_method("read_assignment", &RoutingModel::ReadAssignment)
463
660
  .define_method("restore_assignment", &RoutingModel::RestoreAssignment)
464
- .define_method("read_assignment_from_routes", &RoutingModel::ReadAssignmentFromRoutes)
661
+ .define_method(
662
+ "_read_assignment_from_routes",
663
+ [](RoutingModel& self, const std::vector<std::vector<int64_t>>& routes, bool ignore_inactive_indices, bool release_gvl) {
664
+ if (release_gvl) {
665
+ return Rice::detail::no_gvl([&]() {
666
+ return self.ReadAssignmentFromRoutes(routes, ignore_inactive_indices);
667
+ });
668
+ } else {
669
+ return self.ReadAssignmentFromRoutes(routes, ignore_inactive_indices);
670
+ }
671
+ })
465
672
  .define_method("routes_to_assignment", &RoutingModel::RoutesToAssignment)
466
673
  .define_method("assignment_to_routes", &RoutingModel::AssignmentToRoutes)
467
674
  .define_method("compact_assignment", &RoutingModel::CompactAssignment)
@@ -1,6 +1,6 @@
1
1
  require "digest"
2
2
  require "fileutils"
3
- require "net/http"
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
- tar_args = Gem.win_platform? ? ["--force-local"] : []
128
- system "tar", "zxf", download_path, "-C", extract_path, "--strip-components=1", *tar_args
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"))
@@ -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
@@ -16,5 +16,9 @@ module ORTools
16
16
  def objective_value
17
17
  @response&.objective_value
18
18
  end
19
+
20
+ def stop_search
21
+ @stopped = true
22
+ end
19
23
  end
20
24
  end
@@ -21,5 +21,27 @@ 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 read_assignment_from_routes(routes, ignore_inactive_indices)
34
+ _read_assignment_from_routes(routes, ignore_inactive_indices, !@ruby_callback)
35
+ end
36
+
37
+ def register_unary_transit_callback(callback)
38
+ @ruby_callback = true
39
+ _register_unary_transit_callback(callback)
40
+ end
41
+
42
+ def register_transit_callback(callback)
43
+ @ruby_callback = true
44
+ _register_transit_callback(callback)
45
+ end
24
46
  end
25
47
  end