diff --git a/docqueries/pgr_pickDeliver/pgr_pickDeliverEuclidean.result b/docqueries/pgr_pickDeliver/pgr_pickDeliverEuclidean.result index e173dc10d..c85828369 100644 --- a/docqueries/pgr_pickDeliver/pgr_pickDeliverEuclidean.result +++ b/docqueries/pgr_pickDeliver/pgr_pickDeliverEuclidean.result @@ -16,12 +16,12 @@ SELECT * FROM vrp_pgr_pickDeliverEuclidean( 3 | 1 | 1 | 3 | 3 | 3 | 0 | 1 | 6 | 0 | 3 | 9 4 | 1 | 1 | 4 | 2 | 2 | 20 | 1 | 10 | 0 | 2 | 12 5 | 1 | 1 | 5 | 3 | 2 | 0 | 1 | 13 | 0 | 3 | 16 - 6 | 1 | 1 | 6 | 6 | -1 | 0 | 3 | 19 | 0 | 0 | 19 - 7 | 2 | 2 | 1 | 1 | -1 | 0 | 0 | 0 | 0 | 0 | 0 - 8 | 2 | 2 | 2 | 2 | 1 | 10 | 2 | 2 | 0 | 3 | 5 + 6 | 1 | 1 | 6 | 6 | -1 | 0 | 1 | 17 | 0 | 0 | 17 + 7 | 2 | 2 | 1 | 1 | -1 | 0 | 0 | 0 | 1 | 0 | 1 + 8 | 2 | 2 | 2 | 2 | 1 | 10 | 1 | 2 | 0 | 3 | 5 9 | 2 | 2 | 3 | 3 | 1 | 0 | 2 | 7 | 0 | 3 | 10 - 10 | 2 | 2 | 4 | 6 | -1 | 0 | 0 | 10 | 0 | 0 | 10 - 11 | -2 | 0 | 0 | -1 | -1 | -1 | 11 | -1 | 1 | 17 | 29 + 10 | 2 | 2 | 4 | 6 | -1 | 0 | 2 | 12 | 0 | 0 | 12 + 11 | -2 | 0 | 0 | -1 | -1 | -1 | 10 | -1 | 2 | 17 | 29 (11 rows) /* --q2 */ diff --git a/include/cpp_common/base_matrix.hpp b/include/cpp_common/base_matrix.hpp index e6629cd9f..11e772620 100644 --- a/include/cpp_common/base_matrix.hpp +++ b/include/cpp_common/base_matrix.hpp @@ -34,7 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_types/typedefs.h" #include "cpp_common/identifiers.hpp" -typedef struct Matrix_cell_t Matrix_cell_t; +using Matrix_cell_t = struct Matrix_cell_t; namespace vrprouting { namespace base { @@ -57,7 +57,7 @@ class Base_Matrix { /** @brief Constructs an emtpy matrix */ Base_Matrix() = default; /** @brief Constructs a matrix for only specific identifiers */ - Base_Matrix(Matrix_cell_t*, size_t, const Identifiers&, Multiplier); + Base_Matrix(const std::vector&, const Identifiers&, Multiplier); /** @brief Constructs a matrix for the euclidean */ Base_Matrix(const std::map, Id>&, Multiplier); diff --git a/include/cpp_common/vroom_matrix.hpp b/include/cpp_common/vroom_matrix.hpp index 69a94ee02..fed3ac8c7 100644 --- a/include/cpp_common/vroom_matrix.hpp +++ b/include/cpp_common/vroom_matrix.hpp @@ -56,7 +56,7 @@ class Matrix { public: /** @brief Constructs an emtpy matrix */ Matrix() = default; - Matrix(Vroom_matrix_t *, size_t, const Identifiers &, double); + Matrix(const std::vector&, const Identifiers&, double); ::vroom::Matrix<::vroom::Duration> get_vroom_duration_matrix() const; ::vroom::Matrix<::vroom::Cost> get_vroom_cost_matrix() const; diff --git a/include/problem/fleet.hpp b/include/problem/fleet.hpp index dbe237f71..f54960624 100644 --- a/include/problem/fleet.hpp +++ b/include/problem/fleet.hpp @@ -53,13 +53,13 @@ class Fleet: protected std::vector { /** @brief Create a fleet based on the Vehicles of the problem */ Fleet( - Vehicle_t* , size_t, + const std::vector&, const Orders&, std::vector&, size_t&); /** @brief Create a fleet based on the Vehicles of the problem */ Fleet( - Vehicle_t*, size_t, + const std::vector&, const std::vector&, const Orders&, std::vector&, @@ -121,7 +121,7 @@ class Fleet: protected std::vector { /** @brief build the fleet */ void build_fleet( - Vehicle_t*, size_t, + std::vector, const std::vector&, const Orders&, std::vector&, size_t&); diff --git a/include/problem/matrix.hpp b/include/problem/matrix.hpp index 428dfc5d3..497592e62 100644 --- a/include/problem/matrix.hpp +++ b/include/problem/matrix.hpp @@ -46,10 +46,13 @@ class Matrix : public base::Base_Matrix { Matrix() = default; /** brief constructor for matrix version with time dependant multipliers */ - Matrix(Matrix_cell_t *, size_t, Time_multipliers_t*, size_t, const Identifiers&, Multiplier = 1.0); + Matrix( + const std::vector&, + const std::vector&, + const Identifiers&, Multiplier = 1.0); /** brief constructor for matrix version default multipliers */ - Matrix(Matrix_cell_t *, size_t, const Identifiers&, Multiplier = 1.0); + Matrix(const std::vector&, const Identifiers&, Multiplier = 1.0); /** brief constructor for euclidean version default multipliers */ explicit Matrix(const std::map, Id>&, Multiplier = 1.0); diff --git a/include/problem/orders.hpp b/include/problem/orders.hpp index 72077c50a..a959f3d4e 100644 --- a/include/problem/orders.hpp +++ b/include/problem/orders.hpp @@ -33,18 +33,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include "problem/order.hpp" -#include "cpp_common/orders_t.hpp" -#include "cpp_common/assert.hpp" #include "cpp_common/identifiers.hpp" -#include "problem/tw_node.hpp" #include "problem/vehicle_node.hpp" -#include "problem/node_types.hpp" +using Orders_t = struct Orders_t; namespace vrprouting { namespace problem { +class Vehicle_node; class PickDeliver; class Orders : public std::vector { @@ -52,7 +50,7 @@ class Orders : public std::vector { using std::vector::size; Orders() = default; - Orders(Orders_t* , size_t, PickDeliver&); + Orders(const std::vector&, PickDeliver&); /** @brief find the best order -> @b this */ size_t find_best_I(const Identifiers &within_this_set) const; @@ -69,22 +67,13 @@ class Orders : public std::vector { /** @brief is the order valid? */ bool is_valid(Speed = 1.0) const; - friend std::ostream& operator<<(std::ostream &log, const Orders &p_orders) { - log << "Orders\n"; - for (const auto &o : p_orders) log << o << "\n"; - log << "end Orders\n"; - return log; - } + friend std::ostream& operator<<(std::ostream &log, const Orders &p_orders); private: - void build_orders(Orders_t *, size_t, PickDeliver&); + void build_orders(std::vector, PickDeliver&); /** @brief add in an order */ - void add_order(const Orders_t &order, - const Vehicle_node &pick, - const Vehicle_node &drop) { - push_back(Order(size(), order.id, pick, drop)); - } + void add_order(const Orders_t&, const Vehicle_node&, const Vehicle_node&); }; } // namespace problem diff --git a/include/problem/pickDeliver.hpp b/include/problem/pickDeliver.hpp index 8072aa163..4ddd8aba8 100644 --- a/include/problem/pickDeliver.hpp +++ b/include/problem/pickDeliver.hpp @@ -55,16 +55,16 @@ class PickDeliver { public: /** @brief General Constructor */ PickDeliver( - Orders_t* p_orders, size_t p_orders_size, - Vehicle_t* p_vehicles, size_t p_vehicles_size, + const std::vector&, + const std::vector&, const Matrix &); /** @brief Override stops constructor */ PickDeliver( - Orders_t* p_orders, size_t p_orders_size, - Vehicle_t* p_vehicles, size_t p_vehicles_size, + const std::vector&, + const std::vector&, std::vector, - const Matrix &); + const Matrix&); virtual ~PickDeliver() = default; diff --git a/include/vroom/vroom.hpp b/include/vroom/vroom.hpp index 03cca5630..7320f5517 100644 --- a/include/vroom/vroom.hpp +++ b/include/vroom/vroom.hpp @@ -61,20 +61,17 @@ class Vroom : public vrprouting::Messages { void add_jobs( const std::vector&, const MapTW&); - void add_jobs(const Vroom_job_t*, size_t, const Vroom_time_window_t*, size_t); /** @brief sets m_shipments by adding the Vroom_shipment_t */ void add_shipments( const std::vector&, const MapTW&); - void add_shipments(const Vroom_shipment_t*, size_t, const Vroom_time_window_t*, size_t); /** @brief sets m_vehicles by adding the Vroom_vehicle_t */ void add_vehicles( const std::vector&, const std::vector&, const MapTW&); - void add_vehicles(const Vroom_vehicle_t*, size_t, const Vroom_break_t*, size_t, const Vroom_time_window_t*, size_t); /** @brief sets m_matrix */ void add_matrix(const vrprouting::vroom::Matrix&); diff --git a/pgtap/pgr_pickDeliver/pickDeliver/issue-1725.pg b/pgtap/pgr_pickDeliver/pickDeliver/issue-1725.pg index 5ef2f700e..62ddc20ad 100644 --- a/pgtap/pgr_pickDeliver/pickDeliver/issue-1725.pg +++ b/pgtap/pgr_pickDeliver/pickDeliver/issue-1725.pg @@ -12,7 +12,7 @@ SELECT * FROM vrp_pgr_pickDeliver( $$ SELECT * FROM edges_matrix WHERE start_vid IN (3, 4, 5, 8, 9, 11) AND end_vid IN (3, 4, 5, 8, 9, 11) $$ ); -SELECT throws_ok('missing_id_on_matrix', 'XX000', 'An Infinity value was found on the Matrix. Might be missing information of a node', 'Should throw: matrix is missing node 6'); +SELECT throws_ok('missing_id_on_matrix', 'XX000', 'An Infinity value was found on the Matrix', 'Should throw: matrix is missing node 6'); SELECT finish(); diff --git a/pgtap/vroom/vroom-plain-eq-timestamp.test.pg b/pgtap/vroom/vroom-plain-eq-timestamp.pg similarity index 100% rename from pgtap/vroom/vroom-plain-eq-timestamp.test.pg rename to pgtap/vroom/vroom-plain-eq-timestamp.pg diff --git a/pgtap/vroom/vroomJobs-eq-vroom.test.pg b/pgtap/vroom/vroomJobs-eq-vroom.pg similarity index 100% rename from pgtap/vroom/vroomJobs-eq-vroom.test.pg rename to pgtap/vroom/vroomJobs-eq-vroom.pg diff --git a/pgtap/vroom/vroomShipments-eq-vroom.test.pg b/pgtap/vroom/vroomShipments-eq-vroom.pg similarity index 100% rename from pgtap/vroom/vroomShipments-eq-vroom.test.pg rename to pgtap/vroom/vroomShipments-eq-vroom.pg diff --git a/src/compatibleVehicles/compatibleVehicles.c b/src/compatibleVehicles/compatibleVehicles.c index a33a8f531..9d9a2feb0 100644 --- a/src/compatibleVehicles/compatibleVehicles.c +++ b/src/compatibleVehicles/compatibleVehicles.c @@ -55,6 +55,12 @@ process( CompatibleVehicles_rt **result_tuples, size_t *result_count) { + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; + + vrp_SPI_connect(); + if (factor <= 0) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -62,8 +68,6 @@ process( errhint("Value found: %f <= 0", factor))); } - vrp_SPI_connect(); - Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; @@ -172,13 +176,7 @@ process( PGR_DBG("Total %ld matrix cells in query:", total_cells); PGR_DBG("Total %ld multipliers in query:", total_cells); -#ifdef PROFILE clock_t start_t = clock(); -#endif - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; - vrp_do_compatibleVehicles( pd_orders_arr, total_pd_orders, vehicles_arr, total_vehicles, @@ -193,10 +191,8 @@ process( &log_msg, ¬ice_msg, &err_msg); - -#ifdef PROFILE time_msg("vrp_compatibleVehicles", start_t, clock()); -#endif + if (err_msg && (*result_tuples)) { pfree(*result_tuples); (*result_count) = 0; @@ -286,20 +282,8 @@ _vrp_compatiblevehicles(PG_FUNCTION_ARGS) { tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); - - tuple = heap_form_tuple(tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); - - - pfree(values); values = NULL; - pfree(nulls); nulls = NULL; - SRF_RETURN_NEXT(funcctx, result); } else { - if (result_tuples) { - pfree(result_tuples); result_tuples = NULL; - } - funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); } } diff --git a/src/compatibleVehicles/compatibleVehicles_driver.cpp b/src/compatibleVehicles/compatibleVehicles_driver.cpp index 19ec45729..2875da45c 100644 --- a/src/compatibleVehicles/compatibleVehicles_driver.cpp +++ b/src/compatibleVehicles/compatibleVehicles_driver.cpp @@ -31,68 +31,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include #include +#include #include "c_types/compatibleVehicles_rt.h" #include "cpp_common/alloc.hpp" #include "cpp_common/assert.hpp" +#include "cpp_common/matrix_cell_t.hpp" +#include "cpp_common/time_multipliers_t.hpp" #include "cpp_common/orders_t.hpp" #include "cpp_common/vehicle_t.hpp" #include "problem/pickDeliver.hpp" #include "problem/matrix.hpp" -/** - * - * @param[in] customers_arr A C Array of pickup and dropoff orders - * @param[in] total_customers size of the customers_arr - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr - * @param[in] matrix_cells_arr A C Array of the (time) matrix cells - * @param[in] total_cells size of the matrix_cells_arr - * @param[in] multipliers_arr A C Array of the multipliers - * @param[in] total_multipliers size of the multipliers_arr - * @param[in] factor A global multiplier for the (time) matrix cells - * - * @param[out] return_tuples C array of contents to be returned to postgres - * @param[out] return_count number of tuples returned - * @param[out] log_msg special log message pointer - * @param[out] notice_msg special message pointer to be returned as NOTICE - * @param[out] err_msg special message pointer to be returned as ERROR - * - * @pre The messages: log_msg, notice_msg, err_msg must be empty (=nullptr) - * @pre The C arrays: customers_arr, vehicles_arr, matrix_cells_arr must not be empty - * @pre The C array: return_tuples must be empty - * @pre Only matrix cells (i, i) can be missing and are considered as 0 (time units) - * - * @post The C array: return_tuples contains the result for the problem given - * @post The return_tuples array size is return_count - * @post err_msg is empty if no throw from the process is catched - * @post log_msg contains some logging - * @post notice_msg is empty - * - @dot -digraph G { - node[fontsize=11, nodesep=0.75,ranksep=0.75]; - - start [shape=Mdiamond]; - n1 [label="Verify preconditions",shape=rect]; - n3 [label="Verify matrix preconditions",shape=rect]; - n4 [label="Construct problem",shape=cds,color=blue]; - n7 [label="Prepare results",shape=rect]; - end [shape=Mdiamond]; - error [shape=Mdiamond,color=red] - start -> n1 -> n3 -> n4 -> n7 -> end; - n1 -> error [ label="throw",color=red]; - n3 -> error [ label="throw",color=red]; -} -@enddot - - * - */ void vrp_do_compatibleVehicles( - Orders_t customers_arr[], size_t total_customers, + Orders_t orders_arr[], size_t total_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, Time_multipliers_t *multipliers_arr, size_t total_multipliers, @@ -115,92 +70,99 @@ vrp_do_compatibleVehicles( std::ostringstream notice; std::ostringstream err; try { + using Matrix = vrprouting::problem::Matrix; + /* * verify preconditions */ pgassert(!(*log_msg)); pgassert(!(*notice_msg)); pgassert(!(*err_msg)); - pgassert(total_customers); - pgassert(total_vehicles); + pgassert(total_orders); pgassert(total_vehicles); + pgassert(total_cells); pgassert(*return_count == 0); pgassert(!(*return_tuples)); - log << "do_compatibleVehicles\n"; + /* Data input starts */ + + /* + * transform to C++ containers + */ + std::vector vehicles(vehicles_arr, vehicles_arr + total_vehicles); + std::vector orders(orders_arr, orders_arr + total_orders); + std::vector costs(matrix_cells_arr, matrix_cells_arr + total_cells); + std::vector multipliers(multipliers_arr, multipliers_arr + total_multipliers); + + /* Data input ends */ + + /* Processing starts */ Identifiers node_ids; - for (size_t i = 0; i < total_customers; ++i) { - auto o = customers_arr[i]; + for (const auto &o : orders) { node_ids += o.pick_node_id; node_ids += o.deliver_node_id; } - for (size_t i = 0; i < total_vehicles; ++i) { - auto v = vehicles_arr[i]; + for (const auto &v : vehicles) { node_ids += v.start_node_id; node_ids += v.end_node_id; } /* - * Verify matrix cells preconditions + * Prepare matrix */ - vrprouting::problem::Matrix cost_matrix( - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers, - node_ids, static_cast(factor)); + Matrix matrix(costs, multipliers, node_ids, static_cast(factor)); -#ifdef TODO /* * Verify matrix triangle inequality */ - if (!cost_matrix.obeys_triangle_inequality()) { - log << "[Compatible Vehicles] Fixing Matrix that does not obey triangle inequality "; - log << cost_matrix.fix_triangle_inequality() << " cycles used"; + if (!matrix.obeys_triangle_inequality()) { + log << "\nFixing Matrix that does not obey triangle inequality.\t" + << matrix.fix_triangle_inequality() << " cycles used"; - if (!cost_matrix.obeys_triangle_inequality()) { - log << "[Compatible Vehicles] Matrix Still does not obey triangle inequality"; + if (!matrix.obeys_triangle_inequality()) { + log << "\nMatrix Still does not obey triangle inequality."; } } -#endif - if (!cost_matrix.has_no_infinity()) { - err << "An Infinity value was found on the Matrix"; - *err_msg = to_pg_msg(err.str()); + /* + * Verify matrix cells preconditions + */ + if (!matrix.has_no_infinity()) { + *err_msg = to_pg_msg("An Infinity value was found on the Matrix"); + *log_msg = to_pg_msg(log.str()); return; } /* * Construct problem */ - log << "Initialize problem\n"; - vrprouting::problem::PickDeliver pd_problem( - customers_arr, total_customers, - vehicles_arr, total_vehicles, - cost_matrix); - - err << pd_problem.msg.get_error(); - if (!err.str().empty()) { + vrprouting::problem::PickDeliver pd_problem(orders, vehicles, matrix); + + if (pd_problem.msg.has_error()) { *log_msg = to_pg_msg(pd_problem.msg.get_log()); *err_msg = to_pg_msg(pd_problem.msg.get_error()); return; } log << pd_problem.msg.get_log(); - log << "Finish Reading data\n"; + log << "Finish constructing problem\n"; pd_problem.msg.clear(); /* - * Prepare results + * get the solution */ auto solution = pd_problem.get_pg_compatibleVehicles(); + log << pd_problem.msg.get_log(); log << "solution size: " << solution.size() << "\n"; - log << "solution empty: " << solution.empty() << "\n"; + /* + * Prepare results + */ if (!solution.empty()) { - log << "solution empty " << "\n"; (*return_tuples) = alloc(solution.size(), (*return_tuples)); - int seq = 0; + size_t seq = 0; for (const auto &row : solution) { (*return_tuples)[seq] = row; ++seq; diff --git a/src/cpp_common/base_matrix.cpp b/src/cpp_common/base_matrix.cpp index a118af62a..5bb6240e8 100644 --- a/src/cpp_common/base_matrix.cpp +++ b/src/cpp_common/base_matrix.cpp @@ -29,9 +29,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "cpp_common/base_matrix.hpp" +#include #include #include #include +#include #include #include #include @@ -215,7 +217,6 @@ Base_Matrix::get_original_id(Idx index) const { /** * @param [in] data_costs The set of costs - * @param [in] size_matrix The size of the set of costs * @param [in] node_ids The selected node identifiers to be added * @param [in] multiplier All times are multiplied by this value * @@ -228,7 +229,7 @@ Base_Matrix::get_original_id(Idx index) const { * */ Base_Matrix::Base_Matrix( - Matrix_cell_t *data_costs, size_t size_matrix, + const std::vector &data_costs, const Identifiers& node_ids, Multiplier multiplier) { /* @@ -252,8 +253,7 @@ Base_Matrix::Base_Matrix( /* * Cycle the matrix data */ - for (size_t i = 0; i < size_matrix; ++i) { - auto data = data_costs[i]; + for (const auto &data : data_costs) { /* * skip if row is not from selected nodes */ diff --git a/src/cpp_common/vroom_matrix.cpp b/src/cpp_common/vroom_matrix.cpp index ead977b2b..cc1a96330 100644 --- a/src/cpp_common/vroom_matrix.cpp +++ b/src/cpp_common/vroom_matrix.cpp @@ -95,8 +95,7 @@ Matrix::get_original_id(Idx index) const { /** * @brief Constructor for VROOM matrix input * - * @param [in] matrix_rows The set of costs - * @param [in] total_matrix_rows The size of the set of costs + * @param [in] matrix The set of costs * @param [in] location_ids The location identifiers * @param [in] scaling_factor Multiplier * @@ -108,7 +107,7 @@ Matrix::get_original_id(Idx index) const { * */ Matrix::Matrix( - Vroom_matrix_t *matrix_rows, size_t total_matrix_rows, + const std::vector &matrix, const Identifiers &location_ids, double scaling_factor) { /* * Sets the selected nodes identifiers @@ -131,8 +130,7 @@ Matrix::Matrix( /* * Cycle the matrix data */ - for (size_t i = 0; i < total_matrix_rows; ++i) { - auto cell = matrix_rows[i]; + for (const auto &cell : matrix) { /* * skip if row is not from selected nodes */ diff --git a/src/optimize/optimize.c b/src/optimize/optimize.c index 985ed4b61..1b3821fa7 100644 --- a/src/optimize/optimize.c +++ b/src/optimize/optimize.c @@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ********************************************************************PGR-GNU*/ -#include #include "c_common/postgres_connection.h" #include "c_common/debug_macro.h" #include "c_common/e_report.h" @@ -62,6 +61,12 @@ process( Short_vehicle_rt **result_tuples, size_t *result_count) { + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; + + vrp_SPI_connect(); + //! [Factor must be postive] if (factor <= 0) { ereport(ERROR, @@ -86,8 +91,6 @@ process( errhint("Value found: %d", max_cycles))); } - vrp_SPI_connect(); - Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; if (use_timestamps) { @@ -206,10 +209,6 @@ process( PGR_DBG("Total %ld time dependant multipliers:", total_multipliers_arr); clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; - vrp_do_optimize( pd_orders_arr, total_pd_orders, vehicles_arr, total_vehicles, @@ -230,8 +229,7 @@ process( &log_msg, ¬ice_msg, &err_msg); - - time_msg("pgr_pickDeliver", start_t, clock()); + time_msg("vrp_optimize", start_t, clock()); if (err_msg && (*result_tuples)) { pfree(*result_tuples); @@ -330,15 +328,8 @@ _vrp_optimize(PG_FUNCTION_ARGS) { tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); - pfree(values); values = NULL; - pfree(nulls); nulls = NULL; - SRF_RETURN_NEXT(funcctx, result); } else { - if (result_tuples) { - pfree(result_tuples); result_tuples = NULL; - } - funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); } } diff --git a/src/optimize/optimize_driver.cpp b/src/optimize/optimize_driver.cpp index d9c90040d..0708d6cc9 100644 --- a/src/optimize/optimize_driver.cpp +++ b/src/optimize/optimize_driver.cpp @@ -42,6 +42,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "cpp_common/interruption.hpp" #include "cpp_common/messages.hpp" +#include "cpp_common/matrix_cell_t.hpp" +#include "cpp_common/time_multipliers_t.hpp" #include "cpp_common/orders_t.hpp" #include "cpp_common/short_vehicle.hpp" #include "cpp_common/vehicle_t.hpp" @@ -53,28 +55,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. namespace { +using Vehicle_t = struct Vehicle_t; +using Orders_t = struct Orders_t; using Short_vehicle = vrprouting::Short_vehicle; /** @brief Executes an optimization with the input data * - * @param[in] shipments_arr A C Array of pickup and dropoff shipments - * @param[in] total_shipments size of the shipments_arr - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr + * @param[in] orders orders to be processed + * @param[in] vehicles vehicles involved with in those orders * * @param[in] new_stops stops that override the original stops. - * @param[in] time_matrix The unique time matrix + * @param[in] matrix The unique time matrix * @param[in] max_cycles number of cycles to perform during the optimization phase - * @param[in] execution_date Value used for not moving shipments that are before this date + * @param[in] execution_date Value used for not moving orders that are before this date * * @returns (vehicle id, stops vector) pair which hold the the new stops structure */ std::vector one_processing( - Orders_t *shipments_arr, size_t total_shipments, - Vehicle_t *vehicles_arr, size_t total_vehicles, - std::vector new_stops, - const vrprouting::problem::Matrix &time_matrix, + const std::vector &orders, + const std::vector &vehicles, + const std::vector &new_stops, + const vrprouting::problem::Matrix &matrix, int max_cycles, int64_t execution_date) { try { @@ -82,10 +84,10 @@ one_processing( * Construct problem */ vrprouting::problem::PickDeliver pd_problem( - shipments_arr, total_shipments, - vehicles_arr, total_vehicles, + orders, + vehicles, new_stops, - time_matrix); + matrix); /* * Unknown problem when createing the pick Deliver problem @@ -116,18 +118,14 @@ one_processing( } -/** @brief: extract the times where the shipments opens or closes - * - * @param[in] shipments_arr A C Array of pickup and dropoff shipments - * @param[in] total_shipments size of the shipments_arr - * +/** @brief: extract the times where the orders opens or closes + * @param[in] orders orders to be processed * @returns processing times */ Identifiers -processing_times_by_shipment(Orders_t *shipments_arr, size_t total_shipments) { +processing_times_by_order(const std::vector &orders) { Identifiers processing_times; - for (size_t i = 0; i < total_shipments; ++i) { - auto o = shipments_arr[i]; + for (const auto &o : orders) { processing_times += o.pick_open_t; processing_times += o.pick_close_t; processing_times += o.deliver_open_t; @@ -137,17 +135,13 @@ processing_times_by_shipment(Orders_t *shipments_arr, size_t total_shipments) { } /** @brief: extract the times where the vehicle opens or closes - * - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr - * + * @param[in] vehicles vehicles for processing * @returns processing times */ Identifiers -processing_times_by_vehicle(Vehicle_t *vehicles_arr, size_t total_vehicles) { +processing_times_by_vehicle(const std::vector &vehicles) { Identifiers processing_times; - for (size_t i = 0; i < total_vehicles; ++i) { - auto v = vehicles_arr[i]; + for (const auto &v : vehicles) { processing_times += v.start_open_t; processing_times += v.start_close_t; processing_times += v.end_open_t; @@ -158,23 +152,20 @@ processing_times_by_vehicle(Vehicle_t *vehicles_arr, size_t total_vehicles) { /** @brief get the original stops * - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr + * @param[in] vehicles vehicles for processing * * @returns (vehicle id, stops vector) pair which hold the stops structure */ std::vector -get_initial_stops(Vehicle_t *vehicles_arr, size_t total_vehicles) { +get_initial_stops(const std::vector &vehicles) { std::vector the_stops; - for (size_t i = 0; i < total_vehicles; ++i) { + for (const auto &v : vehicles) { std::vector stops; - for (size_t j = 0; j < vehicles_arr[i].stops_size; ++j) { - stops.push_back(vehicles_arr[i].stops[j]); + for (size_t j = 0; j < v.stops_size; ++j) { + stops.push_back(v.stops[j]); } - the_stops.push_back({vehicles_arr[i].id, stops}); + the_stops.push_back({v.id, stops}); } - std::sort(the_stops.begin(), the_stops.end(), [] - (const Short_vehicle &lhs, const Short_vehicle &rhs) {return lhs.id < rhs.id;}); return the_stops; } @@ -198,80 +189,91 @@ update_stops(std::vector& the_stops, // NOLINT [runtime/referenc /** @brief Executes an optimization by subdivision of data * - * @param[in] shipments_arr A C Array of pickup and dropoff shipments - * @param[in] total_shipments size of the shipments_arr - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr - * @param[in] new_stops stops that override the original stops. - * @param[in] time_matrix The unique time matrix + * @param[in] orders orders to be processed + * @param[in] vehicles vehicles involved with in those orders + * @param[in] matrix The unique time matrix * @param[in] max_cycles number of cycles to perform during the optimization phase - * @param[in] execution_date Value used for not moving shipments that are before this date + * @param[in] execution_date Value used for not moving orders that are before this date + * @param[in] subdivide_by_vehicle When true: incremental optimization based on vehicles. otherwise by orders + * @param[in,out] log log of function * * @returns (vehicle id, stops vector) pair which hold the the new stops structure */ std::vector subdivide_processing( - Orders_t *shipments_arr, size_t total_shipments, - Vehicle_t *vehicles_arr, size_t total_vehicles, - const vrprouting::problem::Matrix &time_matrix, + const std::vector &orders, + const std::vector &vehicles, + const vrprouting::problem::Matrix &matrix, int max_cycles, int64_t execution_date, bool subdivide_by_vehicle, std::ostringstream &log) { try { - auto the_stops = get_initial_stops(vehicles_arr, total_vehicles); + auto the_stops = get_initial_stops(vehicles); auto processing_times = subdivide_by_vehicle? - processing_times_by_vehicle(vehicles_arr, total_vehicles) - : processing_times_by_shipment(shipments_arr, total_shipments); + processing_times_by_vehicle(vehicles) + : processing_times_by_order(orders); - Identifiers prev_shipments_in_stops; + Identifiers prev_orders_in_stops; + /* + * process active vehicles and orders at time \b t + */ for (const auto &t : processing_times) { CHECK_FOR_INTERRUPTS(); /* * Get active vehicles at time t + * v.open <= t <= v.close */ - auto vehicles_to_process = static_cast(std::distance(vehicles_arr, - std::partition( - vehicles_arr, vehicles_arr + total_vehicles, + std::vector active_vehicles; + std::vector inactive_vehicles; + std::partition_copy(vehicles.begin(), vehicles.end(), + std::back_inserter(active_vehicles), std::back_inserter(inactive_vehicles), [&](const Vehicle_t& v) - {return v.start_open_t <= t && t <= v.end_close_t;}))); - - /* Get shipments in stops of active vehicles */ - Identifiers shipments_in_stops; - for (size_t i = 0; i < vehicles_to_process; ++i) { - auto v_id = vehicles_arr[i].id; + {return v.start_open_t <= t && t <= v.end_close_t;}); + + /* Get orders in stops of active vehicles */ + Identifiers orders_in_stops; + for (const auto &v : active_vehicles) { + /* + * On previous cycles the stops have changed + * So instead of getting the stops from the vehicles + * get the stops from the the history of stops + */ auto v_to_modify = std::find_if( the_stops.begin(), the_stops.end(), [&] - (const Short_vehicle& v) -> bool {return v.id == v_id;}); + (const Short_vehicle& sv) -> bool {return sv.id == v.id;}); for (const auto &s : v_to_modify->stops) { - shipments_in_stops += s; + orders_in_stops += s; } } /* * Nothing to do: - * - no shipments to process - * - last optimization had exactly the same shipments + * - no orders to process + * - last optimization had exactly the same orders */ - if ((shipments_in_stops.size() == 0) - || (prev_shipments_in_stops == shipments_in_stops)) continue; + if (orders_in_stops.empty() + || (prev_orders_in_stops == orders_in_stops)) continue; log << "\nOptimizing at time: " << t; - prev_shipments_in_stops = shipments_in_stops; + prev_orders_in_stops = orders_in_stops; + + std::vector active_orders; + std::vector inactive_orders; - auto shipments_to_process = static_cast(std::distance(shipments_arr, - std::partition(shipments_arr, shipments_arr + total_shipments, - [&](const Orders_t& s){return shipments_in_stops.has(s.id);}))); + std::partition_copy(orders.begin(), orders.end(), + std::back_inserter(active_orders), std::back_inserter(inactive_orders), + [&](const Orders_t& o) + {return orders_in_stops.has(o.id);}); - pgassert(shipments_to_process > 0); - pgassert(shipments_in_stops.size() == static_cast(shipments_to_process)); + pgassert(active_orders.size() > 0); + pgassert(active_orders.size() == orders_in_stops.size()); auto new_stops = one_processing( - shipments_arr, shipments_to_process, - vehicles_arr, vehicles_to_process, the_stops, - time_matrix, + active_orders, active_vehicles, the_stops, + matrix, max_cycles, execution_date); update_stops(the_stops, new_stops); @@ -286,64 +288,9 @@ subdivide_processing( } // namespace -/** - * - * @param[in] shipments_arr A C Array of pickup and dropoff shipments - * @param[in] total_shipments size of the shipments_arr - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr - * @param[in] matrix_cells_arr A C Array of the (time) matrix cells - * @param[in] total_cells size of the matrix_cells_arr - * @param[in] multipliers_arr A C Array of the multipliers - * @param[in] total_multipliers size of the multipliers_arr - * - * @param[in] factor A global multiplier for the (time) matrix cells - * @param[in] max_cycles number of cycles to perform during the optimization phase - * @param[in] check_triangle_inequality When true tirangle inequality will be checked - * @param[in] subdivide @todo - * @param[in] subdivide_by_vehicle @todo - * @param[in] execution_date Value used for not moving shipments that are before this date - * - * @param[out] return_tuples C array of contents to be returned to postgres - * @param[out] return_count number of tuples returned - * @param[out] log_msg special log message pointer - * @param[out] notice_msg special message pointer to be returned as NOTICE - * @param[out] err_msg special message pointer to be returned as ERROR - * - * @pre The messages: log_msg, notice_msg, err_msg must be empty (=nullptr) - * @pre The C array: return_tuples must be empty - * @pre Only matrix cells (i, i) can be missing and are considered as 0 (time units) - * - * @post The C array: return_tuples contains the result for the problem given - * @post The return_tuples array size is return_count - * @post err_msg is empty if no throw from the process is catched - * @post log_msg contains some logging - * @post notice_msg is empty - * - * - @dot - digraph G { - node[fontsize=11, nodesep=0.75,ranksep=0.75]; - - start [shape=Mdiamond]; - n1 [label="Verify preconditions",shape=rect]; - n3 [label="Verify matrix cells preconditions",shape=rect]; - n4 [label="Construct problem",shape=cds,color=blue]; - n5 [label="get initial solutions",shape=cds,color=blue]; - n6 [label="solve (optimize)",shape=cds,color=blue]; - n7 [label="Prepare results",shape=rect]; - end [shape=Mdiamond]; - error [shape=Mdiamond,color=red] - start -> n1 -> n3 -> n4 -> n5 -> n6 -> n7 -> end; - n1 -> error [ label="Caller error",color=red]; - n3 -> error [ label="User error",color=red]; - - } - @enddot - */ void vrp_do_optimize( - Orders_t *shipments_arr, size_t total_shipments, + Orders_t *orders_arr, size_t total_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, Time_multipliers_t *multipliers_arr, size_t total_multipliers, @@ -373,20 +320,37 @@ vrp_do_optimize( std::ostringstream notice; std::ostringstream err; try { + using Matrix = vrprouting::problem::Matrix; + /* * verify preconditions */ pgassert(!(*log_msg)); pgassert(!(*notice_msg)); pgassert(!(*err_msg)); - pgassert(total_shipments); + pgassert(total_orders); pgassert(total_vehicles); pgassert(total_cells); pgassert(*return_count == 0); pgassert(!(*return_tuples)); + /* Data input starts */ + + /* + * transform to C++ containers + */ + std::vector vehicles(vehicles_arr, vehicles_arr + total_vehicles); + std::vector orders(orders_arr, orders_arr + total_orders); + std::vector costs(matrix_cells_arr, matrix_cells_arr + total_cells); + std::vector multipliers(multipliers_arr, multipliers_arr + total_multipliers); + + /* Data input ends */ + + /* Processing starts */ + Identifiers node_ids; - Identifiers shipments_in_stops; + Identifiers order_ids; + Identifiers orders_found; /* * Remove vehicles not going to be optimized and sort remaining vehicles @@ -395,89 +359,94 @@ vrp_do_optimize( * - data comes from query that could possibly give a duplicate * 3. remove vehicles that closes(end) before the execution time */ - std::sort(vehicles_arr, vehicles_arr + total_vehicles, + std::sort(vehicles.begin(), vehicles.end(), [](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id < rhs.id;}); - total_vehicles = static_cast(std::distance(vehicles_arr, - std::unique(vehicles_arr, vehicles_arr + total_vehicles, - [&](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id == rhs.id;}))); + vehicles.erase( + std::unique(vehicles.begin(), vehicles.end(), + [](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id == rhs.id;}), + vehicles.end()); - total_vehicles = static_cast(std::distance(vehicles_arr, - std::remove_if(vehicles_arr, vehicles_arr + total_vehicles, - [&](const Vehicle_t& v){return v.end_close_t < execution_date;}))); + vehicles.erase( + std::remove_if(vehicles.begin(), vehicles.end(), + [&](const Vehicle_t& v){return v.end_close_t < execution_date;}), + vehicles.end()); /* - * Remove shipments not involved in optimization - * 1. get the shipments on the stops of the vehicles - * - getting the node_ids in the same cycle - * 2. Remove duplicates - * 2. Remove shipments not on the stops + * nodes involved & orders involved */ - for (size_t i = 0; i < total_vehicles; ++i) { - node_ids += vehicles_arr[i].start_node_id; - node_ids += vehicles_arr[i].end_node_id; - for (size_t j = 0; j < vehicles_arr[i].stops_size; ++j) { - shipments_in_stops += vehicles_arr[i].stops[j]; + for (const auto &v : vehicles) { + node_ids += v.start_node_id; + node_ids += v.end_node_id; + for (size_t j = 0; j < v.stops_size; ++j) { + order_ids += v.stops[j]; } } - std::sort(shipments_arr, shipments_arr + total_shipments, + /* + * Remove orders not involved in optimization + * 1. get the orders on the stops of the vehicles + * - getting the node_ids in the same cycle + * 2. Remove duplicates + * 2. Remove orders not on the stops + */ + std::sort(orders.begin(), orders.end(), [](const Orders_t& lhs, const Orders_t& rhs){return lhs.id < rhs.id;}); - total_shipments = static_cast(std::distance(shipments_arr, - std::unique(shipments_arr, shipments_arr + total_shipments, - [&](const Orders_t& lhs, const Orders_t& rhs){return lhs.id == rhs.id;}))); + orders.erase( + std::unique( + orders.begin(), orders.end(), + [&](const Orders_t& lhs, const Orders_t& rhs) + {return lhs.id == rhs.id;}), + orders.end()); - total_shipments = static_cast(std::distance(shipments_arr, - std::remove_if(shipments_arr, shipments_arr + total_shipments, - [&](const Orders_t& s){return !shipments_in_stops.has(s.id);}))); + orders.erase( + std::remove_if( + orders.begin(), orders.end(), + [&](const Orders_t& s){return !order_ids.has(s.id);}), + orders.end()); /* - * Verify shipments complete data + * nodes involved & orders found */ - if (shipments_in_stops.size() != total_shipments) { - for (size_t i = 0; i < total_shipments; ++i) { - shipments_in_stops -= shipments_arr[i].id; - } - std::ostringstream hint; - err << "Missing shipments for processing "; - hint << "Shipments missing: " << shipments_in_stops << log.str(); - *log_msg = to_pg_msg(hint.str()); - *err_msg = to_pg_msg(err.str()); - return; + for (const auto &o : orders) { + orders_found += o.id; + node_ids += o.pick_node_id; + node_ids += o.deliver_node_id; } /* - * Finish getting the node ids involved on the process + * Verify orders complete data */ - for (size_t i = 0; i < total_shipments; ++i) { - node_ids += shipments_arr[i].pick_node_id; - node_ids += shipments_arr[i].deliver_node_id; + if (!(order_ids - orders_found).empty()) { + log << "Shipments missing: " << (order_ids - orders_found) << log.str(); + *log_msg = to_pg_msg(log.str()); + *err_msg = to_pg_msg("Missing orders for processing"); + return; } /* - * Dealing with time matrix: - * - Create the unique time matrix to be used for all optimizations - * - Verify matrix triangle inequality - * - Verify matrix cells preconditions + * Prepare matrix */ - vrprouting::problem::Matrix time_matrix( - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers, - node_ids, static_cast(factor)); + Matrix matrix(costs, multipliers, node_ids, static_cast(factor)); - if (check_triangle_inequality && !time_matrix.obeys_triangle_inequality()) { - log << "\nFixing Matrix that does not obey triangle inequality " - << time_matrix.fix_triangle_inequality() << " cycles used"; + /* + * Verify matrix triangle inequality + */ + if (check_triangle_inequality && !matrix.obeys_triangle_inequality()) { + log << "\nFixing Matrix that does not obey triangle inequality.\t" + << matrix.fix_triangle_inequality() << " cycles used"; - if (!time_matrix.obeys_triangle_inequality()) { - log << "\nMatrix Still does not obey triangle inequality "; + if (!matrix.obeys_triangle_inequality()) { + log << "\nMatrix Still does not obey triangle inequality."; } } - if (!time_matrix.has_no_infinity()) { - err << "\nAn Infinity value was found on the Matrix"; - *err_msg = to_pg_msg(err.str()); + /* + * Verify matrix cells preconditions + */ + if (!matrix.has_no_infinity()) { + *err_msg = to_pg_msg("An Infinity value was found on the Matrix"); *log_msg = to_pg_msg(log.str()); return; } @@ -487,23 +456,21 @@ vrp_do_optimize( */ auto solution = subdivide? subdivide_processing( - shipments_arr, total_shipments, - vehicles_arr, total_vehicles, - time_matrix, + orders, vehicles, + matrix, max_cycles, execution_date, subdivide_by_vehicle, log) : one_processing( - shipments_arr, total_shipments, - vehicles_arr, total_vehicles, {}, - time_matrix, + orders, vehicles, {}, + matrix, max_cycles, execution_date); /* * Prepare results */ if (!solution.empty()) { - (*return_tuples) = alloc(total_shipments * 2, (*return_tuples)); + (*return_tuples) = alloc(orders.size() * 2, (*return_tuples)); size_t seq = 0; for (const auto &row : solution) { @@ -514,8 +481,7 @@ vrp_do_optimize( } } } - - (*return_count) = total_shipments * 2; + (*return_count) = orders.size() * 2; pgassert(*err_msg == nullptr); *log_msg = log.str().empty()? nullptr : to_pg_msg(log.str()); diff --git a/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp b/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp index b0f9a4f3b..513178d51 100644 --- a/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp +++ b/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp @@ -1,5 +1,5 @@ /*PGR-GNU***************************************************************** -File: pickDeliver_driver.cpp +File: pgr_pickDeliver_driver.cpp Copyright (c) 2015 pgRouting developers Mail: project@pgrouting.org @@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "optimizers/simple.hpp" #include "problem/matrix.hpp" #include "problem/pickDeliver.hpp" +#include "problem/solution.hpp" namespace { @@ -71,8 +72,7 @@ get_initial_solution(vrprouting::problem::PickDeliver &problem_ptr, int m_initia bool are_shipments_ok( - Orders_t *customers_arr, - size_t total_customers, + const std::vector &orders, std::string *err_string, std::string *hint_string) { /** @@ -82,8 +82,7 @@ are_shipments_ok( * - p_open <= p_close * - d_open <= d_close */ - for (size_t i = 0; i < total_customers; ++i) { - auto o = customers_arr[i]; + for (const auto &o : orders) { if (o.demand == 0) { *err_string = "Unexpected zero value found on column 'demand' of shipments"; *hint_string = "Check shipment id #:" + std::to_string(o.id); @@ -121,7 +120,7 @@ are_shipments_ok( void vrp_do_pgr_pickDeliverEuclidean( - Orders_t *customers_arr, size_t total_customers, + Orders_t *orders_arr, size_t total_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, double factor, @@ -144,6 +143,13 @@ vrp_do_pgr_pickDeliverEuclidean( std::ostringstream notice; std::ostringstream err; try { + using Matrix = vrprouting::problem::Matrix; + using Optimize = vrprouting::optimizers::simple::Optimize; + using Initials_code = vrprouting::initialsol::simple::Initials_code; + + /* + * verify preconditions + */ pgassert(!(*log_msg)); pgassert(!(*notice_msg)); pgassert(!(*err_msg)); @@ -153,25 +159,33 @@ vrp_do_pgr_pickDeliverEuclidean( std::string err_string; std::string hint_string; - if (!are_shipments_ok(customers_arr, total_customers, &err_string, &hint_string)) { + /* + * Data input starts + */ + + /* + * transform to C++ containers + */ + std::vector orders(orders_arr, orders_arr + total_orders); + std::vector vehicles(vehicles_arr, vehicles_arr + total_vehicles); + + if (!are_shipments_ok(orders, &err_string, &hint_string)) { *err_msg = to_pg_msg(err_string); *log_msg = to_pg_msg(hint_string); return; } + /* Data input ends */ + + Identifiers node_ids; + Identifiers unique_ids; + /* - * transform to C++ containers + * Prepare identifiers */ - std::vector orders( - customers_arr, customers_arr + total_customers); - std::vector vehicles( - vehicles_arr, vehicles_arr + total_vehicles); - std::map, Id> matrix_data; for (const auto &o : orders) { - pgassert(o.pick_node_id == 0); - pgassert(o.deliver_node_id == 0); matrix_data[std::pair(o.pick_x, o.pick_y)] = 0; matrix_data[std::pair(o.deliver_x, o.deliver_y)] = 0; } @@ -181,22 +195,17 @@ vrp_do_pgr_pickDeliverEuclidean( matrix_data[std::pair(v.end_x, v.end_y)] = 0; } - Identifiers unique_ids; /* - * Data does not have ids for the locations' + * Data does not have ids for the locations */ Id id(0); for (auto &e : matrix_data) { e.second = id++; - } - - for (const auto &e : matrix_data) { unique_ids += e.second; - log << e.second << "(" << e.first.first << "," << e.first.second << ")\n"; } - for (size_t i = 0; i < total_customers; ++i) { - auto &o = customers_arr[i]; + + for (auto &o : orders) { o.pick_node_id = matrix_data[std::pair(o.pick_x, o.pick_y)]; o.deliver_node_id = matrix_data[std::pair(o.deliver_x, o.deliver_y)]; } @@ -206,38 +215,48 @@ vrp_do_pgr_pickDeliverEuclidean( v.end_node_id = matrix_data[std::pair(v.end_x, v.end_y)]; } - vrprouting::problem::Matrix matrix(matrix_data, static_cast(factor)); + /* + * Prepare matrix + */ + Matrix matrix(matrix_data, static_cast(factor)); - log << "Initialize problem\n"; - vrprouting::problem::PickDeliver pd_problem( - customers_arr, total_customers, - vehicles_arr, total_vehicles, - matrix); + /* + * Construct problem + */ + vrprouting::problem::PickDeliver pd_problem(orders, vehicles, matrix); - err << pd_problem.msg.get_error(); - if (!err.str().empty()) { - *err_msg = to_pg_msg(pd_problem.msg.get_error()); + if (pd_problem.msg.has_error()) { *log_msg = to_pg_msg(pd_problem.msg.get_log()); + *err_msg = to_pg_msg(pd_problem.msg.get_error()); return; } log << pd_problem.msg.get_log(); - log << "Finish Reading data\n"; + log << "Finish constructing problem\n"; + pd_problem.msg.clear(); + /* + * get initial solutions + */ auto sol = get_initial_solution(pd_problem, initial_solution_id); - using Optimize = vrprouting::optimizers::simple::Optimize; - using Initials_code = vrprouting::initialsol::simple::Initials_code; + + /* + * Solve (optimize) + */ sol = Optimize(sol, static_cast(max_cycles), (Initials_code)initial_solution_id); - log << pd_problem.msg.get_log(); - log << "Finish solve\n"; + /* + * get the solution + */ auto solution = sol.get_postgres_result(); - log << pd_problem.msg.get_log(); + log << sol.get_log(); log << "solution size: " << solution.size() << "\n"; - + /* + * Prepare results + */ if (!solution.empty()) { (*return_tuples) = alloc(solution.size(), (*return_tuples)); - int seq = 0; + size_t seq = 0; for (const auto &row : solution) { (*return_tuples)[seq] = row; ++seq; diff --git a/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp b/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp index cefa32dc3..912ce0e22 100644 --- a/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp +++ b/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp @@ -1,5 +1,5 @@ /*PGR-GNU***************************************************************** -File: pickDeliver_driver.cpp +File: pgr_pickDeliver_driver.cpp Copyright (c) 2015 pgRouting developers Mail: project@pgrouting.org @@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "cpp_common/alloc.hpp" #include "cpp_common/assert.hpp" +#include "cpp_common/matrix_cell_t.hpp" #include "cpp_common/orders_t.hpp" #include "cpp_common/vehicle_t.hpp" #include "initialsol/initials_code.hpp" @@ -75,7 +76,7 @@ get_initial_solution(vrprouting::problem::PickDeliver &problem_ptr, int m_initia void vrp_do_pgr_pickDeliver( - struct Orders_t customers_arr[], size_t total_customers, + struct Orders_t orders_arr[], size_t total_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, @@ -99,113 +100,100 @@ vrp_do_pgr_pickDeliver( std::ostringstream notice; std::ostringstream err; try { + using Matrix = vrprouting::problem::Matrix; + + /* + * verify preconditions + */ pgassert(!(*log_msg)); pgassert(!(*notice_msg)); pgassert(!(*err_msg)); - pgassert(total_customers); + pgassert(total_orders); pgassert(total_vehicles); pgassert(total_vehicles); pgassert(*return_count == 0); pgassert(!(*return_tuples)); + /* Data input starts */ + + /* + * transform to C++ containers + */ + std::vector vehicles(vehicles_arr, vehicles_arr + total_vehicles); + std::vector orders(orders_arr, orders_arr + total_orders); + std::vector costs(matrix_cells_arr, matrix_cells_arr + total_cells); + + /* Data input ends */ + + /* Processing starts */ Identifiers node_ids; Identifiers order_ids; - for (size_t i = 0; i < total_customers; ++i) { - auto o = customers_arr[i]; + for (const auto &o : orders) { node_ids += o.pick_node_id; node_ids += o.deliver_node_id; order_ids += o.id; } - for (size_t i = 0; i < total_vehicles; ++i) { - auto v = vehicles_arr[i]; + for (const auto &v : vehicles) { node_ids += v.start_node_id; node_ids += v.end_node_id; } - log << node_ids; - /* - * transform to C++ containers + * Prepare matrix */ - std::vector vehicles( - vehicles_arr, vehicles_arr + total_vehicles); - - vrprouting::problem::Matrix matrix(matrix_cells_arr, total_cells, node_ids, static_cast(factor)); - -#ifdef TODO - auto depot_node = vehicles[0].start_node_id; + Matrix matrix(costs, node_ids, static_cast(factor)); /* - * This applies to the one depot problem + * Verify matrix cells preconditions */ - if ((Initials_code)(initial_solution_id) == Initials_code::OneDepot) { - /* - * All Vehicles must depart from same location - */ - for (const auto &v : vehicles) { - if (v.start_node_id != depot_node && v.end_node_id != depot_node) { - err << "All vehicles must depart & arrive to same node"; - *err_msg = to_pg_msg(err.str()); - return; - } - } - - /* - * All Orders must depart from depot - */ - for (size_t i = 0; i < total_customers; ++i) { - if (customers_arr[i].pick_node_id != depot_node) { - err << "All orders must be picked at depot"; - *err_msg = to_pg_msg(err.str()); - return; - } - } - } -#endif - if (!matrix.has_no_infinity()) { - err << "An Infinity value was found on the Matrix. Might be missing information of a node"; - *err_msg = to_pg_msg(err.str()); + *err_msg = to_pg_msg("An Infinity value was found on the Matrix"); + *log_msg = to_pg_msg(log.str()); return; } - log << "Initialize problem\n"; - vrprouting::problem::PickDeliver pd_problem( - customers_arr, total_customers, - vehicles_arr, total_vehicles, - matrix); + /* + * Construct problem + */ + vrprouting::problem::PickDeliver pd_problem(orders, vehicles, matrix); - err << pd_problem.msg.get_error(); - if (!err.str().empty()) { - *err_msg = to_pg_msg(pd_problem.msg.get_error()); + if (pd_problem.msg.has_error()) { *log_msg = to_pg_msg(pd_problem.msg.get_log()); + *err_msg = to_pg_msg(pd_problem.msg.get_error()); return; } log << pd_problem.msg.get_log(); - log << "Finish Reading data\n"; + log << "Finish constructing problem\n"; pd_problem.msg.clear(); + /* + * get initial solutions + */ using Initials_code = vrprouting::initialsol::simple::Initials_code; auto sol = get_initial_solution(pd_problem, initial_solution_id); + + /* + * Solve (optimize) + */ using Optimize = vrprouting::optimizers::simple::Optimize; sol = Optimize(sol, static_cast(max_cycles), (Initials_code)initial_solution_id); - log << pd_problem.msg.get_log(); - log << "Finish solve\n"; - pd_problem.msg.clear(); - + /* + * get the solution + */ auto solution = sol.get_postgres_result(); - log << pd_problem.msg.get_log(); - pd_problem.msg.clear(); + log << sol.get_log(); log << "solution size: " << solution.size() << "\n"; - + /* + * Prepare results + */ if (!solution.empty()) { (*return_tuples) = alloc(solution.size(), (*return_tuples)); - int seq = 0; + size_t seq = 0; for (const auto &row : solution) { (*return_tuples)[seq] = row; ++seq; diff --git a/src/pgr_pickDeliver/pickDeliver.c b/src/pgr_pickDeliver/pickDeliver.c index 60ce2aea1..3428547bc 100644 --- a/src/pgr_pickDeliver/pickDeliver.c +++ b/src/pgr_pickDeliver/pickDeliver.c @@ -53,6 +53,12 @@ process( Solution_rt **result_tuples, size_t *result_count) { + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; + + vrp_SPI_connect(); + if (factor <= 0) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -83,7 +89,6 @@ process( return; } - vrp_SPI_connect(); Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; @@ -221,10 +226,6 @@ process( PGR_DBG("Starting processing"); clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; - vrp_do_pgr_pickDeliver( pd_orders_arr, total_pd_orders, vehicles_arr, total_vehicles, @@ -240,8 +241,7 @@ process( &log_msg, ¬ice_msg, &err_msg); - - time_msg("pgr_pickDeliver", start_t, clock()); + time_msg("vrp_pgr_pickDeliver", start_t, clock()); if (err_msg && (*result_tuples)) { pfree(*result_tuples); @@ -264,11 +264,6 @@ process( vrp_SPI_finish(); } - - -/******************************************************************************/ - - PGDLLEXPORT Datum _vrp_pgr_pickdeliver(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; @@ -341,8 +336,6 @@ _vrp_pgr_pickdeliver(PG_FUNCTION_ARGS) { values[11] = Int64GetDatum(result_tuples[call_cntr].serviceDuration); values[12] = Int64GetDatum(result_tuples[call_cntr].departureTime); - /*********************************************************************/ - tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); diff --git a/src/pgr_pickDeliver/pickDeliverEuclidean.c b/src/pgr_pickDeliver/pickDeliverEuclidean.c index 24942dcf1..1445a04d5 100644 --- a/src/pgr_pickDeliver/pickDeliverEuclidean.c +++ b/src/pgr_pickDeliver/pickDeliverEuclidean.c @@ -52,6 +52,12 @@ process( int initial_solution_id, Solution_rt **result_tuples, size_t *result_count) { + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; + + vrp_SPI_connect(); + if (factor <= 0) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -79,8 +85,6 @@ process( return; } - vrp_SPI_connect(); - PGR_DBG("Load orders"); struct Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; @@ -154,9 +158,6 @@ process( PGR_DBG("Starting processing"); clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; vrp_do_pgr_pickDeliverEuclidean( pd_orders_arr, total_pd_orders, vehicles_arr, total_vehicles, @@ -171,7 +172,7 @@ process( &log_msg, ¬ice_msg, &err_msg); - time_msg("_pgr_pickDeliverEuclidean", start_t, clock()); + time_msg("vrp_pgr_pickDeliverEuclidean", start_t, clock()); if (err_msg && (*result_tuples)) { pfree(*result_tuples); @@ -200,7 +201,6 @@ _vrp_pgr_pickdelivereuclidean(PG_FUNCTION_ARGS) { funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - PGR_DBG("Calling process"); process( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), @@ -244,8 +244,6 @@ _vrp_pgr_pickdelivereuclidean(PG_FUNCTION_ARGS) { nulls[i] = false; } - - // postgres starts counting from 1 values[0] = Int32GetDatum(funcctx->call_cntr + 1); values[1] = Int32GetDatum(result_tuples[call_cntr].vehicle_seq); values[2] = Int64GetDatum(result_tuples[call_cntr].vehicle_id); @@ -259,8 +257,6 @@ _vrp_pgr_pickdelivereuclidean(PG_FUNCTION_ARGS) { values[10] = Int64GetDatum(result_tuples[call_cntr].serviceDuration); values[11] = Int64GetDatum(result_tuples[call_cntr].departureTime); - /*********************************************************************/ - tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); diff --git a/src/pickDeliver/pickDeliver.c b/src/pickDeliver/pickDeliver.c index ce92f5532..719205d66 100644 --- a/src/pickDeliver/pickDeliver.c +++ b/src/pickDeliver/pickDeliver.c @@ -65,6 +65,12 @@ process( Solution_rt **result_tuples, size_t *result_count) { + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; + + vrp_SPI_connect(); + /* * Adjusting timestamp data to timezone UTC */ @@ -90,8 +96,6 @@ process( errhint("Value found: %d <= 0", max_cycles))); } - vrp_SPI_connect(); - Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; if (use_timestamps) { @@ -212,10 +216,6 @@ process( PGR_DBG("Total %ld time dependant multipliers:", total_multipliers_arr); clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; - vrp_do_pickDeliver( pd_orders_arr, total_pd_orders, vehicles_arr, total_vehicles, @@ -235,8 +235,7 @@ process( &log_msg, ¬ice_msg, &err_msg); - - time_msg("pgr_pickDeliver", start_t, clock()); + time_msg("vrp_pickDeliver", start_t, clock()); if (err_msg && (*result_tuples)) { pfree(*result_tuples); @@ -273,7 +272,7 @@ _vrp_pickdeliver(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - Solution_rt *result_tuples = 0; + Solution_rt *result_tuples = NULL; size_t result_count = 0; if (SRF_IS_FIRSTCALL()) { @@ -351,16 +350,8 @@ _vrp_pickdeliver(PG_FUNCTION_ARGS) { tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); - - pfree(values); values = NULL; - pfree(nulls); nulls = NULL; - SRF_RETURN_NEXT(funcctx, result); } else { - if (result_tuples) { - pfree(result_tuples); result_tuples = NULL; - } - funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); } } @@ -452,16 +443,8 @@ _vrp_pickdeliverraw(PG_FUNCTION_ARGS) { tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); - - pfree(values); values = NULL; - pfree(nulls); nulls = NULL; - SRF_RETURN_NEXT(funcctx, result); } else { - if (result_tuples) { - pfree(result_tuples); result_tuples = NULL; - } - funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); } } diff --git a/src/pickDeliver/pickDeliver_driver.cpp b/src/pickDeliver/pickDeliver_driver.cpp index 1e60c6d82..e13ccc237 100644 --- a/src/pickDeliver/pickDeliver_driver.cpp +++ b/src/pickDeliver/pickDeliver_driver.cpp @@ -33,12 +33,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include #include +#include #include "c_types/solution_rt.h" #include "cpp_common/alloc.hpp" #include "cpp_common/assert.hpp" +#include "cpp_common/matrix_cell_t.hpp" +#include "cpp_common/time_multipliers_t.hpp" #include "cpp_common/orders_t.hpp" #include "cpp_common/vehicle_t.hpp" #include "initialsol/tabu.hpp" @@ -46,63 +49,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "problem/matrix.hpp" #include "problem/pickDeliver.hpp" - -/** - * - * @param[in] customers_arr A C Array of pickup and dropoff orders - * @param[in] total_customers size of the customers_arr - * @param[in] vehicles_arr A C Array of vehicles - * @param[in] total_vehicles size of the vehicles_arr - * @param[in] matrix_cells_arr A C Array of the (time) matrix cells - * @param[in] total_cells size of the matrix_cells_arr - * @param[in] multipliers_arr A C Array of the multipliers - * @param[in] total_multipliers size of the multipliers_arr - * @param[in] optimize flag to control optimization - * @param[in] factor A global multiplier for the (time) matrix cells - * @param[in] max_cycles number of cycles to perform during the optimization phase - * @param[in] stop_on_all_served Indicator to stop optimization when all orders are served - * @param[in] execution_date Value used for not moving orders that are before this date - * @param[out] return_tuples C array of contents to be returned to postgres - * @param[out] return_count number of tuples returned - * @param[out] log_msg special log message pointer - * @param[out] notice_msg special message pointer to be returned as NOTICE - * @param[out] err_msg special message pointer to be returned as ERROR - * - * @pre The messages: log_msg, notice_msg, err_msg must be empty (=nullptr) - * @pre The C arrays: customers_arr, vehicles_arr, matrix_cells_arr must not be empty - * @pre The C array: return_tuples must be empty - * @pre Only matrix cells (i, i) can be missing and are considered as 0 (time units) - * - * @post The C arrays: customers_arr, vehicles_arr, matrix_cells_arr Do not change - * @post The C array: return_tuples contains the result for the problem given - * @post The return_tuples array size is return_count - * @post err_msg is empty if no throw from the process is catched - * @post log_msg contains some logging - * @post notice_msg is empty - * - @dot -digraph G { - node[fontsize=11, nodesep=0.75,ranksep=0.75]; - - start [shape=Mdiamond]; - n1 [label="Verify preconditions",shape=rect]; - n3 [label="Verify matrix cells preconditions",shape=rect]; - n4 [label="Construct problem",shape=cds,color=blue]; - n5 [label="get initial solutions",shape=cds,color=blue]; - n6 [label="solve (optimize)",shape=cds,color=blue]; - n7 [label="Prepare results",shape=rect]; - end [shape=Mdiamond]; - error [shape=Mdiamond,color=red] - start -> n1 -> n3 -> n4 -> n5 -> n6 -> n7 -> end; - n1 -> error [ label="Caller error",color=red]; - n3 -> error [ label="User error",color=red]; - -} -@enddot - */ void vrp_do_pickDeliver( - Orders_t *customers_arr, size_t total_customers, + Orders_t *orders_arr, size_t total_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, Time_multipliers_t *multipliers_arr, size_t total_multipliers, @@ -130,32 +79,48 @@ vrp_do_pickDeliver( std::ostringstream notice; std::ostringstream err; try { + using Matrix = vrprouting::problem::Matrix; + /* * verify preconditions */ pgassert(!(*log_msg)); pgassert(!(*notice_msg)); pgassert(!(*err_msg)); - pgassert(total_customers); + pgassert(total_orders); pgassert(total_vehicles); pgassert(total_cells); pgassert(*return_count == 0); pgassert(!(*return_tuples)); - log << "do_pickDeliver\n"; + + /* Data input starts */ + + /* + * transform to C++ containers + */ + std::vector vehicles(vehicles_arr, vehicles_arr + total_vehicles); + std::vector orders(orders_arr, orders_arr + total_orders); + std::vector costs(matrix_cells_arr, matrix_cells_arr + total_cells); + std::vector multipliers(multipliers_arr, multipliers_arr + total_multipliers); + + /* Data input ends */ + + /* Processing starts */ Identifiers node_ids; Identifiers order_ids; - for (size_t i = 0; i < total_customers; ++i) { - auto o = customers_arr[i]; + /* + * nodes involved & orders involved + */ + for (const auto &o : orders) { node_ids += o.pick_node_id; node_ids += o.deliver_node_id; order_ids += o.id; } bool missing = false; - for (size_t i = 0; i < total_vehicles; ++i) { - auto v = vehicles_arr[i]; + for (const auto &v : vehicles) { node_ids += v.start_node_id; node_ids += v.end_node_id; for (size_t j = 0; j < v.stops_size; ++j) { @@ -163,66 +128,56 @@ vrp_do_pickDeliver( if (!order_ids.has(s)) { if (!missing) err << "Order in 'stops' information missing"; missing = true; - err << "Missing information of order " << s << "\n"; + log << "Missing information of order " << s << "\n"; } } if (missing) { *err_msg = to_pg_msg(err.str()); + *log_msg = to_pg_msg(log.str()); return; } } - vrprouting::problem::Matrix cost_matrix( - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers, - node_ids, static_cast(factor)); + /* + * Prepare matrix + */ + Matrix matrix(costs, multipliers, node_ids, static_cast(factor)); /* * Verify matrix triangle inequality */ - if (!cost_matrix.obeys_triangle_inequality()) { - log << "[PickDeliver] Fixing Matrix that does not obey triangle inequality "; - log << cost_matrix.fix_triangle_inequality() << " cycles used"; + if (!matrix.obeys_triangle_inequality()) { + log << "\nFixing Matrix that does not obey triangle inequality.\t" + << matrix.fix_triangle_inequality() << " cycles used"; - if (!cost_matrix.obeys_triangle_inequality()) { - log << "[pickDeliver] Matrix Still does not obey triangle inequality "; + if (!matrix.obeys_triangle_inequality()) { + log << "\nMatrix Still does not obey triangle inequality."; } } /* * Verify matrix cells preconditions */ - if (!cost_matrix.has_no_infinity()) { - err << "An Infinity value was found on the Matrix"; - *err_msg = to_pg_msg(err.str()); + if (!matrix.has_no_infinity()) { + *err_msg = to_pg_msg("An Infinity value was found on the Matrix"); + *log_msg = to_pg_msg(log.str()); return; } - - log << "stop_on_all_served" << stop_on_all_served << "\n"; - log << "execution_date" << execution_date << "\n"; - log << "Initialize problem\n"; /* * Construct problem */ - vrprouting::problem::PickDeliver pd_problem( - customers_arr, total_customers, - vehicles_arr, total_vehicles, - cost_matrix); - - err << pd_problem.msg.get_error(); - if (!err.str().empty()) { - log << pd_problem.msg.get_error(); - log << pd_problem.msg.get_log(); - *log_msg = to_pg_msg(log.str()); - *err_msg = to_pg_msg(err.str()); + vrprouting::problem::PickDeliver pd_problem(orders, vehicles, matrix); + + if (pd_problem.msg.has_error()) { + *log_msg = to_pg_msg(pd_problem.msg.get_log()); + *err_msg = to_pg_msg(pd_problem.msg.get_error()); return; } log << pd_problem.msg.get_log(); + log << "Finish constructing problem\n"; pd_problem.msg.clear(); - log << "Finish Initialize problem\n"; - /* * get initial solutions */ @@ -236,22 +191,19 @@ vrp_do_pickDeliver( using Optimize = vrprouting::optimizers::tabu::Optimize; sol = Optimize(sol, static_cast(max_cycles), stop_on_all_served, optimize); - log << pd_problem.msg.get_log(); - pd_problem.msg.clear(); - log << "Finish solve\n"; - /* - * Prepare results + * get the solution */ auto solution = sol.get_postgres_result(); - log << pd_problem.msg.get_log(); - pd_problem.msg.clear(); + log << sol.get_log(); log << "solution size: " << solution.size() << "\n"; - + /* + * Prepare results + */ if (!solution.empty()) { (*return_tuples) = alloc(solution.size(), (*return_tuples)); - int seq = 0; + size_t seq = 0; for (const auto &row : solution) { (*return_tuples)[seq] = row; ++seq; diff --git a/src/problem/fleet.cpp b/src/problem/fleet.cpp index dbea54b36..39ef641a4 100644 --- a/src/problem/fleet.cpp +++ b/src/problem/fleet.cpp @@ -357,15 +357,13 @@ Fleet::set_compatibles(const Orders &orders) { builds a fleet from a vector of Vehicle_t @param[in] vehicles the list of vehicles - @param[in] size_vehicles @param [in] new_stops overides vehicles stops @param[in] p_orders @param[in,out] p_nodes @param[in,out] node_id */ -void -Fleet::build_fleet( - Vehicle_t *vehicles, size_t size_vehicles, +void Fleet::build_fleet( + std::vector vehicles, const std::vector& new_stops, const Orders& p_orders, std::vector& p_nodes, @@ -373,7 +371,7 @@ Fleet::build_fleet( /** * Sort vehicles: ASC start_open_t, end_close_t, id */ - std::sort(vehicles, vehicles + size_vehicles, + std::sort(vehicles.begin(), vehicles.end(), [] (const Vehicle_t &lhs, const Vehicle_t &rhs) { if (lhs.start_open_t == rhs.start_open_t) { if (lhs.end_close_t == rhs.end_close_t) { @@ -389,8 +387,8 @@ Fleet::build_fleet( /** * Add the vehicles */ - for (size_t i = 0; i < size_vehicles; ++i) { - add_vehicle(vehicles[i], new_stops, p_orders, p_nodes, node_id); + for (const auto &v : vehicles) { + add_vehicle(v, new_stops, p_orders, p_nodes, node_id); } /** @@ -443,22 +441,22 @@ Fleet::build_fleet( /* Constructors */ Fleet::Fleet( - Vehicle_t* vehicles , size_t size_vehicles, + const std::vector &vehicles, const Orders& p_orders, std::vector& p_nodes, size_t& node_id) : m_used(), m_unused() { - build_fleet(vehicles, size_vehicles, {}, p_orders, p_nodes, node_id); + build_fleet(vehicles, {}, p_orders, p_nodes, node_id); } Fleet::Fleet( - Vehicle_t* vehicles , size_t size_vehicles, + const std::vector &vehicles, const std::vector &new_stops, const Orders& p_orders, std::vector& p_nodes, size_t& node_id) : m_used(), m_unused() { - build_fleet(vehicles, size_vehicles, new_stops, p_orders, p_nodes, node_id); + build_fleet(vehicles, new_stops, p_orders, p_nodes, node_id); } } // namespace problem diff --git a/src/problem/matrix.cpp b/src/problem/matrix.cpp index 2439658d2..66b43db00 100644 --- a/src/problem/matrix.cpp +++ b/src/problem/matrix.cpp @@ -49,22 +49,21 @@ namespace { /** * @param [in] p_multipliers time dependant multiplier data - * @param [in] size_multipliers number of rows in the data * @returns time dependant multiplier container */ std::vector> -set_tdm(Time_multipliers_t *p_multipliers, size_t size_multipliers) { - pgassert(size_multipliers > 1); +set_tdm(std::vector p_multipliers) { + pgassert(!p_multipliers.empty()); std::vector> tdm; /* * Sort the multipliers info */ - std::sort(p_multipliers, p_multipliers + size_multipliers, + std::sort(p_multipliers.begin(), p_multipliers.end(), [] (const Time_multipliers_t &lhs, const Time_multipliers_t &rhs) { return lhs.start_time < rhs.start_time; }); - for (size_t i = 0; i < size_multipliers; ++i) { - tdm.emplace_back(p_multipliers[i].start_time, p_multipliers[i].multiplier); + for (const auto &m : p_multipliers) { + tdm.emplace_back(m.start_time, m.multiplier); } return tdm; } @@ -165,22 +164,22 @@ time_change(const std::vector> &tdm, TTimesta } // namespace Matrix::Matrix( - Matrix_cell_t *matrix, size_t size_matrix, - Time_multipliers_t *multipliers, size_t size_multipliers, + const std::vector &matrix, + const std::vector &multipliers, const Identifiers& node_ids, Multiplier multiplier) : - Base_Matrix(matrix, size_matrix, node_ids, multiplier), - m_multipliers(set_tdm(multipliers, size_multipliers)) { } + Base_Matrix(matrix, node_ids, multiplier), + m_multipliers(set_tdm(multipliers)) { } /* * constructor for euclidean default multipliers */ Matrix::Matrix( - Matrix_cell_t *matrix, size_t size_matrix, + const std::vector &matrix, const Identifiers& node_ids, Multiplier multiplier) : - Base_Matrix(matrix, size_matrix, node_ids, multiplier), + Base_Matrix(matrix, node_ids, multiplier), m_multipliers{{0, 1}} { } /* diff --git a/src/problem/orders.cpp b/src/problem/orders.cpp index 8228c9c6d..1780b9fcf 100644 --- a/src/problem/orders.cpp +++ b/src/problem/orders.cpp @@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "cpp_common/assert.hpp" #include "cpp_common/identifiers.hpp" +#include "cpp_common/orders_t.hpp" #include "problem/pickDeliver.hpp" @@ -39,10 +40,10 @@ namespace vrprouting { namespace problem { Orders::Orders( - Orders_t *p_orders, size_t p_size_orders, + const std::vector &p_orders, PickDeliver &problem_ptr) { Tw_node::m_time_matrix_ptr = &(problem_ptr.time_matrix()); - build_orders(p_orders, p_size_orders, problem_ptr); + build_orders(p_orders, problem_ptr); } /** @@ -143,17 +144,16 @@ Orders::set_compatibles(Speed speed) { /** @param [in] orders set of orders - @param [in] sizer_orders @param [in] problem_ptr pointer to problem to get some needed information */ void Orders::build_orders( - Orders_t *orders, size_t size_orders, + std::vector orders, PickDeliver& problem_ptr) { /** * - Sort orders: ASC pick_open_t, deliver_close_t, id */ - std::sort(orders, orders + size_orders, + std::sort(orders.begin(), orders.end(), [] (const Orders_t &lhs, const Orders_t &rhs) { if (lhs.pick_open_t == rhs.pick_open_t) { if (lhs.deliver_close_t == rhs.deliver_close_t) { @@ -166,8 +166,7 @@ Orders::build_orders( } }); - for (size_t i = 0; i < size_orders; ++i) { - auto o = orders[i]; + for (const auto &o : orders) { Vehicle_node pick({problem_ptr.node_id()++, o, NodeType::kPickup}); Vehicle_node drop({problem_ptr.node_id()++, o, NodeType::kDelivery}); @@ -178,6 +177,21 @@ Orders::build_orders( } } +void +Orders::add_order(const Orders_t &order, + const Vehicle_node &pick, + const Vehicle_node &drop) { + push_back(Order(size(), order.id, pick, drop)); +} + +std::ostream& +operator<<(std::ostream &log, const Orders &p_orders) { + log << "Orders\n"; + for (const auto &o : p_orders) log << o << "\n"; + log << "end Orders\n"; + return log; +} + } // namespace problem } // namespace vrprouting diff --git a/src/problem/pickDeliver.cpp b/src/problem/pickDeliver.cpp index 1b79b04cc..84930ed21 100644 --- a/src/problem/pickDeliver.cpp +++ b/src/problem/pickDeliver.cpp @@ -42,12 +42,12 @@ namespace vrprouting { namespace problem { PickDeliver::PickDeliver( - Orders_t* p_orders, size_t p_orders_size, - Vehicle_t* p_vehicles, size_t p_vehicles_size, + const std::vector &p_orders, + const std::vector &p_vehicles, const Matrix &p_cost_matrix) : m_cost_matrix(p_cost_matrix), - m_orders(p_orders, p_orders_size, *this), - m_trucks(p_vehicles, p_vehicles_size, m_orders, m_nodes, m_node_id) { + m_orders(p_orders, *this), + m_trucks(p_vehicles, m_orders, m_nodes, m_node_id) { if (!msg.get_error().empty()) return; m_trucks.clean(); m_orders.set_compatibles(); @@ -56,13 +56,13 @@ PickDeliver::PickDeliver( /** @brief Override stops constructor */ PickDeliver::PickDeliver( - Orders_t* p_orders, size_t p_orders_size, - Vehicle_t* p_vehicles, size_t p_vehicles_size, + const std::vector &p_orders, + const std::vector &p_vehicles, std::vector new_stops, const Matrix &p_cost_matrix) : m_cost_matrix(p_cost_matrix), - m_orders(p_orders, p_orders_size, *this), - m_trucks(p_vehicles, p_vehicles_size, new_stops, m_orders, m_nodes, m_node_id) { + m_orders(p_orders, *this), + m_trucks(p_vehicles, new_stops, m_orders, m_nodes, m_node_id) { if (!msg.get_error().empty()) return; m_trucks.clean(); m_orders.set_compatibles(); diff --git a/src/problem/vroom.cpp b/src/problem/vroom.cpp index 8c05dac17..b4f9225a1 100644 --- a/src/problem/vroom.cpp +++ b/src/problem/vroom.cpp @@ -126,14 +126,6 @@ Vroom::add_jobs( } } -void -Vroom::add_jobs(const Vroom_job_t *jobs, size_t count, - const Vroom_time_window_t *jobs_tws, size_t total_jobs_tws) { - add_jobs( - std::vector(jobs, jobs + count), - std::vector(jobs_tws, jobs_tws + total_jobs_tws)); -} - std::pair<::vroom::Job, ::vroom::Job> Vroom::get_vroom_shipment( const Vroom_shipment_t &shipment, @@ -185,15 +177,6 @@ Vroom::add_shipments( } } -void -Vroom::add_shipments( - const Vroom_shipment_t *shipments, size_t count, - const Vroom_time_window_t *shipment_tws, size_t total_shipment_tws) { - add_shipments( - std::vector(shipments, shipments + count), - std::vector(shipment_tws, shipment_tws + total_shipment_tws)); -} - std::vector<::vroom::Break> Vroom::get_vroom_breaks( const std::vector &breaks, @@ -279,15 +262,6 @@ Vroom::add_vehicles( } } -void -Vroom::add_vehicles(const Vroom_vehicle_t *vehicles, size_t count, - const Vroom_break_t *breaks, size_t total_breaks, - const Vroom_time_window_t *breaks_tws, size_t total_breaks_tws) { - add_vehicles(std::vector(vehicles, vehicles + count), - std::vector(breaks, breaks + total_breaks), - std::vector(breaks_tws, breaks_tws + total_breaks_tws)); -} - /* * param[in] matrix The matrix */ diff --git a/src/vroom/vroom.c b/src/vroom/vroom.c index 4f3fa28d8..302d8ee7d 100644 --- a/src/vroom/vroom.c +++ b/src/vroom/vroom.c @@ -219,10 +219,6 @@ process( } -/** @brief Helps in converting postgres variables to C variables, and returns the result. - * - */ - PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; diff --git a/src/vroom/vroom_driver.cpp b/src/vroom/vroom_driver.cpp index 529d77281..0d80322d6 100644 --- a/src/vroom/vroom_driver.cpp +++ b/src/vroom/vroom_driver.cpp @@ -41,64 +41,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "cpp_common/identifiers.hpp" #include "cpp_common/vroom_job_t.hpp" -#include "cpp_common/vroom_matrix.hpp" +#include "cpp_common/vroom_matrix_t.hpp" #include "cpp_common/vroom_vehicle_t.hpp" #include "cpp_common/vroom_shipment_t.hpp" +#include "cpp_common/vroom_break_t.hpp" +#include "cpp_common/vroom_time_window_t.hpp" + #include "vroom/vroom.hpp" -/** @file vroom_driver.cpp - * @brief Handles actual calling of function in the `vrp_vroom.hpp` file. - */ - -/** @brief Performs exception handling and converts the results to postgres. - * - * @pre log_msg is empty - * @pre notice_msg is empty - * @pre err_msg is empty - * @pre return_tuples is empty - * @pre return_count is 0 - * - * It converts the C types to the C++ types, and passes these variables to the - * function `vrp_vroom` which calls the main function defined in the - * C++ Header file. It also does exception handling. - * - * @param[in] jobs Pointer to the array of jobs - * @param[in] total_jobs The total number of jobs - * @param[in] jobs_tws Pointer to the array of jobs time windows - * @param[in] total_jobs_tws The total number of jobs time windows - * @param[in] shipments Pointer to the array of shipments - * @param[in] total_shipments The total number of shipments - * @param[in] shipments_tws Pointer to the array of shipments time windows - * @param[in] total_shipments_tws The total number of shipments time windows - * @param[in] vehicles Pointer to the array of vehicles - * @param[in] total_vehicles The total number of total vehicles - * @param[in] breaks Pointer to the array of breaks - * @param[in] total_breaks The total number of total breaks - * @param[in] breaks_tws Pointer to the array of break timewindows - * @param[in] total_breaks_tws The total number of total breaks timewindows - * @param[in] matrix_rows Pointer to the array of matrix rows - * @param[in] total_matrix_rows The total number of matrix rows - * - * @param[in] exploration_level Exploration level to use while solving. - * @param[in] timeout Timeout value to stop the solving process (seconds). - * @param[in] loading_time Additional time spent in loading the data from SQL Query (seconds). - * - * @param[out] return_tuples The rows in the result - * @param[out] return_count The count of rows in the result - * @param[out] log_msg Stores the log message - * @param[out] notice_msg Stores the notice message - * @param[out] err_msg Stores the error message - */ void vrp_do_vroom( - Vroom_job_t *jobs, size_t total_jobs, - Vroom_time_window_t *jobs_tws, size_t total_jobs_tws, - Vroom_shipment_t *shipments, size_t total_shipments, - Vroom_time_window_t *shipments_tws, size_t total_shipments_tws, - Vroom_vehicle_t *vehicles, size_t total_vehicles, - Vroom_break_t *breaks, size_t total_breaks, - Vroom_time_window_t *breaks_tws, size_t total_breaks_tws, - Vroom_matrix_t *matrix_rows, size_t total_matrix_rows, + Vroom_job_t *jobs_arr, size_t total_jobs, + Vroom_time_window_t *jobs_tws_arr, size_t total_jobs_tws, + Vroom_shipment_t *shipments_arr, size_t total_shipments, + Vroom_time_window_t *shipments_tws_arr, size_t total_shipments_tws, + Vroom_vehicle_t *vehicles_arr, size_t total_vehicles, + Vroom_break_t *breaks_arr, size_t total_breaks, + Vroom_time_window_t *breaks_tws_arr, size_t total_breaks_tws, + Vroom_matrix_t *matrix_arr, size_t total_matrix, int32_t exploration_level, int32_t timeout, @@ -120,30 +80,50 @@ vrp_do_vroom( std::ostringstream err; std::ostringstream notice; try { + using Matrix = vrprouting::vroom::Matrix; + + /* + * verify preconditions + */ pgassert(!(*log_msg)); pgassert(!(*notice_msg)); pgassert(!(*err_msg)); pgassert(!(*return_tuples)); pgassert(!(*return_count)); - pgassert(jobs || shipments); - pgassert(vehicles); - pgassert(matrix_rows); + pgassert(jobs_arr || shipments_arr); + pgassert(vehicles_arr); + pgassert(matrix_arr); pgassert(total_jobs || total_shipments); pgassert(total_vehicles); - pgassert(total_matrix_rows); + pgassert(total_matrix); - using Matrix = vrprouting::vroom::Matrix; auto start_time = std::chrono::high_resolution_clock::now(); + /* Data input starts */ + + /* + * transform to C++ containers + */ + std::vector jobs(jobs_arr, jobs_arr + total_jobs); + std::vector jobs_tw(jobs_tws_arr, jobs_tws_arr + total_jobs_tws); + std::vector shipments(shipments_arr, shipments_arr + total_shipments); + std::vector shipments_tw(shipments_tws_arr, shipments_tws_arr + total_shipments_tws); + std::vector vehicles(vehicles_arr, vehicles_arr + total_vehicles); + std::vector breaks(breaks_arr, breaks_arr + total_breaks); + std::vector breaks_tw(breaks_tws_arr, breaks_tws_arr + total_breaks_tws); + std::vector costs(matrix_arr, matrix_arr + total_matrix); + + /* Data input ends */ + + /* Processing starts */ Identifiers location_ids; - for (size_t i = 0; i < total_jobs; ++i) { - location_ids += jobs[i].location_id; + for (const auto &j : jobs) { + location_ids += j.location_id; } - for (size_t i = 0; i < total_shipments; ++i) { - auto s = shipments[i]; + for (const auto &s : shipments) { location_ids += s.p_location_id; location_ids += s.d_location_id; } @@ -151,8 +131,7 @@ vrp_do_vroom( double min_speed_factor, max_speed_factor; min_speed_factor = max_speed_factor = vehicles[0].speed_factor; - for (size_t i = 0; i < total_vehicles; ++i) { - auto v = vehicles[i]; + for (const auto &v : vehicles) { min_speed_factor = std::min(min_speed_factor, v.speed_factor); max_speed_factor = std::max(max_speed_factor, v.speed_factor); if (v.start_id != -1) { @@ -179,19 +158,19 @@ vrp_do_vroom( /* * Scale the vehicles speed factors according to the minimum speed factor */ - for (size_t i = 0; i < total_vehicles; ++i) { - vehicles[i].speed_factor = std::round(vehicles[i].speed_factor / min_speed_factor); + for (auto &v : vehicles) { + v.speed_factor = std::round(v.speed_factor / min_speed_factor); } /* * Create the matrix. Also, scale the time matrix according to min_speed_factor */ - Matrix matrix(matrix_rows, total_matrix_rows, location_ids, min_speed_factor); + Matrix matrix(costs, location_ids, min_speed_factor); /* * Verify size of matrix cell lies in the limit */ - if (matrix.size() > (std::numeric_limits::max)()) { + if (matrix.size() > (std::numeric_limits<::vroom::Index>::max)()) { (*return_tuples) = NULL; (*return_count) = 0; err << "The size of time matrix exceeds the limit"; @@ -201,9 +180,9 @@ vrp_do_vroom( vrprouting::problem::Vroom problem; problem.add_matrix(matrix); - problem.add_vehicles(vehicles, total_vehicles, breaks, total_breaks, breaks_tws, total_breaks_tws); - problem.add_jobs(jobs, total_jobs, jobs_tws, total_jobs_tws); - problem.add_shipments(shipments, total_shipments, shipments_tws, total_shipments_tws); + problem.add_vehicles(vehicles, breaks, breaks_tw); + problem.add_jobs(jobs, jobs_tw); + problem.add_shipments(shipments, shipments_tw); auto end_time = std::chrono::high_resolution_clock::now(); loading_time += static_cast(