this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Vincent Barichard <Vincent.Barichard@univ-angers.fr> 5 * 6 * Copyright: 7 * Vincent Barichard, 2013 8 * 9 * Last modified: 10 * $Date$ by $Author$ 11 * $Revision$ 12 * 13 * This file is part of Quacode: 14 * http://quacode.barichard.com 15 * 16 * This file is based on gecode/examples/sat.cpp 17 * and is under the same license as given below: 18 * 19 * Main authors: 20 * Raphael Reischuk <reischuk@cs.uni-sb.de> 21 * Guido Tack <tack@gecode.org> 22 * 23 * Copyright: 24 * Raphael Reischuk, 2008 25 * Guido Tack, 2008 26 * 27 * This file is part of Gecode, the generic constraint 28 * development environment: 29 * http://www.gecode.org 30 * 31 * Permission is hereby granted, free of charge, to any person obtaining 32 * a copy of this software and associated documentation files (the 33 * "Software"), to deal in the Software without restriction, including 34 * without limitation the rights to use, copy, modify, merge, publish, 35 * distribute, sublicense, and/or sell copies of the Software, and to 36 * permit persons to whom the Software is furnished to do so, subject to 37 * the following conditions: 38 * 39 * The above copyright notice and this permission notice shall be 40 * included in all copies or substantial portions of the Software. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 43 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 44 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 45 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 46 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 47 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 48 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 49 * 50 */ 51 52#include <fstream> 53#include <string> 54#include <vector> 55 56#include <quacode/qspaceinfo.hh> 57#include <gecode/driver.hh> 58 59 60using namespace Gecode; 61 62/** \brief Options for %SAT problems 63 * 64 */ 65class QDimacsOptions : public Options { 66public: 67 /// Print strategy or not 68 Gecode::Driver::BoolOption _printStrategy; 69 /// Parameter to decide between optimized quantified constraints or usual ones 70 Driver::BoolOption _qConstraint; 71 /// Name of the QDIMACS file to parse 72 std::string filename; 73 /// Initialize options with file name \a s 74 QDimacsOptions(const char* s, bool _qConstraint0) 75 : Options(s), 76 _printStrategy("-printStrategy","Print strategy",false), 77 _qConstraint("-quantifiedConstraints", 78 "whether to use quantified optimized constraints", 79 _qConstraint0) 80 { 81 add(_printStrategy); 82 add(_qConstraint); 83 } 84 /// Parse options from arguments \a argv (number is \a argc) 85 void parse(int& argc, char* argv[]) { 86 // Parse regular options 87 Options::parse(argc,argv); 88 // Filename, should be at position 1 89 if (argc == 1) { 90 help(); 91 exit(1); 92 } 93 filename = argv[1]; 94 argc--; 95 } 96 /// Return true if the strategy must be printed 97 bool printStrategy(void) const { 98 return _printStrategy.value(); 99 } 100 /// Print help message 101 virtual void help(void) { 102 Options::help(); 103 std::cerr << "\t(string) " << std::endl 104 << "\t\tqdimacs file to parse (.cnf)" << std::endl; 105 } 106}; 107 108/** 109 * \brief %Example: CNF QSAT solver 110 * 111 * QSAT finds models of Quantified Boolean variables such 112 * that a set of clauses is satisfied or shows that 113 * no such model exists. 114 * 115 * This example parses a Q-Dimacs CNF file in which 116 * the constraints are specified. For each line of 117 * the file a clause propagator is posted. 118 * 119 * Format of Q-Dimacs CNF files: 120 * 121 * A dimacs file starts with comments (each line 122 * starts with c). The number of variables and the 123 * number of clauses is defined by the line 124 * 125 * p cnf \<variables\> \<clauses\> 126 * 127 * Then come the quantifiers of the binder. Each lines 128 * starts with a 'a' for universal quantifier or a 'e' 129 * for existential quantifier. The following number until 130 * zero correspond to the id of the variables that take this 131 * quantifier. All variable of the matrix which does not appear 132 * here are considered as the outermost existential variables 133 * of the problem. 134 * 135 * a \<variable list\> 136 * e \<variable list\> 137 * 138 * Each of the subsequent lines specifies a clause. 139 * A positive literal is denoted by a positive 140 * integer, a negative literal is denoted by the 141 * corresponding negative integer. Each line is 142 * terminated by 0. 143 * 144 * c sample CNF file 145 * p cnf 3 2 146 * 3 -1 0 147 * 1 2 -1 0 148 * 149 * \ingroup Example 150 */ 151class QDimacs : public Script, public QSpaceInfo { 152private: 153 /// The Boolean variables 154 typedef std::vector< BoolVarArray > QBoolVarArray; 155 QBoolVarArray qx; 156public: 157 /// The actual problem 158 QDimacs(const QDimacsOptions& opt) : Script(opt), QSpaceInfo() { 159 if (!opt.printStrategy()) strategyMethod(0); // disable build and print strategy 160 parseQDIMACS(opt.filename.c_str(),opt._qConstraint.value()); 161 } 162 163 /// Constructor for cloning 164 QDimacs(bool share, QDimacs& s) : Script(share,s), QSpaceInfo(*this,share,s), qx(s.qx) { 165 for (unsigned int i=0; i<qx.size(); i++) 166 qx[i].update(*this,share,s.qx[i]); 167 } 168 169 /// Perform copying during cloning 170 virtual Space* 171 copy(bool share) { 172 return new QDimacs(share,*this); 173 } 174 175 176 /// Post constraints according to QDIMACS file \a f 177 void parseQDIMACS(const char* f, bool usedQuantifiedConstraint) { 178 BoolVarArray x; 179 std::vector<int> x_rk; 180 std::vector<Gecode::TQuantifier> x_quant; 181 int variables = 0; 182 int clauses = 0; 183 std::ifstream dimacs(f); 184 if (!dimacs) { 185 std::cerr << "error: file '" << f << "' not found" << std::endl; 186 exit(1); 187 } 188 std::cout << "Solving problem from QDIMACS file '" << f << "'" 189 << std::endl; 190 std::string line; 191 int c = 0; 192 while (dimacs.good()) { 193 std::getline(dimacs,line); 194 // Comments (ignore them) 195 if (line[0] == 'c' || line == "") { 196 } 197 // Line has format "p cnf <variables> <clauses>" 198 else if (variables == 0 && clauses == 0 && 199 line[0] == 'p' && line[1] == ' ' && 200 line[2] == 'c' && line[3] == 'n' && 201 line[4] == 'f' && line[5] == ' ') { 202 int i = 6; 203 while (line[i] >= '0' && line[i] <= '9') { 204 variables = 10*variables + line[i] - '0'; 205 i++; 206 } 207 i++; 208 while (line[i] >= '0' && line[i] <= '9') { 209 clauses = 10*clauses + line[i] - '0'; 210 i++; 211 } 212 x = BoolVarArray(*this, variables, 0, 1); 213 x_rk.resize(variables,Int::Limits::max); 214 x_quant.resize(variables,EXISTS); 215 std::cout << "(" << variables << " variables, " 216 << clauses << " clauses)" << std::endl << std::endl; 217 } 218 // Line has format "a <variables>" or "e <variables>" or "r <variables>" 219 else if ( (line[0] == 'a' && line[1] == ' ') || 220 (line[0] == 'e' && line[1] == ' ') || 221 (line[0] == 'r' && line[1] == ' ') ) { 222 if (line[0] == 'r') { 223 std::cerr << "format error in dimacs file, \"r\" quantifier not recognized for now" << std::endl; 224 std::cerr << "context: '" << line << "'" << std::endl; 225 std::exit(EXIT_FAILURE); 226 } 227 BoolVarArgs tmp; 228 Gecode::TQuantifier quant = (line[0]=='e')?EXISTS:FORALL; 229 std::vector<int> values; 230 int i = 2; 231 while (line[i] != 0) { 232 if (line[i] == ' ') { 233 i++; 234 continue; 235 } 236 int value = 0; 237 while (line[i] >= '0' && line[i] <= '9') { 238 value = 10 * value + line[i] - '0'; 239 i++; 240 } 241 if (value != 0) { 242 values.push_back(value); 243 tmp << x[value-1]; 244 x_rk[value-1] = qx.size(); 245 x_quant[value-1] = quant; 246 if (quant == FORALL) setForAll(*this,x[value-1]); 247 i++; 248 } 249 } 250 251 std::cout << "( " << values.size() << " "; 252 std::cout << ((quant==EXISTS)?"existential":"universal"); 253 std::cout << "variables )"<< std::endl; 254 qx.push_back( BoolVarArray(*this,tmp) ); 255 } 256 // Parse regular clause 257 else if (variables > 0 && 258 ((line[0] >= '0' && line[0] <= '9') || line[0] == '-' || line[0] == ' ')) { 259 c++; 260 std::vector<int> pos; 261 std::vector<int> neg; 262 int i = 0; 263 while (line[i] != 0) { 264 if (line[i] == ' ') { 265 i++; 266 continue; 267 } 268 bool positive = true; 269 if (line[i] == '-') { 270 positive = false; 271 i++; 272 } 273 int value = 0; 274 while (line[i] >= '0' && line[i] <= '9') { 275 value = 10 * value + line[i] - '0'; 276 i++; 277 } 278 if (value != 0) { 279 if (positive) 280 pos.push_back(value-1); 281 else 282 neg.push_back(value-1); 283 i++; 284 } 285 } 286 287 // Create positive BoolVarArgs 288 BoolVarArgs positives(pos.size()); 289 QBoolVarArgs qpositives(pos.size()); 290 for (int i=pos.size(); i--;) { 291 positives[i] = x[pos[i]]; 292 qpositives[i] = QBoolVar(x_quant[pos[i]],x[pos[i]],x_rk[pos[i]]); 293 } 294 295 BoolVarArgs negatives(neg.size()); 296 QBoolVarArgs qnegatives(neg.size()); 297 for (int i=neg.size(); i--;) { 298 negatives[i] = x[neg[i]]; 299 qnegatives[i] = QBoolVar(x_quant[neg[i]],x[neg[i]],x_rk[neg[i]]); 300 } 301 302 // Post propagators 303 if (usedQuantifiedConstraint) 304 qclause(*this, BOT_OR, qpositives, qnegatives, 1); 305 else 306 clause(*this, BOT_OR, positives, negatives, 1); 307 } 308 else { 309 std::cerr << "format error in dimacs file" << std::endl; 310 std::cerr << "context: '" << line << "'" << std::endl; 311 std::exit(EXIT_FAILURE); 312 } 313 } 314 dimacs.close(); 315 if (clauses != c) { 316 std::cerr << "error: number of specified clauses seems to be wrong." 317 << std::endl; 318 std::exit(EXIT_FAILURE); 319 } 320 321 for (unsigned int i=0; i<qx.size(); i++) 322 branch(*this, qx[i], INT_VAR_NONE(), INT_VAL_MIN()); 323 324 // FIN DESCRIPTION PB 325 } 326}; 327 328 329/** \brief Main-function 330 */ 331int main(int argc, char* argv[]) { 332 333 QDimacsOptions opt("QDIMACS",true); 334 opt.parse(argc,argv); 335 336 // Check whether all arguments are successfully parsed 337 if (argc > 1) { 338 std::cerr << "Could not parse all arguments." << std::endl; 339 opt.help(); 340 std::exit(EXIT_FAILURE); 341 } 342 343 // Run SAT solver 344 Script::run<QDimacs,DFS,QDimacsOptions>(opt); 345 return 0; 346} 347 348// STATISTICS: example-any