00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <clasp/parser.h>
00021 #include <clasp/program_builder.h>
00022 #include <clasp/logic_program.h>
00023 #include <clasp/minimize_constraint.h>
00024 #include <clasp/shared_context.h>
00025 #include <clasp/solver.h>
00026 #include <clasp/clause.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <limits.h>
00030 #include <stdarg.h>
00031 #ifdef _WIN32
00032 #pragma warning (disable : 4996)
00033 #endif
00034 const char* clasp_format(char* buf, unsigned size, const char* fmt, ...) {
00035 if (size) { buf[0] = 0; --size; }
00036 va_list args;
00037 va_start(args, fmt);
00038 vsnprintf(buf, size, fmt, args);
00039 va_end(args);
00040 return buf;
00041 }
00042 const char* clasp_format_error(const char* fmt, ...) {
00043 static char buf[1024];
00044 buf[0] = 0;
00045 va_list args;
00046 va_start(args, fmt);
00047 vsnprintf(buf, 1023, fmt, args);
00048 va_end(args);
00049 return buf;
00050 }
00051 namespace Clasp {
00052 ParseError::ParseError(unsigned a_line, const char* a_msg) : ClaspError(clasp_format_error("Parse Error: Line %u, %s", a_line, a_msg)), line(a_line) {}
00054
00056 StreamSource::StreamSource(std::istream& is) : in_(is), pos_(0), line_(1) {
00057 underflow();
00058 }
00059
00060 void StreamSource::underflow() {
00061 pos_ = 0;
00062 buffer_[0] = 0;
00063 if (!in_) return;
00064 in_.read( buffer_, sizeof(buffer_)-1 );
00065 buffer_[in_.gcount()] = 0;
00066 }
00067
00068 bool StreamSource::parseInt64(int64& val) {
00069 skipSpace();
00070 bool pos = match('+') || !match('-');
00071 int d = **this - '0';
00072 if (d < 0 || d > 9) { return false; }
00073 val = 0;
00074 do {
00075 val *= 10;
00076 val += d;
00077 d = *(++*this) - '0';
00078 } while (d >= 0 && d <= 9);
00079 val = pos ? val : -val;
00080 return true;
00081 }
00082 bool StreamSource::parseInt(int& val) {
00083 int64 x;
00084 return parseInt64(x)
00085 && x >= INT_MIN
00086 && x <= INT_MAX
00087 && (val=(int)x, true);
00088 }
00089 bool StreamSource::parseInt(int& val, int min, int max) {
00090 int64 x;
00091 return parseInt64(x)
00092 && x >= min
00093 && x <= max
00094 && (val=(int)x, true);
00095 }
00096
00097 bool StreamSource::matchEol() {
00098 if (match('\n')) {
00099 ++line_;
00100 return true;
00101 }
00102 if (match('\r')) {
00103 match('\n');
00104 ++line_;
00105 return true;
00106 }
00107 return false;
00108 }
00109
00110 bool readLine(StreamSource& in, PodVector<char>::type& buf ) {
00111 char buffer[1024];
00112 bool eol = false;
00113 uint32 i;
00114 buf.clear();
00115 for (i = 0; *in && (eol = in.matchEol()) == false; ++in) {
00116 buffer[i] = *in;
00117 if (++i == 1024) {
00118 buf.insert(buf.end(), buffer, buffer+i);
00119 i = 0;
00120 }
00121 }
00122 buf.insert(buf.end(), buffer, buffer+i);
00123 buf.push_back('\0');
00124 return eol;
00125 }
00126
00127 InputFormat Input_t::detectFormat(std::istream& in) {
00128 std::istream::int_type x = std::char_traits<char>::eof();
00129 while (in && (x = in.peek()) != std::char_traits<char>::eof() ) {
00130 unsigned char c = static_cast<unsigned char>(x);
00131 if (c >= '0' && c <= '9') return Problem_t::LPARSE;
00132 if (c == 'c' || c == 'p') return Problem_t::DIMACS;
00133 if (c == '*') return Problem_t::OPB;
00134 if (c == ' ' || c == '\t') { in.get(); continue; }
00135 break;
00136 }
00137 char msg[] = "'c': Unrecognized input format!\n";
00138 msg[1] = (char)(unsigned char)x;
00139 in && x != std::char_traits<char>::eof()
00140 ? throw ParseError(1, msg)
00141 : throw ParseError(0, "Bad input stream!\n");
00142 }
00143
00144 bool Input_t::parseLparse(std::istream& prg, Asp::LogicProgram& api) {
00145 StreamSource input(prg);
00146 return DefaultLparseParser(api).parse(input);
00147 }
00148
00149 bool Input_t::parseDimacs(std::istream& prg, SatBuilder& api) {
00150 StreamSource input(prg);
00151 return DimacsParser(api).parse(input);
00152 }
00153
00154 bool Input_t::parseOPB(std::istream& prg, PBBuilder& api) {
00155 StreamSource input(prg);
00156 return OPBParser(api).parse(input);
00157 }
00158
00159 StreamParser::StreamParser() : source_(0) {}
00160 StreamParser::~StreamParser() {}
00161 bool StreamParser::check(bool cond, const char* err) const { return cond || (source_->error(err), false); }
00162 bool StreamParser::parse(StreamSource& prg) {
00163 source_ = &prg;
00164 return doParse();
00165 }
00166
00167 bool StreamParser::skipComments(const char* str) {
00168 while (match(*source_, str, false)) { skipLine(*source_); }
00169 return true;
00170 }
00172
00174 LparseParser::LparseParser(Asp::LogicProgram& prg)
00175 : builder_(&prg)
00176 , active_(0) {
00177 }
00178 void LparseParser::setProgram(Asp::LogicProgram& prg) {
00179 builder_ = &prg;
00180 }
00181 Var LparseParser::parseAtom() {
00182 int r = -1;
00183 check(input()->parseInt(r, 1, (int)varMax), (r == -1 ? "Atom id expected!" : "Atom out of bounds"));
00184 return static_cast<Var>(r);
00185 }
00186 bool LparseParser::addRule(const Asp::Rule& r) const {
00187 builder_->addRule(r);
00188 return true;
00189 }
00190
00191 bool LparseParser::doParse() {
00192 SingleOwnerPtr<Asp::Rule> active(new Asp::Rule());
00193 active_ = active.get();
00194 return parseRules()
00195 && parseSymbolTable()
00196 && parseComputeStatement()
00197 && parseModels()
00198 && endParse();
00199 }
00200
00201 bool LparseParser::parseRules() {
00202 int rt = -1;
00203 while ( input()->skipWhite() && input()->parseInt(rt) && rt != 0 && parseRule(rt) ) {
00204 active_->clear();
00205 }
00206 return check(rt == 0, "Rule type expected!")
00207 && check(matchEol(*input(), true), "Symbol table expected!")
00208 && input()->skipWhite();
00209 }
00210
00211 bool LparseParser::parseRule(int rt) {
00212 if (knownRuleType(rt)) {
00213 int bound = -1;
00214 bool weights = false;
00215 active_->setType(static_cast<Asp::RuleType>(rt));
00216 if (rt == Asp::CHOICERULE || rt == Asp::DISJUNCTIVERULE) {
00217 int heads = input()->parseInt(1, INT_MAX, "Rule has too few heads");
00218 for (int i = 0; i < heads; ++i) { active_->addHead(parseAtom()); }
00219 }
00220 else if (rt == Asp::OPTIMIZERULE) {
00221 weights = input()->parseInt(0, 0, "Minimize rule: 0 expected!") == 0;
00222 }
00223 else {
00224 active_->addHead(parseAtom());
00225 weights = rt == Asp::WEIGHTRULE && check(input()->parseInt(bound, 0, INT_MAX), "Weightrule: Positive weight expected!");
00226 }
00227 int lits = input()->parseInt(0, INT_MAX, "Number of body literals expected!");
00228 int neg = input()->parseInt(0, lits, "Illegal negative body size!");
00229 check(rt != Asp::CONSTRAINTRULE || input()->parseInt(bound, 0, INT_MAX), "Constraint rule: Positive bound expected!");
00230 if (bound >= 0) { active_->setBound(bound); }
00231 return parseBody(static_cast<uint32>(lits), static_cast<uint32>(neg), weights) && addRule(*active_);
00232 }
00233 else if (rt >= 90 && rt < 93) {
00234 if (rt == 90) { return input()->parseInt(0, 0, "0 expected") == 0; }
00235 int a = input()->parseInt(1, INT_MAX, "atom id expected");
00236 if (rt == 91) { builder_->freeze(a, input()->parseInt(0, 1, "0 or 1 expected") ? value_true:value_false); }
00237 else { builder_->unfreeze(a); }
00238 return true;
00239 }
00240 else {
00241 return parseRuleExtension(rt);
00242 }
00243 }
00244 bool LparseParser::parseBody(uint32 lits, uint32 neg, bool readWeights) {
00245 for (uint32 i = 0; i != lits; ++i) {
00246 active_->addToBody(parseAtom(), i >= neg, 1);
00247 }
00248 if (readWeights) {
00249 for (uint32 i = 0; i < lits; ++i) {
00250 active_->body[i].second = input()->parseInt(0, INT_MAX, "Weight Rule: bad or missing weight!");
00251 }
00252 }
00253 return check(matchEol(*input(), true), "Illformed rule body!");
00254 }
00255 bool LparseParser::parseSymbolTable() {
00256 int a = -1;
00257 PodVector<char>::type buf;
00258 buf.reserve(1024);
00259 while (input()->skipWhite() && input()->parseInt(a) && a != 0) {
00260 check(a >= 1, "Symbol Table: Atom id out of bounds!");
00261 check(input()->skipSpace() && readLine(*input(), buf), "Symbol Table: Atom name too long or end of file!");
00262 builder_->setAtomName(a, &buf[0]);
00263 }
00264 check(a == 0, "Symbol Table: Atom id expected!");
00265 return check(matchEol(*input(), true), "Compute Statement expected!");
00266 }
00267
00268 bool LparseParser::parseComputeStatement() {
00269 const char* B[2] = { "B+", "B-" };
00270 for (int i = 0; i != 2; ++i) {
00271 input()->skipWhite();
00272 check(match(*input(), B[i], false) && matchEol(*input(), true), (i == 0 ? "B+ expected!" : "B- expected!"));
00273 int id = -1;
00274 while (input()->skipWhite() && input()->parseInt(id) && id != 0) {
00275 check(id >= 1, "Compute Statement: Atom out of bounds");
00276 builder_->setCompute(static_cast<Var>(id), B[i][1] == '+');
00277 }
00278 check(id == 0, "Compute Statement: Atom id or 0 expected!");
00279 }
00280 return true;
00281 }
00282
00283 bool LparseParser::parseModels() {
00284 int m = 1;
00285 check(input()->skipWhite() && input()->parseInt(m, 0, INT_MAX), "Number of models expected!");
00286 return true;
00287 }
00288
00289 bool LparseParser::endParse() { return true; }
00290 DefaultLparseParser::DefaultLparseParser(Asp::LogicProgram& api) : LparseParser(api) {}
00291 bool DefaultLparseParser::parseRuleExtension(int) { input()->error("Unsupported rule type!"); return false; }
00293
00295 DimacsParser::DimacsParser(SatBuilder& prg) : builder_(&prg) {}
00296 void DimacsParser::setProgram(SatBuilder& prg) { builder_ = &prg; }
00297
00298 bool DimacsParser::doParse() {
00299 parseHeader();
00300 parseClauses();
00301 check(!**input(), "Unrecognized format!");
00302 return true;
00303 }
00304
00305 void DimacsParser::parseHeader() {
00306 skipComments("c");
00307 check(match(*input(), "p ", false), "Missing problem line!");
00308 wcnf_ = input()->match('w');
00309 check(match(*input(), "cnf", false), "Unrecognized format!");
00310 numVar_ = input()->parseInt(0, (int)varMax, "#vars expected!");
00311 uint32 numC = (uint32)input()->parseInt(0, INT_MAX, "#clauses expected!");
00312 wsum_t cw = 0;
00313 if (wcnf_) { input()->parseInt64(cw); }
00314 builder_->prepareProblem(numVar_, cw, numC);
00315 input()->skipWhite();
00316 }
00317
00318 void DimacsParser::parseClauses() {
00319 LitVec cc;
00320 const bool wcnf = wcnf_;
00321 wsum_t cw = 0;
00322 const int numV = numVar_;
00323 while (input()->skipWhite() && skipComments("c") && **input()) {
00324 cc.clear();
00325 if (wcnf) { check(input()->parseInt64(cw) && cw > 0, "wcnf: clause weight expected!"); }
00326 for (int lit; (lit = input()->parseInt(-numV, numV, "Invalid variable in clause!")) != 0;) {
00327 cc.push_back( Literal(static_cast<uint32>(lit > 0 ? lit : -lit), lit < 0) );
00328 input()->skipWhite();
00329 }
00330 builder_->addClause(cc, cw);
00331 }
00332 input()->skipWhite();
00333 }
00334
00336
00338 OPBParser::OPBParser(PBBuilder& prg) : builder_(&prg) {}
00339 void OPBParser::setProgram(PBBuilder& prg) { builder_ = &prg; }
00340 bool OPBParser::doParse() {
00341 parseHeader();
00342 skipComments("*");
00343 parseOptObjective();
00344 for (;;) {
00345 skipComments("*");
00346 if (!**input()) { return true; }
00347 parseConstraint();
00348 }
00349 }
00350
00351
00352
00353
00354
00355
00356
00357 void OPBParser::parseHeader() {
00358 check(match(*input(), "* #variable=", false), "Missing problem line '* #variable='!");
00359 input()->skipWhite();
00360 int numV = input()->parseInt(0, (int)varMax, "Number of vars expected");
00361 check(match(*input(), "#constraint=", true), "Bad problem line. Missing '#constraint='!");
00362 int numC = input()->parseInt(0, INT_MAX, "Number of constraints expected!");
00363 int numProd = 0, sizeProd = 0, numSoft = 0;
00364 minCost_ = 0, maxCost_ = 0;
00365 while (match(*input(), "#", true)) {
00366 if (match(*input(), "product=", true)) {
00367 numProd = input()->parseInt(0, INT_MAX, "Positive integer expected!");
00368 check(match(*input(), "sizeproduct=", true), "'sizeproduct=' expected!");
00369 sizeProd= input()->parseInt(0, INT_MAX, "Positive integer expected!");
00370 (void)sizeProd;
00371 }
00372 else if (match(*input(), "soft=", true)) {
00373 numSoft = input()->parseInt(0, INT_MAX, "Positive integer expected!");
00374 check(match(*input(), "mincost=", true), "'mincost=' expected!");
00375 minCost_= input()->parseInt(0, INT_MAX, "Positive integer expected!");
00376 check(match(*input(), "maxcost=", true), "'maxcost=' expected!");
00377 maxCost_= input()->parseInt(0, INT_MAX, "Positive integer expected!");
00378 check(match(*input(), "sumcost=", true), "'sumcost=' expected!");
00379 wsum_t sum;
00380 check(input()->parseInt64(sum) && sum > 0, "Positive integer expected!");
00381 }
00382 else { input()->error("Unrecognized problem line!"); }
00383 }
00384 check(matchEol(*input(), true), "Unrecognized characters in problem line!");
00385 builder_->prepareProblem(numV, numProd, numSoft, numC);
00386 }
00387
00388
00389
00390
00391 void OPBParser::parseOptObjective() {
00392 if (match(*input(), "min:", true)) {
00393 input()->skipWhite();
00394 parseSum();
00395 builder_->addObjective(active_.lits);
00396 }
00397 else if (match(*input(), "soft:", true)) {
00398 wsum_t softCost;
00399 check(input()->parseInt64(softCost) && softCost > 0, "Positive integer expected!");
00400 check(match(*input(), ';', true), "Semicolon missing after constraint!");
00401 builder_->setSoftBound(softCost);
00402 input()->skipWhite();
00403 }
00404 }
00405
00406
00407
00408
00409 void OPBParser::parseConstraint() {
00410 weight_t cost = 0;
00411 if (match(*input(), '[', true)) {
00412 cost = input()->parseInt(minCost_, maxCost_, "Invalid soft constraint cost!");
00413 check(match(*input(), "]", true), "Invalid soft constraint!");
00414 }
00415 parseSum();
00416 active_.eq = match(*input(), "=", true);
00417 check(active_.eq || match(*input(), ">=", false), "Relational operator expected!");
00418 input()->skipWhite();
00419 active_.bound = input()->parseInt(INT_MIN, INT_MAX, "Invalid coefficient on rhs of constraint!");
00420 check(match(*input(), ';', true), "Semicolon missing after constraint!");
00421 builder_->addConstraint(active_.lits, active_.bound, active_.eq, cost);
00422 input()->skipWhite();
00423 }
00424
00425
00426
00427 void OPBParser::parseSum() {
00428 active_.lits.clear();
00429 while (!match(*input(), ';', true)) {
00430 int coeff = input()->parseInt(INT_MIN+1, INT_MAX, "Coefficient expected!");
00431 parseTerm();
00432 Literal x = term_.size() == 1 ? term_[0] : builder_->addProduct(term_);
00433 active_.lits.push_back(WeightLiteral(x, coeff));
00434 if (**input() == '>' || **input() == '=') break;
00435 input()->skipWhite();
00436 }
00437 input()->skipWhite();
00438 }
00439
00440
00441
00442 void OPBParser::parseTerm() {
00443 term_.clear();
00444 char peek;
00445 do {
00446 match(*input(), '*', true);
00447 bool sign = match(*input(), '~', true);
00448 check(match(*input(), 'x', true), "Identifier expected!");
00449 int var = input()->parseInt(1, builder_->numVars(), "Invalid identifier!");
00450 term_.push_back(Literal((uint32)var, sign));
00451 input()->skipWhite();
00452 peek = **input();
00453 } while (peek == '*' || peek == '~' || peek == 'x');
00454 }
00455
00456 }