Skip to content

Commit

Permalink
Add tests for subset sum (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
fontanf authored May 3, 2024
1 parent edd1332 commit e830f0c
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 28 deletions.
4 changes: 2 additions & 2 deletions include/knapsacksolver/subset_sum/solution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Solution
/** Create a solution from a file. */
Solution(
const Instance& instance,
std::string certificate_path);
const std::string& certificate_path);

/** Add an item to the solution. */
void add(ItemId item_id);
Expand Down Expand Up @@ -61,7 +61,7 @@ class Solution
*/

/** Write the solution to a file. */
void write(std::string filepath) const;
void write(const std::string& certificate_path) const;

/** Export solution characteristics to a JSON structure. */
nlohmann::json to_json() const;
Expand Down
51 changes: 51 additions & 0 deletions include/knapsacksolver/subset_sum/tests.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#include "knapsacksolver/subset_sum/solution.hpp"

#include <gtest/gtest.h>

namespace knapsacksolver
{
namespace subset_sum
{

std::string get_path(const std::vector<std::string>& path);

struct TestInstancePath
{
std::string instance_path;
std::string instance_format;
std::string certificate_path;
std::string certificate_format;
};

std::vector<TestInstancePath> get_pthree_instance_paths(
ItemId number_of_items);

std::vector<TestInstancePath> get_psix_instance_paths(
ItemId number_of_items);

using Algorithm = std::function<const Output(const Instance&)>;

struct TestParams
{
Algorithm algorithm;
TestInstancePath files;
};

std::vector<TestParams> get_test_params(
const std::vector<Algorithm>& algorithms,
const std::vector<std::vector<TestInstancePath>>& instance_paths);

const Instance get_instance(
const TestInstancePath& files);

const Solution get_solution(
const Instance& instance,
const TestInstancePath& files);

class ExactAlgorithmTest: public testing::TestWithParam<TestParams> { };
class ExactNoSolutionAlgorithmTest: public testing::TestWithParam<TestParams> { };

}
}
2 changes: 1 addition & 1 deletion scripts/download_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ def download(id):
pathlib.Path("data.7z").unlink()

download("1jCf-Ye7pAQLVep6MT1HA_G05gdEgWeKk")
download("1n64Bti7qgImKDtY_bNAR3oNSC-S80-We")
download("1tNIfm81yBp7DU3qfQVLLnewYwKlyzsrt")
15 changes: 9 additions & 6 deletions src/knapsack/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ const Instance knapsacksolver::knapsack::get_instance(
const TestInstancePath& files)
{
InstanceBuilder instance_builder;
std::string data_path = std::getenv("KNAPSACK_DATA");
data_path += "/";
std::string instance_path = get_path({
std::getenv("KNAPSACK_DATA"),
files.instance_path});
std::cout << "Instance path: " << instance_path << std::endl;
instance_builder.read(
data_path + files.instance_path,
instance_path,
files.instance_format);
return instance_builder.build();
}
Expand All @@ -112,10 +114,11 @@ const Solution knapsacksolver::knapsack::get_solution(
const Instance& instance,
const TestInstancePath& files)
{
std::string data_path = std::getenv("KNAPSACK_DATA");
data_path += "/";
std::string certificate_path = get_path({
std::getenv("KNAPSACK_DATA"),
files.certificate_path});
return Solution(
instance,
data_path + files.certificate_path,
certificate_path,
files.certificate_format);
}
9 changes: 9 additions & 0 deletions src/subset_sum/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,12 @@ target_sources(KnapsackSolver_subset_sum_generator PRIVATE
target_link_libraries(KnapsackSolver_subset_sum_generator PUBLIC
KnapsackSolver_subset_sum)
add_library(KnapsackSolver::subset_sum::generator ALIAS KnapsackSolver_subset_sum_generator)

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)
2 changes: 1 addition & 1 deletion src/subset_sum/algorithms/dynamic_programming_bellman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ const Output knapsacksolver::subset_sum::dynamic_programming_bellman_word_ram(
// std::cout << ((values[word] >> bit) & 1);
//std::cout << std::endl;

if (((values[capacity_number_of_words - 1] >> capacity_number_of_bits_to_shift) & 1) == 1)
if (((values[capacity_number_of_words] >> capacity_number_of_bits_to_shift) & 1) == 1)
break;
}

Expand Down
31 changes: 20 additions & 11 deletions src/subset_sum/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,24 @@ void read_args(
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>();
std::string json_output_path = vm["output"].as<std::string>();

std::string certificate_path;
if (vm.count("certificate"))
certificate_path = vm["certificate"].as<std::string>();

std::string json_output_path;
if (vm.count("output"))
json_output_path = vm["output"].as<std::string>();

parameters.new_solution_callback = [
json_output_path,
certificate_path](
const Output& output)
{
output.write_json_output(json_output_path);
output.solution.write(certificate_path);
if (!json_output_path.empty())
output.write_json_output(json_output_path);
if (!certificate_path.empty())
output.solution.write(certificate_path);
};
}
}
Expand Down Expand Up @@ -85,8 +94,8 @@ int main(int argc, char *argv[])
("algorithm,a", po::value<std::string>(), "set algorithm")
("input,i", po::value<std::string>()->required(), "set input file (required)")
("format,f", po::value<std::string>()->default_value(""), "set input file format (default: standard)")
("output,o", po::value<std::string>()->default_value(""), "set JSON output file")
("certificate,c", po::value<std::string>()->default_value(""), "set certificate file")
("output,o", po::value<std::string>(), "set JSON output file")
("certificate,c", po::value<std::string>(), "set certificate file")
("seed,s", po::value<Seed>()->default_value(0), "set seed")
("time-limit,t", po::value<double>(), "set time limit in seconds")
("verbosity-level,v", po::value<int>(), "set verbosity level")
Expand All @@ -103,7 +112,7 @@ int main(int argc, char *argv[])
try {
po::notify(vm);
} catch (const po::required_option& e) {
std::cout << desc << std::endl;;
std::cout << desc << std::endl;
return 1;
}

Expand All @@ -118,10 +127,10 @@ int main(int argc, char *argv[])
Output output = run(instance, vm);

// Write outputs.
std::string certificate_path = vm["certificate"].as<std::string>();
std::string json_output_path = vm["output"].as<std::string>();
output.write_json_output(json_output_path);
output.solution.write(certificate_path);
if (vm.count("certificate"))
output.solution.write(vm["certificate"].as<std::string>());
if (vm.count("output"))
output.write_json_output(vm["output"].as<std::string>());

return 0;
}
5 changes: 3 additions & 2 deletions src/subset_sum/solution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Solution::Solution(const Instance& instance):

Solution::Solution(
const Instance& instance,
std::string certificate_path):
const std::string& certificate_path):
Solution(instance)
{
if (certificate_path.empty())
Expand All @@ -38,7 +38,8 @@ void Solution::add(ItemId item_id)
weight_ += instance().weight(item_id);
}

void Solution::write(std::string certificate_path) const
void Solution::write(
const std::string& certificate_path) const
{
if (certificate_path.empty())
return;
Expand Down
88 changes: 88 additions & 0 deletions src/subset_sum/tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "knapsacksolver/subset_sum/tests.hpp"

#include "knapsacksolver/subset_sum/instance_builder.hpp"

#include <boost/filesystem.hpp>

using namespace knapsacksolver::subset_sum;

namespace fs = boost::filesystem;

std::string knapsacksolver::subset_sum::get_path(
const std::vector<std::string>& 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<TestInstancePath> knapsacksolver::subset_sum::get_pthree_instance_paths(
ItemId number_of_items)
{
std::vector<TestInstancePath> 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<TestInstancePath> knapsacksolver::subset_sum::get_psix_instance_paths(
ItemId number_of_items)
{
std::vector<TestInstancePath> 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<TestParams> knapsacksolver::subset_sum::get_test_params(
const std::vector<Algorithm>& algorithms,
const std::vector<std::vector<TestInstancePath>>& instance_paths)
{
std::vector<TestParams> 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);
}
6 changes: 3 additions & 3 deletions test/knapsack/algorithms/dynamic_programming_bellman_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ TEST_P(ExactNoSolutionAlgorithmTest, ExactNoSolutionAlgorithm)
}

INSTANTIATE_TEST_SUITE_P(
DynamicProgrammingBellmanArray,
KnapsackDynamicProgrammingBellmanArray,
ExactNoSolutionAlgorithmTest,
testing::ValuesIn(get_test_params(
{
Expand All @@ -42,7 +42,7 @@ INSTANTIATE_TEST_SUITE_P(
})));

INSTANTIATE_TEST_SUITE_P(
DynamicProgrammingBellmanNoSolution,
KnapsackDynamicProgrammingBellmanNoSolution,
ExactNoSolutionAlgorithmTest,
testing::ValuesIn(get_test_params(
{
Expand Down Expand Up @@ -74,7 +74,7 @@ INSTANTIATE_TEST_SUITE_P(
})));

INSTANTIATE_TEST_SUITE_P(
DynamicProgrammingBellman,
KnapsackDynamicProgrammingBellman,
ExactAlgorithmTest,
testing::ValuesIn(get_test_params(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ TEST_P(ExactAlgorithmTest, ExactAlgorithm)
}

INSTANTIATE_TEST_SUITE_P(
DynamicProgrammingPrimalDualPartialSolutionSize,
KnapsackDynamicProgrammingPrimalDualPartialSolutionSize,
ExactAlgorithmTest,
testing::ValuesIn(get_test_params(
{
Expand All @@ -43,7 +43,7 @@ INSTANTIATE_TEST_SUITE_P(
{get_test_instance_paths()})));

INSTANTIATE_TEST_SUITE_P(
DynamicProgrammingPrimalDual,
KnapsackDynamicProgrammingPrimalDual,
ExactAlgorithmTest,
testing::ValuesIn(get_test_params(
{
Expand Down
8 changes: 8 additions & 0 deletions test/subset_sum/algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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)
Loading

0 comments on commit e830f0c

Please sign in to comment.