Written from scratch SAT solver (c)

Written from scratch SAT solver (c)

Previous

Core algorithms: DPLL

//DPLL.cpp
#include "DPLL.h"

bool DPLL::check_sat() {
    // TODO: your code here, or in the header file
    std::unordered_map<int,int> atomStatus;//记录节点状态0,1,2
    int clause_num = phi.clauses.size();//子句数量
    int atomNum = phi.num_variable;//变量数量
    for(int i=1;i<=atomNum;i++)
        result.insert(std::make_pair(i,true));
    int* nodeStatus = new int[atomNum];
    for(int i=0;i<atomNum;i++)
        nodeStatus[i]=0;
    int ptr = 0;//指向当前节点
    while(true){
        if(nodeStatus[ptr]==2)
            break;
        else if(nodeStatus[ptr]==0) {
            nodeStatus[ptr]++;
            result[ptr + 1] = false;
        }
        else {
            nodeStatus[ptr]++;
            result[ptr + 1] = true;
        }
        int solveStatus = 2;//0 肯定不是解,1 肯定是解,2 不确定
        //检查是否是解
        bool wholeValue = true;//整个式子的真值
        for(int i=0;i<clause_num;i++) //每个子句
        {
            bool currValue=false;//这个子句是不是假的
            bool any_notsure=false;//有没有不确定的literature
            int len = phi.clauses[i].size();
            for(int j=0;j<len;j++)
            {
                int currvar = phi.clauses[i][j];
                if(VAR(currvar)<=ptr+1)
                {
                    if((POSITIVE(currvar)&&result[currvar])||(NEGATIVE(currvar)&&!result[VAR(currvar)])){//有一个为真,子句为真
                        currValue=true;
                        break;
                    }
                }
                else{
                    any_notsure=true;
                }
            }
            wholeValue=wholeValue&&currValue;
            if(currValue||any_notsure){
                continue;
            }
            else{
                solveStatus=0;
                break;
            }
        }
        if(wholeValue)
            solveStatus=1;
        //检查完毕
        if(solveStatus==0)//肯定不是解,回溯
        {
            while(ptr>0&&nodeStatus[ptr]==2)
                ptr--;
            for(int i=ptr+1;i<atomNum;i++)
                nodeStatus[i]=0;
        }
        else if(solveStatus==1)
            return true;
        else ptr++;
    }
    return false;
}

model DPLL::get_model() {
    // TODO: your code here, or in the header file
    return this->result;
}

The basic process is I give an example:
suppose five variables A, B, C, D, E
I'll assume that A get real, the other is uncertain, then I check whether input CNF is true
if it is true, that would be great return exit
if you are unsure, then I would assume that B really take, then check
if it is false, then the back / take another value
how backtracking:
Another example:
If ABCDE are 1,1,1,1, null, CNF then found to be false!
Now pointer is D, so take another value from D, this time ABCDE respectively 1,1,1,0, null
or not found, CNF is false, then we should go back, go back where? Recursive search for the father of the current node until you find such a node, it also does not get to the value (that is, it is not "dirty"), or to the root (at this time if the root node is "dirty" to prove all case the search is completed, CNF input is not satisfied).
After backtracking is completed, note that all nodes in the current node or less, their status will be re-marked as "clean", that is, they neither take over true value, nor take too false, because their parent state occurs changes, even if they are equivalent before taking the same boolean value, ABCDE as a whole, this combination of the five Boolean values are also different from the previous.

Other files

common.h:

#include <vector>
#include <unordered_map>
#include <string>
#include <sstream>

#ifndef DPLL_COMMON_H
#define DPLL_COMMON_H

// A literal is a atomic formula (that contains a variable). Like in dimacs,
// + positive numbers denote the corresponding variables;
// - negative numbers denote the negations of the corresponding variables.
// Variables are numbered from 1.
typedef int literal;
#define POSITIVE(x) ((x) > 0)
#define NEGATIVE(x) ((x) < 0)
#define VAR(x) (((x) > 0) ? (x) : (-(x)))

// A clause is a list of literals (meaning their disjunction).
typedef std::vector<literal> clause;

// A formula is a list of clauses (meaning their conjunction).
// We also specify the total number of variables, as some of them may not occur in any clause!
struct formula {
    int num_variable;
    std::vector<clause> clauses;
     formula(int n, const std::vector<clause>& clauses): num_variable(n), clauses(clauses) {}
};

// A satisfying model (interpretation).
// e.g. `model[i] = false` means variable `i` is assigned to false.
typedef std::unordered_map<int, bool> model;

#endif //DPLL_COMMON_H

DPLL.h:

#ifndef DPLL_DPLL_H
#define DPLL_DPLL_H

#include "common.h"

class DPLL {
public:
	DPLL(const formula &phi) : phi(phi) {}
	bool check_sat();
	model get_model();
private:
    formula phi;
    model result;
};
#endif //DPLL_DPLL_H

CMakeLists.txt:

# cmake_minimum_required(VERSION <specify CMake version here>)
cmake_minimum_required(VERSION 3.15)
project(dpll)

set(CMAKE_CXX_STANDARD 17)

set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O2 -Wall")

add_executable(dpll main.cpp DimacsParser.h common.h DPLL.cpp DPLL.h common.h DPLL.h DimacsParser.h)

Test results

Input:

c Generated with `cnfgen`
c (C) 2012-2016 Massimo Lauria <lauria.massimo@gmail.com>
c https://massimolauria.github.io/cnfgen
c
p cnf 12 32
1 -2 0
-1 2 0
1 3 4 0
1 -3 -4 0
-1 3 -4 0
-1 -3 4 0
3 -5 0
-3 5 0
2 6 -7 0
2 -6 7 0
-2 6 7 0
-2 -6 -7 0
4 6 8 -9 0
4 6 -8 9 0
4 -6 8 9 0
4 -6 -8 -9 0
-4 6 8 9 0
-4 6 -8 -9 0
-4 -6 8 -9 0
-4 -6 -8 9 0
5 8 -10 0
5 -8 10 0
-5 8 10 0
-5 -8 -10 0
7 11 0
-7 -11 0
9 11 -12 0
9 -11 12 0
-9 11 12 0
-9 -11 -12 0
10 -12 0
-10 12 0

Output:
Here Insert Picture Description

Published 94 original articles · won praise 69 · views 110 000 +

Guess you like

Origin blog.csdn.net/swy_swy_swy/article/details/105019684