// METS lib source file - local-search.hh -*- C++ -*- // /* * Software License Agreement (BSD License) * * Copyright (c) 2006-2012, Mirko Maischberger * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifndef LOCAL_SEARCH_HH_ #define LOCAL_SEARCH_HH_ namespace mets { /// @defgroup local_search Local Search /// @{ /// @brief Local search algorithm. /// /// With customary phase alternation /// and move managers generated neighborhood this can be used to do /// also a Random Restart Local Search, a Greedy Search, /// an Iterated Local Search and a Variable Neighborhood Search. template class local_search : public mets::abstract_search { public: /// @brief Creates a local search instance /// /// @param working The working solution (this will be modified /// during search) /// /// @param best_so_far A different solution /// instance used to store the best solution found /// /// @param moveman A problem specific implementation of the /// move_manager_type concept used to generate the neighborhood. /// /// @param short_circuit Wether the search should stop on /// the first improving move or not. local_search(evaluable_solution& starting_point, solution_recorder& recorder, move_manager_type& moveman, gol_type epsilon = 1e-7, bool short_circuit = false); /// purposely not implemented (see Effective C++) local_search(const local_search&); local_search& operator=(const local_search&); /// @brief This method starts the local search process. /// /// To have a real local search you should provide an /// move_manager_type than enumerates all feasible /// moves. /// virtual void search(); protected: bool short_circuit_m; gol_type epsilon_m; }; /// @} } template mets::local_search::local_search(evaluable_solution& working, solution_recorder& recorder, move_manager_t& moveman, gol_type epsilon, bool short_circuit) : abstract_search(working, recorder, moveman), short_circuit_m(short_circuit), epsilon_m(epsilon) { using base_t = abstract_search; base_t::step_m = 0; } template void mets::local_search::search() { using base_t = abstract_search; typename move_manager_t::iterator best_movit; base_t::solution_recorder_m.accept(base_t::working_solution_m); gol_type best_cost = static_cast(base_t::working_solution_m) .cost_function(); do { base_t::moves_m.refresh(base_t::working_solution_m); best_movit = base_t::moves_m.end(); for(typename move_manager_t::iterator movit = base_t::moves_m.begin(); movit != base_t::moves_m.end(); ++movit) { // evaluate the cost after the move gol_type cost = (*movit)->evaluate(base_t::working_solution_m); if(cost < best_cost - epsilon_m) { best_cost = cost; best_movit = movit; if(short_circuit_m) break; } } // end for each move if(best_movit != base_t::moves_m.end()) { (*best_movit)->apply(base_t::working_solution_m); base_t::solution_recorder_m.accept(base_t::working_solution_m); base_t::current_move_m = best_movit; this->notify(); } } while(best_movit != base_t::moves_m.end()); } #endif