8 #include "inc_solver.h"
9 #include "solver_interface.h"
15 #define NANOSEC 1000000000.0
19 void EqualOneToCNF(vector<int> literals, vector< vector<int> > & cnf){
20 int N = literals.size();
21 cnf.push_back(literals);
24 // this one is a->~b, a->~c, ...
25 for (int j=0; j<N-1; j++){
26 for (int k=j+1; k<N; k++){
27 dnf.push_back(-literals[j]);
28 dnf.push_back(-literals[k]);
35 void verticalSymmetryBreaking(vector<int> col1, vector<int> colN, vector<vector<int> > &cnf){
37 for(int i=0; i<col1.size(); i++){
38 dnf.push_back(-col1[i]);
39 for(int j=i+1; j<colN.size(); j++){
40 dnf.push_back(colN[j]);
49 void Or( vector<int> literals, vector<vector<int> > & cnf){
50 int N= literals.size();
52 for( int i=0; i<N; i++){
53 dnf.push_back(literals[i]);
58 void LessEqualOneToCNF(vector<int> literals, vector< vector<int> > & cnf){
59 int N = literals.size();
61 // this one is a->~b, a->~c, ...
62 for (int j=0; j<N-1; j++){
63 for (int k=j+1; k<N; k++){
64 dnf.push_back(-literals[j]);
65 dnf.push_back(-literals[k]);
72 bool validateSolution(int N, int *table, int size){
73 for(int k=0; k<size; k++){
77 for (int j= row*N; j<(row+1)*N; j++)
78 if(j!=k && table[j] >0){
81 for(int j=0; j<N; j++){
83 if(indx !=k && table[indx]>0){
92 if(k!=indx && table[indx]>0){
100 if(k!=indx && table[indx]>0){
107 int indx = i++*N+j--;
108 if(k!=indx && table[indx]>0){
115 int indx = i++*N+j++;
116 if(k!=indx && table[indx]>0){
126 void printValidationStatus(int N, int *table, int size){
127 if(validateSolution(N, table, size)){
128 printf("***CORRECT****\n");
130 printf("***WRONG******\n");
135 void printSolution(int N, int *table, int size){
136 for(int i=0; i<size; i++){
150 void originalNqueensEncoding(int N){
153 int ** VarName = new int * [N];
154 for (int i=0; i<N; i++){
155 VarName[i] = new int [N];
156 for (int j=0; j<N; j++){
157 VarName[i][j] = kk++;
162 vector< vector<int> > cnf;
166 // generator formula per row
167 // v1 + v2 + v3 + v4 + ... = 1r
168 for (int i=0; i<N; i++){
169 for (int j=0; j<N; j++){
170 vars.push_back(VarName[i][j]);
172 EqualOneToCNF(vars, cnf);
176 // generator formula per col
177 // v1 + v2 + v3 + v4 + ... = 1r
178 for (int i=0; i<N; i++){
179 for (int j=0; j<N; j++){
180 vars.push_back(VarName[j][i]);
182 EqualOneToCNF(vars, cnf);
187 for (int i=0; i<N-1; i++){
188 for (int j=0; j<N-i; j++){
189 vars.push_back(VarName[j][i+j]);
191 LessEqualOneToCNF(vars, cnf);
194 for (int i=1; i<N-1; i++){
195 for (int j=0; j<N-i; j++){
196 vars.push_back(VarName[j+i][j]);
198 LessEqualOneToCNF(vars, cnf);
201 for (int i=0; i<N-1; i++){
202 for (int j=0; j<N-i; j++){
203 vars.push_back(VarName[j][N-1 - (i+j)]);
205 LessEqualOneToCNF(vars, cnf);
208 for (int i=1; i<N-1; i++){
209 for (int j=0; j<N-i; j++){
210 vars.push_back(VarName[j+i][N-1-j]);
212 LessEqualOneToCNF(vars, cnf);
216 //Symmetry breaking constraint
217 int mid = 1+ ((N-1)/2);
218 for (int i=0; i<mid; i++){
219 vars.push_back(VarName[0][i]);
223 for(int i=0; i<N; i++){
224 lastCol.push_back(VarName[N-1][i]);
226 verticalSymmetryBreaking(vars, lastCol, cnf);
228 //That's it ... Let's solve the problem ...
229 IncrementalSolver *solver =allocIncrementalSolver();
231 for (int i=0; i<cnf.size(); i++){
232 addArrayClauseLiteral(solver, cnf[i].size(), cnf[i].data());
234 finishedClauses(solver);
235 long long start = getTimeNano();
236 int result = solve(solver);
237 long long stop = getTimeNano();
238 cout << "SAT Solving time: " << (stop-start)/NANOSEC << endl;
241 printf("Problem is unsat\n");
244 printSolution(N, &solver->solution[1], solver->solutionsize);
245 printValidationStatus(N, &solver->solution[1], solver->solutionsize);
249 printf("Unknown results from SAT Solver...\n");
252 deleteIncrementalSolver(solver);
256 void csolverNQueensSub(int N, bool serialize=false){
257 CSolver *solver = new CSolver();
259 for(int i=0; i<N; i++){
262 uint64_t range[2*N-1];
263 for(int i=0; i<2*N-1; i++){
266 Set *domainSet = solver->createSet(1, domain, N);
267 Set *rangeSet = solver->createSet(1, range, 2*N-1);
268 vector<Element *> Xs;
269 vector<Element *> Ys;
270 for(int i=0; i<N; i++){
271 Xs.push_back(solver->getElementVar(domainSet));
272 Ys.push_back(solver->getElementVar(domainSet));
274 Set *d1[] = {domainSet, domainSet};
275 Function *sub = solver->createFunctionOperator(SATC_SUB, rangeSet, SATC_NOOVERFLOW);
276 //X shouldn't be equal
277 for(int i=0; i<N-1; i++){
278 for(int j=i+1; j<N; j++ ){
279 Element *e1x = Xs[i];
280 Element *e2x = Xs[j];
281 Predicate *eq = solver->createPredicateOperator(SATC_EQUALS);
282 Element *inputs2 [] = {e1x, e2x};
283 BooleanEdge equals = solver->applyPredicate(eq, inputs2, 2);
284 solver->addConstraint(solver->applyLogicalOperation(SATC_NOT, equals));
287 //Y shouldn't be equal
288 for(int i=0; i<N-1; i++){
289 for(int j=i+1; j<N; j++ ){
290 Element *e1y = Ys[i];
291 Element *e2y = Ys[j];
292 Predicate *eq = solver->createPredicateOperator(SATC_EQUALS);
293 Element *inputs2 [] = {e1y, e2y};
294 BooleanEdge equals = solver->applyPredicate(eq, inputs2, 2);
295 solver->addConstraint(solver->applyLogicalOperation(SATC_NOT, equals));
298 //vertical difference and horizontal difference shouldn't be equal shouldn't be equal
299 BooleanEdge overflow = solver->getBooleanVar(2);
300 Set *d2[] = {rangeSet, rangeSet};
301 for(int i=0; i<N-1; i++){
302 for(int j=i+1; j<N; j++ ){
303 Element *e1y = Ys[i];
304 Element *e2y = Ys[j];
305 Element *e1x = Xs[i];
306 Element *e2x = Xs[j];
307 Function *f1 = solver->createFunctionOperator(SATC_SUB, rangeSet, SATC_IGNORE);
308 Element *in1[] = {e1x, e2x};
309 Element *subx = solver->applyFunction(f1, in1, 2, overflow);
310 Element *in2[] = {e1y, e2y};
311 Element *suby = solver->applyFunction(f1, in2, 2, overflow);
312 Predicate *eq = solver->createPredicateOperator(SATC_EQUALS);
313 Element *inputs2 [] = {subx, suby};
314 BooleanEdge equals = solver->applyPredicate(eq, inputs2, 2);
315 solver->addConstraint(solver->applyLogicalOperation(SATC_NOT, equals));
321 if (solver->solve() != 1){
322 printf("Problem is Unsolvable ...\n");
325 memset( table, 0, N*N*sizeof(int) );
326 for(int i=0; i<N; i++){
327 uint x = solver->getElementValue(Xs[i]);
328 uint y = solver->getElementValue(Ys[i]);
329 // printf("X=%d, Y=%d\n", x, y);
333 printSolution(N, table, N*N);
334 printValidationStatus(N, table, N*N);
339 void atmostOneConstraint(CSolver *solver, vector<BooleanEdge> &constraints){
340 int size = constraints.size();
344 solver->addConstraint(constraints[0]);
346 // solver->addConstraint(solver->applyLogicalOperation(SATC_OR, &constraints[0], size))
347 for(int i=0; i<size-1; i++){
348 for(int j=i+1; j<size; j++){
349 BooleanEdge const1 = solver->applyLogicalOperation(SATC_NOT, constraints[i]);
350 BooleanEdge const2 = solver->applyLogicalOperation(SATC_NOT, constraints[j]);
351 BooleanEdge array[] = {const1, const2};
352 solver->addConstraint( solver->applyLogicalOperation(SATC_OR, (BooleanEdge *)array, 2));
359 void mustHaveValueConstraint(CSolver* solver, vector<Element*> &elems){
360 for(int i=0; i<elems.size(); i++){
361 solver->mustHaveValue(elems[i]);
365 void differentInEachRow(CSolver* solver, int N, vector<Element*> &elems){
366 Predicate *eq = solver->createPredicateOperator(SATC_EQUALS);
367 for(int i=0; i<N-1; i++){
368 for(int j=i+1; j<N; j++ ){
369 Element *e1x = elems[i];
370 Element *e2x = elems[j];
371 Element *inputs2 [] = {e1x, e2x};
372 BooleanEdge equals = solver->applyPredicate(eq, inputs2, 2);
373 solver->addConstraint(solver->applyLogicalOperation(SATC_NOT, equals));
380 void oneQueenInEachRow(CSolver* solver, vector<Element*> &elems){
381 Predicate *eq = solver->createPredicateOperator(SATC_EQUALS);
382 int N = elems.size();
383 for(int i=0; i<N; i++){
384 vector<BooleanEdge> rowConstr;
385 for(int j=0; j<N; j++){
386 Element* e1 = elems[j];
387 Element* e2 = solver->getElementConst(1, (uint64_t) i);
388 Element* in[] = {e1, e2};
389 BooleanEdge equals = solver->applyPredicate(eq, in, 2);
390 rowConstr.push_back(equals);
392 if(rowConstr.size()>0){
393 solver->addConstraint(solver->applyLogicalOperation(SATC_OR, &rowConstr[0], rowConstr.size()) );
398 void generateRowConstraints(CSolver* solver, int N, vector<Element*> &elems){
399 oneQueenInEachRow(solver, elems);
400 differentInEachRow(solver, N, elems);
403 void diagonallyDifferentConstraint(CSolver *solver, int N, vector<Element*> &elems){
404 Predicate *eq = solver->createPredicateOperator(SATC_EQUALS);
405 for(int i=N-1; i>0; i--){
406 // cout << "i:" << i << "\t";
407 vector<BooleanEdge> diagonals;
408 for(int j=i; j>=0; j--){
410 Element* e1 = elems[index];
411 // cout << "e" << e1 <<"=" << j << ", ";
412 Element* e2 = solver->getElementConst(1, (uint64_t) j);
413 Element* in[] = {e1, e2};
414 BooleanEdge equals = solver->applyPredicate(eq, in, 2);
415 diagonals.push_back(equals);
419 atmostOneConstraint(solver, diagonals);
421 for(int i=1; i< N-1; i++){
422 // cout << "i:" << i << "\t";
423 vector<BooleanEdge> diagonals;
424 for(int j=i; j<N; j++){
425 int index =N-1- (j-i);
426 Element* e1 = elems[index];
427 // cout << "e" << e1 <<"=" << j << ", ";
428 Element* e2 = solver->getElementConst(1, (uint64_t) j);
429 Element* in[] = {e1, e2};
430 BooleanEdge equals = solver->applyPredicate(eq, in, 2);
431 diagonals.push_back(equals);
435 atmostOneConstraint(solver, diagonals);
441 void diagonallyDifferentConstraintBothDir(CSolver *solver, int N, vector<Element*> &elems){
442 diagonallyDifferentConstraint(solver, N, elems);
443 reverse(elems.begin(), elems.end());
444 // cout << "Other Diagonal:" << endl;
445 diagonallyDifferentConstraint(solver, N, elems);
448 void symmetryBreakingConstraint(CSolver *solver, int N, vector<Element*>& elems){
449 Predicate *lt = solver->createPredicateOperator(SATC_LT);
451 Element *e1x = elems[0];
452 Element *e2x = solver->getElementConst(1, mid);
453 Element *inputs [] = {e1x, e2x};
454 solver->addConstraint(solver->applyPredicate(lt, inputs, 2));
457 Element *inputs2 [] = {e1x, e2x};
458 BooleanEdge equals = solver->applyPredicate(lt, inputs2, 2);
459 solver->addConstraint(equals);
463 void csolverNQueens(int N, bool serialize=false){
468 CSolver *solver = new CSolver();
470 for(int i=0; i<N; i++){
473 Set *domainSet = solver->createSet(1, domain, N);
474 vector<Element *> elems;
475 for(int i=0; i<N; i++){
476 elems.push_back(solver->getElementVar(domainSet));
478 mustHaveValueConstraint(solver, elems);
479 generateRowConstraints(solver, N, elems);
480 diagonallyDifferentConstraintBothDir(solver, N, elems);
481 symmetryBreakingConstraint(solver, N, elems);
482 // solver->printConstraints();
486 if (solver->solve() != 1){
487 printf("Problem is Unsolvable ...\n");
490 memset( table, 0, N*N*sizeof(int) );
491 for(int i=0; i<N; i++){
492 uint x = solver->getElementValue(elems[i]);
493 // printf("X=%d, Y=%d\n", x, i);
497 printSolution(N, table, N*N);
498 printValidationStatus(N, table, N*N);
505 int main(int argc, char * argv[]){
507 printf("Two arguments are needed\n./nqueen <size> [--csolver]\n");
510 int N = atoi(argv[1]);
512 printf("Running the original encoding ...\n");
513 originalNqueensEncoding(N);
514 }else if( strcmp( argv[2], "--csolver") == 0){
515 printf("Running the CSolver encoding ...\n");
517 }else if (strcmp( argv[2], "--dump") == 0){
518 printf("Running the CSolver encoding ...\n");
519 csolverNQueens(N, true);
521 printf("Unknown argument %s", argv[2]);