or-tools 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,212 @@
1
+ #include <ortools/linear_solver/linear_solver.h>
2
+
3
+ #include <rice/Array.hpp>
4
+ #include <rice/Class.hpp>
5
+ #include <rice/Constructor.hpp>
6
+ #include <rice/Module.hpp>
7
+ #include <rice/String.hpp>
8
+ #include <rice/Symbol.hpp>
9
+
10
+ using operations_research::LinearExpr;
11
+ using operations_research::LinearRange;
12
+ using operations_research::MPConstraint;
13
+ using operations_research::MPObjective;
14
+ using operations_research::MPSolver;
15
+ using operations_research::MPVariable;
16
+
17
+ using Rice::Array;
18
+ using Rice::Class;
19
+ using Rice::Module;
20
+ using Rice::Object;
21
+ using Rice::String;
22
+ using Rice::Symbol;
23
+
24
+ template<>
25
+ inline
26
+ MPSolver::OptimizationProblemType from_ruby<MPSolver::OptimizationProblemType>(Object x)
27
+ {
28
+ std::string s = Symbol(x).str();
29
+ if (s == "glop") {
30
+ return MPSolver::OptimizationProblemType::GLOP_LINEAR_PROGRAMMING;
31
+ } else if (s == "cbc") {
32
+ return MPSolver::OptimizationProblemType::CBC_MIXED_INTEGER_PROGRAMMING;
33
+ } else {
34
+ throw std::runtime_error("Unknown optimization problem type: " + s);
35
+ }
36
+ }
37
+
38
+ Class rb_cMPVariable;
39
+ Class rb_cMPConstraint;
40
+ Class rb_cMPObjective;
41
+
42
+ template<>
43
+ inline
44
+ Object to_ruby<MPVariable*>(MPVariable* const &x)
45
+ {
46
+ return Rice::Data_Object<MPVariable>(x, rb_cMPVariable, nullptr, nullptr);
47
+ }
48
+
49
+ template<>
50
+ inline
51
+ Object to_ruby<MPConstraint*>(MPConstraint* const &x)
52
+ {
53
+ return Rice::Data_Object<MPConstraint>(x, rb_cMPConstraint, nullptr, nullptr);
54
+ }
55
+
56
+ template<>
57
+ inline
58
+ Object to_ruby<MPObjective*>(MPObjective* const &x)
59
+ {
60
+ return Rice::Data_Object<MPObjective>(x, rb_cMPObjective, nullptr, nullptr);
61
+ }
62
+
63
+ void init_linear(Rice::Module& m) {
64
+ rb_cMPVariable = Rice::define_class_under<MPVariable>(m, "MPVariable")
65
+ .define_method("name", &MPVariable::name)
66
+ .define_method("solution_value", &MPVariable::solution_value)
67
+ .define_method(
68
+ "+",
69
+ *[](MPVariable& self, LinearExpr& other) {
70
+ LinearExpr s(&self);
71
+ return s + other;
72
+ })
73
+ .define_method(
74
+ "-",
75
+ *[](MPVariable& self, LinearExpr& other) {
76
+ LinearExpr s(&self);
77
+ return s - other;
78
+ })
79
+ .define_method(
80
+ "*",
81
+ *[](MPVariable& self, double other) {
82
+ LinearExpr s(&self);
83
+ return s * other;
84
+ })
85
+ .define_method(
86
+ "inspect",
87
+ *[](MPVariable& self) {
88
+ return "#<ORTools::MPVariable @name=\"" + self.name() + "\">";
89
+ });
90
+
91
+ Rice::define_class_under<LinearExpr>(m, "LinearExpr")
92
+ .define_constructor(Rice::Constructor<LinearExpr>())
93
+ .define_method(
94
+ "_add_linear_expr",
95
+ *[](LinearExpr& self, LinearExpr& other) {
96
+ return self + other;
97
+ })
98
+ .define_method(
99
+ "_add_mp_variable",
100
+ *[](LinearExpr& self, MPVariable &other) {
101
+ LinearExpr o(&other);
102
+ return self + o;
103
+ })
104
+ .define_method(
105
+ "_gte_double",
106
+ *[](LinearExpr& self, double other) {
107
+ LinearExpr o(other);
108
+ return self >= o;
109
+ })
110
+ .define_method(
111
+ "_gte_linear_expr",
112
+ *[](LinearExpr& self, LinearExpr& other) {
113
+ return self >= other;
114
+ })
115
+ .define_method(
116
+ "_lte_double",
117
+ *[](LinearExpr& self, double other) {
118
+ LinearExpr o(other);
119
+ return self <= o;
120
+ })
121
+ .define_method(
122
+ "_lte_linear_expr",
123
+ *[](LinearExpr& self, LinearExpr& other) {
124
+ return self <= other;
125
+ })
126
+ .define_method(
127
+ "==",
128
+ *[](LinearExpr& self, double other) {
129
+ LinearExpr o(other);
130
+ return self == o;
131
+ })
132
+ .define_method(
133
+ "to_s",
134
+ *[](LinearExpr& self) {
135
+ return self.ToString();
136
+ })
137
+ .define_method(
138
+ "inspect",
139
+ *[](LinearExpr& self) {
140
+ return "#<ORTools::LinearExpr \"" + self.ToString() + "\">";
141
+ });
142
+
143
+ Rice::define_class_under<LinearRange>(m, "LinearRange");
144
+
145
+ rb_cMPConstraint = Rice::define_class_under<MPConstraint>(m, "MPConstraint")
146
+ .define_method("set_coefficient", &MPConstraint::SetCoefficient);
147
+
148
+ rb_cMPObjective = Rice::define_class_under<MPObjective>(m, "MPObjective")
149
+ .define_method("value", &MPObjective::Value)
150
+ .define_method("set_coefficient", &MPObjective::SetCoefficient)
151
+ .define_method("set_maximization", &MPObjective::SetMaximization);
152
+
153
+ Rice::define_class_under<MPSolver>(m, "Solver")
154
+ .define_constructor(Rice::Constructor<MPSolver, std::string, MPSolver::OptimizationProblemType>())
155
+ .define_method("infinity", &MPSolver::infinity)
156
+ .define_method(
157
+ "int_var",
158
+ *[](MPSolver& self, double min, double max, const std::string& name) {
159
+ return self.MakeIntVar(min, max, name);
160
+ })
161
+ .define_method("num_var", &MPSolver::MakeNumVar)
162
+ .define_method("bool_var", &MPSolver::MakeBoolVar)
163
+ .define_method("num_variables", &MPSolver::NumVariables)
164
+ .define_method("num_constraints", &MPSolver::NumConstraints)
165
+ .define_method("wall_time", &MPSolver::wall_time)
166
+ .define_method("iterations", &MPSolver::iterations)
167
+ .define_method("nodes", &MPSolver::nodes)
168
+ .define_method("objective", &MPSolver::MutableObjective)
169
+ .define_method(
170
+ "maximize",
171
+ *[](MPSolver& self, LinearExpr& expr) {
172
+ return self.MutableObjective()->MaximizeLinearExpr(expr);
173
+ })
174
+ .define_method(
175
+ "minimize",
176
+ *[](MPSolver& self, LinearExpr& expr) {
177
+ return self.MutableObjective()->MinimizeLinearExpr(expr);
178
+ })
179
+ .define_method(
180
+ "add",
181
+ *[](MPSolver& self, const LinearRange& range) {
182
+ return self.MakeRowConstraint(range);
183
+ })
184
+ .define_method(
185
+ "constraint",
186
+ *[](MPSolver& self, double lb, double ub) {
187
+ return self.MakeRowConstraint(lb, ub);
188
+ })
189
+ .define_method(
190
+ "solve",
191
+ *[](MPSolver& self) {
192
+ auto status = self.Solve();
193
+
194
+ if (status == MPSolver::ResultStatus::OPTIMAL) {
195
+ return Symbol("optimal");
196
+ } else if (status == MPSolver::ResultStatus::FEASIBLE) {
197
+ return Symbol("feasible");
198
+ } else if (status == MPSolver::ResultStatus::INFEASIBLE) {
199
+ return Symbol("infeasible");
200
+ } else if (status == MPSolver::ResultStatus::UNBOUNDED) {
201
+ return Symbol("unbounded");
202
+ } else if (status == MPSolver::ResultStatus::ABNORMAL) {
203
+ return Symbol("abnormal");
204
+ } else if (status == MPSolver::ResultStatus::MODEL_INVALID) {
205
+ return Symbol("model_invalid");
206
+ } else if (status == MPSolver::ResultStatus::NOT_SOLVED) {
207
+ return Symbol("not_solved");
208
+ } else {
209
+ throw std::runtime_error("Unknown status");
210
+ }
211
+ });
212
+ }
@@ -0,0 +1,105 @@
1
+ #include <ortools/graph/max_flow.h>
2
+ #include <ortools/graph/min_cost_flow.h>
3
+
4
+ #include <rice/Array.hpp>
5
+ #include <rice/Constructor.hpp>
6
+ #include <rice/Module.hpp>
7
+
8
+ using operations_research::NodeIndex;
9
+ using operations_research::SimpleMaxFlow;
10
+ using operations_research::SimpleMinCostFlow;
11
+
12
+ using Rice::Array;
13
+ using Rice::Symbol;
14
+
15
+ void init_network_flows(Rice::Module& m) {
16
+ Rice::define_class_under<SimpleMaxFlow>(m, "SimpleMaxFlow")
17
+ .define_constructor(Rice::Constructor<SimpleMaxFlow>())
18
+ .define_method("add_arc_with_capacity", &SimpleMaxFlow::AddArcWithCapacity)
19
+ .define_method("num_nodes", &SimpleMaxFlow::NumNodes)
20
+ .define_method("num_arcs", &SimpleMaxFlow::NumArcs)
21
+ .define_method("tail", &SimpleMaxFlow::Tail)
22
+ .define_method("head", &SimpleMaxFlow::Head)
23
+ .define_method("capacity", &SimpleMaxFlow::Capacity)
24
+ .define_method("optimal_flow", &SimpleMaxFlow::OptimalFlow)
25
+ .define_method("flow", &SimpleMaxFlow::Flow)
26
+ .define_method(
27
+ "solve",
28
+ *[](SimpleMaxFlow& self, NodeIndex source, NodeIndex sink) {
29
+ auto status = self.Solve(source, sink);
30
+
31
+ if (status == SimpleMaxFlow::Status::OPTIMAL) {
32
+ return Symbol("optimal");
33
+ } else if (status == SimpleMaxFlow::Status::POSSIBLE_OVERFLOW) {
34
+ return Symbol("possible_overflow");
35
+ } else if (status == SimpleMaxFlow::Status::BAD_INPUT) {
36
+ return Symbol("bad_input");
37
+ } else if (status == SimpleMaxFlow::Status::BAD_RESULT) {
38
+ return Symbol("bad_result");
39
+ } else {
40
+ throw std::runtime_error("Unknown status");
41
+ }
42
+ })
43
+ .define_method(
44
+ "source_side_min_cut",
45
+ *[](SimpleMaxFlow& self) {
46
+ std::vector<NodeIndex> result;
47
+ self.GetSourceSideMinCut(&result);
48
+
49
+ Array ret;
50
+ for(auto const& it: result) {
51
+ ret.push(it);
52
+ }
53
+ return ret;
54
+ })
55
+ .define_method(
56
+ "sink_side_min_cut",
57
+ *[](SimpleMaxFlow& self) {
58
+ std::vector<NodeIndex> result;
59
+ self.GetSinkSideMinCut(&result);
60
+
61
+ Array ret;
62
+ for(auto const& it: result) {
63
+ ret.push(it);
64
+ }
65
+ return ret;
66
+ });
67
+
68
+ Rice::define_class_under<SimpleMinCostFlow>(m, "SimpleMinCostFlow")
69
+ .define_constructor(Rice::Constructor<SimpleMinCostFlow>())
70
+ .define_method("add_arc_with_capacity_and_unit_cost", &SimpleMinCostFlow::AddArcWithCapacityAndUnitCost)
71
+ .define_method("set_node_supply", &SimpleMinCostFlow::SetNodeSupply)
72
+ .define_method("optimal_cost", &SimpleMinCostFlow::OptimalCost)
73
+ .define_method("maximum_flow", &SimpleMinCostFlow::MaximumFlow)
74
+ .define_method("flow", &SimpleMinCostFlow::Flow)
75
+ .define_method("num_nodes", &SimpleMinCostFlow::NumNodes)
76
+ .define_method("num_arcs", &SimpleMinCostFlow::NumArcs)
77
+ .define_method("tail", &SimpleMinCostFlow::Tail)
78
+ .define_method("head", &SimpleMinCostFlow::Head)
79
+ .define_method("capacity", &SimpleMinCostFlow::Capacity)
80
+ .define_method("supply", &SimpleMinCostFlow::Supply)
81
+ .define_method("unit_cost", &SimpleMinCostFlow::UnitCost)
82
+ .define_method(
83
+ "solve",
84
+ *[](SimpleMinCostFlow& self) {
85
+ auto status = self.Solve();
86
+
87
+ if (status == SimpleMinCostFlow::Status::NOT_SOLVED) {
88
+ return Symbol("not_solved");
89
+ } else if (status == SimpleMinCostFlow::Status::OPTIMAL) {
90
+ return Symbol("optimal");
91
+ } else if (status == SimpleMinCostFlow::Status::FEASIBLE) {
92
+ return Symbol("feasible");
93
+ } else if (status == SimpleMinCostFlow::Status::INFEASIBLE) {
94
+ return Symbol("infeasible");
95
+ } else if (status == SimpleMinCostFlow::Status::UNBALANCED) {
96
+ return Symbol("unbalanced");
97
+ } else if (status == SimpleMinCostFlow::Status::BAD_RESULT) {
98
+ return Symbol("bad_result");
99
+ } else if (status == SimpleMinCostFlow::Status::BAD_COST_RANGE) {
100
+ return Symbol("bad_cost_range");
101
+ } else {
102
+ throw std::runtime_error("Unknown status");
103
+ }
104
+ });
105
+ }
@@ -0,0 +1,368 @@
1
+ #include <ortools/constraint_solver/routing.h>
2
+ #include <ortools/constraint_solver/routing_parameters.h>
3
+
4
+ #include <rice/Array.hpp>
5
+ #include <rice/Class.hpp>
6
+ #include <rice/Constructor.hpp>
7
+ #include <rice/Module.hpp>
8
+ #include <rice/String.hpp>
9
+ #include <rice/Symbol.hpp>
10
+
11
+ using operations_research::DefaultRoutingSearchParameters;
12
+ using operations_research::FirstSolutionStrategy;
13
+ using operations_research::LocalSearchMetaheuristic;
14
+ using operations_research::RoutingDimension;
15
+ using operations_research::RoutingIndexManager;
16
+ using operations_research::RoutingModel;
17
+ using operations_research::RoutingNodeIndex;
18
+ using operations_research::RoutingSearchParameters;
19
+
20
+ using Rice::Array;
21
+ using Rice::Class;
22
+ using Rice::Module;
23
+ using Rice::Object;
24
+ using Rice::String;
25
+ using Rice::Symbol;
26
+
27
+ template<>
28
+ inline
29
+ RoutingNodeIndex from_ruby<RoutingNodeIndex>(Object x)
30
+ {
31
+ const RoutingNodeIndex index{from_ruby<int>(x)};
32
+ return index;
33
+ }
34
+
35
+ template<>
36
+ inline
37
+ Object to_ruby<RoutingNodeIndex>(RoutingNodeIndex const &x)
38
+ {
39
+ return to_ruby<int>(x.value());
40
+ }
41
+
42
+ std::vector<RoutingNodeIndex> nodeIndexVector(Array x) {
43
+ std::vector<RoutingNodeIndex> res;
44
+ for (auto const& v : x) {
45
+ res.push_back(from_ruby<RoutingNodeIndex>(v));
46
+ }
47
+ return res;
48
+ }
49
+
50
+ // need a wrapper class due to const
51
+ class Assignment {
52
+ const operations_research::Assignment* self;
53
+ public:
54
+ Assignment(const operations_research::Assignment* v) {
55
+ self = v;
56
+ }
57
+ int64 ObjectiveValue() {
58
+ return self->ObjectiveValue();
59
+ }
60
+ int64 Value(const operations_research::IntVar* const var) const {
61
+ return self->Value(var);
62
+ }
63
+ int64 Min(const operations_research::IntVar* const var) const {
64
+ return self->Min(var);
65
+ }
66
+ int64 Max(const operations_research::IntVar* const var) const {
67
+ return self->Max(var);
68
+ }
69
+ };
70
+
71
+ Class rb_cIntVar;
72
+ Class rb_cIntervalVar;
73
+ Class rb_cRoutingDimension;
74
+ Class rb_cConstraint;
75
+ Class rb_cSolver2;
76
+
77
+ template<>
78
+ inline
79
+ Object to_ruby<operations_research::IntVar*>(operations_research::IntVar* const &x)
80
+ {
81
+ return Rice::Data_Object<operations_research::IntVar>(x, rb_cIntVar, nullptr, nullptr);
82
+ }
83
+
84
+ template<>
85
+ inline
86
+ Object to_ruby<operations_research::IntervalVar*>(operations_research::IntervalVar* const &x)
87
+ {
88
+ return Rice::Data_Object<operations_research::IntervalVar>(x, rb_cIntervalVar, nullptr, nullptr);
89
+ }
90
+
91
+ template<>
92
+ inline
93
+ Object to_ruby<RoutingDimension*>(RoutingDimension* const &x)
94
+ {
95
+ return Rice::Data_Object<RoutingDimension>(x, rb_cRoutingDimension, nullptr, nullptr);
96
+ }
97
+
98
+ template<>
99
+ inline
100
+ Object to_ruby<operations_research::Constraint*>(operations_research::Constraint* const &x)
101
+ {
102
+ return Rice::Data_Object<operations_research::Constraint>(x, rb_cConstraint, nullptr, nullptr);
103
+ }
104
+
105
+ template<>
106
+ inline
107
+ Object to_ruby<operations_research::Solver*>(operations_research::Solver* const &x)
108
+ {
109
+ return Rice::Data_Object<operations_research::Solver>(x, rb_cSolver2, nullptr, nullptr);
110
+ }
111
+
112
+ void init_routing(Rice::Module& m) {
113
+ m.define_singleton_method("default_routing_search_parameters", &DefaultRoutingSearchParameters);
114
+
115
+ Rice::define_class_under<RoutingSearchParameters>(m, "RoutingSearchParameters")
116
+ .define_method(
117
+ "first_solution_strategy=",
118
+ *[](RoutingSearchParameters& self, Symbol value) {
119
+ std::string s = Symbol(value).str();
120
+
121
+ FirstSolutionStrategy::Value v;
122
+ if (s == "path_cheapest_arc") {
123
+ v = FirstSolutionStrategy::PATH_CHEAPEST_ARC;
124
+ } else if (s == "path_most_constrained_arc") {
125
+ v = FirstSolutionStrategy::PATH_MOST_CONSTRAINED_ARC;
126
+ } else if (s == "evaluator_strategy") {
127
+ v = FirstSolutionStrategy::EVALUATOR_STRATEGY;
128
+ } else if (s == "savings") {
129
+ v = FirstSolutionStrategy::SAVINGS;
130
+ } else if (s == "sweep") {
131
+ v = FirstSolutionStrategy::SWEEP;
132
+ } else if (s == "christofides") {
133
+ v = FirstSolutionStrategy::CHRISTOFIDES;
134
+ } else if (s == "all_unperformed") {
135
+ v = FirstSolutionStrategy::ALL_UNPERFORMED;
136
+ } else if (s == "best_insertion") {
137
+ v = FirstSolutionStrategy::BEST_INSERTION;
138
+ } else if (s == "parallel_cheapest_insertion") {
139
+ v = FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION;
140
+ } else if (s == "sequential_cheapest_insertion") {
141
+ v = FirstSolutionStrategy::SEQUENTIAL_CHEAPEST_INSERTION;
142
+ } else if (s == "local_cheapest_insertion") {
143
+ v = FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION;
144
+ } else if (s == "global_cheapest_arc") {
145
+ v = FirstSolutionStrategy::GLOBAL_CHEAPEST_ARC;
146
+ } else if (s == "local_cheapest_arc") {
147
+ v = FirstSolutionStrategy::LOCAL_CHEAPEST_ARC;
148
+ } else if (s == "first_unbound_min_value") {
149
+ v = FirstSolutionStrategy::FIRST_UNBOUND_MIN_VALUE;
150
+ } else {
151
+ throw std::runtime_error("Unknown first solution strategy: " + s);
152
+ }
153
+
154
+ return self.set_first_solution_strategy(v);
155
+ })
156
+ .define_method(
157
+ "local_search_metaheuristic=",
158
+ *[](RoutingSearchParameters& self, Symbol value) {
159
+ std::string s = Symbol(value).str();
160
+
161
+ LocalSearchMetaheuristic::Value v;
162
+ if (s == "guided_local_search") {
163
+ v = LocalSearchMetaheuristic::GUIDED_LOCAL_SEARCH;
164
+ } else if (s == "tabu_search") {
165
+ v = LocalSearchMetaheuristic::TABU_SEARCH;
166
+ } else if (s == "generic_tabu_search") {
167
+ v = LocalSearchMetaheuristic::GENERIC_TABU_SEARCH;
168
+ } else if (s == "simulated_annealing") {
169
+ v = LocalSearchMetaheuristic::SIMULATED_ANNEALING;
170
+ } else {
171
+ throw std::runtime_error("Unknown local search metaheuristic: " + s);
172
+ }
173
+
174
+ return self.set_local_search_metaheuristic(v);
175
+ })
176
+ .define_method(
177
+ "log_search=",
178
+ *[](RoutingSearchParameters& self, bool value) {
179
+ self.set_log_search(value);
180
+ })
181
+ .define_method(
182
+ "solution_limit=",
183
+ *[](RoutingSearchParameters& self, int64 value) {
184
+ self.set_solution_limit(value);
185
+ })
186
+ .define_method(
187
+ "time_limit=",
188
+ *[](RoutingSearchParameters& self, int64 value) {
189
+ self.mutable_time_limit()->set_seconds(value);
190
+ })
191
+ .define_method(
192
+ "lns_time_limit=",
193
+ *[](RoutingSearchParameters& self, int64 value) {
194
+ self.mutable_lns_time_limit()->set_seconds(value);
195
+ });
196
+
197
+ Rice::define_class_under<RoutingIndexManager>(m, "RoutingIndexManager")
198
+ .define_singleton_method(
199
+ "_new_depot",
200
+ *[](int num_nodes, int num_vehicles, RoutingNodeIndex depot) {
201
+ return RoutingIndexManager(num_nodes, num_vehicles, depot);
202
+ })
203
+ .define_singleton_method(
204
+ "_new_starts_ends",
205
+ *[](int num_nodes, int num_vehicles, Array starts, Array ends) {
206
+ return RoutingIndexManager(num_nodes, num_vehicles, nodeIndexVector(starts), nodeIndexVector(ends));
207
+ })
208
+ .define_method("index_to_node", &RoutingIndexManager::IndexToNode)
209
+ .define_method("node_to_index", &RoutingIndexManager::NodeToIndex);
210
+
211
+ Rice::define_class_under<Assignment>(m, "Assignment")
212
+ .define_method("objective_value", &Assignment::ObjectiveValue)
213
+ .define_method("value", &Assignment::Value)
214
+ .define_method("min", &Assignment::Min)
215
+ .define_method("max", &Assignment::Max);
216
+
217
+ // not to be confused with operations_research::sat::IntVar
218
+ rb_cIntVar = Rice::define_class_under<operations_research::IntVar>(m, "IntVar")
219
+ .define_method(
220
+ "set_range",
221
+ *[](operations_research::IntVar& self, int64 new_min, int64 new_max) {
222
+ self.SetRange(new_min, new_max);
223
+ });
224
+
225
+ rb_cIntervalVar = Rice::define_class_under<operations_research::IntervalVar>(m, "IntervalVar");
226
+
227
+ rb_cRoutingDimension = Rice::define_class_under<RoutingDimension>(m, "RoutingDimension")
228
+ .define_method("global_span_cost_coefficient=", &RoutingDimension::SetGlobalSpanCostCoefficient)
229
+ .define_method("cumul_var", &RoutingDimension::CumulVar);
230
+
231
+ rb_cConstraint = Rice::define_class_under<operations_research::Constraint>(m, "Constraint");
232
+
233
+ rb_cSolver2 = Rice::define_class_under<operations_research::Solver>(m, "Solver2")
234
+ .define_method(
235
+ "add",
236
+ *[](operations_research::Solver& self, Object o) {
237
+ operations_research::Constraint* constraint;
238
+ if (o.respond_to("left")) {
239
+ operations_research::IntExpr* left(from_ruby<operations_research::IntVar*>(o.call("left")));
240
+ operations_research::IntExpr* right(from_ruby<operations_research::IntVar*>(o.call("right")));
241
+ auto op = o.call("operator").to_s().str();
242
+ if (op == "==") {
243
+ constraint = self.MakeEquality(left, right);
244
+ } else if (op == "<=") {
245
+ constraint = self.MakeLessOrEqual(left, right);
246
+ } else {
247
+ throw std::runtime_error("Unknown operator");
248
+ }
249
+ } else {
250
+ constraint = from_ruby<operations_research::Constraint*>(o);
251
+ }
252
+ self.AddConstraint(constraint);
253
+ })
254
+ .define_method(
255
+ "fixed_duration_interval_var",
256
+ *[](operations_research::Solver& self, operations_research::IntVar* const start_variable, int64 duration, const std::string& name) {
257
+ return self.MakeFixedDurationIntervalVar(start_variable, duration, name);
258
+ })
259
+ .define_method(
260
+ "cumulative",
261
+ *[](operations_research::Solver& self, Array rb_intervals, Array rb_demands, int64 capacity, const std::string& name) {
262
+ std::vector<operations_research::IntervalVar*> intervals;
263
+ for (std::size_t i = 0; i < rb_intervals.size(); ++i) {
264
+ intervals.push_back(from_ruby<operations_research::IntervalVar*>(rb_intervals[i]));
265
+ }
266
+
267
+ std::vector<int64> demands;
268
+ for (std::size_t i = 0; i < rb_demands.size(); ++i) {
269
+ demands.push_back(from_ruby<int64>(rb_demands[i]));
270
+ }
271
+
272
+ return self.MakeCumulative(intervals, demands, capacity, name);
273
+ });
274
+
275
+ Rice::define_class_under<RoutingModel>(m, "RoutingModel")
276
+ .define_constructor(Rice::Constructor<RoutingModel, RoutingIndexManager>())
277
+ .define_method(
278
+ "register_transit_callback",
279
+ *[](RoutingModel& self, Object callback) {
280
+ return self.RegisterTransitCallback(
281
+ [callback](int64 from_index, int64 to_index) -> int64 {
282
+ return from_ruby<int64>(callback.call("call", from_index, to_index));
283
+ }
284
+ );
285
+ })
286
+ .define_method(
287
+ "register_unary_transit_callback",
288
+ *[](RoutingModel& self, Object callback) {
289
+ return self.RegisterUnaryTransitCallback(
290
+ [callback](int64 from_index) -> int64 {
291
+ return from_ruby<int64>(callback.call("call", from_index));
292
+ }
293
+ );
294
+ })
295
+ .define_method("depot", &RoutingModel::GetDepot)
296
+ .define_method("size", &RoutingModel::Size)
297
+ .define_method("status", *[](RoutingModel& self) {
298
+ auto status = self.status();
299
+
300
+ if (status == RoutingModel::ROUTING_NOT_SOLVED) {
301
+ return Symbol("not_solved");
302
+ } else if (status == RoutingModel::ROUTING_SUCCESS) {
303
+ return Symbol("success");
304
+ } else if (status == RoutingModel::ROUTING_FAIL) {
305
+ return Symbol("fail");
306
+ } else if (status == RoutingModel::ROUTING_FAIL_TIMEOUT) {
307
+ return Symbol("fail_timeout");
308
+ } else if (status == RoutingModel::ROUTING_INVALID) {
309
+ return Symbol("invalid");
310
+ } else {
311
+ throw std::runtime_error("Unknown solver status");
312
+ }
313
+ })
314
+ .define_method("vehicle_var", &RoutingModel::VehicleVar)
315
+ .define_method("set_arc_cost_evaluator_of_all_vehicles", &RoutingModel::SetArcCostEvaluatorOfAllVehicles)
316
+ .define_method("set_arc_cost_evaluator_of_vehicle", &RoutingModel::SetArcCostEvaluatorOfVehicle)
317
+ .define_method("set_fixed_cost_of_all_vehicles", &RoutingModel::SetFixedCostOfAllVehicles)
318
+ .define_method("set_fixed_cost_of_vehicle", &RoutingModel::SetFixedCostOfVehicle)
319
+ .define_method("fixed_cost_of_vehicle", &RoutingModel::GetFixedCostOfVehicle)
320
+ .define_method("add_dimension", &RoutingModel::AddDimension)
321
+ .define_method(
322
+ "add_dimension_with_vehicle_capacity",
323
+ *[](RoutingModel& self, int evaluator_index, int64 slack_max, Array vc, bool fix_start_cumul_to_zero, const std::string& name) {
324
+ std::vector<int64> vehicle_capacities;
325
+ for (std::size_t i = 0; i < vc.size(); ++i) {
326
+ vehicle_capacities.push_back(from_ruby<int64>(vc[i]));
327
+ }
328
+ self.AddDimensionWithVehicleCapacity(evaluator_index, slack_max, vehicle_capacities, fix_start_cumul_to_zero, name);
329
+ })
330
+ .define_method(
331
+ "add_dimension_with_vehicle_transits",
332
+ *[](RoutingModel& self, Array rb_indices, int64 slack_max, int64 capacity, bool fix_start_cumul_to_zero, const std::string& name) {
333
+ std::vector<int> evaluator_indices;
334
+ for (std::size_t i = 0; i < rb_indices.size(); ++i) {
335
+ evaluator_indices.push_back(from_ruby<int>(rb_indices[i]));
336
+ }
337
+ self.AddDimensionWithVehicleTransits(evaluator_indices, slack_max, capacity, fix_start_cumul_to_zero, name);
338
+ })
339
+ .define_method(
340
+ "add_disjunction",
341
+ *[](RoutingModel& self, Array rb_indices, int64 penalty) {
342
+ std::vector<int64> indices;
343
+ for (std::size_t i = 0; i < rb_indices.size(); ++i) {
344
+ indices.push_back(from_ruby<int64>(rb_indices[i]));
345
+ }
346
+ self.AddDisjunction(indices, penalty);
347
+ })
348
+ .define_method("add_pickup_and_delivery", &RoutingModel::AddPickupAndDelivery)
349
+ .define_method("solver", &RoutingModel::solver)
350
+ .define_method("start", &RoutingModel::Start)
351
+ .define_method("end", &RoutingModel::End)
352
+ .define_method("start?", &RoutingModel::IsStart)
353
+ .define_method("end?", &RoutingModel::IsEnd)
354
+ .define_method("vehicle_index", &RoutingModel::VehicleIndex)
355
+ .define_method("next", &RoutingModel::Next)
356
+ .define_method("vehicle_used?", &RoutingModel::IsVehicleUsed)
357
+ .define_method("next_var", &RoutingModel::NextVar)
358
+ .define_method("arc_cost_for_vehicle", &RoutingModel::GetArcCostForVehicle)
359
+ .define_method("mutable_dimension", &RoutingModel::GetMutableDimension)
360
+ .define_method("add_variable_minimized_by_finalizer", &RoutingModel::AddVariableMinimizedByFinalizer)
361
+ .define_method(
362
+ "solve_with_parameters",
363
+ *[](RoutingModel& self, const RoutingSearchParameters& search_parameters) {
364
+ auto assignment = self.SolveWithParameters(search_parameters);
365
+ // std::cout << assignment->DebugString();
366
+ return (Assignment) assignment;
367
+ });
368
+ }