diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1cd0d7ba..b751d82e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,9 +15,7 @@ jobs: python-version: ["3.8"] env: - KNAPSACK_DATA: ${{ github.workspace }}/data/knapsack - SUBSET_SUM_DATA: ${{ github.workspace }}/data/subset_sum - MULITPLE_CHOICE_SUBSET_SUM_DATA: ${{ github.workspace }}/data/multiple_choice_subset_sum + KNAPSACK_DATA: ${{ github.workspace }}/data steps: - name: Checkout code @@ -28,7 +26,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Download data run: | - python3 -m pip install gdown + python3 -m pip install -r requirements.txt python3 -u scripts/download_data.py - name: Build run: | @@ -36,8 +34,7 @@ jobs: cmake --build build --config Release --parallel cmake --install build --config Release --prefix install - name: Run unit tests - working-directory: build/test - run: ctest --parallel + run: ctest --test-dir build/test --parallel - name: Run tests run: python3 -u scripts/run_tests.py test_results - name: Checkout main branch diff --git a/README.md b/README.md index eb985fa0..0b1d487d 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,18 @@ # KnapsackSolver -A solver for some knapsack problems: -* 0-1 knapsack problem -* Subset sum problem -* Multiple-choice subset sum problem +A solver for the 0-1 knapsack problem ![knapsack](knapsack.png?raw=true "knapsack") [image source](https://commons.wikimedia.org/wiki/File:Knapsack.svg) -These problems often appear as subproblems of more complex problems. For example: -* To generate cuts in branch-and-cut algorithms -* To solve pricing problems in column generation algorithms -* To lift bin and item dimensions in packing problems - -And therefore, having efficient algorithms with reliable implementations to solve them is very useful. - -The goal of this repository is to provide such efficient and reliable implementations. - -Here are some usage examples of this library: -* [Lifting the length of a bin in a 3D packing problem](https://github.com/fontanf/packingsolver/blob/2cddb90686fb4a0e92f4ee1b4335ceaa2048d2f4/src/boxstacks/branching_scheme.cpp#L272) -* [Solving a 0-1 knapsack subproblem inside an algorithm for a geometrical variable-sized bin packing problem](https://github.com/fontanf/packingsolver/blob/2cddb90686fb4a0e92f4ee1b4335ceaa2048d2f4/src/algorithms/dichotomic_search.hpp#L149) -* Solving the pricing problem inside a column generation algorithm for the [cutting stock problem](https://github.com/fontanf/columngenerationsolver/blob/096802d9e20d2826aed5b44e3b68ac9df6b20da2/include/columngenerationsolver/examples/cutting_stock.hpp#L123), the [multiple knapsack problem](https://github.com/fontanf/columngenerationsolver/blob/096802d9e20d2826aed5b44e3b68ac9df6b20da2/include/columngenerationsolver/examples/multiple_knapsack.hpp#L154), or the [genralized assignment problem](https://github.com/fontanf/generalizedassignmentsolver/blob/68be0ab77efd897fd583f1031dd6cbc946b33f5a/src/algorithms/column_generation.cpp#L177) -* [Solving a 0-1 knapsack subproblem inside an algorithm for the packing while travelling problem](https://github.com/fontanf/travellingthiefsolver/blob/ce1b6805e8aee8ee3300fbbc97dbc9153eecff01/src/packing_while_travelling/algorithms/sequential_value_correction.cpp#L19) + + + + ## Implemented algorithms -### Knapsack - * Greedy * `O(n)` `-a greedy` @@ -47,25 +32,6 @@ Here are some usage examples of this library: * Primal-dual (minknap) * List (partial solution) `-a "dynamic-programming-primal-dual --partial-solution-size 64 --pairing 0"` -### Subset sum - -* Dynamic programming - * Bellman - * Array `-a dynamic-programming-bellman-array` - * List (only optimal value) `-a dynamic-programming-bellman-list` - * Word RAM (only optimal value) `-a dynamic-programming-bellman-word-ram` - * Word RAM with recursive scheme `-a dynamic-programming-bellman-word-ram-rec` - * Balancing - * Array (only optimal value) `-a dynamic-programming-balancing-array` - -### Multiple-choice subset sum - -* Dynamic programming - * Bellman - * Array `-a dynamic-programming-bellman-array` - * Word RAM (only optimal value) `-a dynamic-programming-bellman-word-ram` - * Word RAM with recursive scheme `-a dynamic-programming-bellman-word-ram-rec` - ## Usage ### Command line @@ -85,17 +51,13 @@ python3 scripts/download_data.py Solve: ```shell -./install/bin/knapsacksolver_knapsack --verbosity-level 1 --algorithm dynamic-programming-primal-dual --input data/knapsack/largecoeff/knapPI_2_10000_10000000/knapPI_2_10000_10000000_50.csv --format pisinger +./install/bin/knapsacksolver --verbosity-level 1 --algorithm dynamic-programming-primal-dual --input data/knapsack/largecoeff/knapPI_2_10000_10000000/knapPI_2_10000_10000000_50.csv --format pisinger ``` ``` ==================================== KnapsackSolver ==================================== -Problem -------- -Knapsack problem - Instance -------- Number of items: 10000 @@ -205,61 +167,6 @@ Profit: 27018122468 Feasible: 1 ``` -```shell -./install/bin/knapsacksolver_subset_sum --verbosity-level 1 --input data/subset_sum/pthree/pthree_1000_1 --algorithm dynamic-programming-bellman-word-ram-rec -``` -``` -==================================== - KnapsackSolver -==================================== - -Problem -------- -Subset sum problem - -Instance --------- -Number of items: 1000 -Capacity: 250000 - -Algorithm ---------- -Dynamic programming - Bellman - word RAM - recursive scheme - -Parameters ----------- -Time limit: inf -Messages - Verbosity level: 1 - Standard output: 1 - File path: - # streams: 0 -Logger - Has logger: 0 - Standard error: 0 - File path: - - Time (s) Sol. Value Bound Gap Gap (%) Comment - -------- ---- ----- ----- --- ------- ------- - 0.000 1 0 250000 250000 100.00 - 0.033 1 250000 250000 0 0.00 algorithm end (solution) - -Final statistics ----------------- -Value: 250000 -Has solution: 1 -Bound: 250000 -Absolute optimality gap: 0 -Relative optimality gap (%): 0 -Time (s): 0.0330949 - -Solution --------- -Number of items: 484 / 1000 (48.4%) -Weight: 250000 / 250000 (100%) -Feasible: 1 -``` - Run tests: ``` export KNAPSACK_DATA=$(pwd)/data/knapsack diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 3d5c30f6..6484f15e 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -14,13 +14,13 @@ endif() # Fetch googletest. if(KNAPSACKSOLVER_BUILD_TEST) - FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip) - # For Windows: Prevent overriding the parent project's compiler/linker settings - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - set(INSTALL_GTEST OFF) - FetchContent_MakeAvailable(googletest) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip) + # For Windows: Prevent overriding the parent project's compiler/linker settings + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + set(INSTALL_GTEST OFF) + FetchContent_MakeAvailable(googletest) endif() # Fetch fontanf/optimizationtools. diff --git a/include/knapsacksolver/knapsack/algorithm_formatter.hpp b/include/knapsacksolver/algorithm_formatter.hpp similarity index 94% rename from include/knapsacksolver/knapsack/algorithm_formatter.hpp rename to include/knapsacksolver/algorithm_formatter.hpp index 847cfc87..d0cf9f3a 100644 --- a/include/knapsacksolver/knapsack/algorithm_formatter.hpp +++ b/include/knapsacksolver/algorithm_formatter.hpp @@ -1,11 +1,9 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" namespace knapsacksolver { -namespace knapsack -{ class AlgorithmFormatter { @@ -63,4 +61,3 @@ class AlgorithmFormatter }; } -} diff --git a/include/knapsacksolver/knapsack/algorithms/dynamic_programming_bellman.hpp b/include/knapsacksolver/algorithms/dynamic_programming_bellman.hpp similarity index 98% rename from include/knapsacksolver/knapsack/algorithms/dynamic_programming_bellman.hpp rename to include/knapsacksolver/algorithms/dynamic_programming_bellman.hpp index c15e7fc8..30171f33 100644 --- a/include/knapsacksolver/knapsack/algorithms/dynamic_programming_bellman.hpp +++ b/include/knapsacksolver/algorithms/dynamic_programming_bellman.hpp @@ -1,11 +1,9 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" namespace knapsacksolver { -namespace knapsack -{ Output dynamic_programming_bellman_rec( const Instance& instance, @@ -157,4 +155,3 @@ Output dynamic_programming_bellman_list( const DynamicProgrammingBellmanListParameters& parameters = {}); } -} diff --git a/include/knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp b/include/knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp similarity index 96% rename from include/knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp rename to include/knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp index 85306693..93c226a2 100644 --- a/include/knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp +++ b/include/knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp @@ -1,11 +1,9 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" namespace knapsacksolver { -namespace knapsack -{ struct DynamicProgrammingPrimalDualParameters: Parameters { @@ -73,4 +71,3 @@ const DynamicProgrammingPrimalDualOutput dynamic_programming_primal_dual( const DynamicProgrammingPrimalDualParameters& parameters = {}); } -} diff --git a/include/knapsacksolver/knapsack/algorithms/greedy.hpp b/include/knapsacksolver/algorithms/greedy.hpp similarity index 90% rename from include/knapsacksolver/knapsack/algorithms/greedy.hpp rename to include/knapsacksolver/algorithms/greedy.hpp index f952b58e..906a21de 100644 --- a/include/knapsacksolver/knapsack/algorithms/greedy.hpp +++ b/include/knapsacksolver/algorithms/greedy.hpp @@ -1,12 +1,10 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" -#include "knapsacksolver/knapsack/sort.hpp" +#include "knapsacksolver/solution.hpp" +#include "knapsacksolver/sort.hpp" namespace knapsacksolver { -namespace knapsack -{ Output trivial( const Instance& instance, @@ -49,4 +47,3 @@ Output greedy( const GreedyParameters& parameters = {}); } -} diff --git a/include/knapsacksolver/knapsack/algorithms/surrogate_relaxation.hpp b/include/knapsacksolver/algorithms/surrogate_relaxation.hpp similarity index 84% rename from include/knapsacksolver/knapsack/algorithms/surrogate_relaxation.hpp rename to include/knapsacksolver/algorithms/surrogate_relaxation.hpp index 0996c788..68a113b8 100644 --- a/include/knapsacksolver/knapsack/algorithms/surrogate_relaxation.hpp +++ b/include/knapsacksolver/algorithms/surrogate_relaxation.hpp @@ -1,11 +1,9 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" namespace knapsacksolver { -namespace knapsack -{ using SolveCallback = std::function; @@ -19,4 +17,3 @@ Output surrogate_relaxation( const SurrogateRelaxationParameters& parameters = {}); } -} diff --git a/include/knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp b/include/knapsacksolver/algorithms/upper_bound_dantzig.hpp similarity index 90% rename from include/knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp rename to include/knapsacksolver/algorithms/upper_bound_dantzig.hpp index 4326f747..85e04741 100644 --- a/include/knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp +++ b/include/knapsacksolver/algorithms/upper_bound_dantzig.hpp @@ -1,12 +1,10 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" -#include "knapsacksolver/knapsack/sort.hpp" +#include "knapsacksolver/solution.hpp" +#include "knapsacksolver/sort.hpp" namespace knapsacksolver { -namespace knapsack -{ struct UpperBoundDantzigParameters: Parameters { @@ -44,4 +42,3 @@ Output upper_bound_dantzig( const UpperBoundDantzigParameters& parameters = {}); } -} diff --git a/include/knapsacksolver/knapsack/generator.hpp b/include/knapsacksolver/generator.hpp similarity index 77% rename from include/knapsacksolver/knapsack/generator.hpp rename to include/knapsacksolver/generator.hpp index 6499c013..fd3ba54e 100644 --- a/include/knapsacksolver/knapsack/generator.hpp +++ b/include/knapsacksolver/generator.hpp @@ -1,13 +1,11 @@ #pragma once -#include "knapsacksolver/knapsack/instance.hpp" +#include "knapsacksolver/instance.hpp" #include namespace knapsacksolver { -namespace knapsack -{ Instance generate_u( ItemPos number_of_items, @@ -17,4 +15,3 @@ Instance generate_u( std::mt19937_64& generator); } -} diff --git a/include/knapsacksolver/knapsack/instance.hpp b/include/knapsacksolver/instance.hpp similarity index 99% rename from include/knapsacksolver/knapsack/instance.hpp rename to include/knapsacksolver/instance.hpp index 1c2b17e5..e6fd0255 100644 --- a/include/knapsacksolver/knapsack/instance.hpp +++ b/include/knapsacksolver/instance.hpp @@ -6,8 +6,6 @@ namespace knapsacksolver { -namespace knapsack -{ using Weight = int64_t; using Profit = int64_t; @@ -131,4 +129,3 @@ class Instance }; } -} diff --git a/include/knapsacksolver/knapsack/instance_builder.hpp b/include/knapsacksolver/instance_builder.hpp similarity index 96% rename from include/knapsacksolver/knapsack/instance_builder.hpp rename to include/knapsacksolver/instance_builder.hpp index 24472fbd..25da2c49 100644 --- a/include/knapsacksolver/knapsack/instance_builder.hpp +++ b/include/knapsacksolver/instance_builder.hpp @@ -1,11 +1,9 @@ #pragma once -#include "knapsacksolver/knapsack/instance.hpp" +#include "knapsacksolver/instance.hpp" namespace knapsacksolver { -namespace knapsack -{ class InstanceBuilder { @@ -107,4 +105,3 @@ class InstanceFromFloatProfitsBuilder }; } -} diff --git a/include/knapsacksolver/multiple_choice_subset_sum/algorithm_formatter.hpp b/include/knapsacksolver/multiple_choice_subset_sum/algorithm_formatter.hpp deleted file mode 100644 index 9db76d56..00000000 --- a/include/knapsacksolver/multiple_choice_subset_sum/algorithm_formatter.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "knapsacksolver/multiple_choice_subset_sum/solution.hpp" - -namespace knapsacksolver -{ -namespace multiple_choice_subset_sum -{ - -class AlgorithmFormatter -{ - -public: - - /** Constructor. */ - AlgorithmFormatter( - const Parameters& parameters, - Output& output): - parameters_(parameters), - output_(output), - os_(parameters.create_os()) { } - - /** Print the header. */ - void start( - const std::string& algorithm_name); - - /** Print the header. */ - void print_header(); - - /** Print current state. */ - void print( - const std::string& s); - - /** Update the solution. */ - void update_solution( - const Solution& solution_new, - const std::string& s); - - /** Update the solution value. */ - void update_value( - Weight value, - const std::string& s); - - /** Update the bound. */ - void update_bound( - Weight bound_new, - const std::string& s); - - /** Method to call at the end of the algorithm. */ - void end(); - -private: - - /** Parameters. */ - const Parameters& parameters_; - - /** Output. */ - Output& output_; - - /** Output stream. */ - std::unique_ptr os_; - -}; - -} -} diff --git a/include/knapsacksolver/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.hpp b/include/knapsacksolver/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.hpp deleted file mode 100644 index 468e6d0d..00000000 --- a/include/knapsacksolver/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "knapsacksolver/multiple_choice_subset_sum/solution.hpp" - -namespace knapsacksolver -{ -namespace multiple_choice_subset_sum -{ - -Output dynamic_programming_bellman_array( - const Instance& instance, - const Parameters& parameters = {}); - -Output dynamic_programming_bellman_word_ram( - const Instance& instance, - const Parameters& parameters = {}); - -Output dynamic_programming_bellman_word_ram_rec( - const Instance& instance, - const Parameters& parameters = {}); - -} -} - diff --git a/include/knapsacksolver/multiple_choice_subset_sum/instance.hpp b/include/knapsacksolver/multiple_choice_subset_sum/instance.hpp deleted file mode 100644 index b8d145b1..00000000 --- a/include/knapsacksolver/multiple_choice_subset_sum/instance.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once - -#include "optimizationtools/utils/output.hpp" - -namespace knapsacksolver -{ -namespace multiple_choice_subset_sum -{ - -using Weight = int64_t; -using ItemId = int64_t; -using ItemPos = int64_t; -using GroupId = int64_t; -using StateId = int64_t; -using Counter = int64_t; -using Seed = int64_t; - -/** - * Structure for a group of items. - */ -struct Group -{ - /** Items. */ - std::vector item_ids; -}; - -/** - * Structure for an item. - */ -struct Item -{ - /** Group of the item. */ - GroupId group_id; - - /** Weight of the item. */ - Weight weight; -}; - -/** - * Instance group for a multiple-choice subset sum problem. - */ -class Instance -{ - -public: - - /* - * Getters - */ - - /** Get the number of groups in the instance. */ - inline GroupId number_of_groups() const { return groups_.size(); } - - /** Get the number of items in the instance. */ - inline ItemPos number_of_items() const { return items_.size(); } - - /** Get the capacity of the instance. */ - inline Weight capacity() const { return capacity_; } - - /** Get an item. */ - inline const Item& item(ItemId item_id) const { return items_[item_id]; } - - /** Get a group. */ - inline const Group& group(GroupId group_id) const { return groups_[group_id]; } - - /** Get the number of items of a group. */ - inline ItemPos number_of_items(GroupId group_id) const { return groups_[group_id].item_ids.size(); } - - /* - * Export. - */ - - /** Print the instance into a stream. */ - void format( - std::ostream& os, - int verbosity_level = 1) const; - - /** Write the instance to a file. */ - void write(std::string instance_path) const; - -private: - - /* - * Private methods. - */ - - /** Manual constructor. */ - Instance() { } - - /* - * Private attributes - */ - - /** Items. */ - std::vector items_; - - /** Group. */ - std::vector groups_; - - /** Capacity of the knapsack. */ - Weight capacity_; - - friend class InstanceBuilder; - -}; - -} -} diff --git a/include/knapsacksolver/multiple_choice_subset_sum/instance_builder.hpp b/include/knapsacksolver/multiple_choice_subset_sum/instance_builder.hpp deleted file mode 100644 index d21a509a..00000000 --- a/include/knapsacksolver/multiple_choice_subset_sum/instance_builder.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "knapsacksolver/multiple_choice_subset_sum/instance.hpp" - -namespace knapsacksolver -{ -namespace multiple_choice_subset_sum -{ - -class InstanceBuilder -{ - -public: - - /** Constructor. */ - InstanceBuilder() { } - - /** Add an item to the knapsack. */ - void add_item( - GroupId group_id, - Weight weight); - - /** Set the capacity of the knapsack. */ - void set_capacity(Weight capacity) { instance_.capacity_ = capacity; } - - /** Read an instance from a file. */ - void read( - const std::string& instance_path, - const std::string& format); - - /* - * Build - */ - - /** Build. */ - Instance build(); - -private: - - /* - * Private methods - */ - - /* - * Read input file - */ - - /** Read an instance file in 'standard' format. */ - void read_standard(std::ifstream& file); - - /* - * Private attributes - */ - - /** Instance. */ - Instance instance_; - -}; - -} -} diff --git a/include/knapsacksolver/multiple_choice_subset_sum/solution.hpp b/include/knapsacksolver/multiple_choice_subset_sum/solution.hpp deleted file mode 100644 index 0ba2e0fd..00000000 --- a/include/knapsacksolver/multiple_choice_subset_sum/solution.hpp +++ /dev/null @@ -1,220 +0,0 @@ -#pragma once - -#include "knapsacksolver/multiple_choice_subset_sum/instance.hpp" - -#include "optimizationtools/utils/utils.hpp" - -#include - -namespace knapsacksolver -{ -namespace multiple_choice_subset_sum -{ - -/** - * Solution group for a multiple-choice subset sum problem. - */ -class Solution -{ - -public: - - /* - * Constructors and destructor - */ - - /** Create an empty solution. */ - Solution(const Instance& instance); - - /** Create a solution from a file. */ - Solution(const Instance& instance, std::string certificate_path); - - /** Add an item to the solution. */ - void add(ItemId item_id); - - /* - * Getters - */ - - /** Get the instance. */ - inline const Instance& instance() const { return *instance_; } - - /** Get the number of items in the solution. */ - inline ItemPos number_of_items() const { return number_of_items_; } - - /** Get the total weight of the solution. */ - inline Weight weight() const { return weight_; } - - /** Return 'true' iff the solution contains item 'j'. */ - int8_t contains_item(ItemId item_id) const { return contains_item_[item_id]; } - - /** Return 'true' iff the solution contains an item from group 'group_id'. */ - int8_t contains_group(GroupId group_id) const { return contains_group_[group_id]; } - - /** Return 'true' iff the solution is feasible. */ - bool feasible() const { return weight_ <= instance().capacity(); } - - /** Get the total cost of the solution. */ - inline Weight objective_value() const { return weight(); } - - /* - * Export - */ - - /** Write the solution to a file. */ - void write(std::string filepath) const; - - /** Export solution characteristics to a JSON structure. */ - nlohmann::json to_json() const; - - /** Write a formatted output of the instance to a stream. */ - void format( - std::ostream& os, - int verbosity_level = 1) const; - -private: - - /** Instance. */ - const Instance* instance_; - - /** Number of items in the solution. */ - ItemPos number_of_items_ = 0; - - /** Weight of the solution. */ - Weight weight_ = 0; - - /** 'contains_item_[j] == true' iff the solution contains item 'j'. */ - std::vector contains_item_; - - /** - * 'contains_group_[group_id] == true' iff the solution contains an item - * from group 'group_id'. - */ - std::vector contains_group_; - -}; - -/** Stream insertion operator. */ -std::ostream& operator<<(std::ostream& os, const Solution& solution); - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////// Output //////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -inline optimizationtools::ObjectiveDirection objective_direction() -{ - return optimizationtools::ObjectiveDirection::Maximize; -} - -/** - * Output structure for a set covering problem. - */ -struct Output: optimizationtools::Output -{ - /** Constructor. */ - Output(const Instance& instance): - solution(instance), - bound(instance.capacity()) - { } - - - /** Solution. */ - Solution solution; - - /** Value. */ - Weight value = 0; - - /** Bound. */ - Weight bound = -1; - - /** Elapsed time. */ - double time = 0.0; - - - std::string solution_value() const - { - return optimizationtools::solution_value( - objective_direction(), - solution.feasible(), - value); - } - - double absolute_optimality_gap() const - { - return optimizationtools::absolute_optimality_gap( - objective_direction(), - solution.feasible(), - value, - bound); - } - - double relative_optimality_gap() const - { - return optimizationtools::relative_optimality_gap( - objective_direction(), - solution.feasible(), - value, - bound); - } - - bool has_solution() const { return solution.feasible() && solution.objective_value() == value; } - - virtual nlohmann::json to_json() const - { - return nlohmann::json { - {"Solution", solution.to_json()}, - {"HasSolution", has_solution()}, - {"Value", value}, - {"Bound", bound}, - {"AbsoluteOptimalityGap", absolute_optimality_gap()}, - {"RelativeOptimalityGap", relative_optimality_gap()}, - {"Time", time} - }; - } - - virtual int format_width() const { return 30; } - - virtual void format(std::ostream& os) const - { - int width = format_width(); - os - << std::setw(width) << std::left << "Value: " << value << std::endl - << std::setw(width) << std::left << "Has solution: " << has_solution() << std::endl - << std::setw(width) << std::left << "Bound: " << bound << std::endl - << std::setw(width) << std::left << "Absolute optimality gap: " << absolute_optimality_gap() << std::endl - << std::setw(width) << std::left << "Relative optimality gap (%): " << relative_optimality_gap() * 100 << std::endl - << std::setw(width) << std::left << "Time (s): " << time << std::endl - ; - } -}; - -using NewSolutionCallback = std::function; - -struct Parameters: optimizationtools::Parameters -{ - /** Callback function called when a new best solution is found. */ - NewSolutionCallback new_solution_callback = [](const Output&) { }; - - - virtual nlohmann::json to_json() const override - { - nlohmann::json json = optimizationtools::Parameters::to_json(); - json.merge_patch( - {}); - return json; - } - - virtual int format_width() const override { return 23; } - - virtual void format(std::ostream& os) const override - { - optimizationtools::Parameters::format(os); - //int width = format_width(); - //os - // << std::setw(width) << std::left << " Enable: " << reduction_parameters.reduce << std::endl - // ; - } -}; - -} -} diff --git a/include/knapsacksolver/knapsack/solution.hpp b/include/knapsacksolver/solution.hpp similarity index 98% rename from include/knapsacksolver/knapsack/solution.hpp rename to include/knapsacksolver/solution.hpp index 44272c8d..4a203287 100644 --- a/include/knapsacksolver/knapsack/solution.hpp +++ b/include/knapsacksolver/solution.hpp @@ -1,6 +1,6 @@ #pragma once -#include "knapsacksolver/knapsack/instance.hpp" +#include "knapsacksolver/instance.hpp" #include "optimizationtools/utils/utils.hpp" #include "optimizationtools/utils/output.hpp" @@ -9,8 +9,6 @@ namespace knapsacksolver { -namespace knapsack -{ /** * Solution class for a subset sum problem. @@ -227,4 +225,3 @@ struct Parameters: optimizationtools::Parameters }; } -} diff --git a/include/knapsacksolver/knapsack/sort.hpp b/include/knapsacksolver/sort.hpp similarity index 98% rename from include/knapsacksolver/knapsack/sort.hpp rename to include/knapsacksolver/sort.hpp index c29fd3f0..0197d1b7 100644 --- a/include/knapsacksolver/knapsack/sort.hpp +++ b/include/knapsacksolver/sort.hpp @@ -1,11 +1,9 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" namespace knapsacksolver { -namespace knapsack -{ class FullSort { @@ -186,4 +184,3 @@ class PartialSort }; } -} diff --git a/include/knapsacksolver/subset_sum/algorithm_formatter.hpp b/include/knapsacksolver/subset_sum/algorithm_formatter.hpp deleted file mode 100644 index 98e4f746..00000000 --- a/include/knapsacksolver/subset_sum/algorithm_formatter.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/solution.hpp" - -namespace knapsacksolver -{ -namespace subset_sum -{ - -class AlgorithmFormatter -{ - -public: - - /** Constructor. */ - AlgorithmFormatter( - const Parameters& parameters, - Output& output): - parameters_(parameters), - output_(output), - os_(parameters.create_os()) { } - - /** Print the header. */ - void start( - const std::string& algorithm_name); - - /** Print the header. */ - void print_header(); - - /** Print current state. */ - void print( - const std::string& s); - - /** Update the solution. */ - void update_solution( - const Solution& solution_new, - const std::string& s); - - /** Update the solution value. */ - void update_value( - Weight value, - const std::string& s); - - /** Update the bound. */ - void update_bound( - Weight bound_new, - const std::string& s); - - /** Method to call at the end of the algorithm. */ - void end(); - -private: - - /** Parameters. */ - const Parameters& parameters_; - - /** Output. */ - Output& output_; - - /** Output stream. */ - std::unique_ptr os_; - -}; - -} -} diff --git a/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_balancing.hpp b/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_balancing.hpp deleted file mode 100644 index d8a13146..00000000 --- a/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_balancing.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/solution.hpp" - -namespace knapsacksolver -{ -namespace subset_sum -{ - -Output dynamic_programming_balancing_array( - const Instance& instance, - const Parameters& parameters = {}); - -} -} - diff --git a/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_bellman.hpp b/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_bellman.hpp deleted file mode 100644 index 7f02def6..00000000 --- a/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_bellman.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/solution.hpp" - -namespace knapsacksolver -{ -namespace subset_sum -{ - -struct DynamicProgrammingBellmanArrayOutput: public Output -{ - /** Constructor. */ - DynamicProgrammingBellmanArrayOutput(const Instance& instance): - Output(instance) - { } - - std::vector values; - - bool is_reachable(Weight weight) const - { - return values[weight] != -1; - } -}; - -DynamicProgrammingBellmanArrayOutput dynamic_programming_bellman_array( - const Instance& instance, - const Parameters& parameters = {}); - -Output dynamic_programming_bellman_list( - const Instance& instance, - const Parameters& parameters = {}); - -struct DynamicProgrammingBellmanWordRamOutput: public Output -{ - /** Constructor. */ - DynamicProgrammingBellmanWordRamOutput(const Instance& instance): - Output(instance) - { } - - std::vector values; - - bool is_reachable(Weight weight) const - { - Weight word = weight / 64; - int bit = weight % 64; - return (values[word] >> bit); - } -}; - -DynamicProgrammingBellmanWordRamOutput dynamic_programming_bellman_word_ram( - const Instance& instance, - const Parameters& parameters = {}); - -Output dynamic_programming_bellman_word_ram_rec( - const Instance& instance, - const Parameters& parameters = {}); - -} -} diff --git a/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_primal_dual.hpp b/include/knapsacksolver/subset_sum/algorithms/dynamic_programming_primal_dual.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/include/knapsacksolver/subset_sum/generator.hpp b/include/knapsacksolver/subset_sum/generator.hpp deleted file mode 100644 index d23dbdea..00000000 --- a/include/knapsacksolver/subset_sum/generator.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/instance.hpp" - -#include - -namespace knapsacksolver -{ -namespace subset_sum -{ - -Instance generate_pthree( - ItemPos number_of_items, - std::mt19937_64& generator); - -Instance generate_psix( - ItemPos number_of_items, - std::mt19937_64& generator); - -Instance generate_evenodd( - ItemPos number_of_items, - std::mt19937_64& generator); - -Instance generate_avis( - ItemPos number_of_items); - -Instance generate_todd( - ItemPos number_of_items); - -Instance generate_somatoth( - ItemPos number_of_items, - std::mt19937_64& generator); - -/** - * See: - * "A low-space algorithm for the subset-sum problem on GPU" (Curtis and - * Sanches, 2017) - * https://doi.org/10.1016/j.cor.2017.02.006 - */ -Instance generate_evenodd6( - ItemPos number_of_items, - std::mt19937_64& generator); - -/** - * See: - * "A low-space algorithm for the subset-sum problem on GPU" (Curtis and - * Sanches, 2017) - * https://doi.org/10.1016/j.cor.2017.02.006 - */ -Instance generate_evenodd8( - ItemPos number_of_items, - std::mt19937_64& generator); - -/** - * See: - * "A low-space algorithm for the subset-sum problem on GPU" (Curtis and - * Sanches, 2017) - * https://doi.org/10.1016/j.cor.2017.02.006 - */ -Instance generate_tenfive6( - ItemPos number_of_items, - std::mt19937_64& generator); - -/** - * See: - * "A low-space algorithm for the subset-sum problem on GPU" (Curtis and - * Sanches, 2017) - * https://doi.org/10.1016/j.cor.2017.02.006 - */ -Instance generate_tenfive8( - ItemPos number_of_items, - std::mt19937_64& generator); - -} -} diff --git a/include/knapsacksolver/subset_sum/instance.hpp b/include/knapsacksolver/subset_sum/instance.hpp deleted file mode 100644 index ba60e9ed..00000000 --- a/include/knapsacksolver/subset_sum/instance.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "optimizationtools/utils/output.hpp" - -namespace knapsacksolver -{ -namespace subset_sum -{ - -using Weight = int64_t; -using ItemId = int64_t; -using ItemPos = int64_t; -using StateId = int64_t; -using Counter = int64_t; -using Seed = int64_t; - -/** - * Instance class for a subset sum problem. - */ -class Instance -{ - -public: - - /* - * Getters - */ - - /** Get the number of items in the instance. */ - inline ItemPos number_of_items() const { return weights_.size(); } - - /** Get the capacity of the instance. */ - inline Weight capacity() const { return capacity_; } - - /** Get the weight of an item. */ - inline Weight weight(ItemId item_id) const { return weights_[item_id]; } - - /* - * Export. - */ - - /** Print the instance into a stream. */ - void format( - std::ostream& os, - int verbosity_level = 1) const; - - /** Write the instance to a file. */ - void write(std::string instance_path) const; - -private: - - /* - * Private methods. - */ - - /** Manual constructor. */ - Instance() { } - - /* - * Private attributes - */ - - /** Weights. */ - std::vector weights_; - - /** Capacity of the knapsack. */ - Weight capacity_; - - friend class InstanceBuilder; - -}; - -} -} diff --git a/include/knapsacksolver/subset_sum/instance_builder.hpp b/include/knapsacksolver/subset_sum/instance_builder.hpp deleted file mode 100644 index 03114d5a..00000000 --- a/include/knapsacksolver/subset_sum/instance_builder.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/instance.hpp" - -namespace knapsacksolver -{ -namespace subset_sum -{ - -class InstanceBuilder -{ - -public: - - /** Constructor. */ - InstanceBuilder() { } - - /** Add an item to the knapsack. */ - void add_item(Weight weight) { instance_.weights_.push_back(weight); }; - - /** Set the capacity of the knapsack. */ - void set_capacity(Weight capacity) { instance_.capacity_ = capacity; } - - /** Read an instance from a file. */ - void read( - const std::string& instance_path, - const std::string& format); - - /* - * Build - */ - - /** Build. */ - Instance build(); - -private: - - /* - * Private methods - */ - - /* - * Read input file - */ - - /** Read an instance file in 'standard' format. */ - void read_standard(std::ifstream& file); - - /* - * Private attributes - */ - - /** Instance. */ - Instance instance_; - -}; - -} -} diff --git a/include/knapsacksolver/subset_sum/solution.hpp b/include/knapsacksolver/subset_sum/solution.hpp deleted file mode 100644 index 7e4e5af7..00000000 --- a/include/knapsacksolver/subset_sum/solution.hpp +++ /dev/null @@ -1,213 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/instance.hpp" - -#include "optimizationtools/utils/utils.hpp" - -#include - -namespace knapsacksolver -{ -namespace subset_sum -{ - -/** - * Solution class for a subset sum problem. - */ -class Solution -{ - -public: - - /* - * Constructors and destructor - */ - - /** Create an empty solution. */ - Solution(const Instance& instance); - - /** Create a solution from a file. */ - Solution( - const Instance& instance, - const std::string& certificate_path); - - /** Add an item to the solution. */ - void add(ItemId item_id); - - /* - * Getters - */ - - /** Get the instance. */ - inline const Instance& instance() const { return *instance_; } - - /** Get the number of items in the solution. */ - inline ItemPos number_of_items() const { return number_of_items_; } - - /** Get the total weight of the solution. */ - inline Weight weight() const { return weight_; } - - /** Return 'true' iff the solution contains item 'j'. */ - int8_t contains(ItemId item_id) const { return contains_[item_id]; } - - /** Return 'true' iff the solution is feasible. */ - bool feasible() const { return weight_ <= instance().capacity(); } - - /** Get the total cost of the solution. */ - inline Weight objective_value() const { return weight(); } - - /* - * Export - */ - - /** Write the solution to a file. */ - void write(const std::string& certificate_path) const; - - /** Export solution characteristics to a JSON structure. */ - nlohmann::json to_json() const; - - /** Write a formatted output of the instance to a stream. */ - void format( - std::ostream& os, - int verbosity_level = 1) const; - -private: - - /** Instance. */ - const Instance* instance_; - - /** Number of items in the solution. */ - ItemPos number_of_items_ = 0; - - /** Weight of the solution. */ - Weight weight_ = 0; - - /** 'contains_[j] == true' iff the solution contains item 'j'. */ - std::vector contains_; - -}; - -/** Stream insertion operator. */ -std::ostream& operator<<(std::ostream& os, const Solution& solution); - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////// Output //////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -inline optimizationtools::ObjectiveDirection objective_direction() -{ - return optimizationtools::ObjectiveDirection::Maximize; -} - -/** - * Output structure for a set covering problem. - */ -struct Output: optimizationtools::Output -{ - /** Constructor. */ - Output(const Instance& instance): - solution(instance), - bound(instance.capacity()) - { } - - - /** Solution. */ - Solution solution; - - /** Value. */ - Weight value = 0; - - /** Bound. */ - Weight bound = -1; - - /** Elapsed time. */ - double time = 0.0; - - - std::string solution_value() const - { - return optimizationtools::solution_value( - objective_direction(), - solution.feasible(), - value); - } - - double absolute_optimality_gap() const - { - return optimizationtools::absolute_optimality_gap( - objective_direction(), - solution.feasible(), - value, - bound); - } - - double relative_optimality_gap() const - { - return optimizationtools::relative_optimality_gap( - objective_direction(), - solution.feasible(), - value, - bound); - } - - bool has_solution() const { return solution.feasible() && solution.objective_value() == value; } - - virtual nlohmann::json to_json() const - { - return nlohmann::json { - {"Solution", solution.to_json()}, - {"HasSolution", has_solution()}, - {"Value", value}, - {"Bound", bound}, - {"AbsoluteOptimalityGap", absolute_optimality_gap()}, - {"RelativeOptimalityGap", relative_optimality_gap()}, - {"Time", time} - }; - } - - virtual int format_width() const { return 30; } - - virtual void format(std::ostream& os) const - { - int width = format_width(); - os - << std::setw(width) << std::left << "Value: " << value << std::endl - << std::setw(width) << std::left << "Has solution: " << has_solution() << std::endl - << std::setw(width) << std::left << "Bound: " << bound << std::endl - << std::setw(width) << std::left << "Absolute optimality gap: " << absolute_optimality_gap() << std::endl - << std::setw(width) << std::left << "Relative optimality gap (%): " << relative_optimality_gap() * 100 << std::endl - << std::setw(width) << std::left << "Time (s): " << time << std::endl - ; - } -}; - -using NewSolutionCallback = std::function; - -struct Parameters: optimizationtools::Parameters -{ - /** Callback function called when a new best solution is found. */ - NewSolutionCallback new_solution_callback = [](const Output&) { }; - - - virtual nlohmann::json to_json() const override - { - nlohmann::json json = optimizationtools::Parameters::to_json(); - json.merge_patch( - {}); - return json; - } - - virtual int format_width() const override { return 23; } - - virtual void format(std::ostream& os) const override - { - optimizationtools::Parameters::format(os); - //int width = format_width(); - //os - // << std::setw(width) << std::left << " Enable: " << reduction_parameters.reduce << std::endl - // ; - } -}; - -} -} diff --git a/include/knapsacksolver/subset_sum/tests.hpp b/include/knapsacksolver/subset_sum/tests.hpp deleted file mode 100644 index 6448cfa0..00000000 --- a/include/knapsacksolver/subset_sum/tests.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "knapsacksolver/subset_sum/solution.hpp" - -#include - -namespace knapsacksolver -{ -namespace subset_sum -{ - -std::string get_path(const std::vector& path); - -struct TestInstancePath -{ - std::string instance_path; - std::string instance_format; - std::string certificate_path; - std::string certificate_format; -}; - -std::vector get_pthree_instance_paths( - ItemId number_of_items); - -std::vector get_psix_instance_paths( - ItemId number_of_items); - -using Algorithm = std::function; - -struct TestParams -{ - Algorithm algorithm; - TestInstancePath files; -}; - -std::vector get_test_params( - const std::vector& algorithms, - const std::vector>& instance_paths); - -const Instance get_instance( - const TestInstancePath& files); - -const Solution get_solution( - const Instance& instance, - const TestInstancePath& files); - -class ExactAlgorithmTest: public testing::TestWithParam { }; -class ExactNoSolutionAlgorithmTest: public testing::TestWithParam { }; - -} -} diff --git a/include/knapsacksolver/knapsack/tests.hpp b/include/knapsacksolver/tests.hpp similarity index 94% rename from include/knapsacksolver/knapsack/tests.hpp rename to include/knapsacksolver/tests.hpp index 343b998a..480ea6a0 100644 --- a/include/knapsacksolver/knapsack/tests.hpp +++ b/include/knapsacksolver/tests.hpp @@ -1,13 +1,11 @@ #pragma once -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" #include namespace knapsacksolver { -namespace knapsack -{ std::string get_path(const std::vector& path); @@ -48,4 +46,3 @@ class ExactAlgorithmTest: public testing::TestWithParam { }; class ExactNoSolutionAlgorithmTest: public testing::TestWithParam { }; } -} diff --git a/include/knapsacksolver/knapsack/upper_bound.hpp b/include/knapsacksolver/upper_bound.hpp similarity index 95% rename from include/knapsacksolver/knapsack/upper_bound.hpp rename to include/knapsacksolver/upper_bound.hpp index 13b7fd72..073754cd 100644 --- a/include/knapsacksolver/knapsack/upper_bound.hpp +++ b/include/knapsacksolver/upper_bound.hpp @@ -1,13 +1,11 @@ #pragma once -#include "knapsacksolver/knapsack/instance.hpp" +#include "knapsacksolver/instance.hpp" #include namespace knapsacksolver { -namespace knapsack -{ /** * Value of the solution if all the remaining capacity is filled with items @@ -57,4 +55,3 @@ inline Profit upper_bound_reverse( } } -} diff --git a/python/knapsacksolver.cpp b/python/knapsacksolver.cpp index 29f8d838..93340b2c 100644 --- a/python/knapsacksolver.cpp +++ b/python/knapsacksolver.cpp @@ -1,17 +1,17 @@ -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp" -#include "knapsacksolver/knapsack/instance_builder.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp" +#include "knapsacksolver/instance_builder.hpp" #include namespace py = pybind11; -knapsacksolver::knapsack::Solution solve( - knapsacksolver::knapsack::Instance& instance, +knapsacksolver::Solution solve( + knapsacksolver::Instance& instance, bool verbosity_level) { - knapsacksolver::knapsack::DynamicProgrammingPrimalDualParameters parameters; + knapsacksolver::DynamicProgrammingPrimalDualParameters parameters; parameters.verbosity_level = verbosity_level; - auto output = knapsacksolver::knapsack::dynamic_programming_primal_dual( + auto output = knapsacksolver::dynamic_programming_primal_dual( instance, parameters); return output.solution; @@ -19,17 +19,17 @@ knapsacksolver::knapsack::Solution solve( PYBIND11_MODULE(knapsacksolver, m) { - py::class_(m, "Instance"); - py::class_(m, "Instance") + py::class_(m, "Instance"); + py::class_(m, "Instance") .def(py::init<>()) - .def("read", &knapsacksolver::knapsack::InstanceBuilder::read) - .def("set_capacity", &knapsacksolver::knapsack::InstanceBuilder::set_capacity) - .def("add_item", &knapsacksolver::knapsack::InstanceBuilder::add_item); - py::class_(m, "Solution") - .def("contains", &knapsacksolver::knapsack::Solution::contains) - .def("number_of_items", &knapsacksolver::knapsack::Solution::number_of_items) - .def("profit", &knapsacksolver::knapsack::Solution::profit) - .def("weight", &knapsacksolver::knapsack::Solution::weight); + .def("read", &knapsacksolver::InstanceBuilder::read) + .def("set_capacity", &knapsacksolver::InstanceBuilder::set_capacity) + .def("add_item", &knapsacksolver::InstanceBuilder::add_item); + py::class_(m, "Solution") + .def("contains", &knapsacksolver::Solution::contains) + .def("number_of_items", &knapsacksolver::Solution::number_of_items) + .def("profit", &knapsacksolver::Solution::profit) + .def("weight", &knapsacksolver::Solution::weight); m.def("solve", &solve, py::arg("instance"), py::arg("verbosity_level") = 1); diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..88826804 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +gdown +py7zr +numpy +plotly +matplotlib +streamlit diff --git a/scripts/download_data.py b/scripts/download_data.py index 228482a6..48b112d0 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -1,12 +1,10 @@ import gdown -import os import pathlib +import py7zr +import shutil - -def download(id): - gdown.download(id=id, output="data.7z") - os.system("7z x data.7z -odata") - pathlib.Path("data.7z").unlink() - -download("1jCf-Ye7pAQLVep6MT1HA_G05gdEgWeKk") -download("1tNIfm81yBp7DU3qfQVLLnewYwKlyzsrt") +gdown.download(id="1jCf-Ye7pAQLVep6MT1HA_G05gdEgWeKk", output="data.7z") +with py7zr.SevenZipFile("data.7z", mode="r") as z: + z.extractall() +shutil.move("knapsack", "data") +pathlib.Path("data.7z").unlink() diff --git a/scripts/run_tests.py b/scripts/run_tests.py index be2f465f..0000f94a 100644 --- a/scripts/run_tests.py +++ b/scripts/run_tests.py @@ -16,7 +16,7 @@ knapsack_main = os.path.join( "install", "bin", - "knapsacksolver_knapsack") + "knapsacksolver") knapsack_data = os.environ['KNAPSACK_DATA'] @@ -49,41 +49,3 @@ print() print() print() - - -subset_sum_main = os.path.join( - "install", - "bin", - "knapsacksolver_subset_sum") -subset_sum_data = os.environ['SUBSET_SUM_DATA'] - - -if args.tests is None or "subset-sum-dynamic-programming-bellman-word-ram-rec" in args.tests: - print("Subset sum problem / dynamic programming - Bellman - word RAM - recursive scheme") - print("--------------------------------------------------------------------------------") - print() - - data = [ - (os.path.join("pthree", "pthree_1000_1"), "")] - for instance, instance_format in data: - instance_path = os.path.join(subset_sum_data, instance) - json_output_path = os.path.join( - args.directory, - "subset_sum", - instance) - if not os.path.exists(os.path.dirname(json_output_path)): - os.makedirs(os.path.dirname(json_output_path)) - command = ( - subset_sum_main - + " --verbosity-level 1" - + " --input \"" + instance_path + "\"" - + " --format \"" + instance_format + "\"" - + " --algorithm dynamic-programming-bellman-word-ram-rec" - + " --output \"" + json_output_path + "\"") - print(command) - status = os.system(command) - if status != 0: - sys.exit(1) - print() - print() - print() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b10ad34f..840bd8a7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,47 @@ -add_subdirectory(knapsack) -add_subdirectory(subset_sum) -add_subdirectory(multiple_choice_subset_sum) +add_library(KnapsackSolver) +target_sources(KnapsackSolver PRIVATE + instance.cpp + instance_builder.cpp + solution.cpp + algorithm_formatter.cpp + sort.cpp + upper_bound.cpp) +target_include_directories(KnapsackSolver PUBLIC + ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(KnapsackSolver PUBLIC + OptimizationTools::utils + OptimizationTools::containers) +add_library(KnapsackSolver ALIAS KnapsackSolver) + +add_subdirectory(algorithms) + +if(KNAPSACKSOLVER_BUILD_MAIN) + add_executable(KnapsackSolver_main) + target_sources(KnapsackSolver_main PRIVATE + main.cpp) + target_link_libraries(KnapsackSolver_main PUBLIC + KnapsackSolver_greedy + KnapsackSolver_dynamic_programming_bellman + KnapsackSolver_dynamic_programming_primal_dual + Boost::program_options) + set_target_properties(KnapsackSolver_main PROPERTIES OUTPUT_NAME "knapsacksolver") + install(TARGETS KnapsackSolver_main) +endif() + +add_library(KnapsackSolver_generator) +target_sources(KnapsackSolver_generator PRIVATE + generator.cpp) +target_link_libraries(KnapsackSolver_generator PUBLIC + KnapsackSolver) +add_library(KnapsackSolver::generator ALIAS KnapsackSolver_generator) + +if(KNAPSACKSOLVER_BUILD_TEST) + add_library(KnapsackSolver_tests) + target_sources(KnapsackSolver_tests PRIVATE + tests.cpp) + target_link_libraries(KnapsackSolver_tests PUBLIC + KnapsackSolver + Boost::filesystem + GTest::gtest_main) + add_library(KnapsackSolver::tests ALIAS KnapsackSolver_tests) +endif() diff --git a/src/knapsack/algorithm_formatter.cpp b/src/algorithm_formatter.cpp similarity index 95% rename from src/knapsack/algorithm_formatter.cpp rename to src/algorithm_formatter.cpp index 481162bb..2ca6d799 100644 --- a/src/knapsack/algorithm_formatter.cpp +++ b/src/algorithm_formatter.cpp @@ -1,10 +1,10 @@ -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" +#include "knapsacksolver/algorithm_formatter.hpp" #include "optimizationtools/utils/utils.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; void AlgorithmFormatter::start( const std::string& algorithm_name) @@ -19,10 +19,6 @@ void AlgorithmFormatter::start( << " KnapsackSolver " << std::endl << "====================================" << std::endl << std::endl - << "Problem" << std::endl - << "-------" << std::endl - << "Knapsack problem" << std::endl - << std::endl << "Instance" << std::endl << "--------" << std::endl; output_.solution.instance().format(*os_, parameters_.verbosity_level); diff --git a/src/algorithms/CMakeLists.txt b/src/algorithms/CMakeLists.txt new file mode 100644 index 00000000..bf5361a3 --- /dev/null +++ b/src/algorithms/CMakeLists.txt @@ -0,0 +1,41 @@ +add_library(KnapsackSolver_upper_bound_dantzig) +target_sources(KnapsackSolver_upper_bound_dantzig PRIVATE + upper_bound_dantzig.cpp) +target_include_directories(KnapsackSolver_upper_bound_dantzig PUBLIC + ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(KnapsackSolver_upper_bound_dantzig PUBLIC + KnapsackSolver) +add_library(KnapsackSolver::upper_bound_dantzig ALIAS KnapsackSolver_upper_bound_dantzig) + +add_library(KnapsackSolver_greedy) +target_sources(KnapsackSolver_greedy PRIVATE + greedy.cpp) +target_include_directories(KnapsackSolver_greedy PUBLIC + ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(KnapsackSolver_greedy PUBLIC + KnapsackSolver) +add_library(KnapsackSolver::greedy ALIAS KnapsackSolver_greedy) + +find_package(Threads) +add_library(KnapsackSolver_dynamic_programming_bellman) +target_sources(KnapsackSolver_dynamic_programming_bellman PRIVATE + dynamic_programming_bellman.cpp) +target_include_directories(KnapsackSolver_dynamic_programming_bellman PUBLIC + ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(KnapsackSolver_dynamic_programming_bellman PUBLIC + KnapsackSolver + KnapsackSolver_upper_bound_dantzig + KnapsackSolver_greedy + Threads::Threads) +add_library(KnapsackSolver::dynamic_programming_bellman ALIAS KnapsackSolver_dynamic_programming_bellman) + +add_library(KnapsackSolver_dynamic_programming_primal_dual) +target_sources(KnapsackSolver_dynamic_programming_primal_dual PRIVATE + dynamic_programming_primal_dual.cpp) +target_include_directories(KnapsackSolver_dynamic_programming_primal_dual PUBLIC + ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(KnapsackSolver_dynamic_programming_primal_dual PUBLIC + KnapsackSolver + KnapsackSolver_upper_bound_dantzig + KnapsackSolver_greedy) +add_library(KnapsackSolver::dynamic_programming_primal_dual ALIAS KnapsackSolver_dynamic_programming_primal_dual) diff --git a/src/knapsack/algorithms/dynamic_programming_bellman.cpp b/src/algorithms/dynamic_programming_bellman.cpp similarity index 96% rename from src/knapsack/algorithms/dynamic_programming_bellman.cpp rename to src/algorithms/dynamic_programming_bellman.cpp index 7d284e5d..5b7349eb 100644 --- a/src/knapsack/algorithms/dynamic_programming_bellman.cpp +++ b/src/algorithms/dynamic_programming_bellman.cpp @@ -1,22 +1,22 @@ -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_bellman.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_bellman.hpp" -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" -#include "knapsacksolver/knapsack/sort.hpp" -#include "knapsacksolver/knapsack/upper_bound.hpp" -#include "knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp" -#include "knapsacksolver/knapsack/algorithms/greedy.hpp" +#include "knapsacksolver/algorithm_formatter.hpp" +#include "knapsacksolver/sort.hpp" +#include "knapsacksolver/upper_bound.hpp" +#include "knapsacksolver/algorithms/upper_bound_dantzig.hpp" +#include "knapsacksolver/algorithms/greedy.hpp" #include "optimizationtools/containers/partial_set.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; //////////////////////////////////////////////////////////////////////////////// ////////////////////// dynamic_programming_bellman_array /////////////////////// //////////////////////////////////////////////////////////////////////////////// -Output knapsacksolver::knapsack::dynamic_programming_bellman_array( +Output knapsacksolver::dynamic_programming_bellman_array( const Instance& instance, const Parameters& parameters) { @@ -93,7 +93,7 @@ void dynamic_programming_bellman_array_parallel_worker( } } -Output knapsacksolver::knapsack::dynamic_programming_bellman_array_parallel( +Output knapsacksolver::dynamic_programming_bellman_array_parallel( const Instance& instance, const Parameters& parameters) { @@ -222,7 +222,7 @@ Profit dynamic_programming_bellman_rec_rec( return values[state_id]; } -Output knapsacksolver::knapsack::dynamic_programming_bellman_rec( +Output knapsacksolver::dynamic_programming_bellman_rec( const Instance& instance, const Parameters& parameters) { @@ -281,7 +281,7 @@ Output knapsacksolver::knapsack::dynamic_programming_bellman_rec( //////////////////// dynamic_programming_bellman_array_all ///////////////////// //////////////////////////////////////////////////////////////////////////////// -Output knapsacksolver::knapsack::dynamic_programming_bellman_array_all( +Output knapsacksolver::dynamic_programming_bellman_array_all( const Instance& instance, const Parameters& parameters) { @@ -360,7 +360,7 @@ Output knapsacksolver::knapsack::dynamic_programming_bellman_array_all( //////////////////// dynamic_programming_bellman_array_one ///////////////////// //////////////////////////////////////////////////////////////////////////////// -const DynamicProgrammingBellmanArrayOneOutput knapsacksolver::knapsack::dynamic_programming_bellman_array_one( +const DynamicProgrammingBellmanArrayOneOutput knapsacksolver::dynamic_programming_bellman_array_one( const Instance& instance, const Parameters& parameters) { @@ -476,7 +476,7 @@ const DynamicProgrammingBellmanArrayOneOutput knapsacksolver::knapsack::dynamic_ /////////////////// dynamic_programming_bellman_array_part ///////////////////// //////////////////////////////////////////////////////////////////////////////// -const DynamicProgrammingBellmanArrayPartOutput knapsacksolver::knapsack::dynamic_programming_bellman_array_part( +const DynamicProgrammingBellmanArrayPartOutput knapsacksolver::dynamic_programming_bellman_array_part( const Instance& instance, const DynamicProgrammingBellmanArrayPartParameters& parameters) { @@ -727,7 +727,7 @@ void dynamic_programming_bellman_array_rec_rec( } } -Output knapsacksolver::knapsack::dynamic_programming_bellman_array_rec( +Output knapsacksolver::dynamic_programming_bellman_array_rec( const Instance& instance, const Parameters& parameters) { @@ -804,7 +804,7 @@ std::ostream& operator<<(std::ostream& os, const std::vector& l) return os; } -Output knapsacksolver::knapsack::dynamic_programming_bellman_list( +Output knapsacksolver::dynamic_programming_bellman_list( const Instance& instance, const DynamicProgrammingBellmanListParameters& parameters) { diff --git a/src/knapsack/algorithms/dynamic_programming_primal_dual.cpp b/src/algorithms/dynamic_programming_primal_dual.cpp similarity index 97% rename from src/knapsack/algorithms/dynamic_programming_primal_dual.cpp rename to src/algorithms/dynamic_programming_primal_dual.cpp index e9ceeff7..64020743 100644 --- a/src/knapsack/algorithms/dynamic_programming_primal_dual.cpp +++ b/src/algorithms/dynamic_programming_primal_dual.cpp @@ -1,15 +1,15 @@ -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp" -#include "knapsacksolver/knapsack/instance_builder.hpp" -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" -#include "knapsacksolver/knapsack/sort.hpp" -#include "knapsacksolver/knapsack/upper_bound.hpp" -#include "knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp" -#include "knapsacksolver/knapsack/algorithms/greedy.hpp" +#include "knapsacksolver/instance_builder.hpp" +#include "knapsacksolver/algorithm_formatter.hpp" +#include "knapsacksolver/sort.hpp" +#include "knapsacksolver/upper_bound.hpp" +#include "knapsacksolver/algorithms/upper_bound_dantzig.hpp" +#include "knapsacksolver/algorithms/greedy.hpp" #include "optimizationtools/containers/partial_set.hpp" -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; namespace { @@ -369,7 +369,7 @@ ItemPos dynamic_programming_primal_dual_find_state( } -const DynamicProgrammingPrimalDualOutput knapsacksolver::knapsack::dynamic_programming_primal_dual( +const DynamicProgrammingPrimalDualOutput knapsacksolver::dynamic_programming_primal_dual( const Instance& instance, const DynamicProgrammingPrimalDualParameters& parameters) { diff --git a/src/knapsack/algorithms/greedy.cpp b/src/algorithms/greedy.cpp similarity index 93% rename from src/knapsack/algorithms/greedy.cpp rename to src/algorithms/greedy.cpp index 7012d486..aa432ca2 100644 --- a/src/knapsack/algorithms/greedy.cpp +++ b/src/algorithms/greedy.cpp @@ -1,11 +1,11 @@ -#include "knapsacksolver/knapsack/algorithms/greedy.hpp" +#include "knapsacksolver/algorithms/greedy.hpp" -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" -#include "knapsacksolver/knapsack/sort.hpp" +#include "knapsacksolver/algorithm_formatter.hpp" +#include "knapsacksolver/sort.hpp" -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; -Output knapsacksolver::knapsack::greedy( +Output knapsacksolver::greedy( const Instance& instance, const GreedyParameters& parameters) { diff --git a/src/knapsack/algorithms/greedy_test.cpp b/src/algorithms/greedy_test.cpp similarity index 100% rename from src/knapsack/algorithms/greedy_test.cpp rename to src/algorithms/greedy_test.cpp diff --git a/src/knapsack/algorithms/surrogate_relaxation.cpp b/src/algorithms/surrogate_relaxation.cpp similarity index 96% rename from src/knapsack/algorithms/surrogate_relaxation.cpp rename to src/algorithms/surrogate_relaxation.cpp index cce990f2..f3e68e36 100644 --- a/src/knapsack/algorithms/surrogate_relaxation.cpp +++ b/src/algorithms/surrogate_relaxation.cpp @@ -1,12 +1,12 @@ -#include "knapsacksolver/knapsack/algorithms/surrogate_relaxation.hpp" +#include "knapsacksolver/algorithms/surrogate_relaxation.hpp" -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" -#include "knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp" -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp" +#include "knapsacksolver/algorithm_formatter.hpp" +#include "knapsacksolver/algorithms/upper_bound_dantzig.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; ItemId maximum_cardinality( const Instance& instance) @@ -212,7 +212,7 @@ UBS surrogate_solve( return {ub, s_best}; } -Output knapsacksolver::knapsack::surrogate_relaxation( +Output knapsacksolver::surrogate_relaxation( const Instance& instance, const SurrogateRelaxationParameters& parameters) { diff --git a/src/knapsack/algorithms/upper_bound_dantzig.cpp b/src/algorithms/upper_bound_dantzig.cpp similarity index 85% rename from src/knapsack/algorithms/upper_bound_dantzig.cpp rename to src/algorithms/upper_bound_dantzig.cpp index 81616536..ff246cf5 100644 --- a/src/knapsack/algorithms/upper_bound_dantzig.cpp +++ b/src/algorithms/upper_bound_dantzig.cpp @@ -1,11 +1,11 @@ -#include "knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp" +#include "knapsacksolver/algorithms/upper_bound_dantzig.hpp" -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" -#include "knapsacksolver/knapsack/upper_bound.hpp" +#include "knapsacksolver/algorithm_formatter.hpp" +#include "knapsacksolver/upper_bound.hpp" -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; -Output knapsacksolver::knapsack::upper_bound_dantzig( +Output knapsacksolver::upper_bound_dantzig( const Instance& instance, const UpperBoundDantzigParameters& parameters) { diff --git a/src/knapsack/generator.cpp b/src/generator.cpp similarity index 83% rename from src/knapsack/generator.cpp rename to src/generator.cpp index 1c14fd90..c7e3177b 100644 --- a/src/knapsack/generator.cpp +++ b/src/generator.cpp @@ -1,12 +1,12 @@ -#include "knapsacksolver/knapsack/generator.hpp" +#include "knapsacksolver/generator.hpp" -#include "knapsacksolver/knapsack/instance_builder.hpp" +#include "knapsacksolver/instance_builder.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; -Instance knapsacksolver::knapsack::generate_u( +Instance knapsacksolver::generate_u( ItemPos number_of_items, Weight maximum_weight, Profit maximum_profit, diff --git a/src/knapsack/generator_main.cpp b/src/generator_main.cpp similarity index 95% rename from src/knapsack/generator_main.cpp rename to src/generator_main.cpp index eb6826af..1d769a94 100644 --- a/src/knapsack/generator_main.cpp +++ b/src/generator_main.cpp @@ -1,8 +1,8 @@ -#include "knapsacksolver/knapsack/generator.hpp" +#include "knapsacksolver/generator.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; int main(int argc, char *argv[]) { diff --git a/src/knapsack/instance.cpp b/src/instance.cpp similarity index 95% rename from src/knapsack/instance.cpp rename to src/instance.cpp index 5f7e7d86..1212e1b2 100644 --- a/src/knapsack/instance.cpp +++ b/src/instance.cpp @@ -1,9 +1,9 @@ -#include "knapsacksolver/knapsack/instance.hpp" +#include "knapsacksolver/instance.hpp" #include #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; void Instance::format( std::ostream& os, diff --git a/src/knapsack/instance_builder.cpp b/src/instance_builder.cpp similarity index 99% rename from src/knapsack/instance_builder.cpp rename to src/instance_builder.cpp index 083fe7a0..859c84d9 100644 --- a/src/knapsack/instance_builder.cpp +++ b/src/instance_builder.cpp @@ -1,10 +1,10 @@ -#include "knapsacksolver/knapsack/instance_builder.hpp" +#include "knapsacksolver/instance_builder.hpp" #include "optimizationtools/utils/utils.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; void InstanceBuilder::add_item( Profit profit, diff --git a/src/knapsack/CMakeLists.txt b/src/knapsack/CMakeLists.txt deleted file mode 100644 index 78f87375..00000000 --- a/src/knapsack/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -add_library(KnapsackSolver_knapsack) -target_sources(KnapsackSolver_knapsack PRIVATE - instance.cpp - instance_builder.cpp - solution.cpp - algorithm_formatter.cpp - sort.cpp - upper_bound.cpp) -target_include_directories(KnapsackSolver_knapsack PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_knapsack PUBLIC - OptimizationTools::utils - OptimizationTools::containers) -add_library(KnapsackSolver::knapsack ALIAS KnapsackSolver_knapsack) - -add_subdirectory(algorithms) - -if(KNAPSACKSOLVER_BUILD_MAIN) - add_executable(KnapsackSolver_knapsack_main) - target_sources(KnapsackSolver_knapsack_main PRIVATE - main.cpp) - target_link_libraries(KnapsackSolver_knapsack_main PUBLIC - KnapsackSolver_knapsack_greedy - KnapsackSolver_knapsack_dynamic_programming_bellman - KnapsackSolver_knapsack_dynamic_programming_primal_dual - Boost::program_options) - set_target_properties(KnapsackSolver_knapsack_main PROPERTIES OUTPUT_NAME "knapsacksolver_knapsack") - install(TARGETS KnapsackSolver_knapsack_main) -endif() - -add_library(KnapsackSolver_knapsack_generator) -target_sources(KnapsackSolver_knapsack_generator PRIVATE - generator.cpp) -target_link_libraries(KnapsackSolver_knapsack_generator PUBLIC - KnapsackSolver_knapsack) -add_library(KnapsackSolver::knapsack::generator ALIAS KnapsackSolver_knapsack_generator) - -if(KNAPSACKSOLVER_BUILD_TEST) - add_library(KnapsackSolver_knapsack_tests) - target_sources(KnapsackSolver_knapsack_tests PRIVATE - tests.cpp) - target_link_libraries(KnapsackSolver_knapsack_tests PUBLIC - KnapsackSolver_knapsack - Boost::filesystem - GTest::gtest_main) - add_library(KnapsackSolver::knapsack::tests ALIAS KnapsackSolver_knapsack_tests) -endif() diff --git a/src/knapsack/algorithms/CMakeLists.txt b/src/knapsack/algorithms/CMakeLists.txt deleted file mode 100644 index b1ef107f..00000000 --- a/src/knapsack/algorithms/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -add_library(KnapsackSolver_knapsack_upper_bound_dantzig) -target_sources(KnapsackSolver_knapsack_upper_bound_dantzig PRIVATE - upper_bound_dantzig.cpp) -target_include_directories(KnapsackSolver_knapsack_upper_bound_dantzig PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_knapsack_upper_bound_dantzig PUBLIC - KnapsackSolver_knapsack) -add_library(KnapsackSolver::knapsack::upper_bound_dantzig ALIAS KnapsackSolver_knapsack_upper_bound_dantzig) - -add_library(KnapsackSolver_knapsack_greedy) -target_sources(KnapsackSolver_knapsack_greedy PRIVATE - greedy.cpp) -target_include_directories(KnapsackSolver_knapsack_greedy PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_knapsack_greedy PUBLIC - KnapsackSolver_knapsack) -add_library(KnapsackSolver::knapsack::greedy ALIAS KnapsackSolver_knapsack_greedy) - -find_package(Threads) -add_library(KnapsackSolver_knapsack_dynamic_programming_bellman) -target_sources(KnapsackSolver_knapsack_dynamic_programming_bellman PRIVATE - dynamic_programming_bellman.cpp) -target_include_directories(KnapsackSolver_knapsack_dynamic_programming_bellman PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_knapsack_dynamic_programming_bellman PUBLIC - KnapsackSolver_knapsack - KnapsackSolver_knapsack_upper_bound_dantzig - KnapsackSolver_knapsack_greedy - Threads::Threads) -add_library(KnapsackSolver::knapsack::dynamic_programming_bellman ALIAS KnapsackSolver_knapsack_dynamic_programming_bellman) - -add_library(KnapsackSolver_knapsack_dynamic_programming_primal_dual) -target_sources(KnapsackSolver_knapsack_dynamic_programming_primal_dual PRIVATE - dynamic_programming_primal_dual.cpp) -target_include_directories(KnapsackSolver_knapsack_dynamic_programming_primal_dual PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_knapsack_dynamic_programming_primal_dual PUBLIC - KnapsackSolver_knapsack - KnapsackSolver_knapsack_upper_bound_dantzig - KnapsackSolver_knapsack_greedy) -add_library(KnapsackSolver::knapsack::dynamic_programming_primal_dual ALIAS KnapsackSolver_knapsack_dynamic_programming_primal_dual) diff --git a/src/knapsack/upper_bound.cpp b/src/knapsack/upper_bound.cpp deleted file mode 100644 index d0543a92..00000000 --- a/src/knapsack/upper_bound.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "knapsacksolver/knapsack/upper_bound.hpp" - -#include "knapsacksolver/knapsack/algorithm_formatter.hpp" - -using namespace knapsacksolver::knapsack; - diff --git a/src/knapsack/main.cpp b/src/main.cpp similarity index 93% rename from src/knapsack/main.cpp rename to src/main.cpp index 0c6a1c57..cf9961db 100644 --- a/src/knapsack/main.cpp +++ b/src/main.cpp @@ -1,14 +1,14 @@ -#include "knapsacksolver/knapsack/instance_builder.hpp" +#include "knapsacksolver/instance_builder.hpp" -#include "knapsacksolver/knapsack/upper_bound.hpp" -#include "knapsacksolver/knapsack/algorithms/upper_bound_dantzig.hpp" -#include "knapsacksolver/knapsack/algorithms/greedy.hpp" -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_bellman.hpp" -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp" +#include "knapsacksolver/upper_bound.hpp" +#include "knapsacksolver/algorithms/upper_bound_dantzig.hpp" +#include "knapsacksolver/algorithms/greedy.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_bellman.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; namespace po = boost::program_options; diff --git a/src/multiple_choice_subset_sum/CMakeLists.txt b/src/multiple_choice_subset_sum/CMakeLists.txt deleted file mode 100644 index 9e5b5da7..00000000 --- a/src/multiple_choice_subset_sum/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_library(KnapsackSolver_multiple_choice_subset_sum) -target_sources(KnapsackSolver_multiple_choice_subset_sum PRIVATE - instance.cpp - instance_builder.cpp - solution.cpp - algorithm_formatter.cpp) -target_include_directories(KnapsackSolver_multiple_choice_subset_sum PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_multiple_choice_subset_sum PUBLIC - OptimizationTools::utils) -add_library(KnapsackSolver::multiple_choice_subset_sum ALIAS KnapsackSolver_multiple_choice_subset_sum) - -add_subdirectory(algorithms) - -if(KNAPSACKSOLVER_BUILD_MAIN) - add_executable(KnapsackSolver_multiple_choice_subset_sum_main) - target_sources(KnapsackSolver_multiple_choice_subset_sum_main PRIVATE - main.cpp) - target_link_libraries(KnapsackSolver_multiple_choice_subset_sum_main PUBLIC - KnapsackSolver_multiple_choice_subset_sum_dynamic_programming_bellman - Boost::program_options) - set_target_properties(KnapsackSolver_multiple_choice_subset_sum_main PROPERTIES OUTPUT_NAME "knapsacksolver_multiple_choice_subset_sum") - install(TARGETS KnapsackSolver_multiple_choice_subset_sum_main) -endif() diff --git a/src/multiple_choice_subset_sum/algorithm_formatter.cpp b/src/multiple_choice_subset_sum/algorithm_formatter.cpp deleted file mode 100644 index bdcd73a2..00000000 --- a/src/multiple_choice_subset_sum/algorithm_formatter.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "knapsacksolver/multiple_choice_subset_sum/algorithm_formatter.hpp" - -#include "optimizationtools/utils/utils.hpp" - -#include - -using namespace knapsacksolver::multiple_choice_subset_sum; - -void AlgorithmFormatter::start( - const std::string& algorithm_name) -{ - output_.json["Parameters"] = parameters_.to_json(); - - if (parameters_.verbosity_level == 0) - return; - *os_ - << "====================================" << std::endl - << " KnapsackSolver " << std::endl - << "====================================" << std::endl - << std::endl - << "Problem" << std::endl - << "-------" << std::endl - << "Multiple-choice subset sum problem" << std::endl - << std::endl - << "Instance" << std::endl - << "--------" << std::endl; - output_.solution.instance().format(*os_, parameters_.verbosity_level); - *os_ - << std::endl - << "Algorithm" << std::endl - << "---------" << std::endl - << algorithm_name << std::endl - << std::endl - << "Parameters" << std::endl - << "----------" << std::endl; - parameters_.format(*os_); -} - -void AlgorithmFormatter::print_header() -{ - if (parameters_.verbosity_level == 0) - return; - *os_ - << std::right - << std::endl - << std::setw(12) << "Time (s)" - << std::setw(6) << "Sol." - << std::setw(12) << "Value" - << std::setw(12) << "Bound" - << std::setw(12) << "Gap" - << std::setw(12) << "Gap (%)" - << std::setw(32) << "Comment" - << std::endl - << std::setw(12) << "--------" - << std::setw(6) << "----" - << std::setw(12) << "-----" - << std::setw(12) << "-----" - << std::setw(12) << "---" - << std::setw(12) << "-------" - << std::setw(32) << "-------" - << std::endl; - print(""); -} - -void AlgorithmFormatter::print( - const std::string& s) -{ - if (parameters_.verbosity_level == 0) - return; - std::streamsize precision = std::cout.precision(); - *os_ - << std::setw(12) << std::fixed << std::setprecision(3) << output_.time << std::defaultfloat << std::setprecision(precision) - << std::setw(6) << output_.has_solution() - << std::setw(12) << output_.value - << std::setw(12) << output_.bound - << std::setw(12) << output_.absolute_optimality_gap() - << std::setw(12) << std::fixed << std::setprecision(2) << output_.relative_optimality_gap() * 100 << std::defaultfloat << std::setprecision(precision) - << std::setw(32) << s << std::endl; -} - -void AlgorithmFormatter::update_solution( - const Solution& solution_new, - const std::string& s) -{ - if ((output_.has_solution() && optimizationtools::is_solution_strictly_better( - objective_direction(), - output_.value, - solution_new.feasible(), - solution_new.objective_value())) - || (!output_.has_solution() && optimizationtools::is_solution_better_or_equal( - objective_direction(), - output_.value, - solution_new.feasible(), - solution_new.objective_value()))) { - output_.time = parameters_.timer.elapsed_time(); - output_.solution = solution_new; - output_.value = output_.solution.objective_value(); - print(s); - output_.json["IntermediaryOutputs"].push_back(output_.to_json()); - parameters_.new_solution_callback(output_); - } -} - -void AlgorithmFormatter::update_value( - Weight value_new, - const std::string& s) -{ - if (optimizationtools::is_value_strictly_better( - objective_direction(), - output_.value, - value_new)) { - output_.time = parameters_.timer.elapsed_time(); - output_.value = value_new; - print(s); - output_.json["IntermediaryOutputs"].push_back(output_.to_json()); - parameters_.new_solution_callback(output_); - } -} - -void AlgorithmFormatter::update_bound( - Weight bound_new, - const std::string& s) -{ - if (optimizationtools::is_bound_strictly_better( - objective_direction(), - output_.bound, - bound_new)) { - output_.time = parameters_.timer.elapsed_time(); - output_.bound = bound_new; - print(s); - output_.json["IntermediaryOutputs"].push_back(output_.to_json()); - parameters_.new_solution_callback(output_); - } -} - -void AlgorithmFormatter::end() -{ - output_.time = parameters_.timer.elapsed_time(); - output_.json["Output"] = output_.to_json(); - - if (parameters_.verbosity_level == 0) - return; - *os_ - << std::endl - << "Final statistics" << std::endl - << "----------------" << std::endl; - output_.format(*os_); - *os_ - << std::endl - << "Solution" << std::endl - << "--------" << std::endl; - output_.solution.format(*os_, parameters_.verbosity_level); -} diff --git a/src/multiple_choice_subset_sum/algorithms/CMakeLists.txt b/src/multiple_choice_subset_sum/algorithms/CMakeLists.txt deleted file mode 100644 index 2de87454..00000000 --- a/src/multiple_choice_subset_sum/algorithms/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_library(KnapsackSolver_multiple_choice_subset_sum_dynamic_programming_bellman) -target_sources(KnapsackSolver_multiple_choice_subset_sum_dynamic_programming_bellman PRIVATE - dynamic_programming_bellman.cpp) -target_include_directories(KnapsackSolver_multiple_choice_subset_sum_dynamic_programming_bellman PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_multiple_choice_subset_sum_dynamic_programming_bellman PUBLIC - KnapsackSolver_multiple_choice_subset_sum) -add_library(KnapsackSolver::multiple_choice_subset_sum::dynamic_programming_bellman ALIAS KnapsackSolver_multiple_choice_subset_sum_dynamic_programming_bellman) diff --git a/src/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.cpp b/src/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.cpp deleted file mode 100644 index 8847802b..00000000 --- a/src/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.cpp +++ /dev/null @@ -1,409 +0,0 @@ -#include "knapsacksolver/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.hpp" - -#include "knapsacksolver/multiple_choice_subset_sum/algorithm_formatter.hpp" - -#include - -using namespace knapsacksolver::multiple_choice_subset_sum; - -//////////////////////////////////////////////////////////////////////////////// -////////////////////// dynamic_programming_bellman_array /////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -Output knapsacksolver::multiple_choice_subset_sum::dynamic_programming_bellman_array( - const Instance& instance, - const Parameters& parameters) -{ - Output output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - array"); - algorithm_formatter.print_header(); - - std::vector values_prev(instance.capacity() + 1, -1); - std::vector values_next(instance.capacity() + 1, -1); - values_next[0] = -2; - Weight weight_sum = 0; - for (GroupId group_id = 0; group_id < instance.number_of_groups(); ++group_id) { - // Check time - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - // Update DP table - values_prev = values_next; - Weight weight_max = 0; - Weight weight_min = instance.capacity(); - for (ItemId item_id: instance.group(group_id).item_ids) { - weight_max = std::max(weight_max, instance.item(item_id).weight); - weight_min = std::min(weight_min, instance.item(item_id).weight); - } - weight_sum += weight_max; - for (Weight weight = std::min(instance.capacity(), weight_sum); - weight >= weight_min; - weight--) { - if (values_prev[weight] != -1) - continue; - for (ItemId item_id: instance.group(group_id).item_ids) { - const Item& item = instance.item(item_id); - if (weight - item.weight >= 0 - && values_prev[weight - item.weight] != -1) { - values_next[weight] = item_id; - break; - } - } - } - - //for (Weight w = 0; w < c; ++w) - // std::cout << (values[w] >= 0); - //std::cout << std::endl; - - if (values_next[instance.capacity()] != -1) - break; - } - - Solution solution(instance); - Weight weight_cur = 0; - for (Weight weight = instance.capacity(); weight >= 0; weight--) { - if (values_next[weight] != -1) { - weight_cur = weight; - break; - } - } - //std::cout << "retrieve" << std::endl; - while (weight_cur > 0) { - ItemId item_id = values_next[weight_cur]; - solution.add(item_id); - weight_cur -= instance.item(item_id).weight; - //std::cout << "j " << j - // << " group " << instance.item(j).group_id - // << " w " << instance.item(j).weight - // << std::endl; - } - - // Update solution. - algorithm_formatter.update_solution( - solution, - "algorithm end (solution)"); - // Update bound. - algorithm_formatter.update_bound( - solution.weight(), - "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} - -//////////////////////////////////////////////////////////////////////////////// -///////////////////// dynamic_programming_bellman_word_ram ///////////////////// -//////////////////////////////////////////////////////////////////////////////// - -Output knapsacksolver::multiple_choice_subset_sum::dynamic_programming_bellman_word_ram( - const Instance& instance, - const Parameters& parameters) -{ - Output output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - word RAM"); - algorithm_formatter.print_header(); - - Weight capacity_number_of_words = (instance.capacity() >> 6); - Weight capacity_number_of_bits_to_shift = instance.capacity() - (capacity_number_of_words << 6); - std::vector values_prev(capacity_number_of_words + 1, 0); - std::vector values_next(capacity_number_of_words + 1, 0); - values_next[0] = 1; - - Weight weight_sum = 0; - std::vector number_of_words_to_shift; - std::vector number_of_bits_to_shift_left; - std::vector number_of_bits_to_shift_right; - std::vector word_write; - for (GroupId group_id = 0; group_id < instance.number_of_groups(); ++group_id) { - // Check time - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - Weight weight_max = 0; - for (ItemId item_id: instance.group(group_id).item_ids) - weight_max = std::max(weight_max, instance.item(item_id).weight); - weight_sum += weight_max; - - values_prev = values_next; - - for (ItemId item_id: instance.group(group_id).item_ids) { - const Item& item = instance.item(item_id); - if (item.weight > instance.capacity()) - continue; - Weight number_of_words_to_shift = (item.weight >> 6); - Weight number_of_bits_to_shift_left = item.weight - (number_of_words_to_shift << 6); - Weight number_of_bits_to_shift_right = 64 - number_of_bits_to_shift_left; - weight_sum += item.weight; - Weight word_read = std::min(capacity_number_of_words, (weight_sum >> 6)); - Weight word_write = word_read - number_of_words_to_shift; - if (number_of_bits_to_shift_left != 0) { - while (word_write > 0) { - values_next[word_read] |= (values_prev[word_write] << number_of_bits_to_shift_left); - values_next[word_read] |= (values_prev[word_write - 1] >> number_of_bits_to_shift_right); - word_read--; - word_write--; - } - values_next[word_read] |= (values_prev[word_write] << number_of_bits_to_shift_left); - } else { - while (word_write >= 0) { - values_next[word_read] |= values_prev[word_write]; - word_read--; - word_write--; - } - } - } - - //for (Weight word = 0; word < number_of_words; ++word) - // for (int bit = 0; bit < 64; ++bit) - // std::cout << ((values[word] >> bit) & 1); - //std::cout << std::endl; - - if (((values_next[capacity_number_of_words] >> capacity_number_of_bits_to_shift) & 1) == 1) - break; - } - - Weight opt = -1; - for (Weight word = capacity_number_of_words; opt == -1; --word) { - //std::cout << "word " << word << " / " << capacity_number_of_words << std::endl; - if (values_next[word] == 0) - continue; - for (int bit = 63; bit >= 0; --bit) { - Weight w = 64 * word + bit; - //std::cout << "w " << w << " val " << ((values_next[word] >> bit) & 1) << std::endl; - if (w <= instance.capacity() - && ((values_next[word] >> bit) & 1) == 1) { - opt = w; - break; - } - } - } - - // Update value. - algorithm_formatter.update_value(opt, "algorithm end (value)"); - // Update bound. - algorithm_formatter.update_bound(opt, "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// dynamic_programming_bellman_word_ram_rec /////////////////// -//////////////////////////////////////////////////////////////////////////////// - -std::vector dynamic_programming_bellman_word_ram_rec_opts( - const Instance& instance, - GroupId group_id_1, - GroupId group_id_2, - Weight capacity, - const Parameters& parameters) -{ - Weight capacity_number_of_words = (capacity >> 6); - Weight capacity_number_of_bits_to_shift = capacity - (capacity_number_of_words << 6); - std::vector values(capacity_number_of_words + 1, 0); - values[0] = 1; - - Weight weight_sum = 0; - std::vector number_of_words_to_shift; - std::vector number_of_bits_to_shift_left; - std::vector number_of_bits_to_shift_right; - std::vector word_write; - for (GroupId group_id = group_id_1; group_id < group_id_2; ++group_id) { - ItemPos group_size = instance.number_of_items(group_id); - - // Check time - if (parameters.timer.needs_to_end()) - return {}; - - Weight weight_max = 0; - for (ItemId item_id: instance.group(group_id).item_ids) - weight_max = std::max(weight_max, instance.item(item_id).weight); - weight_sum += weight_max; - - Weight word_read = std::min(capacity_number_of_words, (weight_sum >> 6)); - number_of_words_to_shift.clear(); - number_of_bits_to_shift_left.clear(); - number_of_bits_to_shift_right.clear(); - word_write.clear(); - number_of_words_to_shift.resize(group_size); - number_of_bits_to_shift_left.resize(group_size); - number_of_bits_to_shift_right.resize(group_size); - word_write.resize(group_size); - for (ItemPos pos = 0; pos < group_size; ++pos) { - ItemId item_id = instance.group(group_id).item_ids[pos]; - const Item& item = instance.item(item_id); - number_of_words_to_shift[pos] = (item.weight >> 6); - number_of_bits_to_shift_left[pos] = item.weight - (number_of_words_to_shift[pos] << 6); - number_of_bits_to_shift_right[pos] = 64 - number_of_bits_to_shift_left[pos]; - word_write[pos] = word_read - number_of_words_to_shift[pos]; - } - - while (word_read >= 0) { - for (ItemPos pos = 0; pos < group_size; ++pos) { - if (number_of_bits_to_shift_left[pos] != 0) { - if (word_write[pos] > 0) { - values[word_read] |= (values[word_write[pos]] << number_of_bits_to_shift_left[pos]); - values[word_read] |= (values[word_write[pos] - 1] >> number_of_bits_to_shift_right[pos]); - } else if (word_write[pos] == 0) { - values[word_read] = (values[word_write[pos]] << number_of_bits_to_shift_left[pos]); - } - } else { - if (word_write[pos] >= 0) { - values[word_read] |= values[word_write[pos]]; - } - } - word_write[pos]--; - } - word_read--; - } - - if (((values[capacity_number_of_words] >> capacity_number_of_bits_to_shift) & 1) == 1) - break; - } - - return values; -} - -void dynamic_programming_bellman_word_ram_rec_rec( - const Instance& instance, - GroupId group_id_1, - GroupId group_id_2, - Weight capacity, - Solution& solution, - const Parameters& parameters) -{ - ItemPos k = (group_id_1 + group_id_2 - 1) / 2 + 1; - - auto values_1 = dynamic_programming_bellman_word_ram_rec_opts( - instance, - group_id_1, - k, - capacity, - parameters); - if (parameters.timer.needs_to_end()) - return; - auto values_2 = dynamic_programming_bellman_word_ram_rec_opts( - instance, - k, - group_id_2, - capacity, - parameters); - if (parameters.timer.needs_to_end()) - return; - - Weight capacity_1_best = 0; - Weight capacity_2_best = 0; - Weight capacity_1 = 0; - Weight capacity_2 = capacity + 1; - for (;;) { - if (capacity_1 + capacity_2 > capacity) { - // Decrease capacity_2. - for (;;) { - capacity_2--; - Weight word_2 = (capacity_2 >> 6); - Weight bits_2 = capacity_2 - (word_2 << 6); - if (capacity_2 < 0 || ((values_2[word_2] >> bits_2) & 1) == 1) - break; - } - } else { - // Increase capacity_1. - for (;;) { - capacity_1++; - Weight word_1 = (capacity_1 >> 6); - Weight bits_1 = capacity_1 - (word_1 << 6); - if (capacity_1 > capacity || ((values_1[word_1] >> bits_1) & 1) == 1) - break; - } - } - if (capacity_2 < 0 || capacity_1 > capacity) - break; - //std::cout << "capacity_1 " << capacity_1 << " capacity_2 " << capacity_2 << std::endl; - if (capacity_1 + capacity_2 <= capacity - && capacity_1 + capacity_2 > capacity_1_best + capacity_2_best) { - capacity_1_best = capacity_1; - capacity_2_best = capacity_2; - } - } - //std::cout - // << "n1 " << n1 - // << " k " << k - // << " n2 " << n2 - // << " c " << capacity - // << " capacity_1_best " << capacity_1_best - // << " capacity_2_best " << capacity_2_best - // << " capacity_1_best + capacity_2_best " << capacity_1_best + capacity_2_best - // << std::endl; - - if (group_id_1 == k - 1) { - for (ItemId item_id: instance.group(group_id_1).item_ids) { - if (capacity_1_best == instance.item(item_id).weight) { - solution.add(item_id); - break; - } - } - } - if (k == group_id_2 - 1) { - for (ItemId item_id: instance.group(k).item_ids) { - if (capacity_2_best == instance.item(item_id).weight) { - solution.add(k); - break; - } - } - } - - if (group_id_1 != k - 1) { - dynamic_programming_bellman_word_ram_rec_rec( - instance, - group_id_1, - k, - capacity_1_best, - solution, - parameters); - } - if (k != group_id_2 - 1) { - dynamic_programming_bellman_word_ram_rec_rec( - instance, - k, - group_id_2, - capacity_2_best, - solution, - parameters); - } -} - -Output knapsacksolver::multiple_choice_subset_sum::dynamic_programming_bellman_word_ram_rec( - const Instance& instance, - const Parameters& parameters) -{ - Output output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - word RAM - recursve scheme"); - algorithm_formatter.print_header(); - - Solution solution(instance); - dynamic_programming_bellman_word_ram_rec_rec( - instance, - 0, - instance.number_of_groups(), - instance.capacity(), - solution, - parameters); - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - // Update solution. - algorithm_formatter.update_solution(solution, "algorithm end (solution)"); - // Update bound. - algorithm_formatter.update_bound(solution.weight(), "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} diff --git a/src/multiple_choice_subset_sum/instance.cpp b/src/multiple_choice_subset_sum/instance.cpp deleted file mode 100644 index d005c9a5..00000000 --- a/src/multiple_choice_subset_sum/instance.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "knapsacksolver/multiple_choice_subset_sum/instance.hpp" - -#include - -using namespace knapsacksolver::multiple_choice_subset_sum; - -void Instance::format( - std::ostream& os, - int verbosity_level) const -{ - if (verbosity_level >= 1) { - os - << "Number of groups: " << number_of_groups() << std::endl - << "Number of items: " << number_of_items() << std::endl - << "Capacity: " << capacity() << std::endl - ; - } - - if (verbosity_level >= 2) { - os - << std::endl - << std::setw(12) << "Group" - << std::setw(12) << "Size" - << std::endl - << std::setw(12) << "-----" - << std::setw(12) << "----" - << std::endl; - for (GroupId group_id = 0; group_id < number_of_groups(); ++group_id) { - os - << std::setw(12) << group_id - << std::setw(12) << number_of_items(group_id) - << std::endl; - } - - os - << std::endl - << std::setw(12) << "Item" - << std::setw(12) << "Group" - << std::setw(12) << "Weight" - << std::endl - << std::setw(12) << "----" - << std::setw(12) << "-----" - << std::setw(12) << "------" - << std::endl; - for (ItemId item_id = 0; item_id < number_of_items(); ++item_id) { - const Item& item = this->item(item_id); - os - << std::setw(12) << item_id - << std::setw(12) << item.group_id - << std::setw(12) << item.weight - << std::endl; - } - } -} - -void Instance::write( - std::string instance_path) const -{ - std::ofstream file(instance_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + instance_path + "\"."); - } - - file << number_of_groups() << " " << capacity() << std::endl; - for (GroupId group_id = 0; group_id < number_of_groups(); ++group_id) { - file << number_of_items(group_id); - for (ItemPos item_id = 0; - item_id < number_of_items(group_id); - ++item_id) - file << " " << item(item_id).weight; - file << std::endl; - } -} diff --git a/src/multiple_choice_subset_sum/instance_builder.cpp b/src/multiple_choice_subset_sum/instance_builder.cpp deleted file mode 100644 index b6dab66b..00000000 --- a/src/multiple_choice_subset_sum/instance_builder.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "knapsacksolver/multiple_choice_subset_sum/instance_builder.hpp" - -#include - -using namespace knapsacksolver::multiple_choice_subset_sum; - -void InstanceBuilder::add_item( - GroupId group_id, - Weight weight) -{ - ItemId item_id = instance_.items_.size(); - Item item; - item.group_id = group_id; - item.weight = weight; - instance_.items_.push_back(item); - while ((GroupId)instance_.groups_.size() <= group_id) - instance_.groups_.push_back(Group()); - instance_.groups_[group_id].item_ids.push_back(item_id); -} - -void InstanceBuilder::read( - const std::string& instance_path, - const std::string& format) -{ - std::ifstream file(instance_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + instance_path + "\"."); - } - - if (format == "standard" || format == "") { - read_standard(file); - } else { - throw std::invalid_argument( - "Unknown instance format \"" + format + "\"."); - } - - file.close(); -} - -void InstanceBuilder::read_standard(std::ifstream& file) -{ - GroupId number_of_groups; - Weight weight; - ItemPos group_number_of_items; - - file >> number_of_groups >> weight; - set_capacity(weight); - for (GroupId group_id = 0; group_id < number_of_groups; ++group_id) { - file >> group_number_of_items; - for (ItemPos item_id = 0; - item_id < group_number_of_items; - ++item_id) { - file >> weight; - add_item(group_id, weight); - } - } -} - -Instance InstanceBuilder::build() -{ - return std::move(instance_); -} diff --git a/src/multiple_choice_subset_sum/main.cpp b/src/multiple_choice_subset_sum/main.cpp deleted file mode 100644 index b4bc56b8..00000000 --- a/src/multiple_choice_subset_sum/main.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "knapsacksolver/multiple_choice_subset_sum/instance_builder.hpp" - -#include "knapsacksolver/multiple_choice_subset_sum/algorithms/dynamic_programming_bellman.hpp" - -#include - -using namespace knapsacksolver::multiple_choice_subset_sum; - -namespace po = boost::program_options; - -void read_args( - Parameters& parameters, - const po::variables_map& vm) -{ - parameters.timer.set_sigint_handler(); - parameters.messages_to_stdout = true; - if (vm.count("time-limit")) - parameters.timer.set_time_limit(vm["time-limit"].as()); - if (vm.count("verbosity-level")) - parameters.verbosity_level = vm["verbosity-level"].as(); - if (vm.count("log")) - parameters.log_path = vm["log"].as(); - parameters.log_to_stderr = vm.count("log-to-stderr"); - bool only_write_at_the_end = vm.count("only-write-at-the-end"); - if (!only_write_at_the_end) { - std::string certificate_path = vm["certificate"].as(); - std::string json_output_path = vm["output"].as(); - parameters.new_solution_callback = [ - json_output_path, - certificate_path]( - const Output& output) - { - output.write_json_output(json_output_path); - output.solution.write(certificate_path); - }; - } -} - -Output run( - const Instance& instance, - const po::variables_map& vm) -{ - std::mt19937_64 generator(vm["seed"].as()); - Solution solution = (!vm.count("initial-solution"))? - Solution(instance): - Solution(instance, vm["initial-solution"].as()); - - // Run algorithm. - std::string algorithm = vm["algorithm"].as(); - if (algorithm == "dynamic-programming-bellman-array") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_array(instance, parameters); - } else if (algorithm == "dynamic-programming-bellman-word-ram") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_word_ram(instance, parameters); - } else if (algorithm == "dynamic-programming-bellman-word-ram-rec") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_word_ram_rec(instance, parameters); - - } else { - throw std::invalid_argument( - "Unknown algorithm \"" + algorithm + "\"."); - } -} - -int main(int argc, char *argv[]) -{ - // Parse program options - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h", "produce help message") - ("algorithm,a", po::value(), "set algorithm") - ("input,i", po::value()->required(), "set input file (required)") - ("format,f", po::value()->default_value(""), "set input file format (default: standard)") - ("output,o", po::value()->default_value(""), "set JSON output file") - ("certificate,c", po::value()->default_value(""), "set certificate file") - ("seed,s", po::value()->default_value(0), "set seed") - ("time-limit,t", po::value(), "set time limit in seconds") - ("verbosity-level,v", po::value(), "set verbosity level") - ("only-write-at-the-end,e", "only write output and certificate files at the end") - ("log,l", po::value(), "set log file") - ("log-to-stderr", "write log to stderr") - ; - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - if (vm.count("help")) { - std::cout << desc << std::endl;; - return 1; - } - try { - po::notify(vm); - } catch (const po::required_option& e) { - std::cout << desc << std::endl;; - return 1; - } - - // Build instance. - InstanceBuilder instance_builder; - instance_builder.read( - vm["input"].as(), - vm["format"].as()); - const Instance instance = instance_builder.build(); - - // Run. - Output output = run(instance, vm); - - // Write outputs. - std::string certificate_path = vm["certificate"].as(); - std::string json_output_path = vm["output"].as(); - output.write_json_output(json_output_path); - output.solution.write(certificate_path); - - return 0; -} diff --git a/src/multiple_choice_subset_sum/solution.cpp b/src/multiple_choice_subset_sum/solution.cpp deleted file mode 100644 index c8367e10..00000000 --- a/src/multiple_choice_subset_sum/solution.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "knapsacksolver/multiple_choice_subset_sum/solution.hpp" - -#include "optimizationtools/utils/utils.hpp" - -using namespace knapsacksolver::multiple_choice_subset_sum; - -Solution::Solution(const Instance& instance): - instance_(&instance), - contains_item_(instance.number_of_items(), 0), - contains_group_(instance.number_of_groups(), 0) -{ } - -Solution::Solution( - const Instance& instance, - std::string certificate_path): - Solution(instance) -{ - if (certificate_path.empty()) - return; - std::ifstream file(certificate_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + certificate_path + "\"."); - } - - ItemPos number_of_items; - ItemPos item_id; - file >> number_of_items; - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - file >> item_id; - add(item_id); - } -} - -void Solution::add(ItemId item_id) -{ - const Item& item = instance().item(item_id); - contains_item_[item_id] = 1; - contains_group_[item.group_id] = 1; - number_of_items_++; - weight_ += item.weight; -} - -void Solution::write(std::string certificate_path) const -{ - if (certificate_path.empty()) - return; - std::ofstream file(certificate_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + certificate_path + "\"."); - } - - file << number_of_items() << std::endl; - for (ItemId item_id = 0; item_id < instance().number_of_items(); ++item_id) - if (contains_item(item_id)) - file << item_id << std::endl; -} - -void Solution::format( - std::ostream& os, - int verbosity_level) const -{ - if (verbosity_level >= 1) { - os - << "Number of items: " << optimizationtools::Ratio(number_of_items(), instance().number_of_items()) << std::endl - << "Weight: " << optimizationtools::Ratio(weight(), instance().capacity()) << std::endl - << "Feasible: " << feasible() << std::endl - ; - } - - if (verbosity_level >= 2) { - os << std::endl - << std::setw(12) << "Item" - << std::endl - << std::setw(12) << "----" - << std::endl; - for (ItemId item_id = 0; - item_id < number_of_items(); - ++item_id) { - os - << std::setw(12) << item_id - << std::endl; - } - } -} - -nlohmann::json Solution::to_json() const -{ - return nlohmann::json { - {"NumberOfItems", number_of_items()}, - {"Feasible", feasible()}, - {"Weight", weight()}, - }; -} diff --git a/src/knapsack/solution.cpp b/src/solution.cpp similarity index 97% rename from src/knapsack/solution.cpp rename to src/solution.cpp index ab1a8351..c4963d56 100644 --- a/src/knapsack/solution.cpp +++ b/src/solution.cpp @@ -1,6 +1,6 @@ -#include "knapsacksolver/knapsack/solution.hpp" +#include "knapsacksolver/solution.hpp" -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; Solution::Solution(const Instance& instance): instance_(&instance), diff --git a/src/knapsack/sort.cpp b/src/sort.cpp similarity index 99% rename from src/knapsack/sort.cpp rename to src/sort.cpp index f5d777e3..76b37ffc 100644 --- a/src/knapsack/sort.cpp +++ b/src/sort.cpp @@ -1,8 +1,8 @@ -#include "knapsacksolver/knapsack/sort.hpp" +#include "knapsacksolver/sort.hpp" -#include "knapsacksolver/knapsack/upper_bound.hpp" +#include "knapsacksolver/upper_bound.hpp" -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; FullSort::FullSort(const Instance& instance): instance_(&instance), diff --git a/src/subset_sum/CMakeLists.txt b/src/subset_sum/CMakeLists.txt deleted file mode 100644 index 2ad5749e..00000000 --- a/src/subset_sum/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -add_library(KnapsackSolver_subset_sum) -target_sources(KnapsackSolver_subset_sum PRIVATE - instance.cpp - instance_builder.cpp - solution.cpp - algorithm_formatter.cpp) -target_include_directories(KnapsackSolver_subset_sum PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_subset_sum PUBLIC - OptimizationTools::utils) -add_library(KnapsackSolver::subset_sum ALIAS KnapsackSolver_subset_sum) - -add_subdirectory(algorithms) - -if(KNAPSACKSOLVER_BUILD_MAIN) - add_executable(KnapsackSolver_subset_sum_main) - target_sources(KnapsackSolver_subset_sum_main PRIVATE - main.cpp) - target_link_libraries(KnapsackSolver_subset_sum_main PUBLIC - KnapsackSolver_subset_sum_dynamic_programming_bellman - KnapsackSolver_subset_sum_dynamic_programming_balancing - KnapsackSolver_subset_sum_dynamic_programming_primal_dual - Boost::program_options) - set_target_properties(KnapsackSolver_subset_sum_main PROPERTIES OUTPUT_NAME "knapsacksolver_subset_sum") - install(TARGETS KnapsackSolver_subset_sum_main) -endif() - -add_library(KnapsackSolver_subset_sum_generator) -target_sources(KnapsackSolver_subset_sum_generator PRIVATE - generator.cpp) -target_link_libraries(KnapsackSolver_subset_sum_generator PUBLIC - KnapsackSolver_subset_sum) -add_library(KnapsackSolver::subset_sum::generator ALIAS KnapsackSolver_subset_sum_generator) - -if(KNAPSACKSOLVER_BUILD_TEST) - add_library(KnapsackSolver_subset_sum_tests) - target_sources(KnapsackSolver_subset_sum_tests PRIVATE - tests.cpp) - target_link_libraries(KnapsackSolver_subset_sum_tests PUBLIC - KnapsackSolver_subset_sum - Boost::filesystem - GTest::gtest_main) - add_library(KnapsackSolver::subset_sum::tests ALIAS KnapsackSolver_subset_sum_tests) -endif() diff --git a/src/subset_sum/algorithm_formatter.cpp b/src/subset_sum/algorithm_formatter.cpp deleted file mode 100644 index 7fd1b500..00000000 --- a/src/subset_sum/algorithm_formatter.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "knapsacksolver/subset_sum/algorithm_formatter.hpp" - -#include "optimizationtools/utils/utils.hpp" - -#include - -using namespace knapsacksolver::subset_sum; - -void AlgorithmFormatter::start( - const std::string& algorithm_name) -{ - output_.json["Parameters"] = parameters_.to_json(); - - if (parameters_.verbosity_level == 0) - return; - *os_ - << "====================================" << std::endl - << " KnapsackSolver " << std::endl - << "====================================" << std::endl - << std::endl - << "Problem" << std::endl - << "-------" << std::endl - << "Subset sum problem" << std::endl - << std::endl - << "Instance" << std::endl - << "--------" << std::endl; - output_.solution.instance().format(*os_, parameters_.verbosity_level); - *os_ - << std::endl - << "Algorithm" << std::endl - << "---------" << std::endl - << algorithm_name << std::endl - << std::endl - << "Parameters" << std::endl - << "----------" << std::endl; - parameters_.format(*os_); -} - -void AlgorithmFormatter::print_header() -{ - if (parameters_.verbosity_level == 0) - return; - *os_ - << std::right - << std::endl - << std::setw(12) << "Time (s)" - << std::setw(6) << "Sol." - << std::setw(12) << "Value" - << std::setw(12) << "Bound" - << std::setw(12) << "Gap" - << std::setw(12) << "Gap (%)" - << std::setw(32) << "Comment" - << std::endl - << std::setw(12) << "--------" - << std::setw(6) << "----" - << std::setw(12) << "-----" - << std::setw(12) << "-----" - << std::setw(12) << "---" - << std::setw(12) << "-------" - << std::setw(32) << "-------" - << std::endl; - print(std::string("")); -} - -void AlgorithmFormatter::print( - const std::string& s) -{ - if (parameters_.verbosity_level == 0) - return; - std::streamsize precision = std::cout.precision(); - *os_ - << std::setw(12) << std::fixed << std::setprecision(3) << output_.time << std::defaultfloat << std::setprecision(precision) - << std::setw(6) << output_.has_solution() - << std::setw(12) << output_.value - << std::setw(12) << output_.bound - << std::setw(12) << output_.absolute_optimality_gap() - << std::setw(12) << std::fixed << std::setprecision(2) << output_.relative_optimality_gap() * 100 << std::defaultfloat << std::setprecision(precision) - << std::setw(32) << s << std::endl; -} - -void AlgorithmFormatter::update_solution( - const Solution& solution_new, - const std::string& s) -{ - if ((output_.has_solution() && optimizationtools::is_solution_strictly_better( - objective_direction(), - output_.value, - solution_new.feasible(), - solution_new.objective_value())) - || (!output_.has_solution() && optimizationtools::is_solution_better_or_equal( - objective_direction(), - output_.value, - solution_new.feasible(), - solution_new.objective_value()))) { - output_.time = parameters_.timer.elapsed_time(); - output_.solution = solution_new; - output_.value = output_.solution.objective_value(); - print(s); - output_.json["IntermediaryOutputs"].push_back(output_.to_json()); - parameters_.new_solution_callback(output_); - } -} - -void AlgorithmFormatter::update_value( - Weight value_new, - const std::string& s) -{ - if (optimizationtools::is_value_strictly_better( - objective_direction(), - output_.value, - value_new)) { - output_.time = parameters_.timer.elapsed_time(); - output_.value = value_new; - print(s); - output_.json["IntermediaryOutputs"].push_back(output_.to_json()); - parameters_.new_solution_callback(output_); - } -} - -void AlgorithmFormatter::update_bound( - Weight bound_new, - const std::string& s) -{ - if (optimizationtools::is_bound_strictly_better( - objective_direction(), - output_.bound, - bound_new)) { - output_.time = parameters_.timer.elapsed_time(); - output_.bound = bound_new; - print(s); - output_.json["IntermediaryOutputs"].push_back(output_.to_json()); - parameters_.new_solution_callback(output_); - } -} - -void AlgorithmFormatter::end() -{ - output_.time = parameters_.timer.elapsed_time(); - output_.json["Output"] = output_.to_json(); - - if (parameters_.verbosity_level == 0) - return; - *os_ - << std::endl - << "Final statistics" << std::endl - << "----------------" << std::endl; - output_.format(*os_); - *os_ - << std::endl - << "Solution" << std::endl - << "--------" << std::endl; - output_.solution.format(*os_, parameters_.verbosity_level); -} diff --git a/src/subset_sum/algorithms/CMakeLists.txt b/src/subset_sum/algorithms/CMakeLists.txt deleted file mode 100644 index 1d3cf4f9..00000000 --- a/src/subset_sum/algorithms/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -add_library(KnapsackSolver_subset_sum_dynamic_programming_bellman) -target_sources(KnapsackSolver_subset_sum_dynamic_programming_bellman PRIVATE - dynamic_programming_bellman.cpp) -target_include_directories(KnapsackSolver_subset_sum_dynamic_programming_bellman PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_subset_sum_dynamic_programming_bellman PUBLIC - KnapsackSolver_subset_sum) -add_library(KnapsackSolver::subset_sum::dynamic_programming_bellman ALIAS KnapsackSolver_subset_sum_dynamic_programming_bellman) - -add_library(KnapsackSolver_subset_sum_dynamic_programming_balancing) -target_sources(KnapsackSolver_subset_sum_dynamic_programming_balancing PRIVATE - dynamic_programming_balancing.cpp) -target_include_directories(KnapsackSolver_subset_sum_dynamic_programming_balancing PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_subset_sum_dynamic_programming_balancing PUBLIC - KnapsackSolver_subset_sum) -add_library(KnapsackSolver::subset_sum::dynamic_programming_balancing ALIAS KnapsackSolver_subset_sum_dynamic_programming_balancing) - -add_library(KnapsackSolver_subset_sum_dynamic_programming_primal_dual) -target_sources(KnapsackSolver_subset_sum_dynamic_programming_primal_dual PRIVATE - dynamic_programming_primal_dual.cpp) -target_include_directories(KnapsackSolver_subset_sum_dynamic_programming_primal_dual PUBLIC - ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(KnapsackSolver_subset_sum_dynamic_programming_primal_dual PUBLIC - KnapsackSolver_subset_sum) -add_library(KnapsackSolver::subset_sum::dynamic_programming_primal_dual ALIAS KnapsackSolver_subset_sum_dynamic_programming_primal_dual) diff --git a/src/subset_sum/algorithms/dynamic_programming_balancing.cpp b/src/subset_sum/algorithms/dynamic_programming_balancing.cpp deleted file mode 100644 index 7b9e59df..00000000 --- a/src/subset_sum/algorithms/dynamic_programming_balancing.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "knapsacksolver/subset_sum/algorithms/dynamic_programming_balancing.hpp" - -#include "knapsacksolver/subset_sum/algorithm_formatter.hpp" - -using namespace knapsacksolver::subset_sum; - -//////////////////////////////////////////////////////////////////////////////// -///////////////////// dynamic_programming_balancing_array ////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -Output knapsacksolver::subset_sum::dynamic_programming_balancing_array( - const Instance& instance, - const Parameters& parameters) -{ - Output output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - balancing - array"); - algorithm_formatter.print_header(); - - Weight c = instance.capacity(); - Weight w_max = 0; - for (ItemId item_id = 0; item_id < instance.number_of_items(); ++item_id) - w_max = std::max(w_max, instance.weight(item_id)); - // Compute the break item and the weight of the break solution. - Weight w_break = 0; - ItemId break_item_id = 0; - for (ItemId item_id = 0; - item_id < instance.number_of_items(); - ++item_id) { - Weight wj = instance.weight(item_id); - if (w_break + wj > c) { - break_item_id = item_id; - break; - } - w_break += wj; - } - // Create and initialize the tables. - std::vector values_pred(w_max * 2, -1); - std::vector values_next(w_max * 2, -1); - Weight offset = c - w_max + 1; - for (Weight w = c - w_max + 1 - offset; w <= c - offset; ++w) - values_pred[w] = 0; - for (Weight w = c + 1 - offset; w <= c + w_max - offset; ++w) - values_pred[w] = 1; - values_pred[w_break - offset] = break_item_id; - - for (ItemId item_id = break_item_id; - item_id < instance.number_of_items(); - ++item_id) { - - // Check time - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - Weight wj = instance.weight(item_id); - for (Weight w = c - w_max + 1 - offset; w <= c + w_max - offset; ++w) - values_next[w] = values_pred[w]; - for (Weight w = c - w_max + 1 - offset; w <= c - offset; ++w) - values_next[w + wj] = std::max(values_next[w + wj], values_pred[w]); - for (Weight w = c + wj - offset; w >= c + 1 - offset; --w) { - for (ItemId item_id_0 = values_pred[w]; - item_id_0 < values_next[w]; - ++item_id_0) { - Weight wj0 = instance.weight(item_id_0); - values_next[w - wj0] = std::max(values_next[w - wj0], item_id); - } - } - - values_pred.swap(values_next); - - // If optimum reached, stop. - if (values_pred[c - offset] != 0) - break; - } - - // Retrieve optimal value. - Weight optimal_value = 0; - for (Weight weight = c - offset; - weight >= c - w_max + 1 - offset; - --weight) { - if (values_pred[weight] != 0) { - optimal_value = weight + offset; - break; - } - } - // Update lower bound. - algorithm_formatter.update_value( - optimal_value, - "algorithm end (value)"); - // Update upper bound. - algorithm_formatter.update_bound( - optimal_value, - "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} diff --git a/src/subset_sum/algorithms/dynamic_programming_bellman.cpp b/src/subset_sum/algorithms/dynamic_programming_bellman.cpp deleted file mode 100644 index d727490d..00000000 --- a/src/subset_sum/algorithms/dynamic_programming_bellman.cpp +++ /dev/null @@ -1,417 +0,0 @@ -#include "knapsacksolver/subset_sum/algorithms/dynamic_programming_bellman.hpp" - -#include "knapsacksolver/subset_sum/algorithm_formatter.hpp" - -using namespace knapsacksolver::subset_sum; - -//////////////////////////////////////////////////////////////////////////////// -////////////////////// dynamic_programming_bellman_array /////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -DynamicProgrammingBellmanArrayOutput knapsacksolver::subset_sum::dynamic_programming_bellman_array( - const Instance& instance, - const Parameters& parameters) -{ - DynamicProgrammingBellmanArrayOutput output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - array"); - algorithm_formatter.print_header(); - - output.values = std::vector(instance.capacity() + 1, -1); - output.values[0] = -2; - Weight weight_sum = 0; - for (ItemPos item_id = 0; item_id < instance.number_of_items(); ++item_id) { - // Check time - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - // Update DP table - weight_sum += instance.weight(item_id); - for (Weight weight = std::min(instance.capacity(), weight_sum); - weight >= instance.weight(item_id); - weight--) { - if (output.values[weight] == -1 - && output.values[weight - instance.weight(item_id)] != -1) { - output.values[weight] = item_id; - } - } - - //for (Weight w = 0; w < c; ++w) - // std::cout << (values[w] >= 0); - //std::cout << std::endl; - - // If optimum reached, stop. - if (output.values[instance.capacity()] != -1) - break; - } - - Solution solution(instance); - Weight weight_cur = 0; - for (Weight weight = instance.capacity(); weight >= 0; weight--) { - if (output.values[weight] != -1) { - weight_cur = weight; - break; - } - } - while (weight_cur > 0) { - ItemId item_id = output.values[weight_cur]; - solution.add(item_id); - weight_cur -= instance.weight(item_id); - } - - // Update value. - algorithm_formatter.update_solution( - solution, - "algorithm end (solution)"); - // Update bound. - algorithm_formatter.update_bound( - solution.weight(), - "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} - -//////////////////////////////////////////////////////////////////////////////// -/////////////////////// dynamic_programming_bellman_list /////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -Output knapsacksolver::subset_sum::dynamic_programming_bellman_list( - const Instance& instance, - const Parameters& parameters) -{ - Output output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - states"); - algorithm_formatter.print_header(); - - std::vector l0{0}; - std::vector l; - for (ItemId item_id = 0; item_id < instance.number_of_items(); ++item_id) { - // Check time - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - auto it = l0.begin(); - auto it1 = l0.begin(); - while (it != l0.end() || it1 != l0.end()) { - if (it1 != l0.end() && (it == l0.end() || *it > *it1 + instance.weight(item_id))) { - Weight w = *it1 + instance.weight(item_id); - if (w > instance.capacity()) - break; - if (l.empty() || w != l.back()) - l.push_back(w); - it1++; - } else { - assert(it != l0.end()); - if (l.empty() || *it != l.back()) - l.push_back(*it); - it++; - } - } - l0 = std::move(l); - l.clear(); - - // Update value. - if (output.value < l0.back()) { - std::stringstream ss; - ss << "iteration " << item_id; - algorithm_formatter.update_value(l0.back(), ss.str()); - } - - if (output.value == output.bound) - break; - } - - // Update bound. - algorithm_formatter.update_bound( - l0.back(), - "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} - -//////////////////////////////////////////////////////////////////////////////// -///////////////////// dynamic_programming_bellman_word_ram ///////////////////// -//////////////////////////////////////////////////////////////////////////////// - -DynamicProgrammingBellmanWordRamOutput knapsacksolver::subset_sum::dynamic_programming_bellman_word_ram( - const Instance& instance, - const Parameters& parameters) -{ - DynamicProgrammingBellmanWordRamOutput output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - word RAM"); - algorithm_formatter.print_header(); - - Weight capacity_number_of_words = (instance.capacity() >> 6); - Weight capacity_number_of_bits_to_shift = instance.capacity() - (capacity_number_of_words << 6); - output.values = std::vector(capacity_number_of_words + 1, 0); - output.values[0] = 1; - - Weight weight_sum = 0; - - for (ItemPos item_id = 0; item_id < instance.number_of_items(); ++item_id) { - // Check time - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - if (instance.weight(item_id) > instance.capacity()) - continue; - Weight number_of_words_to_shift = (instance.weight(item_id) >> 6); - Weight number_of_bits_to_shift_left = instance.weight(item_id) - (number_of_words_to_shift << 6); - Weight number_of_bits_to_shift_right = 64 - number_of_bits_to_shift_left; - weight_sum += instance.weight(item_id); - Weight word_read = std::min(capacity_number_of_words, (weight_sum >> 6)); - Weight word_write = word_read - number_of_words_to_shift; - if (number_of_bits_to_shift_left != 0) { - while (word_write > 0) { - output.values[word_read] |= (output.values[word_write] << number_of_bits_to_shift_left); - output.values[word_read] |= (output.values[word_write - 1] >> number_of_bits_to_shift_right); - word_read--; - word_write--; - } - output.values[word_read] |= (output.values[word_write] << number_of_bits_to_shift_left); - } else { - while (word_write >= 0) { - output.values[word_read] |= output.values[word_write]; - word_read--; - word_write--; - } - } - - //for (Weight word = 0; word < number_of_words; ++word) - // for (int bit = 0; bit < 64; ++bit) - // std::cout << ((values[word] >> bit) & 1); - //std::cout << std::endl; - - if (((output.values[capacity_number_of_words] >> capacity_number_of_bits_to_shift) & 1) == 1) - break; - } - - Weight optimal_value = 0; - for (Weight word = capacity_number_of_words; optimal_value == 0; --word) { - if (output.values[word] == 0) - continue; - for (int bit = 63; bit >= 0; --bit) { - Weight weight = 64 * word + bit; - if (weight <= instance.capacity() - && ((output.values[word] >> bit) & 1) == 1) { - optimal_value = weight; - break; - } - } - } - // Update bound. - algorithm_formatter.update_value( - optimal_value, - "algorithm end (value)"); - // Update bound. - algorithm_formatter.update_bound( - optimal_value, - "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// dynamic_programming_bellman_word_ram_rec /////////////////// -//////////////////////////////////////////////////////////////////////////////// - -std::vector dynamic_programming_bellman_word_ram_rec_opts( - const Instance& instance, - ItemPos item_pos_1, - ItemPos item_pos_2, - Weight capacity, - const Parameters& parameters) -{ - Weight capacity_number_of_words = (capacity >> 6); - Weight capacity_number_of_bits_to_shift = capacity - (capacity_number_of_words << 6); - std::vector values(capacity_number_of_words + 1, 0); - values[0] = 1; - - Weight weight_sum = 0; - - for (ItemPos item_id = item_pos_1; item_id < item_pos_2; ++item_id) { - // Check time - if (parameters.timer.needs_to_end()) - return {}; - - if (instance.weight(item_id) > capacity) - continue; - Weight number_of_words_to_shift = (instance.weight(item_id) >> 6); - Weight number_of_bits_to_shift_left = instance.weight(item_id) - (number_of_words_to_shift << 6); - Weight number_of_bits_to_shift_right = 64 - number_of_bits_to_shift_left; - weight_sum += instance.weight(item_id); - Weight word_read = std::min(capacity_number_of_words, (weight_sum >> 6)); - Weight word_write = word_read - number_of_words_to_shift; - //std::cout << "weight_sum " << weight_sum << std::endl; - //std::cout << "capacity_number_of_words " << capacity_number_of_words << std::endl; - //std::cout << "number_of_words_to_shift " << number_of_words_to_shift << std::endl; - //std::cout << "word_read " << word_read << std::endl; - //std::cout << "word_write " << word_write << std::endl; - assert(word_read >= 0); - assert(word_write >= 0); - if (number_of_bits_to_shift_left != 0) { - while (word_write > 0) { - values[word_read] |= (values[word_write] << number_of_bits_to_shift_left); - values[word_read] |= (values[word_write - 1] >> number_of_bits_to_shift_right); - word_read--; - word_write--; - } - //std::cout << word_read << " " << word_write << " " << capacity_number_of_words << std::endl; - values[word_read] |= (values[word_write] << number_of_bits_to_shift_left); - } else { - while (word_write >= 0) { - values[word_read] |= values[word_write]; - word_read--; - word_write--; - } - } - - if (((values[capacity_number_of_words] >> capacity_number_of_bits_to_shift) & 1) == 1) - break; - } - - return values; -} - -void dynamic_programming_bellman_word_ram_rec_rec( - const Instance& instance, - ItemPos item_pos_1, - ItemPos item_pos_2, - Weight capacity, - Solution& solution, - const Parameters& parameters) -{ - ItemPos k = (item_pos_1 + item_pos_2 - 1) / 2 + 1; - - auto values_1 = dynamic_programming_bellman_word_ram_rec_opts( - instance, - item_pos_1, - k, - capacity, - parameters); - if (parameters.timer.needs_to_end()) - return; - auto values_2 = dynamic_programming_bellman_word_ram_rec_opts( - instance, - k, - item_pos_2, - capacity, - parameters); - if (parameters.timer.needs_to_end()) - return; - - Weight capacity_1_best = 0; - Weight capacity_2_best = 0; - Weight capacity_1 = 0; - Weight capacity_2 = capacity + 1; - for (;;) { - if (capacity_1 + capacity_2 > capacity) { - // Decrease capacity_2. - for (;;) { - capacity_2--; - Weight word_2 = (capacity_2 >> 6); - Weight bits_2 = capacity_2 - (word_2 << 6); - if (capacity_2 < 0 || ((values_2[word_2] >> bits_2) & 1) == 1) - break; - } - } else { - // Increase capacity_1. - for (;;) { - capacity_1++; - Weight word_1 = (capacity_1 >> 6); - Weight bits_1 = capacity_1 - (word_1 << 6); - if (capacity_1 > capacity || ((values_1[word_1] >> bits_1) & 1) == 1) - break; - } - } - if (capacity_2 < 0 || capacity_1 > capacity) - break; - //std::cout << "capacity_1 " << capacity_1 << " capacity_2 " << capacity_2 << std::endl; - if (capacity_1 + capacity_2 <= capacity - && capacity_1 + capacity_2 > capacity_1_best + capacity_2_best) { - capacity_1_best = capacity_1; - capacity_2_best = capacity_2; - } - } - //std::cout - // << "item_pos_1 " << item_pos_1 - // << " k " << k - // << " item_pos_2 " << item_pos_2 - // << " c " << capacity - // << " capacity_1_best " << capacity_1_best - // << " capacity_2_best " << capacity_2_best - // << " capacity_1_best + capacity_2_best " << capacity_1_best + capacity_2_best - // << std::endl; - - if (item_pos_1 == k - 1) - if (capacity_1_best == instance.weight(item_pos_1)) - solution.add(item_pos_1); - if (k == item_pos_2 - 1) - if (capacity_2_best == instance.weight(k)) - solution.add(k); - - if (item_pos_1 != k - 1) { - dynamic_programming_bellman_word_ram_rec_rec( - instance, - item_pos_1, - k, - capacity_1_best, - solution, - parameters); - } - if (k != item_pos_2 - 1) { - dynamic_programming_bellman_word_ram_rec_rec( - instance, - k, - item_pos_2, - capacity_2_best, - solution, - parameters); - } -} - -Output knapsacksolver::subset_sum::dynamic_programming_bellman_word_ram_rec( - const Instance& instance, - const Parameters& parameters) -{ - Output output(instance); - AlgorithmFormatter algorithm_formatter(parameters, output); - algorithm_formatter.start("Dynamic programming - Bellman - word RAM - recursive scheme"); - algorithm_formatter.print_header(); - - Solution solution(instance); - dynamic_programming_bellman_word_ram_rec_rec( - instance, - 0, - instance.number_of_items(), - instance.capacity(), - solution, - parameters); - if (parameters.timer.needs_to_end()) { - algorithm_formatter.end(); - return output; - } - - // Update value. - algorithm_formatter.update_solution( - solution, - "algorithm end (solution)"); - // Update bound. - algorithm_formatter.update_bound( - solution.weight(), - "algorithm end (bound)"); - - algorithm_formatter.end(); - return output; -} diff --git a/src/subset_sum/algorithms/dynamic_programming_primal_dual.cpp b/src/subset_sum/algorithms/dynamic_programming_primal_dual.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subset_sum/generator.cpp b/src/subset_sum/generator.cpp deleted file mode 100644 index e52f6b57..00000000 --- a/src/subset_sum/generator.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "knapsacksolver/subset_sum/generator.hpp" - -#include "knapsacksolver/subset_sum/instance_builder.hpp" - -#include - -using namespace knapsacksolver::subset_sum; - -namespace -{ - -template -T gcd(T a, T b) -{ - if (b == 0) - return a; - return gcd(b, a % b); -} - -} - -Instance knapsacksolver::subset_sum::generate_pthree( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e3); - instance_builder.set_capacity(number_of_items * 1e3 / 4); - for (ItemPos pos = 0; pos < number_of_items; ++pos) - instance_builder.add_item(distribution(generator)); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_psix( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e6); - instance_builder.set_capacity(number_of_items * 1e6 / 4); - for (ItemPos pos = 0; pos < number_of_items; ++pos) - instance_builder.add_item(distribution(generator)); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_evenodd( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e3 / 2); - instance_builder.set_capacity(2 * (number_of_items * 1e3 / 8) + 1); - for (ItemPos pos = 0; pos < number_of_items; ++pos) - instance_builder.add_item(2 * distribution(generator)); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_avis( - ItemPos number_of_items) -{ - ItemPos n = number_of_items; - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e3); - instance_builder.set_capacity(n * (n + 1) * ((n - 1) / 2) + n * (n - 1) / 2); - for (ItemPos pos = 0; pos < number_of_items; ++pos) - instance_builder.add_item(n * (n + 1) + pos); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_todd( - ItemPos number_of_items) -{ - ItemPos n = number_of_items; - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e3); - Weight weight_sum = 0; - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - int i1 = (int)std::floor(std::log(n)) + n + 1; - int i2 = (int)std::floor(std::log(n)) + pos; - Weight item_weight = (1 << i1) + (1 << i2) + 1; - instance_builder.add_item(item_weight); - weight_sum += item_weight; - } - instance_builder.set_capacity(weight_sum / 2); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_somatoth( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - - std::uniform_int_distribution distribution(1, number_of_items); - Weight w1; - Weight w2; - Weight capacity; - for (;;) { - w1 = distribution(generator); - w2 = distribution(generator); - std::cout << "w1 " << w1 << " w2 " << w2 << " gcd " << gcd(w1, w2) << std::endl; - if (gcd(w1, w2) != 1) - continue; - - capacity = (w1 - 1) * (w2 - 1) - 1; - std::cout << capacity / w1 << " " << capacity / w2 << " " << number_of_items / 2 << std::endl; - if (capacity / w1 >= number_of_items / 2) - continue; - if (capacity / w2 >= number_of_items / 2) - continue; - } - - instance_builder.set_capacity(capacity); - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - if (pos % 2 == 0) { - instance_builder.add_item(std::ceil((double)pos / 2) * w1); - } else { - instance_builder.add_item(std::ceil((double)pos / 2) * w2); - } - } - - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_evenodd6( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e6 / 2); - instance_builder.set_capacity((number_of_items * 1e6 / 60) + 1); - for (ItemPos pos = 0; pos < number_of_items; ++pos) - instance_builder.add_item(2 * distribution(generator)); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_evenodd8( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e8 / 2); - Weight weight_sum = 0; - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - Weight item_weight = 2 * distribution(generator); - instance_builder.add_item(item_weight); - weight_sum += item_weight; - } - instance_builder.set_capacity(weight_sum / 2 + 1); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_tenfive6( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e5); - Weight weight_sum = 0; - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - Weight item_weight = 10 * distribution(generator); - instance_builder.add_item(item_weight); - weight_sum += item_weight; - } - instance_builder.set_capacity((weight_sum / 600) * 10 + 5); - return instance_builder.build(); -} - -Instance knapsacksolver::subset_sum::generate_tenfive8( - ItemPos number_of_items, - std::mt19937_64& generator) -{ - InstanceBuilder instance_builder; - std::uniform_int_distribution distribution(1, 1e7); - Weight weight_sum = 0; - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - Weight item_weight = 10 * distribution(generator); - instance_builder.add_item(item_weight); - weight_sum += item_weight; - } - instance_builder.set_capacity((weight_sum / 20) * 10 + 5); - return instance_builder.build(); -} diff --git a/src/subset_sum/generator_main.cpp b/src/subset_sum/generator_main.cpp deleted file mode 100644 index 3707d51f..00000000 --- a/src/subset_sum/generator_main.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "knapsacksolver/subset_sum/generator.hpp" - -using namespace knapsacksolver::subset_sum; - -int main(int argc, char *argv[]) -{ - (void)argc; - (void)argv; - std::mt19937_64 generator; - - // pthree. - std::cout << "Generate pthree..." << std::endl; - for (ItemPos n: {10, 30, 100, 300, 1000, 3000, 10000}) { - for (int seed = 0; seed < 100; ++seed) { - generator.seed(seed); - Instance instance = generate_pthree(n, generator); - std::string instance_path - = "data/subset_sum/pthree/pthree_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - // psix. - std::cout << "Generate psix..." << std::endl; - for (ItemPos n: {10, 30, 100, 300, 1000, 3000}) { - for (int seed = 0; seed < 100; ++seed) { - generator.seed(seed); - Instance instance = generate_psix(n, generator); - std::string instance_path - = "data/subset_sum/psix/psix_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - // evenodd. - std::cout << "Generate evenodd..." << std::endl; - for (ItemPos n: {10, 30, 100, 300, 1000, 3000, 10000}) { - for (int seed = 0; seed < 100; ++seed) { - generator.seed(seed); - Instance instance = generate_evenodd(n, generator); - std::string instance_path - = "data/subset_sum/evenodd/evenodd_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - // avis. - std::cout << "Generate avis..." << std::endl; - for (ItemPos n: {10, 30, 100, 300, 1000}) { - generator.seed(0); - Instance instance = generate_avis(n); - std::string instance_path - = "data/subset_sum/avis/avis_" - + std::to_string(n); - instance.write(instance_path); - } - - // todd. - std::cout << "Generate todd..." << std::endl; - for (ItemPos n: {10}) { - generator.seed(0); - Instance instance = generate_todd(n); - std::string instance_path - = "data/subset_sum/todd/todd_" - + std::to_string(n); - instance.write(instance_path); - } - - // somatoth. - /* - std::cout << "Generate somatoth..." << std::endl; - for (ItemPos n: {10, 30, 100, 300, 1000, 3000, 10000}) { - std::cout << "n " << n << std::endl; - for (int seed = 0; seed < 100; ++seed) { - generator.seed(seed); - Instance instance = generate_somatoth(n, generator); - std::string instance_path - = "data/subset_sum/somatoth/somatoth_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - */ - - // evenodd6. - std::cout << "Generate evenodd6..." << std::endl; - for (ItemPos n: {1000, 3000, 5000, 8000, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000, 100000}) { - for (int seed = 0; seed < 1; ++seed) { - generator.seed(seed); - Instance instance = generate_evenodd6(n, generator); - std::string instance_path - = "data/subset_sum/evenodd6/evenodd6_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - // evenodd8. - std::cout << "Generate evenodd8..." << std::endl; - for (ItemPos n: {10, 50, 100, 150, 200, 300, 500, 1000, 5000, 10000, 50000}) { - for (int seed = 0; seed < 1; ++seed) { - generator.seed(seed); - Instance instance = generate_evenodd8(n, generator); - std::string instance_path - = "data/subset_sum/evenodd8/evenodd8_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - // tenfive6. - std::cout << "Generate tenfive6..." << std::endl; - for (ItemPos n: {1000, 3000, 5000, 8000, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000, 100000}) { - for (int seed = 0; seed < 1; ++seed) { - generator.seed(seed); - Instance instance = generate_tenfive6(n, generator); - std::string instance_path - = "data/subset_sum/tenfive6/tenfive6_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - // tenfive8. - std::cout << "Generate tenfive8..." << std::endl; - for (ItemPos n: {10, 50, 100, 150, 200, 300, 500, 1000, 5000, 10000, 50000}) { - for (int seed = 0; seed < 1; ++seed) { - generator.seed(seed); - Instance instance = generate_tenfive8(n, generator); - std::string instance_path - = "data/subset_sum/tenfive8/tenfive8_" - + std::to_string(n) + "_" + std::to_string(seed); - instance.write(instance_path); - } - } - - return 0; -} diff --git a/src/subset_sum/instance.cpp b/src/subset_sum/instance.cpp deleted file mode 100644 index a8301726..00000000 --- a/src/subset_sum/instance.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "knapsacksolver/subset_sum/instance.hpp" - -#include - -using namespace knapsacksolver::subset_sum; - -void Instance::format( - std::ostream& os, - int verbosity_level) const -{ - if (verbosity_level >= 1) { - os - << "Number of items: " << number_of_items() << std::endl - << "Capacity: " << capacity() << std::endl - ; - } - - if (verbosity_level >= 2) { - os - << std::endl - << std::setw(12) << "Item" - << std::setw(12) << "Weight" - << std::endl - << std::setw(12) << "----" - << std::setw(12) << "------" - << std::endl; - for (ItemId item_id = 0; item_id < number_of_items(); ++item_id) { - os - << std::setw(12) << item_id - << std::setw(12) << weight(item_id) - << std::endl; - } - } -} - -void Instance::write( - std::string instance_path) const -{ - std::ofstream file(instance_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + instance_path + "\"."); - } - - file << number_of_items() << " " << capacity() << std::endl; - for (ItemId item_id = 0; item_id < number_of_items(); ++item_id) - file << weight(item_id) << std::endl; -} diff --git a/src/subset_sum/instance_builder.cpp b/src/subset_sum/instance_builder.cpp deleted file mode 100644 index c36ef3f6..00000000 --- a/src/subset_sum/instance_builder.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "knapsacksolver/subset_sum/instance_builder.hpp" - -#include - -using namespace knapsacksolver::subset_sum; - -void InstanceBuilder::read( - const std::string& instance_path, - const std::string& format) -{ - std::ifstream file(instance_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + instance_path + "\"."); - } - - if (format == "standard" || format == "") { - read_standard(file); - } else { - throw std::invalid_argument( - "Unknown instance format \"" + format + "\"."); - } - - file.close(); -} - -void InstanceBuilder::read_standard(std::ifstream& file) -{ - ItemId number_of_items; - Weight weight; - file >> number_of_items >> weight; - set_capacity(weight); - for (ItemPos item_id = 0; item_id < number_of_items; ++item_id) { - file >> weight; - add_item(weight); - } -} - -Instance InstanceBuilder::build() -{ - return std::move(instance_); -} diff --git a/src/subset_sum/main.cpp b/src/subset_sum/main.cpp deleted file mode 100644 index f50f7ee0..00000000 --- a/src/subset_sum/main.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "knapsacksolver/subset_sum/instance_builder.hpp" - -#include "knapsacksolver/subset_sum/algorithms/dynamic_programming_bellman.hpp" -#include "knapsacksolver/subset_sum/algorithms/dynamic_programming_balancing.hpp" - -#include - -using namespace knapsacksolver::subset_sum; - -namespace po = boost::program_options; - -void read_args( - Parameters& parameters, - const po::variables_map& vm) -{ - parameters.timer.set_sigint_handler(); - parameters.messages_to_stdout = true; - if (vm.count("time-limit")) - parameters.timer.set_time_limit(vm["time-limit"].as()); - if (vm.count("verbosity-level")) - parameters.verbosity_level = vm["verbosity-level"].as(); - if (vm.count("log")) - parameters.log_path = vm["log"].as(); - parameters.log_to_stderr = vm.count("log-to-stderr"); - bool only_write_at_the_end = vm.count("only-write-at-the-end"); - if (!only_write_at_the_end) { - - std::string certificate_path; - if (vm.count("certificate")) - certificate_path = vm["certificate"].as(); - - std::string json_output_path; - if (vm.count("output")) - json_output_path = vm["output"].as(); - - parameters.new_solution_callback = [ - json_output_path, - certificate_path]( - const Output& output) - { - if (!json_output_path.empty()) - output.write_json_output(json_output_path); - if (!certificate_path.empty()) - output.solution.write(certificate_path); - }; - } -} - -Output run( - const Instance& instance, - const po::variables_map& vm) -{ - std::mt19937_64 generator(vm["seed"].as()); - Solution solution = (!vm.count("initial-solution"))? - Solution(instance): - Solution(instance, vm["initial-solution"].as()); - - // Run algorithm. - std::string algorithm = vm["algorithm"].as(); - if (algorithm == "dynamic-programming-bellman-array") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_array(instance, parameters); - } else if (algorithm == "dynamic-programming-bellman-list") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_list(instance, parameters); - } else if (algorithm == "dynamic-programming-bellman-word-ram") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_word_ram(instance, parameters); - } else if (algorithm == "dynamic-programming-bellman-word-ram-rec") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_bellman_word_ram_rec(instance, parameters); - - } else if (algorithm == "dynamic-programming-balancing-array") { - Parameters parameters; - read_args(parameters, vm); - return dynamic_programming_balancing_array(instance, parameters); - - } else { - throw std::invalid_argument( - "Unknown algorithm \"" + algorithm + "\"."); - } -} - -int main(int argc, char *argv[]) -{ - // Parse program options - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h", "produce help message") - ("algorithm,a", po::value(), "set algorithm") - ("input,i", po::value()->required(), "set input file (required)") - ("format,f", po::value()->default_value(""), "set input file format (default: standard)") - ("output,o", po::value(), "set JSON output file") - ("certificate,c", po::value(), "set certificate file") - ("seed,s", po::value()->default_value(0), "set seed") - ("time-limit,t", po::value(), "set time limit in seconds") - ("verbosity-level,v", po::value(), "set verbosity level") - ("only-write-at-the-end,e", "only write output and certificate files at the end") - ("log,l", po::value(), "set log file") - ("log-to-stderr", "write log to stderr") - ; - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - if (vm.count("help")) { - std::cout << desc << std::endl;; - return 1; - } - try { - po::notify(vm); - } catch (const po::required_option& e) { - std::cout << desc << std::endl; - return 1; - } - - // Build instance. - InstanceBuilder instance_builder; - instance_builder.read( - vm["input"].as(), - vm["format"].as()); - const Instance instance = instance_builder.build(); - - // Run. - Output output = run(instance, vm); - - // Write outputs. - if (vm.count("certificate")) - output.solution.write(vm["certificate"].as()); - if (vm.count("output")) - output.write_json_output(vm["output"].as()); - - return 0; -} diff --git a/src/subset_sum/solution.cpp b/src/subset_sum/solution.cpp deleted file mode 100644 index 73d9ccd9..00000000 --- a/src/subset_sum/solution.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "knapsacksolver/subset_sum/solution.hpp" - -#include "optimizationtools/utils/utils.hpp" - -using namespace knapsacksolver::subset_sum; - -Solution::Solution(const Instance& instance): - instance_(&instance), - contains_(instance.number_of_items(), 0) -{ } - -Solution::Solution( - const Instance& instance, - const std::string& certificate_path): - Solution(instance) -{ - if (certificate_path.empty()) - return; - std::ifstream file(certificate_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + certificate_path + "\"."); - } - - ItemPos number_of_items; - ItemPos item_id; - file >> number_of_items; - for (ItemPos pos = 0; pos < number_of_items; ++pos) { - file >> item_id; - add(item_id); - } -} - -void Solution::add(ItemId item_id) -{ - contains_[item_id] = 1; - number_of_items_++; - weight_ += instance().weight(item_id); -} - -void Solution::write( - const std::string& certificate_path) const -{ - if (certificate_path.empty()) - return; - std::ofstream file(certificate_path); - if (!file.good()) { - throw std::runtime_error( - "Unable to open file \"" + certificate_path + "\"."); - } - - file << number_of_items() << std::endl; - for (ItemId item_id = 0; item_id < instance().number_of_items(); ++item_id) - if (contains(item_id)) - file << item_id << std::endl; -} - -void Solution::format( - std::ostream& os, - int verbosity_level) const -{ - if (verbosity_level >= 1) { - os - << "Number of items: " << optimizationtools::Ratio(number_of_items(), instance().number_of_items()) << std::endl - << "Weight: " << optimizationtools::Ratio(weight(), instance().capacity()) << std::endl - << "Feasible: " << feasible() << std::endl - ; - } - - if (verbosity_level >= 2) { - os << std::endl - << std::setw(12) << "Item" - << std::endl - << std::setw(12) << "----" - << std::endl; - for (ItemId item_id = 0; - item_id < number_of_items(); - ++item_id) { - os - << std::setw(12) << item_id - << std::endl; - } - } -} - -nlohmann::json Solution::to_json() const -{ - return nlohmann::json { - {"NumberOfItems", number_of_items()}, - {"Feasible", feasible()}, - {"Weight", weight()}, - }; -} diff --git a/src/subset_sum/tests.cpp b/src/subset_sum/tests.cpp deleted file mode 100644 index b2024d39..00000000 --- a/src/subset_sum/tests.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "knapsacksolver/subset_sum/tests.hpp" - -#include "knapsacksolver/subset_sum/instance_builder.hpp" - -#include - -using namespace knapsacksolver::subset_sum; - -namespace fs = boost::filesystem; - -std::string knapsacksolver::subset_sum::get_path( - const std::vector& path) -{ - if (path.empty()) - return ""; - fs::path p(path[0]); - for (size_t i = 1; i < path.size(); ++i) - p /= path[i]; - return p.string(); -} - -std::vector knapsacksolver::subset_sum::get_pthree_instance_paths( - ItemId number_of_items) -{ - std::vector instance_paths; - for (int i = 0; i < 100; ++i) { - instance_paths.push_back({ - get_path({"pthree", "pthree_" + std::to_string(number_of_items) + "_" + std::to_string(i)}), "standard", - get_path({"pthree", "pthree_" + std::to_string(number_of_items) + "_" + std::to_string(i) + "_solution.txt"}), "standard"}); - } - return instance_paths; -} - -std::vector knapsacksolver::subset_sum::get_psix_instance_paths( - ItemId number_of_items) -{ - std::vector instance_paths; - for (int i = 0; i < 100; ++i) { - instance_paths.push_back({ - get_path({"psix", "psix_" + std::to_string(number_of_items) + "_" + std::to_string(i)}), "standard", - get_path({"psix", "psix_" + std::to_string(number_of_items) + "_" + std::to_string(i) + "_solution.txt"}), "standard"}); - } - return instance_paths; -} - -std::vector knapsacksolver::subset_sum::get_test_params( - const std::vector& algorithms, - const std::vector>& instance_paths) -{ - std::vector res; - for (const Algorithm& algorithm: algorithms) { - for (const auto& v: instance_paths) { - for (const TestInstancePath& files: v) { - TestParams test_params; - test_params.algorithm = algorithm; - test_params.files = files; - res.push_back(test_params); - } - } - } - return res; -} - -const Instance knapsacksolver::subset_sum::get_instance( - const TestInstancePath& files) -{ - InstanceBuilder instance_builder; - std::string instance_path = get_path({ - std::getenv("SUBSET_SUM_DATA"), - files.instance_path}); - std::cout << "Instance path: " << instance_path << std::endl; - instance_builder.read( - instance_path, - files.instance_format); - return instance_builder.build(); -} - -const Solution knapsacksolver::subset_sum::get_solution( - const Instance& instance, - const TestInstancePath& files) -{ - std::string certificate_path = get_path({ - std::getenv("SUBSET_SUM_DATA"), - files.certificate_path}); - return Solution( - instance, - certificate_path); -} diff --git a/src/knapsack/tests.cpp b/src/tests.cpp similarity index 88% rename from src/knapsack/tests.cpp rename to src/tests.cpp index 7c99ff26..eb9cad29 100644 --- a/src/knapsack/tests.cpp +++ b/src/tests.cpp @@ -1,14 +1,14 @@ -#include "knapsacksolver/knapsack/tests.hpp" +#include "knapsacksolver/tests.hpp" -#include "knapsacksolver/knapsack/instance_builder.hpp" +#include "knapsacksolver/instance_builder.hpp" #include -using namespace knapsacksolver::knapsack; +using namespace knapsacksolver; namespace fs = boost::filesystem; -std::string knapsacksolver::knapsack::get_path( +std::string knapsacksolver::get_path( const std::vector& path) { if (path.empty()) @@ -19,7 +19,7 @@ std::string knapsacksolver::knapsack::get_path( return p.string(); } -std::vector knapsacksolver::knapsack::get_test_instance_paths() +std::vector knapsacksolver::get_test_instance_paths() { return { { @@ -65,7 +65,7 @@ std::vector knapsacksolver::knapsack::get_test_instance_paths( }; } -std::vector knapsacksolver::knapsack::get_pisinger_instance_paths( +std::vector knapsacksolver::get_pisinger_instance_paths( const std::string& s1, const std::string& s2) { @@ -78,7 +78,7 @@ std::vector knapsacksolver::knapsack::get_pisinger_instance_pa return instance_paths; } -std::vector knapsacksolver::knapsack::get_test_params( +std::vector knapsacksolver::get_test_params( const std::vector& algorithms, const std::vector>& instance_paths) { @@ -96,7 +96,7 @@ std::vector knapsacksolver::knapsack::get_test_params( return res; } -const Instance knapsacksolver::knapsack::get_instance( +const Instance knapsacksolver::get_instance( const TestInstancePath& files) { InstanceBuilder instance_builder; @@ -110,7 +110,7 @@ const Instance knapsacksolver::knapsack::get_instance( return instance_builder.build(); } -const Solution knapsacksolver::knapsack::get_solution( +const Solution knapsacksolver::get_solution( const Instance& instance, const TestInstancePath& files) { diff --git a/src/upper_bound.cpp b/src/upper_bound.cpp new file mode 100644 index 00000000..c90ef2a5 --- /dev/null +++ b/src/upper_bound.cpp @@ -0,0 +1,6 @@ +#include "knapsacksolver/upper_bound.hpp" + +#include "knapsacksolver/algorithm_formatter.hpp" + +using namespace knapsacksolver; + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1184f265..27adb0e5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,4 @@ enable_testing() include(GoogleTest) -add_subdirectory(knapsack) -add_subdirectory(subset_sum) -add_subdirectory(multiple_choice_subset_sum) +add_subdirectory(algorithms) diff --git a/test/algorithms/CMakeLists.txt b/test/algorithms/CMakeLists.txt new file mode 100644 index 00000000..240f698b --- /dev/null +++ b/test/algorithms/CMakeLists.txt @@ -0,0 +1,18 @@ +add_executable(KnapsackSolver_dynamic_programming_bellman_test) +target_sources(KnapsackSolver_dynamic_programming_bellman_test PRIVATE + dynamic_programming_bellman_test.cpp) +target_link_libraries(KnapsackSolver_dynamic_programming_bellman_test + KnapsackSolver_dynamic_programming_bellman + KnapsackSolver_tests + GTest::gtest_main) +gtest_discover_tests(KnapsackSolver_dynamic_programming_bellman_test) + +add_executable(KnapsackSolver_dynamic_programming_primal_dual_test) +target_sources(KnapsackSolver_dynamic_programming_primal_dual_test PRIVATE + dynamic_programming_primal_dual_test.cpp) +target_link_libraries(KnapsackSolver_dynamic_programming_primal_dual_test + KnapsackSolver_dynamic_programming_primal_dual + KnapsackSolver_tests + GTest::gtest_main) +add_test(KnapsackSolver_dynamic_programming_primal_dual_test KnapsackSolver_dynamic_programming_primal_dual_test) +set_tests_properties(KnapsackSolver_dynamic_programming_primal_dual_test PROPERTIES TIMEOUT 10000) diff --git a/test/knapsack/algorithms/dynamic_programming_bellman_test.cpp b/test/algorithms/dynamic_programming_bellman_test.cpp similarity index 96% rename from test/knapsack/algorithms/dynamic_programming_bellman_test.cpp rename to test/algorithms/dynamic_programming_bellman_test.cpp index 56d4ecaa..aab5d153 100644 --- a/test/knapsack/algorithms/dynamic_programming_bellman_test.cpp +++ b/test/algorithms/dynamic_programming_bellman_test.cpp @@ -1,9 +1,8 @@ -#include "knapsacksolver/knapsack/tests.hpp" +#include "knapsacksolver/tests.hpp" -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_bellman.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_bellman.hpp" using namespace knapsacksolver; -using namespace knapsacksolver::knapsack; TEST_P(ExactAlgorithmTest, ExactAlgorithm) { diff --git a/test/knapsack/algorithms/dynamic_programming_primal_dual_test.cpp b/test/algorithms/dynamic_programming_primal_dual_test.cpp similarity index 99% rename from test/knapsack/algorithms/dynamic_programming_primal_dual_test.cpp rename to test/algorithms/dynamic_programming_primal_dual_test.cpp index a6e5754d..f81b1995 100644 --- a/test/knapsack/algorithms/dynamic_programming_primal_dual_test.cpp +++ b/test/algorithms/dynamic_programming_primal_dual_test.cpp @@ -1,9 +1,8 @@ -#include "knapsacksolver/knapsack/tests.hpp" +#include "knapsacksolver/tests.hpp" -#include "knapsacksolver/knapsack/algorithms/dynamic_programming_primal_dual.hpp" +#include "knapsacksolver/algorithms/dynamic_programming_primal_dual.hpp" using namespace knapsacksolver; -using namespace knapsacksolver::knapsack; TEST_P(ExactAlgorithmTest, ExactAlgorithm) { diff --git a/test/knapsack/CMakeLists.txt b/test/knapsack/CMakeLists.txt deleted file mode 100644 index 24c12bf9..00000000 --- a/test/knapsack/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(algorithms) diff --git a/test/knapsack/algorithms/CMakeLists.txt b/test/knapsack/algorithms/CMakeLists.txt deleted file mode 100644 index a61b5aaf..00000000 --- a/test/knapsack/algorithms/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_executable(KnapsackSolver_knapsack_dynamic_programming_bellman_test) -target_sources(KnapsackSolver_knapsack_dynamic_programming_bellman_test PRIVATE - dynamic_programming_bellman_test.cpp) -target_link_libraries(KnapsackSolver_knapsack_dynamic_programming_bellman_test - KnapsackSolver_knapsack_dynamic_programming_bellman - KnapsackSolver_knapsack_tests - GTest::gtest_main) -gtest_discover_tests(KnapsackSolver_knapsack_dynamic_programming_bellman_test) - -add_executable(KnapsackSolver_knapsack_dynamic_programming_primal_dual_test) -target_sources(KnapsackSolver_knapsack_dynamic_programming_primal_dual_test PRIVATE - dynamic_programming_primal_dual_test.cpp) -target_link_libraries(KnapsackSolver_knapsack_dynamic_programming_primal_dual_test - KnapsackSolver_knapsack_dynamic_programming_primal_dual - KnapsackSolver_knapsack_tests - GTest::gtest_main) -add_test(KnapsackSolver_knapsack_dynamic_programming_primal_dual_test KnapsackSolver_knapsack_dynamic_programming_primal_dual_test) -set_tests_properties(KnapsackSolver_knapsack_dynamic_programming_primal_dual_test PROPERTIES TIMEOUT 10000) diff --git a/test/multiple_choice_subset_sum/CMakeLists.txt b/test/multiple_choice_subset_sum/CMakeLists.txt deleted file mode 100644 index 24c12bf9..00000000 --- a/test/multiple_choice_subset_sum/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(algorithms) diff --git a/test/multiple_choice_subset_sum/algorithms/CMakeLists.txt b/test/multiple_choice_subset_sum/algorithms/CMakeLists.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/test/subset_sum/CMakeLists.txt b/test/subset_sum/CMakeLists.txt deleted file mode 100644 index 24c12bf9..00000000 --- a/test/subset_sum/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(algorithms) diff --git a/test/subset_sum/algorithms/CMakeLists.txt b/test/subset_sum/algorithms/CMakeLists.txt deleted file mode 100644 index d0d15adc..00000000 --- a/test/subset_sum/algorithms/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_executable(KnapsackSolver_subset_sum_dynamic_programming_bellman_test) -target_sources(KnapsackSolver_subset_sum_dynamic_programming_bellman_test PRIVATE - dynamic_programming_bellman_test.cpp) -target_link_libraries(KnapsackSolver_subset_sum_dynamic_programming_bellman_test - KnapsackSolver_subset_sum_dynamic_programming_bellman - KnapsackSolver_subset_sum_tests - GTest::gtest_main) -add_test(KnapsackSolver_subset_sum_dynamic_programming_bellman_test KnapsackSolver_subset_sum_dynamic_programming_bellman_test) diff --git a/test/subset_sum/algorithms/dynamic_programming_bellman_test.cpp b/test/subset_sum/algorithms/dynamic_programming_bellman_test.cpp deleted file mode 100644 index e9354c53..00000000 --- a/test/subset_sum/algorithms/dynamic_programming_bellman_test.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "knapsacksolver/subset_sum/tests.hpp" - -#include "knapsacksolver/subset_sum/algorithms/dynamic_programming_bellman.hpp" - -using namespace knapsacksolver; -using namespace knapsacksolver::subset_sum; - -TEST_P(ExactAlgorithmTest, ExactAlgorithm) -{ - TestParams test_params = GetParam(); - const Instance instance = get_instance(test_params.files); - const Solution solution = get_solution(instance, test_params.files); - auto output = test_params.algorithm(instance); - EXPECT_EQ(output.value, solution.weight()); - EXPECT_EQ(output.value, output.solution.weight()); - EXPECT_EQ(output.bound, solution.weight()); -} - -TEST_P(ExactNoSolutionAlgorithmTest, ExactNoSolutionAlgorithm) -{ - TestParams test_params = GetParam(); - const Instance instance = get_instance(test_params.files); - const Solution solution = get_solution(instance, test_params.files); - auto output = test_params.algorithm(instance); - EXPECT_EQ(output.value, solution.weight()); - EXPECT_EQ(output.bound, solution.weight()); -} - -INSTANTIATE_TEST_SUITE_P( - SubsetSumDynamicProgrammingBellmanArray, - ExactAlgorithmTest, - testing::ValuesIn(get_test_params( - { - [](const Instance& instance) - { - return dynamic_programming_bellman_array(instance); - }, - }, - { - get_pthree_instance_paths(10), - get_pthree_instance_paths(30), - get_pthree_instance_paths(100), - get_pthree_instance_paths(300), - get_pthree_instance_paths(1000), - get_psix_instance_paths(10), - }))); - -INSTANTIATE_TEST_SUITE_P( - SubsetSumDynamicProgrammingBellmanList, - ExactNoSolutionAlgorithmTest, - testing::ValuesIn(get_test_params( - { - [](const Instance& instance) - { - return dynamic_programming_bellman_list(instance); - }, - }, - { - get_pthree_instance_paths(10), - get_pthree_instance_paths(30), - get_pthree_instance_paths(100), - get_pthree_instance_paths(300), - get_pthree_instance_paths(1000), - get_psix_instance_paths(10), - }))); - -INSTANTIATE_TEST_SUITE_P( - SubsetSumDynamicProgrammingBellmanWordRam, - ExactNoSolutionAlgorithmTest, - testing::ValuesIn(get_test_params( - { - [](const Instance& instance) - { - return dynamic_programming_bellman_word_ram(instance); - }, - }, - { - get_pthree_instance_paths(10), - get_pthree_instance_paths(30), - get_pthree_instance_paths(100), - get_pthree_instance_paths(300), - get_pthree_instance_paths(1000), - get_psix_instance_paths(10), - }))); - -INSTANTIATE_TEST_SUITE_P( - SubsetSumDynamicProgrammingBellmanWordRamRec, - ExactAlgorithmTest, - testing::ValuesIn(get_test_params( - { - [](const Instance& instance) - { - return dynamic_programming_bellman_word_ram_rec(instance); - }, - }, - { - get_pthree_instance_paths(10), - get_pthree_instance_paths(30), - get_pthree_instance_paths(100), - get_pthree_instance_paths(300), - get_pthree_instance_paths(1000), - get_psix_instance_paths(10), - })));