From f6901de81f3aa7ff8aec292583462c6dadb22c25 Mon Sep 17 00:00:00 2001 From: Abhishekrana254 Date: Sat, 29 Jul 2017 01:25:01 +0530 Subject: [PATCH] adding multiple capacity vehicle capability --- src/adaptors.h | 23 +++++++++++++++++++++-- src/tsp.cc | 3 +-- src/tsp_worker.h | 33 +++++++++++++++++++++------------ src/vrp_params.h | 27 ++++++++++++++++++++------- src/vrp_worker.h | 42 +++++++++++++++++++++++++++++++++++++----- test/vrp.js | 9 ++++++++- 6 files changed, 108 insertions(+), 29 deletions(-) diff --git a/src/adaptors.h b/src/adaptors.h index 7445044..b091752 100644 --- a/src/adaptors.h +++ b/src/adaptors.h @@ -2,7 +2,7 @@ #define NODE_OR_TOOLS_ADAPTORS_F1FF74E9681C_H #include - +#include #include "types.h" // We adapt matrices and vectors for or-tools since it expects them to have specific signatures and types. @@ -134,11 +134,30 @@ template inline auto makeVectorFromJsNumberArray(v8::LocalIsNumber()) throw std::runtime_error{"Expected array element of types Number"}; - + //std::cout<<"hello"<(num).FromJust(); } return vec; } +// our function for changing js array into vector of long long int + +template inline auto makeVectorFromJsNumberArray1(v8::Local array) { + const int64 len = array->Length(); + + Vector vec(len); + + for (int64 atIdx = 0; atIdx < len; ++atIdx) { + auto num = Nan::Get(array, atIdx).ToLocalChecked(); + + if (!num->IsNumber()) + throw std::runtime_error{"Expected array element of types Number"}; + //std::cout<<"hello"<(num).FromJust(); + } + + return vec; +} + #endif diff --git a/src/tsp.cc b/src/tsp.cc index 5c0b25a..4ac3ef7 100755 --- a/src/tsp.cc +++ b/src/tsp.cc @@ -66,14 +66,13 @@ NAN_METHOD(TSP::Solve) try { const std::int32_t numNodes = self->costs->dim(); const std::int32_t numVehicles = 1; // Always one for TSP - auto* worker = new TSPWorker{self->costs, // + auto worker = new TSPWorker{self->costs, // new Nan::Callback{userParams.callback}, // modelParams, // searchParams, // numNodes, // numVehicles, // userParams.depotNode}; // - Nan::AsyncQueueWorker(worker); } catch (const std::exception& e) { return Nan::ThrowError(e.what()); diff --git a/src/tsp_worker.h b/src/tsp_worker.h index 04c0729..db85b71 100644 --- a/src/tsp_worker.h +++ b/src/tsp_worker.h @@ -10,16 +10,18 @@ #include #include -struct TSPWorker final : Nan::AsyncWorker { - using Base = Nan::AsyncWorker; +struct TSPWorker final { TSPWorker(std::shared_ptr costs_, Nan::Callback* callback, const RoutingModelParameters& modelParams_, const RoutingSearchParameters& searchParams_, std::int32_t numNodes, std::int32_t numVehicles, std::int32_t vehicleDepot) - : Base(callback), costs{std::move(costs_)}, model{numNodes, numVehicles, NodeIndex{vehicleDepot}, modelParams_}, - modelParams{modelParams_}, searchParams{searchParams_} {} + : mCallback(callback), costs{std::move(costs_)}, model{numNodes, numVehicles, NodeIndex{vehicleDepot}, modelParams_}, + modelParams{modelParams_}, searchParams{searchParams_} + { + Execute(); + } - void Execute() override { + void Execute() { auto costAdaptor = makeBinaryAdaptor(*costs); auto costEvaluator = makeCallback(costAdaptor); @@ -27,16 +29,21 @@ struct TSPWorker final : Nan::AsyncWorker { const auto* assignment = model.SolveWithParameters(searchParams); - if (!assignment || (model.status() != RoutingModel::Status::ROUTING_SUCCESS)) - SetErrorMessage("Unable to find a solution"); + std::string jsError; + if (!assignment || (model.status() != RoutingModel::Status::ROUTING_SUCCESS)) { + jsError = "Unable to find a solution"; + } model.AssignmentToRoutes(*assignment, &routes); - if (routes.size() != 1) - SetErrorMessage("Expected route for one vehicle"); + if (routes.size() != 1) { + jsError = "Expected route for one vehicle"; + } + + HandleOKCallback(jsError); } - void HandleOKCallback() override { + void HandleOKCallback(std::string jsError) { Nan::HandleScope scope; const auto& route = routes.front(); @@ -47,9 +54,10 @@ struct TSPWorker final : Nan::AsyncWorker { (void)Nan::Set(jsRoute, j, Nan::New(route[j].value())); const auto argc = 2u; - v8::Local argv[argc] = {Nan::Null(), jsRoute}; + v8::Local errorStr = v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), jsError.c_str()); + v8::Local argv[argc] = {errorStr, jsRoute}; - callback->Call(argc, argv); + mCallback->Call(argc, argv); } std::shared_ptr costs; // inc ref count to keep alive for async cb @@ -58,6 +66,7 @@ struct TSPWorker final : Nan::AsyncWorker { RoutingModelParameters modelParams; RoutingSearchParameters searchParams; + Nan::Callback* mCallback; // Stores solution until we can translate back to v8 objects std::vector> routes; }; diff --git a/src/vrp_params.h b/src/vrp_params.h index 630b202..cf542be 100644 --- a/src/vrp_params.h +++ b/src/vrp_params.h @@ -25,7 +25,7 @@ struct VRPSearchParams { std::int32_t numVehicles; std::int32_t depotNode; std::int32_t timeHorizon; - std::int32_t vehicleCapacity; + std::vector vehicleCapacity; // type changed to vector RouteLocks routeLocks; @@ -40,8 +40,8 @@ inline auto makeTimeWindowsFrom2dArray(std::int32_t n, v8::Local arra if (n < 0) throw std::runtime_error{"Negative size"}; - if (static_cast(array->Length()) != n) - throw std::runtime_error{"Array dimension do not match size"}; + // if (static_cast(array->Length()) != n) + // throw std::runtime_error{"Array dimension do not match size"}; TimeWindows timeWindows(n); @@ -78,8 +78,8 @@ inline auto makeRouteLocksFrom2dArray(std::int32_t n, v8::Local array if (n < 0) throw std::runtime_error{"Negative size"}; - if (static_cast(array->Length()) != n) - throw std::runtime_error{"Array dimension do not match size"}; + // if (static_cast(array->Length()) != n) + // throw std::runtime_error{"Array dimension do not match size"}; // Note: use (n) for construction because RouteLocks is a weak alias to a std::vector. // Using vec(n) creates a vector of n items, using vec{n} creates a vector with a single element n. @@ -130,6 +130,13 @@ VRPSolverParams::VRPSolverParams(const Nan::FunctionCallbackInfo& inf auto timeWindowsVectorOk = !maybeTimeWindowsVector.IsEmpty() && maybeTimeWindowsVector.ToLocalChecked()->IsArray(); auto demandMatrixOk = !maybeDemandMatrix.IsEmpty() && maybeDemandMatrix.ToLocalChecked()->IsArray(); + + if(!numNodesOk ) throw std::runtime_error{"ERROR TYPE 1"}; + else if(!costMatrixOk) throw std::runtime_error{"ERROR TYPE 2"}; + else if(!durationMatrixOk) throw std::runtime_error{"ERROR TYPE 3"}; + else if(!timeWindowsVectorOk) throw std::runtime_error{"ERROR TYPE 4"}; + else if(!demandMatrixOk) throw std::runtime_error{"ERROR TYPE 5"}; + if (!numNodesOk || !costMatrixOk || !durationMatrixOk || !timeWindowsVectorOk || !demandMatrixOk) throw std::runtime_error{"SolverOptions expects" " 'numNodes' (Number)," @@ -170,7 +177,7 @@ VRPSearchParams::VRPSearchParams(const Nan::FunctionCallbackInfo& inf auto numVehiclesOk = !maybeNumVehicles.IsEmpty() && maybeNumVehicles.ToLocalChecked()->IsNumber(); auto depotNodeOk = !maybeDepotNode.IsEmpty() && maybeDepotNode.ToLocalChecked()->IsNumber(); auto timeHorizonOk = !maybeTimeHorizon.IsEmpty() && maybeTimeHorizon.ToLocalChecked()->IsNumber(); - auto vehicleCapacityOk = !maybeVehicleCapacity.IsEmpty() && maybeVehicleCapacity.ToLocalChecked()->IsNumber(); + auto vehicleCapacityOk = !maybeVehicleCapacity.IsEmpty() && maybeVehicleCapacity.ToLocalChecked()->IsArray(); // IsNumber() changed to IsArray() auto routeLocksOk = !maybeRouteLocks.IsEmpty() && maybeRouteLocks.ToLocalChecked()->IsArray(); auto pickupsOk = !maybePickups.IsEmpty() && maybePickups.ToLocalChecked()->IsArray(); auto deliveriesOk = !maybeDeliveries.IsEmpty() && maybeDeliveries.ToLocalChecked()->IsArray(); @@ -192,7 +199,9 @@ VRPSearchParams::VRPSearchParams(const Nan::FunctionCallbackInfo& inf numVehicles = Nan::To(maybeNumVehicles.ToLocalChecked()).FromJust(); depotNode = Nan::To(maybeDepotNode.ToLocalChecked()).FromJust(); timeHorizon = Nan::To(maybeTimeHorizon.ToLocalChecked()).FromJust(); - vehicleCapacity = Nan::To(maybeVehicleCapacity.ToLocalChecked()).FromJust(); + //vehicleCapacity = Nan::To(maybeVehicleCapacity.ToLocalChecked()).FromJust(); + + auto routeLocksArray = maybeRouteLocks.ToLocalChecked().As(); routeLocks = makeRouteLocksFrom2dArray(numVehicles, routeLocksArray); @@ -203,6 +212,10 @@ VRPSearchParams::VRPSearchParams(const Nan::FunctionCallbackInfo& inf auto deliveriesArray = maybeDeliveries.ToLocalChecked().As(); deliveries = makeVectorFromJsNumberArray(deliveriesArray); + auto vehicleCapacityArray = maybeVehicleCapacity.ToLocalChecked().As(); + vehicleCapacity = makeVectorFromJsNumberArray1 >(vehicleCapacityArray); + // new function call added to make vehicle capacity vector calls function in adapter.h + callback = info[1].As(); } diff --git a/src/vrp_worker.h b/src/vrp_worker.h index 4ff0196..b78058e 100644 --- a/src/vrp_worker.h +++ b/src/vrp_worker.h @@ -32,7 +32,7 @@ struct VRPWorker final : Nan::AsyncWorker { std::int32_t numVehicles_, // std::int32_t vehicleDepot_, // std::int32_t timeHorizon_, // - std::int32_t vehicleCapacity_, // + std::vector vehicleCapacity_, // type changed to vector int64 RouteLocks routeLocks_, // Pickups pickups_, // Deliveries deliveries_) // @@ -47,7 +47,7 @@ struct VRPWorker final : Nan::AsyncWorker { numVehicles{numVehicles_}, vehicleDepot{vehicleDepot_}, timeHorizon{timeHorizon_}, - vehicleCapacity{vehicleCapacity_}, + vehicleCapacity{std::move(vehicleCapacity_)}, routeLocks{std::move(routeLocks_)}, pickups{std::move(pickups_)}, deliveries{std::move(deliveries_)}, @@ -120,14 +120,38 @@ struct VRPWorker final : Nan::AsyncWorker { auto demandAdaptor = makeBinaryAdaptor(*demands); auto demandCallback = makeCallback(demandAdaptor); - const static auto kDimensionCapacity = "capacity"; + + //std::vector vehicle_capacities + // vehicle capacity call back - model.AddDimension(demandCallback, /*slack=*/0, vehicleCapacity, /*fix_start_cumul_to_zero=*/true, kDimensionCapacity); + //auto vehicleCapacityAdaptor = makeUnaryAdaptor(vehicleCapacity); + // auto vehicleCapacityCallback = makeCallback(vehicleCapacityAdaptor); + +// if(model.status() != RoutingModel::Status::ROUTING_SUCCESS) +// return SetErrorMessage("Unable to find a solution -2"); + + + const static std::string& kDimensionCapacity = "capacity"; + + //function for handling different capacitated vehicles + model.AddDimensionWithVehicleCapacity(demandCallback, /*slack=*/0, vehicleCapacity, /*fix_start_cumul_to_zero=*/true, kDimensionCapacity); + const auto& capacityDimension = model.GetDimensionOrDie(kDimensionCapacity); + + // if(model.status() != RoutingModel::Status::ROUTING_SUCCESS) + // return SetErrorMessage("Unable to find a solution -1"); + //old + //const static auto kDimensionCapacity = "capacity"; + + //model.AddDimension(demandCallback, /*slack=*/0, vehicleCapacity, /*fix_start_cumul_to_zero=*/true, kDimensionCapacity); // const auto& capacityDimension = model.GetDimensionOrDie(kDimensionCapacity); + + // Pickup and Deliveries auto* solver = model.solver(); + // if(model.status() != RoutingModel::Status::ROUTING_SUCCESS) + // return SetErrorMessage("Unable to find a solution 0"); for (std::int32_t atIdx = 0; atIdx < pickups.size(); ++atIdx) { const auto pickupIndex = model.NodeToIndex(pickups.at(atIdx)); @@ -144,14 +168,22 @@ struct VRPWorker final : Nan::AsyncWorker { model.AddPickupAndDelivery(pickups.at(atIdx), deliveries.at(atIdx)); } + // if(model.status() != RoutingModel::Status::ROUTING_SUCCESS) + // return SetErrorMessage("Unable to find a solution 0"); // Done with modifications to the routing model model.CloseModel(); + // if(model.status() != RoutingModel::Status::ROUTING_SUCCESS) + // return SetErrorMessage("Unable to find a solution 1"); + // Locking routes into place needs to happen after the model is closed and the underlying vars are established const auto validLocks = model.ApplyLocksToAllVehicles(routeLocks, /*close_routes=*/false); + // if(model.status() != RoutingModel::Status::ROUTING_SUCCESS) + // return SetErrorMessage("Unable to find a solution 2"); + if (!validLocks) return SetErrorMessage("Invalid locks"); @@ -238,7 +270,7 @@ struct VRPWorker final : Nan::AsyncWorker { std::int32_t numVehicles; std::int32_t vehicleDepot; std::int32_t timeHorizon; - std::int32_t vehicleCapacity; + std::vector vehicleCapacity; // changed type of vehicle capacity from int32_t to vector const RouteLocks routeLocks; diff --git a/test/vrp.js b/test/vrp.js index 0d94821..2cf85a5 100644 --- a/test/vrp.js +++ b/test/vrp.js @@ -111,7 +111,14 @@ tap.test('Test VRP', function(assert) { var numVehicles = 10; var timeHorizon = dayEnds - dayStarts; - var vehicleCapacity = 10; + + //vehicle capacity array + var vehicleCapacity = new Array(numVehicles); + for (var i = 0; i < numVehicles; i++) { + + vehicleCapacity[i]=10; + } + // Dummy lock to let vehicle 0 go to location 2 and 3 first - to test route locks var routeLocks = new Array(numVehicles);