Aufnahme SatHelper implementation
This commit is contained in:
commit
4ead56c9c9
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cmake-build-debug/
|
6
CMakeLists.txt
Normal file
6
CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(sathelper)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_library(sathelper sathelper.cpp)
|
1
sathelper.cpp
Normal file
1
sathelper.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "sathelper.h"
|
153
sathelper.h
Normal file
153
sathelper.h
Normal file
@ -0,0 +1,153 @@
|
||||
#ifndef SATHELPER_SATHELPER_H
|
||||
#define SATHELPER_SATHELPER_H
|
||||
#endif // SATHELPER_SATHELPER_H
|
||||
#include <unordered_map>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
class SatHelper {
|
||||
private:
|
||||
int nextIntId = 1;
|
||||
std::unordered_map<std::string, int> varIntMap;
|
||||
std::unordered_map<int, std::string> intVarMap;
|
||||
std::vector<std::vector<int>> clauses;
|
||||
int varToInt(const std::string &name) { return varIntMap[name]; };
|
||||
std::string intToVar(const int var) {
|
||||
if (var == 0)
|
||||
return "0";
|
||||
if (var > 0) {
|
||||
return intVarMap[var];
|
||||
}
|
||||
return "-" + intVarMap[-var];
|
||||
}
|
||||
static std::string getVarName(const std::string &lit) {
|
||||
if (isNegated(lit)) {
|
||||
return lit.substr(1);
|
||||
}
|
||||
return lit;
|
||||
}
|
||||
static bool isNegated(const std::string &lit) { return lit[0] == '-'; }
|
||||
int literalToInt(const std::string &lit) {
|
||||
int code = varToInt(getVarName(lit));
|
||||
if (isNegated(lit)) {
|
||||
return -code;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
std::vector<int> literalsToIntStr(const std::vector<std::string> &clause) {
|
||||
std::vector<int> res(clause.size() + 1, 0);
|
||||
std::for_each(clause.begin(), clause.end(),
|
||||
[idx = 0, &res, this](const auto &elem) mutable {
|
||||
res[idx] = literalToInt(elem);
|
||||
++idx;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
static std::string getNegated(const std::string &lit) {
|
||||
if (isNegated(lit)) {
|
||||
return getVarName(lit);
|
||||
}
|
||||
return "-" + lit;
|
||||
}
|
||||
|
||||
static std::string clauseToStr(const std::vector<int> &clause) {
|
||||
std::string res;
|
||||
for (const auto &lit : clause) {
|
||||
res += std::to_string(lit);
|
||||
if (lit == 0) {
|
||||
continue;
|
||||
}
|
||||
res += " ";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string formulaToStr() {
|
||||
std::string res = "p cnf " + std::to_string(nextIntId - 1) + " " +
|
||||
std::to_string((int)clauses.size()) + "\n";
|
||||
std::for_each(clauses.begin(), clauses.end(), [&res](const auto &clause) {
|
||||
res += clauseToStr(clause) + "\n";
|
||||
});
|
||||
return res;
|
||||
}
|
||||
const std::string FORMULA_FNAME = "/tmp/formula.cnf";
|
||||
|
||||
public:
|
||||
/*
|
||||
* you need to declare vars first before use to create a mapping from name to
|
||||
* int (dimacs doesn't use names)
|
||||
*/
|
||||
void declareVar(const std::string &name) {
|
||||
this->varIntMap[name] = this->nextIntId;
|
||||
this->intVarMap[this->nextIntId] = name;
|
||||
this->nextIntId += 1;
|
||||
}
|
||||
/*
|
||||
* add a cnf clause
|
||||
*/
|
||||
void addClause(const std::vector<std::string> &clause) {
|
||||
this->clauses.push_back(literalsToIntStr(clause));
|
||||
}
|
||||
/*
|
||||
* add a clause with at-most-one constraint
|
||||
*/
|
||||
void addAtMostOne(const std::vector<std::string> &clause) {
|
||||
std::for_each(clause.begin(), clause.end(),
|
||||
[idx = 0, &clause, this](const auto &lit) mutable {
|
||||
for (int j = idx; j < clause.size(); ++j) {
|
||||
std::vector<std::string> tmp = {getNegated(lit),
|
||||
getNegated(clause[j])};
|
||||
this->addClause(tmp);
|
||||
}
|
||||
++idx;
|
||||
});
|
||||
}
|
||||
void printFormula() { std::cout << formulaToStr() << std::endl; }
|
||||
bool solveSat() {
|
||||
const std::string formula = formulaToStr();
|
||||
std::ofstream fout(FORMULA_FNAME);
|
||||
fout << formula << std::endl;
|
||||
FILE *fp = popen(("glucose -model " + FORMULA_FNAME).c_str(), "r");
|
||||
std::ostringstream out;
|
||||
while (!feof(fp) && !ferror(fp)) {
|
||||
char buf[128];
|
||||
int bytesRead = fread(buf, 1, 128, fp);
|
||||
out.write(buf, bytesRead);
|
||||
}
|
||||
// this can probably be written more elegant
|
||||
std::istringstream stream;
|
||||
stream.str(out.str());
|
||||
std::string line;
|
||||
while (getline(stream, line)) {
|
||||
if (line == "s SATISFIABLE") {
|
||||
getline(stream, line);
|
||||
std::string var;
|
||||
std::vector<std::string> actual_vars;
|
||||
std::istringstream var_line(line.substr(2));
|
||||
while (getline(var_line, var, ' ')) {
|
||||
int varCode = atoi(var.c_str());
|
||||
actual_vars.push_back(intToVar(varCode));
|
||||
};
|
||||
std::cout << "SATISFIABLE WITH VARS ";
|
||||
for (int i = 0; i < actual_vars.size(); ++i) {
|
||||
std::cout << actual_vars[i] << " ";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (line == "s UNSATISFIABLE") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void reset() {
|
||||
this->nextIntId = 1;
|
||||
this->clauses = {};
|
||||
this->intVarMap = {};
|
||||
this->varIntMap = {};
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user