bool CSolutionInfo::addTour(CTourInfo& tour) { m_vtourAll.push_back(tour); int vid = tour.getVehicleId(); std::vector<int>::iterator it; it = std::find(m_vUnusedVehicles.begin(), m_vUnusedVehicles.end(), vid); if (it != m_vUnusedVehicles.end()) { m_vUnusedVehicles.erase(it); } m_iVehicleUsed++; m_dTotalDistance += tour.getDistance(); m_dTotalTravelTime += tour.getTravelTime(); m_dTotalCost += tour.getCost(); std::vector<int> vecOrders = tour.getOrderVector(); m_iOrdersServed += static_cast<int>(vecOrders.size()); for (const auto &order : vecOrders) { int oid = order; it = std::find(m_vUnservedOrderId.begin(), m_vUnservedOrderId.end(), oid); if (it != m_vUnservedOrderId.end()) { m_vUnservedOrderId.erase(it); } } return true; }
void CVRPSolver::attemptVehicleExchange(CSolutionInfo& solutionInfo) { ++m_iGeneratedSolutionCount; ++m_iStepsSinceLastSolution; CMoveInfo curMove; CMoveInfo bestMove; int bestFreeCapacity = 0; std::pair<int, int> bestSwapIndex; int totalTour = static_cast<int>(solutionInfo.getTourCount()); for (int i = 0; i < totalTour; ++i) { CTourInfo firstTour = solutionInfo.getTour(i); int firstTourLoad = firstTour.getVehicleInfo().getCurrentLoad(); int firstVehicleCapacity = firstTour.getVehicleInfo().getCapacity(); for (int j = i + 1; j < totalTour; ++j) { CTourInfo secondTour = solutionInfo.getTour(j); curMove.setInitialTour(firstTour, secondTour); int FirstTourRemainingCapacity = firstVehicleCapacity - secondTour.getVehicleInfo().getCurrentLoad(); int SecondTourRemainingCapacity = secondTour.getVehicleInfo().getCapacity() - firstTourLoad; // int prevFreeCapacity = max(secondTour.getRemainingCapacity(), firstTour.getRemainingCapacity() ); int curFreeCapacity = (std::max)(FirstTourRemainingCapacity, SecondTourRemainingCapacity); if ((FirstTourRemainingCapacity > 0) && (SecondTourRemainingCapacity > 0) && // curFreeCapacity > curFreeCapacity autological compare evaluates to false (error on MAC) (curFreeCapacity > bestFreeCapacity)) { CVehicleInfo tempVehicle = m_vVehicleInfos[firstTour.getVehicleId()]; firstTour.setVehicleInfo(m_vVehicleInfos[secondTour.getVehicleId()]); secondTour.setVehicleInfo(tempVehicle); curMove.setModifiedTour(firstTour, secondTour); if (!isTabuMove(curMove)) { bestMove = curMove; bestFreeCapacity = curFreeCapacity; bestSwapIndex = std::make_pair(i, j); } curMove.getInitialTour(firstTour, secondTour); } } } if (bestFreeCapacity > 0) { CTourInfo tempTour; bestMove.getModifiedTourAt(0, tempTour); solutionInfo.replaceTourAt(bestSwapIndex.first, tempTour); bestMove.getModifiedTourAt(1, tempTour); solutionInfo.replaceTourAt(bestSwapIndex.second, tempTour); updateTabuCount(bestMove); updateFinalSolution(solutionInfo); } }
void CVRPSolver::attemptFeasibleNodeExchange(CSolutionInfo& solutionInfo) { ++m_iGeneratedSolutionCount; ++m_iStepsSinceLastSolution; CMoveInfo bestMove, curMove; int totalTour = solutionInfo.getTourCount(); for (int i = 0; i < totalTour; ++i) { CTourInfo curTour = solutionInfo.getTour(i); std::vector<int> vecOrderId = curTour.getOrderVector(); curMove.setInitialTour(curTour); int totalCustomer = curTour.getServedOrderCount(); std::pair<int, int> bestSwapIndex; double lowestCost = DOUBLE_MAX; for (int j = 0; j < totalCustomer; ++j) { for (int k = j + 1; k < totalCustomer; ++k) { COrderInfo firstCustomer = m_vOrderInfos[m_mapOrderIdToIndex[vecOrderId[j]]]; COrderInfo secondCustomer = m_vOrderInfos[m_mapOrderIdToIndex[vecOrderId[k]]]; if (curTour->isFeasibleReplace(j, pSecondCustomer) && pCurTour->isFeasibleReplace(k, pFirstCustomer)) { pCurTour->removeCustomer(j, false); pCurTour->addCustomer(pSecondCustomer, j); pCurTour->removeCustomer(k, false); pCurTour->addCustomer(pFirstCustomer, k); pCurMove->setModifiedTour(pCurTour); if (isTabuMove(pCurMove)) { pCurMove->getInitialTour(pCurTour); continue; } double curTourCost = pCurTour->getTourData()->calcCost(pCurTour->getAssignedVehicle()); if (curTourCost < lowestCost) { *pBestMove = *pCurMove; lowestCost = curTourCost; bestSwapIndex = std::make_pair(j, k); } pCurMove->getInitialTour(pCurTour); } } } if (lowestCost!= DOUBLE_MAX) { m_pCurrentSolution->replaceTourAt(i, pBestMove->getModifiedTourAt(0)); this->updateTabuCount(pBestMove); this->evaluateCurrentSolution(); } } delete pCurMove; delete pBestMove; }
bool CVRPSolver::insertOrder(CTourInfo& tourInfo, int orderId, int pos) { if (pos < 0 || (unsigned int) pos > tourInfo.getOrderVector().size()) return false; int orderIndex = m_mapOrderIdToIndex[orderId]; if (!tourInfo.getVehicleInfo().loadUnit(m_vOrderInfos[orderIndex].getOrderUnit())) return false; tourInfo.insertOrder(orderId, pos); if (!updateTourCosts(tourInfo)) { tourInfo.removeOrder(pos); return false; } return true; }
void CSolutionInfo::replaceTour(CTourInfo curTour) { unsigned int i; for (i = 0; i < m_vtourAll.size(); i++) { if (m_vtourAll[i].getVehicleId() == curTour.getVehicleId()) { m_vtourAll[i] = curTour; return; } } return; }
std::pair<int, double> CVRPSolver::getPotentialInsert(CTourInfo& curTour, COrderInfo& curOrder) { std::pair<int, double> bestInsert = std::make_pair(-1, DOUBLE_MAX); if (curOrder.getOrderUnit() > curTour.getRemainingCapacity()) { return bestInsert; } // check if ith position insert is fisible. std::vector<int> vecOrderId = curTour.getOrderVector(); for (unsigned int i = 0; i <= vecOrderId.size(); ++i) { CostPack costToOrder, costFromOrder; if (!i) { costToOrder = getDepotToOrderCost(curTour.getStartDepot(), curOrder.getOrderId()); } else { costToOrder = getOrderToOrderCost(vecOrderId[i-1], curOrder.getOrderId()); } double dArrivalTime = costToOrder.traveltime + curTour.getStartTime(i); if (dArrivalTime > curOrder.getCloseTime()) { continue; } if (i == vecOrderId.size()) { costFromOrder = getOrderToDepotCost(curOrder.getOrderId(), curTour.getEndDepot()); } else { costFromOrder = getOrderToOrderCost(curOrder.getOrderId(), vecOrderId[i]); } dArrivalTime += curOrder.getServiceTime() + costFromOrder.traveltime; if (i < vecOrderId.size() && dArrivalTime > m_vOrderInfos[m_mapOrderIdToIndex[vecOrderId[i]]].getCloseTime()) { continue; } CostPack totalCost = getCostForInsert(curTour, curOrder, i); if (totalCost.cost < bestInsert.second) { bestInsert = std::make_pair(i, totalCost.cost); } } return bestInsert; }
CostPack CVRPSolver::getCostForInsert(CTourInfo& curTour, COrderInfo& curOrder, int pos) { std::vector<int> vecOrderId = curTour.getOrderVector(); vecOrderId.insert(vecOrderId.begin() + pos, curOrder.getOrderId()); double dCost, dDistance, dTravelTime; dCost = dDistance = dTravelTime = 0.0; CostPack costRet; costRet.cost = INF; costRet.distance = INF; costRet.traveltime = INF; CostPack cPack = getDepotToOrderCost(curTour.getStartDepot(), vecOrderId[0]); dCost += cPack.cost; dDistance += cPack.distance; int ind = m_mapOrderIdToIndex[vecOrderId[0]]; if (dTravelTime + cPack.traveltime > m_vOrderInfos[ind].getCloseTime()) return costRet; dTravelTime = (std::max)(dTravelTime + cPack.traveltime + m_vOrderInfos[ind].getServiceTime(), static_cast<double>(m_vOrderInfos[ind].getOpenTime() + m_vOrderInfos[ind].getServiceTime())); unsigned int i; for (i = 1; i < vecOrderId.size(); i++) { cPack = getOrderToOrderCost(vecOrderId[i - 1], vecOrderId[i]); dCost += cPack.cost; dDistance += cPack.distance; ind = m_mapOrderIdToIndex[vecOrderId[i]]; if (dTravelTime + cPack.traveltime > m_vOrderInfos[ind].getCloseTime()) return costRet; dTravelTime = (std::max)(dTravelTime + cPack.traveltime + m_vOrderInfos[ind].getServiceTime(), static_cast<double>(m_vOrderInfos[ind].getOpenTime() + m_vOrderInfos[ind].getServiceTime())); } cPack = getOrderToDepotCost(vecOrderId[i - 1], curTour.getEndDepot()); dCost += cPack.cost; dDistance += cPack.distance; dTravelTime += cPack.traveltime; ind = m_mapDepotIdToIndex[curTour.getEndDepot()]; if (dTravelTime > m_vDepotInfos[ind].getCloseTime()) return costRet; costRet.cost = dCost - curTour.getCost(); costRet.distance = dDistance - curTour.getDistance(); costRet.traveltime = dTravelTime - curTour.getTravelTime(); return costRet; }
bool CVRPSolver::updateTourCosts(CTourInfo& tourInfo) { std::vector<int> vecOrderId = tourInfo.getOrderVector(); std::vector<int> vecStartTimes; double dCost, dDistance, dTravelTime; dCost = dDistance = dTravelTime = 0.0; CostPack cPack = getDepotToOrderCost(tourInfo.getStartDepot(), vecOrderId[0]); dCost += cPack.cost; dDistance += cPack.distance; int ind = m_mapOrderIdToIndex[vecOrderId[0]]; vecStartTimes.push_back(0); if (dTravelTime + cPack.traveltime > m_vOrderInfos[ind].getCloseTime()) return false; dTravelTime = (std::max)(dTravelTime + cPack.traveltime + m_vOrderInfos[ind].getServiceTime(), static_cast<double>(m_vOrderInfos[ind].getOpenTime() + m_vOrderInfos[ind].getServiceTime())); vecStartTimes.push_back(static_cast<int>(ceil(dTravelTime))); unsigned int i; for (i = 1; i < vecOrderId.size(); i++) { cPack = getOrderToOrderCost(vecOrderId[i - 1], vecOrderId[i]); dCost += cPack.cost; dDistance += cPack.distance; ind = m_mapOrderIdToIndex[vecOrderId[i]]; if (dTravelTime + cPack.traveltime > m_vOrderInfos[ind].getCloseTime()) return false; dTravelTime = (std::max)(dTravelTime + cPack.traveltime + m_vOrderInfos[ind].getServiceTime(), static_cast<double>(m_vOrderInfos[ind].getOpenTime() + m_vOrderInfos[ind].getServiceTime())); vecStartTimes.push_back(static_cast<int>(ceil(dTravelTime))); } cPack = getOrderToDepotCost(vecOrderId[i - 1], tourInfo.getEndDepot()); dCost += cPack.cost; dDistance += cPack.distance; dTravelTime += cPack.traveltime; vecStartTimes.push_back(static_cast<int>(ceil(dTravelTime))); ind = m_mapDepotIdToIndex[tourInfo.getEndDepot()]; if (dTravelTime > m_vDepotInfos[ind].getCloseTime()) return false; tourInfo.updateCost(dCost, dDistance, dTravelTime); tourInfo.setStartTime(vecStartTimes); return true; }
int find_vrp_solution(vrp_vehicles_t *vehicles, size_t vehicle_count, vrp_orders_t *orders, size_t order_count, vrp_cost_element_t *costmatrix, size_t cost_count, int depot_id, vrp_result_element_t **results, size_t *result_count, char **err_msg) { int res; std::string strError; try { PGR_LOG("Before load order"); loadOrders(orders, static_cast<int>(order_count), depot_id); PGR_LOG("After load order"); loadVehicles(vehicles, static_cast<int>(vehicle_count)); PGR_LOG("After load vehicles"); loadDistanceMatrix(costmatrix, static_cast<int>(cost_count), depot_id); PGR_LOG("After load distance matrix"); res = solver.solveVRP(strError); PGR_LOG("After VRP Solve"); } catch(std::exception& e) { *err_msg = (char *) e.what(); return -1; } catch(...) { *err_msg = (char *) "Caught unknown exception!"; return -1; } if (res < 0) { return res; } else { try { CSolutionInfo solution; CTourInfo ctour; // bool bOK = solver.getSolution(solution, strError); auto totalRoute = solution.getTourInfoVector().size(); size_t totRows = 0; for (size_t i = 0; i < totalRoute; i++) { totRows += (solution.getTour(static_cast<int>(i)).getServedOrderCount() + 2); } *results = (vrp_result_element_t *) malloc(totRows * sizeof(vrp_result_element_t)); *result_count = totRows; int cnt = 0; for (size_t i = 0; i < totalRoute; i++) { ctour = solution.getTour(static_cast<int>(i)); std::vector<int> vecOrder = ctour.getOrderVector(); auto totalOrder = vecOrder.size(); // For start depot (*results)[cnt].order_id = ctour.getStartDepot(); (*results)[cnt].order_pos = 0; (*results)[cnt].vehicle_id = ctour.getVehicleId(); (*results)[cnt].arrival_time = -1; (*results)[cnt].depart_time = ctour.getStartTime(0); cnt++; // For each order for (size_t j = 0; j < totalOrder; j++) { (*results)[cnt].order_id = vecOrder[j]; (*results)[cnt].order_pos = static_cast<int>(j) + 1; (*results)[cnt].vehicle_id = ctour.getVehicleId(); (*results)[cnt].depart_time = ctour.getStartTime(static_cast<int>(j) + 1); (*results)[cnt].arrival_time = ctour.getStartTime(static_cast<int>(j) + 1) - solver.getServiceTime(vecOrder[j]); cnt++; } // For return depot (*results)[cnt].order_id = ctour.getEndDepot(); (*results)[cnt].order_pos = static_cast<int>(totalOrder) + 1; (*results)[cnt].vehicle_id = ctour.getVehicleId(); (*results)[cnt].arrival_time = ctour.getStartTime(static_cast<int>(totalOrder) + 1); (*results)[cnt].depart_time = -1; cnt++; } } catch(std::exception& e) { *err_msg = (char *) e.what(); return -1; } catch(...) { *err_msg = (char *) "Caught unknown exception!"; return -1; } } return EXIT_SUCCESS; }
CSolutionInfo CVRPSolver::generateInitialSolution() { CSolutionInfo initialSolution; PGR_LOG("Inside gen ini sol"); std::vector<int> vecOrders, vecVehicles; for (unsigned int i = 0; i < m_vOrderInfos.size(); i++) { vecOrders.push_back(m_vOrderInfos[i].getOrderId()); } for (unsigned int i = 0; i < m_vVehicleInfos.size(); i++) { vecVehicles.push_back(m_vVehicleInfos[i].getId()); } initialSolution.init(vecOrders, static_cast<int>(vecOrders.size()), vecVehicles); int iUnusedVehicles = static_cast<int>(initialSolution.getUnusedVehicleCount()); int iUnservedOrders = static_cast<int>(initialSolution.getUnservedOrderCount()); // m_viUnservedOrderIndex.size(); PGR_LOG("before while"); while (iUnusedVehicles && iUnservedOrders) { CTourInfo curTour; int vehicleIndex = rand() % iUnusedVehicles--; int vehicleInd = m_mapVehicleIdToIndex[initialSolution.getUnusedVehicleAt(vehicleIndex)]; curTour.setVehicleInfo(m_vVehicleInfos[vehicleInd]); // m_viUnusedVehicleIndex[vehicleIndex] initialSolution.removeVehicle(vehicleIndex); curTour.setStartDepot(m_vDepotInfos[0].getDepotId()); curTour.setEndDepot(m_vDepotInfos[0].getDepotId()); // use a random seed to start to tour. (we can use better approach in future) bool insertAvailable = true; while (insertAvailable) { insertAvailable = false; std::pair<int, int> PotentialInsert; // first = insert_index, second = removed_order_index; std::pair<int, double> bestInsert = std::make_pair(-1, DOUBLE_MAX); // first = order_insert_index, second = cost; for (int i = 0; i < iUnservedOrders; ++i) { int orderInd = m_mapOrderIdToIndex[initialSolution.getUnservedOrderAt(i)]; COrderInfo curOrder = m_vOrderInfos[orderInd]; std::pair<int, double> curInsert = getPotentialInsert(curTour, curOrder); if (curInsert.second < bestInsert.second) { insertAvailable = true; bestInsert = curInsert; PotentialInsert = std::make_pair(curInsert.first, i); } } if (insertAvailable) { if (insertOrder(curTour, initialSolution.getUnservedOrderAt(PotentialInsert.second), PotentialInsert.first)) { iUnservedOrders--; initialSolution.removeOrder(PotentialInsert.second); } } } initialSolution.addTour(curTour); } return initialSolution; }