@@ -11,6 +11,7 @@ from pylibraft.common.handle cimport *
1111
1212from cuopt.routing.structure.routing_utilities cimport *
1313from cuopt.routing.vehicle_routing cimport (
14+ call_batch_solve,
1415 call_solve,
1516 data_model_view_t,
1617 node_type_t,
@@ -32,8 +33,10 @@ from libc.stdlib cimport free, malloc
3233from libc.string cimport memcpy, strcpy, strlen
3334from libcpp cimport bool
3435from libcpp.memory cimport unique_ptr
36+ from libcpp.pair cimport pair
3537from libcpp.string cimport string
3638from libcpp.utility cimport move
39+ from libcpp.vector cimport vector
3740
3841from rmm.pylibrmm.device_buffer cimport DeviceBuffer
3942
@@ -834,3 +837,129 @@ def Solve(DataModel data_model, SolverSettings solver_settings):
834837 error_message,
835838 unserviced_nodes
836839 )
840+
841+
842+ cdef create_assignment_from_vr_ret(vehicle_routing_ret_t& vr_ret):
843+ """ Helper function to create an Assignment from a vehicle_routing_ret_t"""
844+ vehicle_count = vr_ret.vehicle_count_
845+ total_objective_value = vr_ret.total_objective_value_
846+
847+ objective_values = {}
848+ for k in vr_ret.objective_values_:
849+ obj = Objective(int (k.first))
850+ objective_values[obj] = k.second
851+
852+ status = vr_ret.status_
853+ cdef char * c_sol_string = c_get_string(vr_ret.solution_string_)
854+ try :
855+ solver_status_string = \
856+ c_sol_string[:vr_ret.solution_string_.length()].decode(' UTF-8' )
857+ finally :
858+ free(c_sol_string)
859+
860+ route = DeviceBuffer.c_from_unique_ptr(move(vr_ret.d_route_))
861+ route_locations = DeviceBuffer.c_from_unique_ptr(
862+ move(vr_ret.d_route_locations_)
863+ )
864+ arrival_stamp = DeviceBuffer.c_from_unique_ptr(
865+ move(vr_ret.d_arrival_stamp_)
866+ )
867+ truck_id = DeviceBuffer.c_from_unique_ptr(move(vr_ret.d_truck_id_))
868+ node_types = DeviceBuffer.c_from_unique_ptr(move(vr_ret.d_node_types_))
869+ unserviced_nodes_buf = \
870+ DeviceBuffer.c_from_unique_ptr(move(vr_ret.d_unserviced_nodes_))
871+ accepted_buf = \
872+ DeviceBuffer.c_from_unique_ptr(move(vr_ret.d_accepted_))
873+
874+ route_df = cudf.DataFrame()
875+ route_df[' route' ] = series_from_buf(route, pa.int32())
876+ route_df[' arrival_stamp' ] = series_from_buf(arrival_stamp, pa.float64())
877+ route_df[' truck_id' ] = series_from_buf(truck_id, pa.int32())
878+ route_df[' location' ] = series_from_buf(route_locations, pa.int32())
879+ route_df[' type' ] = series_from_buf(node_types, pa.int32())
880+
881+ unserviced_nodes = cudf.Series._from_column(
882+ series_from_buf(unserviced_nodes_buf, pa.int32())
883+ )
884+ accepted = cudf.Series._from_column(
885+ series_from_buf(accepted_buf, pa.int32())
886+ )
887+
888+ def get_type_from_int (type_in_int ):
889+ if type_in_int == int (NodeType.DEPOT):
890+ return " Depot"
891+ elif type_in_int == int (NodeType.PICKUP):
892+ return " Pickup"
893+ elif type_in_int == int (NodeType.DELIVERY):
894+ return " Delivery"
895+ elif type_in_int == int (NodeType.BREAK):
896+ return " Break"
897+
898+ node_types_string = [
899+ get_type_from_int(type_in_int)
900+ for type_in_int in route_df[' type' ].to_pandas()]
901+ route_df[' type' ] = node_types_string
902+ error_status = vr_ret.error_status_
903+ error_message = vr_ret.error_message_
904+
905+ return Assignment(
906+ vehicle_count,
907+ total_objective_value,
908+ objective_values,
909+ route_df,
910+ accepted,
911+ < solution_status_t> status,
912+ solver_status_string,
913+ < error_type_t> error_status,
914+ error_message,
915+ unserviced_nodes
916+ )
917+
918+
919+ def BatchSolve (py_data_model_list , SolverSettings solver_settings ):
920+ """
921+ Solve multiple routing problems in batch mode using parallel execution.
922+
923+ Parameters
924+ ----------
925+ py_data_model_list : list of DataModel
926+ List of data model objects representing routing problems to solve.
927+ solver_settings : SolverSettings
928+ Solver settings to use for all problems.
929+
930+ Returns
931+ -------
932+ tuple
933+ A tuple containing:
934+ - list of Assignment: Solutions for each routing problem
935+ - float: Total solve time in seconds
936+ """
937+ cdef solver_settings_t[int , float ]* c_solver_settings = (
938+ solver_settings.c_solver_settings.get()
939+ )
940+
941+ cdef vector[data_model_view_t[int , float ] * ] data_model_views
942+
943+ for data_model_obj in py_data_model_list:
944+ data_model_views.push_back(
945+ (< DataModel> data_model_obj).c_data_model_view.get()
946+ )
947+
948+ cdef pair[
949+ vector[unique_ptr[vehicle_routing_ret_t]],
950+ double ] batch_solve_result = (
951+ move(call_batch_solve(data_model_views, c_solver_settings))
952+ )
953+
954+ cdef vector[unique_ptr[vehicle_routing_ret_t]] c_solutions = (
955+ move(batch_solve_result.first)
956+ )
957+ cdef double solve_time = batch_solve_result.second
958+
959+ solutions = []
960+ for i in range (c_solutions.size()):
961+ solutions.append(
962+ create_assignment_from_vr_ret(c_solutions[i].get()[0 ])
963+ )
964+
965+ return solutions, solve_time
0 commit comments