3-CNF(slightly improved?)
A. Second Edition#ifndef SET_H
#define SET_H
#include <iostream>
#include <bitset>
using namespace std;
const int MaxAttrNumber=100;
class Set
{
//this is a long-pain for me, I have no other way to
//let compiler recognize this "friend" function outside declaration
friend ostream& operator<<(ostream& out, const Set& dummy)
{
for (int i=0; i<dummy.size; i++)
{
if (dummy.theSet.test(i))
{
out<<'1';
}
else
{
out<<'0';
}
}
return out;
}
private:
bitset<MaxAttrNumber> theSet;
int size;
int current;
public:
void setSize(const Set& dummy);
int getSize(){ return size;}
int next(int current) const;
int first() const;
int count() const;
Set intersection(const Set& dummy) const;
Set unionSet(const Set& dummy) const;
Set difference(const Set& dummy) const;
bool isEmpty();
//I am crazy about operator overloading!!!:)
Set operator-(const Set& dummy) const;
Set operator+(const Set& dummy) const;
Set operator*(const Set& dummy) const;
void operator=(const Set& dummy);
bool operator==(const Set& dummy) const;
bool operator!=(const Set& dummy) const;
bool operator>(const Set& dummy) const;
bool operator>=(const Set& dummy) const;
bool operator<(const Set& dummy) const;
bool operator<=(const Set& dummy) const;
void set(int pos);
void forEachSubSet(Set& dummy) const;//must be called before "eachSub()"
bool eachSub(Set& dummy) const;
bool eachSub(Set& dummy, const Set& excluding) const;
void set();
void reset(int pos);
void reset();
bool test(int pos) const;
bool isIn(const Set& dummy) const;
void setSize(int theSize) {size=theSize;}
Set(int theSize=10);
void print();
};
#endif
file name: set.cpp
#include "Set.h"
void Set::print()
{
char str[MaxAttrNumber+1];
strcpy(str, (theSet.to_string()).c_str()+MaxAttrNumber-size);
printf("%s", str);
}
bool Set::isEmpty()
{
for (int i=0; i<size; i++)
{
if (theSet.test(i))
{
return false;
}
}
return true;
}
bool Set::isIn(const Set& dummy) const
{
for (int i=0; i<size; i++)
{
if (theSet.test(i))
{
if (!dummy.test(i))//here I use Set.test() instead of set.test()
{
return false;
}
}
}
return true;
}
bool Set::test(int pos) const
{
return (pos<size&&theSet.test(pos));
}
//current=-1;//initialize to -1 to prepare for being called
int Set::next(int current) const
{
for (int i=current+1; i<size; i++)//include situation current>=size
{
if (theSet.test(i))
{
return i;
}
}
return -1;//not found
}
bool Set::operator !=(const Set& dummy)const
{
return !(this->operator ==(dummy));
}
bool Set::operator <(const Set& dummy)const
{
return (this->isIn(dummy)&&this->operator !=(dummy));
}
bool Set::operator <=(const Set& dummy)const
{
return isIn(dummy);
}
bool Set::operator >(const Set& dummy)const
{
return !(this->operator <=(dummy));
}
bool Set::operator >=(const Set& dummy)const
{
return !(this->operator <(dummy));
}
bool Set::operator ==(const Set& dummy)const
{
for (int i=0; i<(size>dummy.size?size:dummy.size); i++)
{
if (test(i)^dummy.test(i))
{
return false;
}
}
return true;
}
void Set::setSize(const Set& dummy)
{
size=dummy.size;
}
void Set::operator =(const Set& dummy)
{
size=dummy.size;
for (int i=0; i<size; i++)
{
if (dummy.test(i))
{
theSet.set(i);
}
else
{
theSet.reset(i);
}
}
}
Set::Set(int theSize)
{
size=theSize;
reset();
}
void Set::reset()
{
for (int i=0; i<size; i++)
{
theSet.reset(i);
}
}
void Set::reset(int pos)
{
if (pos<size)
{
theSet.reset(pos);
}
}
void Set::set()
{
theSet.set();
}
void Set::set(int pos)
{
theSet.set(pos);
}
void Set::forEachSubSet(Set& dummy) const
{
dummy.size=size;
dummy.reset();//emptyset
}
bool Set::eachSub(Set& dummy, const Set& excluding) const
{
int index=first();//starting from very first
while (index!=-1)//not exceeding boundery
{
if (!excluding.test(index))//exluding this set
{
if (dummy.test(index))
{
dummy.reset(index);
}
else
{
dummy.set(index);
//return true;
if (dummy<*this)//only return the proper subset
{
return true;
}
}
}
index=next(index);
}
return false;
}
bool Set::eachSub(Set& dummy) const
{
int index=first();//starting from very first
while (index!=-1)//not exceeding boundery
{
if (dummy.test(index))
{
dummy.reset(index);
index=next(index);
}
else
{
dummy.set(index);
//return true;
if (dummy<*this)
{
return true;
}
}
}
return false;
}
int Set::first()const
{
return next(-1);
}
int Set::count()const
{
return theSet.count();
}
Set Set::unionSet(const Set& dummy) const
{
Set result;
result.size=size>dummy.size?size:dummy.size;
for (int i=0; i<result.size; i++)
{
if (test(i)||dummy.test(i))
{
result.set(i);
}
}
return result;//this is a temparory object;
}
Set Set::difference(const Set& dummy) const
{
Set result;
result.size=size>dummy.size?size:dummy.size;
for (int i=0; i<result.size; i++)
{
if (test(i)&&!dummy.test(i))
{
result.set(i);
}
}
return result;
}
Set Set::operator +(const Set& dummy) const
{
return unionSet(dummy);
}
Set Set::operator -(const Set& dummy) const
{
return difference(dummy);
}
Set Set::intersection(const Set& dummy) const
{
Set result;
result.size=size<dummy.size?size:dummy.size;
for (int i=0; i<result.size; i++)
{
if (test(i)&&dummy.test(i))
{
result.set(i);
}
}
return result;
}
Set Set::operator *(const Set& dummy) const
{
return intersection(dummy);
}
file name: 3cnf.h
#include "set.h"
const int MaxSymbolCount=50;
const int MaxExprCount=MaxSymbolCount*8;
class CNF
{
private:
char* symbols[MaxSymbolCount];
int expr[MaxExprCount][3];//expression
Set cnf_pos[MaxSymbolCount];//positive set of simbol
Set cnf_neg[MaxSymbolCount];//neg all starts from 1
int symbolCount;//
int exprCount;
int chooseSymbol(Set& symbolSet, Set& exprSet);
int chooseMaxCover(Set& symbolSet, Set& exprSet);
int chooseComplement(Set& symbolSet, Set& exprSet);
bool solve(Set& symbolSet, Set& exprSet, int resultSet[]=NULL, int* count=NULL);
bool converge(Set& symbolSet, Set& environSet, Set& workingSet);
public:
void randomGenerate(int symCount, int expCount);
void printSymbol(int index);
void displayExpr();
bool satisfy(int resultSet[], int* count, int option);
};
file name: 3cnf.cpp
#include "3CNF.H"
#include <stdlib.h>
#include <string.h>
int optionIndex;
void CNF::randomGenerate(int symCount, int expCount)
{
symbolCount=symCount;
exprCount=expCount;
for (int i=0; i<symbolCount; i++)
{
symbols[i]=new char[4];
sprintf(symbols[i], "A%d", i);
cnf_pos[i].setSize(exprCount);
cnf_neg[i].setSize(exprCount);
}
for (i=0; i<exprCount; i++)
{
for (int j=0; j<3; j++)
{
//must check if there is repeat, otherwise never satisfy
//i.e. ~A&&A ==false
while (true)
{
expr[i][j]=rand()%symbolCount;
if (j==0)
{
break;
}
if (j==1)
{
if (expr[i][j]!=expr[i][j-1]&&expr[i][j]!=-expr[i][j-1])
{
break;
}
}
if (j==2)
{
if (expr[i][j]!=expr[i][j-1]&&expr[i][j]!=-expr[i][j-1]
&&expr[i][j]!=expr[i][j-2]&&expr[i][j]!=-expr[i][j-2])
{
break;
}
}
}
if (rand()%2==0)
{
cnf_pos[expr[i][j]].set(i);
}
else
{
cnf_neg[expr[i][j]].set(i);
expr[i][j]*=-1;
}
}
}
}
void CNF::displayExpr()
{
printf("print the 3CNF format:\n");
for (int i=0; i<exprCount; i++)
{
if (i%5==0)
{
printf("\n");
}
printf("(");
for (int j=0; j<3; j++)
{
if (expr[i][j]<0)
{
printf("~%s", symbols[-expr[i][j]]);
}
else
{
printf("%s", symbols[expr[i][j]]);
}
if (j!=2)
{
printf("||");
}
}
printf(")");
if (i!=exprCount-1)
{
printf("&&");
}
}
printf("\n");
}
bool CNF::satisfy(int resultSet[], int* count, int option)
{
Set symbolSet, exprSet;
symbolSet.setSize(symbolCount);
exprSet.setSize(exprCount);
symbolSet.set();
exprSet.set();
//symbolSet.print();
optionIndex=option;
return solve(symbolSet, exprSet, resultSet, count);
}
bool CNF::solve(Set& symbolSet, Set& exprSet, int resultSet[], int* count)
{
int index;
//printf("no.%d call of solve: \n", count);
//printf("symbolSet=");
//symbolSet.print();
//printf("exprSet=");
//exprSet.print();
//printf("\n");
if (exprSet.isEmpty())
{
return true;
}
if (symbolSet.isEmpty())
{
return false;
}
//index must return absolue value bigger than 1
//so that allow -1,1
index=chooseSymbol(symbolSet, exprSet);
//printf("\nand choose index of %d\n", index);
//0 means the symbol set cannot cover expression set
if (index==0)
{
return false;
}
if (resultSet!=NULL&&count!=NULL)
{
resultSet[*count]=index;
(*count)++;
}
if (index<0)
{
index*=-1;
index-=1;
exprSet=exprSet-cnf_neg[index];
}
else
{
index-=1;
exprSet=exprSet-cnf_pos[index];
}
//printf("and expr is\n");
//exprSet.print();
//in any case, we reduce the symbol set
symbolSet.reset(index);
return solve(symbolSet, exprSet, resultSet, count);
}
bool CNF::converge(Set& symbolSet, Set& environSet, Set& workingSet)
{
int index;
if (workingSet.isEmpty())
{
return true;
}
//here it implied workingset is NOT empty
if (symbolSet.isEmpty())
{
return false;
}
//a simple
index=chooseMaxCover(symbolSet, workingSet);
if (index==0)
{
return false;
}
if (index<0)
{
index=-index-1;
workingSet=workingSet-cnf_neg[index];//reduced working set
//* means intersection, + is union
workingSet=workingSet+(environSet*cnf_pos[index]);
}
else
{
index-=1;
workingSet=workingSet-cnf_pos[index];
workingSet=workingSet+(environSet*cnf_neg[index]);
}
symbolSet.reset(index);
return converge(symbolSet, environSet, workingSet);
}
int CNF::chooseMaxCover(Set& symbolSet, Set& exprSet)
{
int count=exprCount, result, index=0;
Set temp;
//printf("symbol set is\n");
//symbolSet.print();
for (int i=0; i<symbolCount; i++)
{
if (symbolSet.test(i))
{
result=(exprSet-cnf_pos[i]).count();
if (result<count)
{
count=result;
index=i+1;
}
result=(exprSet-cnf_neg[i]).count();
if (result<count)
{
count=result;
index=(i+1)*(-1);
}
}
}
return index;
}
int CNF::chooseComplement(Set& symbolSet, Set& exprSet)
{
int index;
Set workingSet, curSymbolSet;
index=symbolSet.first();
while (index!=-1)
{
//try positive first
workingSet=cnf_neg[index] - exprSet;
curSymbolSet=symbolSet;
curSymbolSet.reset(index);
if (converge(curSymbolSet, exprSet, workingSet))
{
return index+1;
}
//try negative secondly
workingSet=cnf_pos[index]-exprSet;
curSymbolSet=symbolSet;
curSymbolSet.reset(index);
if (converge(curSymbolSet, exprSet, workingSet))
{
return (index+1)*(-1);
}
index=symbolSet.next(index);
}
if (index==-1)
{
return 0;//cannot find
}
}
//if no max symbol can be found, index is 0
int CNF::chooseSymbol(Set& symbolSet, Set& exprSet)
{
if (optionIndex==0)
{
return chooseMaxCover(symbolSet, exprSet);
}
else
{
return chooseComplement(symbolSet, exprSet);
}
}
void CNF::printSymbol(int index)
{
printf("%s", symbols[index]);
}
file name: main.cpp
#include "3cnf.h"
#include <time.h>
int main()
{
CNF cnf;
int count=0;
int resultSet[MaxSymbolCount]={0};
srand(time(0));
cnf.randomGenerate(10, 20);
cnf.displayExpr();
if (cnf.satisfy(resultSet, &count, 0))
{
printf("\nchooseMaxCover works and it is satisfiable\n");
for (int i=0; i<count; i++)
{
if (resultSet[i]<0)
{
printf("~");
cnf.printSymbol(resultSet[i]*(-1)-1);
}
else
{
cnf.printSymbol(resultSet[i]-1);
}
printf(",");
}
}
else
{
printf("\nchooseMaxCover unsatisfiable\n");
}
printf("\n");
count=0;
if (cnf.satisfy(resultSet, &count, 0))
{
printf("\nchooseComplement works and it is satisfiable\n");
for (int i=0; i<count; i++)
{
if (resultSet[i]<0)
{
printf("~");
cnf.printSymbol(resultSet[i]*(-1)-1);
}
else
{
cnf.printSymbol(resultSet[i]-1);
}
printf(",");
}
}
else
{
printf("\nchooseComplement unsatisfiable\n");
}
printf("\n");
return 0;
}
How to run? The result is not very interesting. First I am not sure if the "unsatisfied" message really means
there is no solution. This is completely beyond my knowledge.
print the 3CNF format:
(A1||~A14||~A10)&&(~A20||~A15||A10)&&(A6||~A26||~A8)&&(~A12||~A6||~A19)&&(A0||~A19||~A22)&&
(~A28||~A12||A4)&&(~A12||A17||A15)&&(A20||A17||A14)&&(A20||~A7||~A3)&&(A6||A12||~A11)&&
(A27||~A13||~A23)&&(~A26||~A20||A24)&&(~A20||~A22||A16)&&(A1||A12||A15)&&(A28||A23||~A6)&&
(~A20||A0||~A7)&&(~A21||~A2||~A10)&&(A14||~A4||~A27)&&(A14||A24||A0)&&(A3||A19||A0)&&
(~A16||A19||~A11)&&(A27||~A5||A4)&&(A23||A29||~A15)&&(~A12||~A7||A26)&&(~A21||A29||~A9)&&
(~A15||~A26||~A16)&&(~A18||A12||A19)&&(A10||~A29||~A28)&&(~A28||A17||A14)&&(~A23||~A3||~A15)&&
(~A8||A7||A0)&&(A17||~A20||~A15)&&(~A14||A2||~A16)&&(A4||A5||A20)&&(~A23||~A9||~A5)&&
(A9||A11||~A2)&&(A18||~A23||~A22)&&(A27||A11||~A15)&&(~A5||~A9||A1)&&(~A3||A20||~A29)&&
(A27||A6||~A9)&&(A10||A12||A17)&&(~A16||~A2||~A25)&&(A3||A4||A12)&&(~A1||~A6||~A8)&&
(~A5||~A11||A3)&&(~A22||A0||A25)&&(A25||~A29||~A10)&&(A12||A5||A29)&&(~A28||A8||~A20)
chooseMaxCover works and it is satisfiable
A12,~A15,~A0,~A5,A20,~A28,~A2,~A6,~A22,~A8,~A9,~A10,~A16,~A4,~A7,~A13,A17,A24,
chooseComplement works and it is satisfiable
A12,~A15,~A0,~A5,A20,~A28,~A2,~A6,~A22,~A8,~A9,~A10,~A16,~A4,~A7,~A13,A17,A24,
Press any key to continue