void Optimize::decrease_truck(size_t cycle, bool &decreased) { /* end recursion */ if (cycle == 0) return; std::ostringstream err_log; err_log << " --- Cycle " << cycle << "\n"; /* the front truck move to back */ std::rotate(fleet.begin(), fleet.begin() + 1, fleet.end()); err_log << "\n after rotate" << tau(); auto orders(fleet.back().orders_in_vehicle); while (!orders.empty()) { /* Step 2: grab an order */ auto order(problem->orders()[*orders.begin()]); orders.erase(orders.begin()); err_log << "\n truck with order: " << fleet.back().tau(); err_log << "\nOrder" << order << "\n"; /* Step 3: delete the order from the back of the fleet */ pgassertwm(fleet.back().has_order(order), err_log.str()); fleet.back().erase(order); pgassertwm(!fleet.back().has_order(order), err_log.str()); /* Step 3: cycle the fleet & insert in best truck possible */ /* current truck is tried last */ err_log << " trying "; auto best_truck(fleet.size() - 1); auto current_duration(duration()); auto min_delta_duration = (std::numeric_limits<double>::max)(); size_t t_i(0); for (auto &truck : fleet) { truck.insert(order); if (!truck.is_feasable()) { err_log << "\n" << truck.tau(); } else { err_log << "\n ******* success " << truck.tau() << "\n"; auto delta_duration = duration()-current_duration; if (t_i != fleet.size() - 1 && (delta_duration < min_delta_duration)) { min_delta_duration = delta_duration; best_truck = t_i; } } truck.erase(order); ++t_i; } fleet[best_truck].insert(order); save_if_best(); } if (fleet.back().empty()) { decreased = true; fleet.pop_back(); save_if_best(); } decrease_truck(--cycle, decreased); }
void Optimize::delete_empty_truck() { while (fleet.back().empty()) { problem->log << "\nEmpty truck"; fleet.pop_back(); save_if_best(); } save_if_best(); }
/* * Optimize decreasing truck * * - Objective: try to remove truck with less duration * - Secundary objective, acts like a shake operation * */ void Optimize::decrease_truck() { bool decreased(false); for (size_t i = 1; i < fleet.size(); ++i) { decreased = decrease_truck(i) || decreased; } if (decreased) { delete_empty_truck(); save_if_best(); decrease_truck(); } save_if_best(); }
void Optimize::delete_empty_truck() { fleet.erase(std::remove_if( fleet.begin(), fleet.end(), [](const Vehicle_pickDeliver &v){ return v.orders_in_vehicle().empty();}), fleet.end()); save_if_best(); }
bool Optimize::swap_order() { #if 0 msg.log << "++++++++" << p_swaps; #endif while (!p_swaps.empty()) { auto swap_data = p_swaps.top(); p_swaps.pop(); size_t from_pos = 0; size_t to_pos = 0; for (; from_pos < fleet.size() && fleet[from_pos].idx() != swap_data.from_truck.idx() ; ++from_pos) { } pgassert(from_pos < fleet.size()); for (; to_pos < fleet.size() && fleet[to_pos].idx() != swap_data.to_truck.idx() ; ++to_pos) { } pgassert(to_pos < fleet.size()); if (swap_order( fleet[from_pos].orders()[swap_data.from_order], fleet[from_pos], fleet[to_pos].orders()[swap_data.to_order], fleet[to_pos])) { save_if_best(); #if 0 msg.log << "\n Swapping order " << fleet[from_pos].orders()[ swap_data.from_order].pickup().original_id() << " from truck " << fleet[from_pos].id() << " with order " << fleet[to_pos].orders()[ swap_data.to_order].pickup().original_id() << " of truck " << fleet[to_pos].id(); #endif #if 0 msg.log << "\nswappping after:"; msg.log << "\n" << fleet[to_pos].tau(); msg.log << "\n" << fleet[from_pos].tau(); #endif return true; } } return false; }
/* * from_truck trying to make from_truck's duration smaller * - maybe all orders can be moved * - if that is the case, the from_truck could be removed * * Deleting an order on the from_truck * - number of truck remains the same * - from_truk duration() can not get larger * - the overall duration can get larger * */ bool Optimize::move_reduce_cost(size_t from_pos, size_t to_pos) { pgassert(to_pos < from_pos); auto from_truck = fleet[from_pos]; auto to_truck = fleet[to_pos]; auto moved(false); auto orders(from_truck.orders_in_vehicle); while (!orders.empty()) { /* * get the order that decreases the duration the most * (there is always a worse) */ auto order = from_truck.get_worse_order(orders); orders.erase(order.id()); /* * insert it in the next truck */ to_truck.insert(order); if (to_truck.is_feasable()) { problem->log << "\n Move order " << order.id() << " from truck " << from_truck.id() << " to truck " << to_truck.id(); #ifndef NDEBUG problem->dbg_log << "\nMove before:"; problem->dbg_log << "\n" << fleet[to_pos].tau(); problem->dbg_log << "\n" << fleet[from_pos].tau(); #endif from_truck.erase(order); move_order(order, fleet[from_pos], fleet[to_pos]); moved = true; save_if_best(); #ifndef NDEBUG problem->dbg_log << "\nMove after:"; problem->dbg_log << "\n" << fleet[to_pos].tau(); problem->dbg_log << "\n" << fleet[from_pos].tau(); #endif } } return moved; }
bool Optimize::move_reduce_cost() { if (fleet.size() < 2) return false; size_t from_pos(fleet.size() - 1); while (from_pos > 1) { for (size_t to_pos = 0; to_pos < from_pos; ++to_pos) { // problem->log << "\nmove_reduce_cost (" << fleet[from_pos].id() << ", " << fleet[to_pos].id() << ")"; if (move_reduce_cost(from_pos, to_pos)) { if (fleet[from_pos].empty()) { fleet.erase(fleet.begin() + from_pos); save_if_best(); } return true; } } --from_pos; } return false; }
bool Optimize::inter_swap(bool reversed) { // problem->log << tau("before sort"); sort_by_duration(); delete_empty_truck(); save_if_best(); if (reversed) { std::reverse(fleet.begin(), fleet.end()); } // problem->log << tau("after sort"); auto swapped = false; size_t from_pos(fleet.size()-1); while (from_pos > 1) { for (size_t to_pos = 0; to_pos < from_pos; ++to_pos) { swapped = swap_worse(from_pos, to_pos)? true : swapped; swapped = move_reduce_cost(from_pos, to_pos)? true : swapped; } delete_empty_truck(); --from_pos; } return swapped; }
bool Optimize::swap_worse(size_t from_pos, size_t to_pos) { pgassert(to_pos < from_pos); auto from_truck = fleet[from_pos]; auto to_truck = fleet[to_pos]; auto swapped(false); auto from_orders(from_truck.orders_in_vehicle); auto to_orders(to_truck.orders_in_vehicle); auto local_limit(from_orders.size() * to_orders.size() + 1); while (!from_orders.empty() && --local_limit > 0) { auto from_order(from_truck.get_worse_order(from_orders)); from_orders.erase(from_order.id()); while (!to_orders.empty()) { auto to_order(to_truck.get_worse_order(to_orders)); to_orders.erase(to_order.id()); /* * delete from_order, and to order from their trucks */ auto curr_from_duration(from_truck.duration()); auto curr_to_duration(to_truck.duration()); from_truck.erase(from_order); to_truck.erase(to_order); /* * insert them in the other truck */ from_truck.insert(to_order); to_truck.insert(from_order); if (from_truck.is_feasable() && to_truck.is_feasable()) { /* * Can swap but: * - only swap when the total duration is reduced * - or from_truck duration is reduced */ if (((from_truck.duration() + to_truck.duration()) < (curr_from_duration + curr_to_duration)) || (from_truck.duration() < curr_from_duration)) { problem->log << "\n Swap order " << from_order.id() << " from truck " << from_truck.id() << " with order " << to_order.id() << " of truck " << to_truck.id(); #ifndef NDEBUG problem->dbg_log << "\nswappping before:"; problem->dbg_log << "\n" << fleet[to_pos].tau(); problem->dbg_log << "\n" << fleet[from_pos].tau(); #endif swap_order(from_order, fleet[from_pos], to_order, fleet[to_pos]); swapped = true; save_if_best(); from_orders.insert(to_order.id()); #ifndef NDEBUG problem->dbg_log << "\nswappping after:"; problem->dbg_log << "\n" << fleet[to_pos].tau(); problem->dbg_log << "\n" << fleet[from_pos].tau(); #endif break; } } /* * wasn't swapped */ to_truck = fleet[to_pos]; from_truck = fleet[from_pos]; } } return swapped; }
/* * from_truck trying to make from_truck's duration smaller * - maybe all orders can be moved * - if that is the case, the from_truck could be removed * * Deleting an order on the from_truck * - number of truck remains the same * - from_truk duration() can not get larger * - the overall duration can get larger * */ bool Optimize::move_reduce_cost( Vehicle_pickDeliver &from, Vehicle_pickDeliver &to) { auto from_truck = from; auto to_truck = to; /* * don't move from a real truck to a phoney truck */ if (!from_truck.is_phony() && to_truck.is_phony()) { return false; } #if 0 from.id() > to.id() ? to : from; #endif size_t from_pos = 0; size_t to_pos = 0; for (; from_pos < fleet.size() && fleet[from_pos].idx() != from_truck.idx() ; ++from_pos) { } pgassert(from_pos < fleet.size()); for (; to_pos < fleet.size() && fleet[to_pos].idx() != to_truck.idx() ; ++to_pos) { } pgassert(to_pos < fleet.size()); auto moved = false; auto from_orders = from_truck.orders_in_vehicle(); while (!from_orders.empty()) { /* * removing an order decreases the duration */ auto order = from_truck.orders()[from_orders.front()]; from_orders -= order.idx(); /* * insert it in the "to" truck */ to_truck.insert(order); if (to_truck.is_feasable()) { msg.log << "\n Move order " << order.pickup().id() << " from truck " << from_truck.idx() << " to truck " << to_truck.idx(); #ifndef NDEBUG msg.dbg_log << "\nMove before:"; msg.dbg_log << "\n" << fleet[to_pos].tau(); msg.dbg_log << "\n" << fleet[from_pos].tau(); #endif #if 1 from_truck.erase(order); #else to_truck.insert(order); move_order(order, fleet[from_pos], fleet[to_pos]); #endif moved = true; save_if_best(); #ifndef NDEBUG msg.dbg_log << "\nMove after:"; msg.dbg_log << "\n" << fleet[to_pos].tau(); msg.dbg_log << "\n" << fleet[from_pos].tau(); #endif } else { to_truck.erase(order); } } return moved; }