Skip to content

Commit c869dd1

Browse files
committed
routing: Improve pybind11 binding
1 parent e284ae4 commit c869dd1

File tree

5 files changed

+785
-31
lines changed

5 files changed

+785
-31
lines changed

cmake/python.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ add_custom_command(
540540
COMMAND ${stubgen_EXECUTABLE} -p ortools.math_opt.core.python.solver --output .
541541
COMMAND ${stubgen_EXECUTABLE} -p ortools.pdlp.python.pdlp --output .
542542
COMMAND ${stubgen_EXECUTABLE} -p ortools.routing.pywraprouting --output .
543-
COMMAND ${stubgen_EXECUTABLE} -p ortools.routing.python.routing --output .
543+
COMMAND ${stubgen_EXECUTABLE} -p ortools.routing.python.model --output .
544544
COMMAND ${stubgen_EXECUTABLE} -p ortools.sat.python.swig_helper --output .
545545
COMMAND ${stubgen_EXECUTABLE} -p ortools.scheduling.python.rcpsp --output .
546546
COMMAND ${stubgen_EXECUTABLE} -p ortools.util.python.sorted_interval_list --output .

ortools/constraint_solver/python/constraint_solver.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ PYBIND11_MODULE(constraint_solver, m) {
126126
.def(pybind11::init<const std::string&,
127127
const ConstraintSolverParameters&>())
128128
.def("__str__", &Solver::DebugString)
129+
.def("default_solver_parameters", &Solver::DefaultSolverParameters)
130+
.def("parameters", &Solver::parameters)
131+
.def("local_search_profile", &Solver::LocalSearchProfile)
129132
.def("new_int_var",
130133
pybind11::overload_cast<int64_t, int64_t, const std::string&>(
131134
&Solver::MakeIntVar),

ortools/routing/python/model.cc

Lines changed: 161 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14+
#include <algorithm>
1415
#include <cstdint>
1516
#include <functional>
17+
#include <iterator>
1618
#include <utility>
1719

1820
#include "ortools/constraint_solver/constraint_solver.h"
@@ -30,8 +32,13 @@
3032
#include "pybind11/stl.h"
3133
#include "pybind11_protobuf/native_proto_caster.h"
3234

35+
using ::operations_research::Assignment;
36+
using ::operations_research::DefaultRoutingModelParameters;
3337
using ::operations_research::DefaultRoutingSearchParameters;
3438
using ::operations_research::RoutingIndexManager;
39+
using ::operations_research::RoutingDimension;
40+
using ::operations_research::RoutingModelParameters;
41+
using ::operations_research::RoutingSearchParameters;
3542
using ::operations_research::RoutingModel;
3643
using ::pybind11::arg;
3744

@@ -41,6 +48,9 @@ PYBIND11_MODULE(model, m) {
4148
pybind11::module::import(
4249
"ortools.constraint_solver.python.constraint_solver");
4350

51+
m.def("default_routing_model_parameters", &DefaultRoutingModelParameters,
52+
DOC(operations_research, DefaultRoutingModelParameters));
53+
4454
m.def("default_routing_search_parameters", &DefaultRoutingSearchParameters,
4555
DOC(operations_research, DefaultRoutingSearchParameters));
4656

@@ -52,6 +62,23 @@ PYBIND11_MODULE(model, m) {
5262
RoutingIndexManager::NodeIndex(depot));
5363
}),
5464
DOC(operations_research, RoutingIndexManager, RoutingIndexManager))
65+
.def(pybind11::init([](int num_nodes, int num_vehicles,
66+
const std::vector<int> starts,
67+
const std::vector<int> ends) {
68+
std::vector<RoutingIndexManager::NodeIndex> start_nodes;
69+
start_nodes.reserve(starts.size());
70+
std::transform(starts.cbegin(), starts.cend(), std::back_inserter(start_nodes),
71+
[](int node){return RoutingIndexManager::NodeIndex(node);});
72+
73+
std::vector<RoutingIndexManager::NodeIndex> end_nodes;
74+
end_nodes.reserve(ends.size());
75+
std::transform(ends.cbegin(), ends.cend(), std::back_inserter(end_nodes),
76+
[](int node){return RoutingIndexManager::NodeIndex(node);});
77+
78+
return new RoutingIndexManager(
79+
num_nodes, num_vehicles, start_nodes, end_nodes);
80+
}),
81+
DOC(operations_research, RoutingIndexManager, RoutingIndexManager))
5582
.def("num_nodes", &RoutingIndexManager::num_nodes,
5683
DOC(operations_research, RoutingIndexManager, num_nodes))
5784
.def("num_vehicles", &RoutingIndexManager::num_vehicles,
@@ -76,33 +103,146 @@ PYBIND11_MODULE(model, m) {
76103
.def("get_end_index", &RoutingIndexManager::GetEndIndex,
77104
DOC(operations_research, RoutingIndexManager, GetEndIndex));
78105

79-
pybind11::class_<RoutingModel>(m, "RoutingModel")
80-
.def(pybind11::init([](const RoutingIndexManager& routing_index_manager) {
81-
return new RoutingModel(routing_index_manager);
82-
}))
83-
.def("register_transit_callback",
106+
pybind11::class_<RoutingDimension>(m, "RoutingDimension")
107+
.def("model", &RoutingDimension::model,
108+
pybind11::return_value_policy::reference_internal)
109+
.def("get_transit_value", &RoutingDimension::GetTransitValue,
110+
arg("from_index"), arg("to_index"), arg("vehicle"))
111+
.def("cumul_var", &RoutingDimension::CumulVar,
112+
pybind11::return_value_policy::reference_internal, arg("index"));
113+
114+
115+
pybind11::class_<RoutingModel> rm(m, "RoutingModel");
116+
rm.def(pybind11::init([](const RoutingIndexManager& index_manager) {
117+
return new RoutingModel(index_manager);
118+
}));
119+
rm.def(pybind11::init([](
120+
const RoutingIndexManager& index_manager,
121+
const RoutingModelParameters& parameters) {
122+
return new RoutingModel(index_manager, parameters);
123+
}));
124+
rm.def("register_transit_matrix",
125+
[](RoutingModel* routing_model,
126+
std::vector<std::vector<int64_t>> transit_matrix) {
127+
return routing_model->RegisterTransitMatrix(
128+
std::move(transit_matrix));
129+
});
130+
rm.def("register_unary_transit_vector",
131+
[](RoutingModel* routing_model,
132+
std::vector<int64_t> transit_vector) {
133+
return routing_model->RegisterUnaryTransitVector(
134+
std::move(transit_vector));
135+
});
136+
rm.def("register_unary_transit_callback",
137+
[](RoutingModel* routing_model,
138+
std::function<int64_t(int64_t)> transit_callback) {
139+
return routing_model->RegisterUnaryTransitCallback(
140+
std::move(transit_callback));
141+
});
142+
rm.def("register_transit_callback",
84143
[](RoutingModel* routing_model,
85144
std::function<int64_t(int64_t, int64_t)> transit_callback) {
86145
return routing_model->RegisterTransitCallback(
87146
std::move(transit_callback));
88-
})
89-
.def("set_arc_cost_evaluator_of_all_vehicles",
147+
});
148+
rm.def("set_arc_cost_evaluator_of_all_vehicles",
90149
&RoutingModel::SetArcCostEvaluatorOfAllVehicles,
91-
arg("transit_callback_index"))
92-
.def("solve", &RoutingModel::Solve,
150+
arg("transit_callback_index"));
151+
rm.def("add_dimension", &RoutingModel::AddDimension,
152+
arg("evaluator_index"),
153+
arg("slack_max"),
154+
arg("capacity"),
155+
arg("fix_start_cumul_to_zero"),
156+
arg("name"));
157+
rm.def("add_dimension_with_vehicle_capacity", &RoutingModel::AddDimensionWithVehicleCapacity,
158+
arg("evaluator_index"),
159+
arg("slack_max"),
160+
arg("vehicle_capacities"),
161+
arg("fix_start_cumul_to_zero"),
162+
arg("name"));
163+
rm.def("add_dimension_with_vehicle_transits", &RoutingModel::AddDimensionWithVehicleTransits,
164+
arg("evaluator_indices"),
165+
arg("slack_max"),
166+
arg("capacity"),
167+
arg("fix_start_cumul_to_zero"),
168+
arg("name"));
169+
rm.def("add_dimension_with_vehicle_transit_and_capacity", &RoutingModel::AddDimensionWithVehicleTransitAndCapacity,
170+
arg("evaluator_indices"),
171+
arg("slack_max"),
172+
arg("vehicle_capacities"),
173+
arg("fix_start_cumul_to_zero"),
174+
arg("name"));
175+
rm.def("add_constant_dimension", &RoutingModel::AddConstantDimension,
176+
arg("value"),
177+
arg("capacity"),
178+
arg("fix_start_cumul_to_zero"),
179+
arg("name"));
180+
rm.def("add_vector_dimension", &RoutingModel::AddVectorDimension,
181+
arg("values"),
182+
arg("capacity"),
183+
arg("fix_start_cumul_to_zero"),
184+
arg("name"));
185+
rm.def("add_matrix_dimension", &RoutingModel::AddMatrixDimension,
186+
arg("values"),
187+
arg("capacity"),
188+
arg("fix_start_cumul_to_zero"),
189+
arg("name"));
190+
rm.def("get_dimension_or_die", &RoutingModel::GetDimensionOrDie,
93191
pybind11::return_value_policy::reference_internal,
94-
arg("assignment") = nullptr)
95-
.def("solve_with_parameters", &RoutingModel::SolveWithParameters,
192+
arg("dimension_name"));
193+
rm.def("close_model", &RoutingModel::CloseModel);
194+
rm.def("close_model_with_parameters", &RoutingModel::CloseModelWithParameters,
195+
arg("search_parameters"));
196+
rm.def("solve", &RoutingModel::Solve,
96197
pybind11::return_value_policy::reference_internal,
97-
arg("search_parameters"), arg("solutions") = nullptr)
98-
.def("status", &RoutingModel::status)
99-
.def("start", &RoutingModel::Start, arg("vehicle"))
100-
.def("end", &RoutingModel::End, arg("vehicle"))
101-
.def("is_start", &RoutingModel::IsStart, arg("index"))
102-
.def("is_end", &RoutingModel::IsEnd, arg("index"))
103-
.def("next", &RoutingModel::Next, arg("assignment"), arg("index"))
104-
.def("next_var", &RoutingModel::NextVar,
105-
pybind11::return_value_policy::reference_internal, arg("index"))
106-
.def("get_arc_cost_for_vehicle", &RoutingModel::GetArcCostForVehicle,
198+
arg("assignment") = nullptr);
199+
// TODO(mizux) Add support for solutions parameters too.
200+
rm.def("solve_with_parameters",
201+
[](RoutingModel* routing_model
202+
,const RoutingSearchParameters& search_parameters
203+
/*,std::vector<const Assignment*>* solutions = nullptr*/) -> const Assignment* {
204+
return routing_model->SolveWithParameters(search_parameters, nullptr);
205+
}
206+
,pybind11::return_value_policy::reference_internal
207+
,arg("search_parameters")
208+
//, arg("solutions") = nullptr
209+
);
210+
rm.def("status", &RoutingModel::status);
211+
rm.def("nodes", &RoutingModel::nodes);
212+
rm.def("vehicles", &RoutingModel::vehicles);
213+
rm.def("size", &RoutingModel::Size);
214+
rm.def("start", &RoutingModel::Start, arg("vehicle"));
215+
rm.def("end", &RoutingModel::End, arg("vehicle"));
216+
rm.def("is_start", &RoutingModel::IsStart, arg("index"));
217+
rm.def("is_end", &RoutingModel::IsEnd, arg("index"));
218+
rm.def("next", &RoutingModel::Next, arg("assignment"), arg("index"));
219+
rm.def("next_var", &RoutingModel::NextVar,
220+
pybind11::return_value_policy::reference_internal, arg("index"));
221+
rm.def("get_arc_cost_for_vehicle", &RoutingModel::GetArcCostForVehicle,
107222
arg("from_index"), arg("to_index"), arg("vehicle"));
223+
rm.def("solver", &RoutingModel::solver,
224+
pybind11::return_value_policy::reference_internal);
225+
226+
pybind11::enum_<RoutingModel::PenaltyCostBehavior>(rm, "PenaltyCostBehavior")
227+
.value("PENALIZE_ONCE", RoutingModel::PenaltyCostBehavior::PENALIZE_ONCE)
228+
.value("PENALIZE_PER_INACTIVE", RoutingModel::PenaltyCostBehavior::PENALIZE_PER_INACTIVE)
229+
.export_values();
230+
231+
rm.def("add_disjunction",
232+
[](RoutingModel* routing_model,
233+
const std::vector<int64_t>& indices,
234+
int64_t penalty,
235+
int64_t max_cardinality,
236+
RoutingModel::PenaltyCostBehavior penalty_cost_behavior) -> int {
237+
return static_cast<int>(routing_model->AddDisjunction(
238+
indices,
239+
penalty,
240+
max_cardinality,
241+
penalty_cost_behavior).value());
242+
},
243+
//&RoutingModel::AddDisjunction,
244+
arg("indices"),
245+
arg("penalty") = RoutingModel::kNoPenalty,
246+
arg("max_cardinality") = 1,
247+
arg("penalty_cost_behavior") = RoutingModel::PenaltyCostBehavior::PENALIZE_ONCE);
108248
}

0 commit comments

Comments
 (0)