src/drop.cpp
/**
 * This is similar to the exchange_heuristic but drops two consecutive markets
 * from the tour and tries to insert a single one from the unvisited.
 *
 * This looks for a pair of markets to remove from route in a RANDOM order.
 */
This is similar to the exchange_heuristic but drops two consecutive markets
from the tour and tries to insert a single one from the unvisited.

This looks for a pair of markets to remove from route in a RANDOM order.
This is similar to the exchange_heuristic but drops two consecutive markets from the tour and tries to insert a single one from the unvisited . This looks for a pair of markets to remove from route in a RANDOM order .
int double_exchange_heuristic_r(const TPP::Instance &instance, TPP::Solution &sol) {
    LOG_SCOPE_F(INFO, "double_exchange_heuristic_r");
    LOG_F(INFO, "Start cost: %d", sol.cost_);
    auto total_cost_change = 0;
    auto solution_changed = false;
    auto unselected = sol.get_unselected_markets();
    vector<size_t> route_copy(sol.route_.begin() + 1, sol.route_.end());
    shuffle_vector(route_copy);
    for (auto i = 0u; i + 1 < route_copy.size(); ++i) {
        const auto cost_before_removal = sol.cost_;
        const auto market_1 = route_copy.at(i);
        const auto market_2 = route_copy.at(i + 1);
        const auto pos_1 = sol.get_market_pos_in_route(market_1);
        const auto pos_2 = sol.get_market_pos_in_route(market_2);
        CHECK_F(pos_1 != sol.route_.size(), "pos_1 out of bounds");
        CHECK_F(pos_2 != sol.route_.size(), "pos_1 out of bounds");
        if (pos_1 < pos_2) {
            sol.remove_market_at_pos(pos_2);
            sol.remove_market_at_pos(pos_1);
        } else {
            sol.remove_market_at_pos(pos_1);
            sol.remove_market_at_pos(pos_2);
        }
        bool found = false;
        for (auto cand : unselected) {
            const auto verdict = sol.calc_market_add_cost(cand);
            if (sol.cost_ + verdict.cost_change_ < cost_before_removal
                    && verdict.demand_satisfied_) {
                const auto prev_cost = sol.cost_;
                total_cost_change += verdict.cost_change_;
                sol.insert_market_at_pos(cand, verdict.index_);
                CHECK_F(prev_cost + verdict.cost_change_ == sol.cost_,
                        "Updated cost should be OK, %d", sol.cost_);
                unselected.erase(find(begin(unselected), end(unselected), cand));
                found = true;
                break ;
            }
        }
        if (found) {
            solution_changed = true;
            ++i; 
        } else { 
            if (pos_1 < pos_2) {
                sol.insert_market_at_pos(market_1, pos_1);
                sol.insert_market_at_pos(market_2, pos_2);
            } else {
                sol.insert_market_at_pos(market_2, pos_2);
                sol.insert_market_at_pos(market_1, pos_1);
            }
        }
    }
    if (solution_changed) {
        CHECK_F(is_solution_valid(instance, sol.route_),
                "Sol. should be valid");
    }
    return total_cost_change;
}
int double_exchange_heuristic_r ( const TPP :: Instance & instance , TPP :: Solution & sol ) { LOG_SCOPE_F ( INFO , " " ) ; LOG_F ( INFO , " " , sol . cost_ ) ; auto total_cost_change = 0 ; auto solution_changed = false ; auto unselected = sol . get_unselected_markets ( ) ; vector < size_t > route_copy ( sol . route_ . begin ( ) + 1 , sol . route_ . end ( ) ) ; shuffle_vector ( route_copy ) ; for ( auto i = 0u ; i + 1 < route_copy . size ( ) ; ++ i ) { const auto cost_before_removal = sol . cost_ ; const auto market_1 = route_copy . at ( i ) ; const auto market_2 = route_copy . at ( i + 1 ) ; const auto pos_1 = sol . get_market_pos_in_route ( market_1 ) ; const auto pos_2 = sol . get_market_pos_in_route ( market_2 ) ; CHECK_F ( pos_1 != sol . route_ . size ( ) , " " ) ; CHECK_F ( pos_2 != sol . route_ . size ( ) , " " ) ; if ( pos_1 < pos_2 ) { sol . remove_market_at_pos ( pos_2 ) ; sol . remove_market_at_pos ( pos_1 ) ; } else { sol . remove_market_at_pos ( pos_1 ) ; sol . remove_market_at_pos ( pos_2 ) ; } bool found = false ; for ( auto cand : unselected ) { const auto verdict = sol . calc_market_add_cost ( cand ) ; if ( sol . cost_ + verdict . cost_change_ < cost_before_removal && verdict . demand_satisfied_ ) { const auto prev_cost = sol . cost_ ; total_cost_change += verdict . cost_change_ ; sol . insert_market_at_pos ( cand , verdict . index_ ) ; CHECK_F ( prev_cost + verdict . cost_change_ == sol . cost_ , " " , sol . cost_ ) ; unselected . erase ( find ( begin ( unselected ) , end ( unselected ) , cand ) ) ; found = true ; break ; } } if ( found ) { solution_changed = true ; ++ i ; } else { if ( pos_1 < pos_2 ) { sol . insert_market_at_pos ( market_1 , pos_1 ) ; sol . insert_market_at_pos ( market_2 , pos_2 ) ; } else { sol . insert_market_at_pos ( market_2 , pos_2 ) ; sol . insert_market_at_pos ( market_1 , pos_1 ) ; } } } if ( solution_changed ) { CHECK_F ( is_solution_valid ( instance , sol . route_ ) , " " ) ; } return total_cost_change ; }
This is similar to the exchange_heuristic but drops two consecutive markets
 from the tour and tries to insert a single one from the unvisited.
This is similar to the exchange_heuristic but drops two consecutive markets from the tour and tries to insert a single one from the unvisited .
//const auto route_copy = sol.route_; // Look for another market to insert // Skip over market_2 // Restore solution to the previous state