Skip to content

Commit

Permalink
Allow testing external programs with test_solver
Browse files Browse the repository at this point in the history
  • Loading branch information
trolando committed Jul 24, 2024
1 parent e9b7dd9 commit 886547d
Showing 1 changed file with 73 additions and 0 deletions.
73 changes: 73 additions & 0 deletions test/test_solvers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/filesystem.hpp>
#include <boost/random/random_device.hpp>
#include <boost/process.hpp>

#include "tools/cxxopts.hpp"
#include "oink/oink.hpp"
#include "oink/solvers.hpp"
#include "oink/solver.hpp"
#include "verifier.hpp"
#include "lace.h"

using namespace pg;
namespace fs = boost::filesystem;
namespace io = boost::iostreams;
namespace bp = boost::process;

bool opt_inflate = false;
bool opt_compress = false;
Expand Down Expand Up @@ -81,6 +84,66 @@ setsighandlers(void)
}

/*------------------------------------------------------------------------*/
class ExternalSolver : public Solver {
public:
ExternalSolver(Oink* oink, Game* game, std::string cmd) : Solver(oink, game), cmd(cmd) {}
~ExternalSolver() {}

void run() {
// Obtain temporary filenames
auto path1 = fs::unique_path();
auto path2 = fs::unique_path();

// Write parity game to temporary file
// TODO: handle partial files (where some nodes are disabled)
std::ofstream file(path1.native());
game->write_pgsolver(file);
file.close();

// Replace %I with input filename and %O with output filename
replaceAll(cmd, "%I", path1.native());
replaceAll(cmd, "%O", path2.native());

// Run the external program (no timeout)
bp::ipstream out;
bp::ipstream err;
std::string line;
bp::child c("/bin/sh", "-c", cmd, bp::std_out > out, bp::std_err > err);
c.wait();
while (std::getline(out, line)) logger << line << std::endl;
while (std::getline(err, line)) logger << line << std::endl;

// Read solution from temporary file
std::ifstream solution(path2.native());
game->parse_solution(solution);
solution.close();

// Delete temporary files
fs::remove(path1);
fs::remove(path2);

/*
// Extract the subgame if necessary
if (disabled.any()) {
// only keep the ones that are not disabled
bitset selected(disabled);
selected.flip();
auto g = game->extract_subgame(selected);
}
*/
}

private:
std::string cmd;

static void replaceAll(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Move past the replaced substring
}
}
};


int
Expand Down Expand Up @@ -157,6 +220,7 @@ main(int argc, char **argv)
for (const auto& id : Solvers::getSolverIDs()) {
opts.add_options("Solvers")(id, Solvers::desc(id));
}
opts.add_options("Solvers")("e,external", "External solver, e.g., 'python solver.py %I %O'", cxxopts::value<std::vector<std::string>>());
opts.add_options("Solving")
("t,trace", "Write trace with given level (0-3) to stdout", cxxopts::value<int>())
("c,configure", "Additional configuration options for the solver", cxxopts::value<std::string>())
Expand Down Expand Up @@ -210,6 +274,15 @@ main(int argc, char **argv)
std::cout << " " << id;
}
}
if (options.count("external")) {
for (auto& e : options["external"].as<std::vector<std::string>>()) {
Solvers::add(e, "external tool", 0, [&](Oink& oink, Game& game) {
return std::make_unique<ExternalSolver>(&oink, &game, e);
});
solvers.push_back(e);
std::cout << " '" << e << "'";
}
}
if (solvers.size() == 0) {
std::cout << " (none)" << std::endl << std::endl;
std::cout << "Use --help for program options." << std::endl << std::endl;
Expand Down

0 comments on commit 886547d

Please sign in to comment.