{"id":21251222,"url":"https://github.com/gvaliente/hike","last_synced_at":"2025-07-28T16:09:11.317Z","repository":{"id":201436194,"uuid":"119188630","full_name":"GValiente/hike","owner":"GValiente","description":"C++11 mathematical optimization library","archived":false,"fork":false,"pushed_at":"2018-12-22T09:31:19.000Z","size":370,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-07-23T05:44:39.589Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"zlib","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GValiente.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-01-27T17:59:21.000Z","updated_at":"2024-03-07T14:17:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"2434babc-d986-4ec1-8012-5771491c6961","html_url":"https://github.com/GValiente/hike","commit_stats":null,"previous_names":["gvaliente/hike"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/GValiente/hike","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GValiente%2Fhike","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GValiente%2Fhike/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GValiente%2Fhike/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GValiente%2Fhike/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GValiente","download_url":"https://codeload.github.com/GValiente/hike/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GValiente%2Fhike/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267544014,"owners_count":24104675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-21T03:41:05.826Z","updated_at":"2025-07-28T16:09:11.284Z","avatar_url":"https://github.com/GValiente.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"hike\n====\n\nhike is a small C++11 [mathematical optimization](https://en.wikipedia.org/wiki/Mathematical_optimization) library.  \n\nIt currently only provides a [variable neighborhood search (VNS)](https://en.wikipedia.org/wiki/Variable_neighborhood_search) with first improvement (first descent) and best improvement (highest descent) local search.\n\n## Features\n\n- Header-only library.\n- Solutions can be of any type and size.\n- Loss functions can return any type.\n- Calculated losses can be cached to speedup the optimization process.\n- Best improvement local search can be parallelized across all CPU threads.\n- Optimization process can be debugged through callbacks.\n- Low overhead, no heap usage (besides loss caching and parallel local search).\n- Without dependencies (besides [catch](https://github.com/catchorg/Catch2) for testing).\n- Doxygen documentation provided for API reference.\n- Licensed under [zlib license](LICENSE.txt).\n\n## Tested compilers\n\n- GCC 4.9.\n- MSVC 15.0 (Visual Studio 2017).\n\n## Usage\n\nAlthough hike is a header-only library, a CMakeLists.txt file is provided to facilitate being added as a dependency.  \n\nDoxygen documentation can be generated with `doxygen Doxyfile`.\n\n## Example\n\nIn this [catch-mini](https://github.com/GValiente/catch-mini) test, a 3D integer vector is optimized using VNS with first improvement local search:\n\n```C++\n#include \u003carray\u003e\n#include \u003ccatch.hpp\u003e\n#include \"hikefilocalsearch.h\"\n#include \"hikevns.h\"\n\nTEST_CASE(\"VNS example\")\n{\n    // Solution is a 3D integer vector. It can be of any type and size:\n    using Solution = std::array\u003cint, 3\u003e;\n\n    // Loss function return an integer scalar. It can be of any type:\n    struct LossFunction\n    {\n        Solution targetSolution;\n\n        int operator()(const Solution\u0026 solution) const\n        {\n            int loss = 0;\n\n            for(std::size_t i = 0; i \u003c solution.size(); ++i)\n            {\n                loss += std::abs(solution[i] - targetSolution[i]);\n            }\n\n            return loss;\n        }\n    };\n\n    // Loss function returns the Manhattan distance between the target solution and the given one:\n    Solution targetSolution{{ 2, 5, -10 }};\n    LossFunction lossFunction = { targetSolution };\n\n    // VNS uses first improvement (first descent) local search.\n    // Best improvement (highest descent) local search can be used too:\n    using LocalSearch = hike::FILocalSearch\u003cSolution, LossFunction\u003e;\n\n    // Candidate solutions are generated adding and subtracting the parameters of this solution to the given one:\n    Solution stepSolution{{ 1, 1, 1 }};\n\n    // Declare local search object:\n    LocalSearch localSearch(lossFunction, stepSolution);\n\n    // Declare VNS object with a maximum neighborhood (kmax) of 5:\n    hike::VNS\u003cSolution, LocalSearch\u003e vns(localSearch, 5);\n\n    // Optimize a solution:\n    Solution solution{{ 15, -7, 22 }};\n    bool optimized;\n    Solution optimizedSolution = vns.optimize(solution, optimized);\n\n    // The optimized solution should be equals to the target one:\n    REQUIRE(optimized);\n    REQUIRE(optimizedSolution == targetSolution);\n}\n```\n\n## Using loss caching\n\nWith `hike::CachedLossFunction` class, calculated losses for the same solutions are cached to avoid recalculating them in following iterations:\n\n```C++\n#include \u003carray\u003e\n#include \u003ccatch.hpp\u003e\n#include \"hikecachedlossfunction.h\"\n#include \"hikefilocalsearch.h\"\n#include \"hikevns.h\"\n\n// Solution is a 3D integer vector. It can be of any type and size:\nusing Solution = std::array\u003cint, 3\u003e;\n\n// CachedLossFunction uses std::hash to identify a solution, so it must be overloaded for the solution type:\nnamespace std\n{\n    template\u003c\u003e\n    struct hash\u003cSolution\u003e\n    {\n        std::size_t operator()(const Solution\u0026 solution) const\n        {\n            std::size_t hash = 0;\n\n            for(int param : solution)\n            {\n                // https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x:\n                hash ^= std::hash\u003cint\u003e()(param) + 0x9e3779b9 + (hash \u003c\u003c 6) + (hash \u003e\u003e 2);\n            }\n\n            return hash;\n        }\n    };\n}\n\nTEST_CASE(\"CachedLossFunction example\")\n{\n    // Loss function return an integer scalar. It can be of any type:\n    struct LossFunction\n    {\n        Solution targetSolution;\n\n        int operator()(const Solution\u0026 solution) const\n        {\n            int loss = 0;\n\n            for(std::size_t i = 0; i \u003c solution.size(); ++i)\n            {\n                loss += std::abs(solution[i] - targetSolution[i]);\n            }\n\n            return loss;\n        }\n    };\n\n    // Loss function returns the Manhattan distance between the target solution and the given one:\n    Solution targetSolution{{ 2, 5, -10 }};\n    LossFunction lossFunction{targetSolution};\n\n    // Declare cached loss function object using lossFunction as implementation:\n    using CachedLossFunction = hike::CachedLossFunction\u003cSolution, LossFunction\u003e;\n    CachedLossFunction cachedLossFunction(lossFunction);\n\n    // VNS uses first improvement (first descent) local search.\n    // Best improvement (highest descent) local search can be used too:\n    using LocalSearch = hike::FILocalSearch\u003cSolution, CachedLossFunction\u003e;\n\n    // Candidate solutions are generated adding and subtracting the parameters of this solution to the given one:\n    Solution stepSolution{{ 1, 1, 1 }};\n\n    // Declare local search object:\n    LocalSearch localSearch(cachedLossFunction, stepSolution);\n\n    // Declare VNS object with a maximum neighborhood (kmax) of 5:\n    hike::VNS\u003cSolution, LocalSearch\u003e vns(localSearch, 5);\n\n    // Optimize a solution:\n    Solution solution{{ 15, -7, 22 }};\n    bool optimized;\n    Solution optimizedSolution = vns.optimize(solution, optimized);\n\n    // The optimized solution should be equals to the target one:\n    REQUIRE(optimized);\n    REQUIRE(optimizedSolution == targetSolution);\n}\n```\n\n## Parallel best improvement local search\n\n`hike::ParallelBILocalSearch` class provides multithread best improvement (highest descent) local search.  \n\nTo use it, the provided loss function must be thread safe. `hike::TSCachedLossFunction` class provides thread safe loss caching:\n\n```C++\n#include \u003carray\u003e\n#include \u003ccatch.hpp\u003e\n#include \"hike_ts_cached_loss_function.h\"\n#include \"hike_parallel_bi_local_search.h\"\n#include \"hike_vns.h\"\n\n// Solution is a 3D integer vector. It can be of any type and size:\nusing Solution = std::array\u003cint, 3\u003e;\n\n// CachedLossFunction uses std::hash to identify a solution, so it must be overloaded for the solution type:\nnamespace std\n{\n    template\u003c\u003e\n    struct hash\u003cSolution\u003e\n    {\n        std::size_t operator()(const Solution\u0026 solution) const\n\t{\n\t    std::size_t hash = 0;\n\n            for(int param : solution)\n\t    {\n\t        // https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x:\n\t\thash ^= std::hash\u003cint\u003e()(param) + 0x9e3779b9 + (hash \u003c\u003c 6) + (hash \u003e\u003e 2);\n\t    }\n\n            return hash;\n\t}\n    };\n}\n\nTEST_CASE(\"ParallelBILocalSearch example\")\n{\n    // Loss function returns an integer scalar. It can be of any type, but it must be thread safe:\n    struct LossFunction\n    {\n        Solution targetSolution;\n\n        int operator()(const Solution\u0026 solution) const\n\t{\n\t    int loss = 0;\n\n            for(std::size_t i = 0; i \u003c solution.size(); ++i)\n\t    {\n\t        loss += std::abs(solution[i] - targetSolution[i]);\n\t    }\n\n            return loss;\n\t}\n    };\n\n    // Loss function returns the Manhattan distance between the target solution and the given one:\n    Solution targetSolution{{ 2, 5, -10 }};\n    LossFunction lossFunction{targetSolution};\n\n    // Declare thread safe cached loss function object using lossFunction as implementation:\n    using CachedLossFunction = hike::TSCachedLossFunction\u003cSolution, LossFunction\u003e;\n    CachedLossFunction cachedLossFunction(lossFunction);\n\n    // VNS uses parallel best improvement (highest descent) local search:\n    using LocalSearch = hike::ParallelBILocalSearch\u003cSolution, CachedLossFunction\u003e;\n\n    // Candidate solutions are generated adding and subtracting the parameters of this solution to the given one:\n    Solution stepSolution{{ 1, 1, 1 }};\n\n    // Declare local search object:\n    LocalSearch localSearch(std::move(cachedLossFunction), stepSolution);\n\n    // Declare VNS object with a maximum neighborhood (kmax) of 5:\n    hike::VNS\u003cSolution, LocalSearch\u003e vns(std::move(localSearch), 5);\n\n    // Optimize a solution:\n    Solution solution{{ 15, -7, 22 }};\n    bool optimized;\n    Solution optimizedSolution = vns.optimize(solution, optimized);\n\n    // The optimized solution should be equals to the target one:\n    REQUIRE(optimized);\n    REQUIRE(optimizedSolution == targetSolution);\n}\n```\n\n## Debugging the optimization process\n\nOptimization algorithms can receive a callback as parameter. This callback is called when the given solution is improved, allowing to trace the optimization process.  \n\nIn this example, `hike::VNS` class receives a callback which prints in console the input solution and the improved one. Please note that local search classes can receive it too:\n\n```C++\n#include \u003carray\u003e\n#include \u003ciostream\u003e\n#include \u003ccatch.hpp\u003e\n#include \"hike_fi_local_search.h\"\n#include \"hike_vns.h\"\n\nTEST_CASE(\"OnImprovedSolution example\")\n{\n    // Solution is a 2D integer vector. It can be of any type and size:\n    using Solution = std::array\u003cint, 2\u003e;\n\n    // Loss function returns an integer scalar. It can be of any type:\n    struct LossFunction\n    {\n        Solution targetSolution;\n\n        int operator()(const Solution\u0026 solution) const\n        {\n            int loss = 0;\n\n            for(std::size_t i = 0; i \u003c solution.size(); ++i)\n            {\n                loss += std::abs(solution[i] - targetSolution[i]);\n            }\n\n            return loss;\n        }\n    };\n\n    // Callback called when a given solution has been improved in an optimization algorithm:\n    struct OnImprovedSolution\n    {\n        void operator()(const Solution\u0026 inputSolution, int inputLoss, const Solution\u0026 improvedSolution,\n                        int improvedLoss, int k) const noexcept\n        {\n            std::cout \u003c\u003c \"Solution improved (k=\" \u003c\u003c k \u003c\u003c \")! \";\n            std::cout \u003c\u003c \"From (\" \u003c\u003c inputSolution[0] \u003c\u003c \", \" \u003c\u003c inputSolution[1] \u003c\u003c \") \";\n            std::cout \u003c\u003c \"(loss=\" \u003c\u003c inputLoss \u003c\u003c \") \";\n            std::cout \u003c\u003c \"to (\" \u003c\u003c improvedSolution[0] \u003c\u003c \", \" \u003c\u003c improvedSolution[1] \u003c\u003c \") \";\n            std::cout \u003c\u003c \"(loss=\" \u003c\u003c improvedLoss \u003c\u003c \") \" \u003c\u003c std::endl;\n        }\n    };\n\n    // Loss function returns the Manhattan distance between the target solution and the given one:\n    Solution targetSolution{{ 2, 5 }};\n    LossFunction lossFunction = { targetSolution };\n\n    // VNS uses first improvement (first descent) local search.\n    // Best improvement (highest descent) local search can be used too:\n    using LocalSearch = hike::FILocalSearch\u003cSolution, LossFunction\u003e;\n\n    // Candidate solutions are generated adding and subtracting the parameters of this solution to the given one:\n    Solution stepSolution{{ 1, 1 }};\n\n    // Declare local search object:\n    LocalSearch localSearch(lossFunction, stepSolution);\n\n    // Declare VNS object with a maximum neighborhood (kmax) of 5 and the solution improved callback class:\n    hike::VNS\u003cSolution, LocalSearch, OnImprovedSolution\u003e vns(localSearch, 5, OnImprovedSolution());\n\n    // Optimize a solution:\n    Solution solution{{ 15, -7 }};\n    bool optimized;\n    Solution optimizedSolution = vns.optimize(solution, optimized);\n\n    // The optimized solution should be equals to the target one:\n    REQUIRE(optimized);\n    REQUIRE(optimizedSolution == targetSolution);\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvaliente%2Fhike","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgvaliente%2Fhike","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvaliente%2Fhike/lists"}