dlvhex  2.5.0
testsuite/TestHexParser.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
00003  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner
00004  * Copyright (C) 2009, 2010 Peter Schüller
00005  * 
00006  * This file is part of dlvhex.
00007  *
00008  * dlvhex is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License as
00010  * published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * dlvhex is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with dlvhex; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA.
00022  */
00023 
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif // HAVE_CONFIG_H
00034 
00035 #include <boost/cstdint.hpp>
00036 #include "dlvhex2/HexParser.h"
00037 #include "dlvhex2/InputProvider.h"
00038 #include "dlvhex2/ProgramCtx.h"
00039 #include "dlvhex2/Printer.h"
00040 #include "dlvhex2/Registry.h"
00041 #include "dlvhex2/Interpretation.h"
00042 
00043 #define BOOST_TEST_MODULE "TestHexParser"
00044 #include <boost/test/unit_test.hpp>
00045 
00046 #include <iostream>
00047 #include <fstream>
00048 
00049 #define LOG_REGISTRY_PROGRAM(ctx) \
00050   LOG(INFO,*ctx.registry()); \
00051     RawPrinter printer(std::cerr, ctx.registry()); \
00052     std::cerr << "edb = " << *ctx.edb << std::endl; \
00053     LOG(INFO,"idb"); \
00054     printer.printmany(ctx.idb,"\n"); \
00055     std::cerr << std::endl; \
00056     LOG(INFO,"idb end");
00057 
00058 LOG_INIT(Logger::ERROR | Logger::WARNING)
00059 
00060 DLVHEX_NAMESPACE_USE
00061 
00062 BOOST_AUTO_TEST_CASE(testHexParserSimple) 
00063 {
00064   ProgramCtx ctx;
00065   ctx.setupRegistry(RegistryPtr(new Registry));
00066 
00067   std::stringstream ss;
00068   ss <<
00069     "a. b. c(d,e)." << std::endl <<
00070     "f(X) v b :- g(X), not h(X,X)." << std::endl;
00071 
00072   InputProviderPtr ip(new InputProvider);
00073   ip->addStreamInput(ss, "testinput");
00074   ModuleHexParser parser;
00075   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00076 
00077     LOG_REGISTRY_PROGRAM(ctx);
00078 
00079   ID ida = ctx.registry()->ogatoms.getIDByString("a");
00080   ID idb = ctx.registry()->ogatoms.getIDByString("b");
00081   ID idcde = ctx.registry()->ogatoms.getIDByString("c(d,e)");
00082   BOOST_REQUIRE((ida | idb | idcde) != ID_FAIL);
00083 
00084   ID idfX = ctx.registry()->onatoms.getIDByString("f(X)");
00085   ID idgX = ctx.registry()->onatoms.getIDByString("g(X)");
00086   ID idhXX = ctx.registry()->onatoms.getIDByString("h(X,X)");
00087   BOOST_REQUIRE((idfX | idgX | idhXX) != ID_FAIL);
00088 
00089   BOOST_REQUIRE(ctx.edb != 0);
00090   BOOST_CHECK(ctx.edb->getFact(ida.address));
00091   BOOST_CHECK(ctx.edb->getFact(idb.address));
00092   BOOST_CHECK(ctx.edb->getFact(idcde.address));
00093 
00094   BOOST_REQUIRE(ctx.idb.size() == 1);
00095   {
00096     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[0]);
00097     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR | ID::PROPERTY_RULE_DISJ ));
00098     BOOST_CHECK(r.weight == ID_FAIL);
00099     BOOST_CHECK(r.level == ID_FAIL);
00100     BOOST_REQUIRE(r.head.size() == 2);
00101     {
00102       BOOST_CHECK(r.head[0] == idfX);
00103       BOOST_CHECK(r.head[1] == idb);
00104     }
00105     BOOST_REQUIRE(r.body.size() == 2);
00106     {
00107       BOOST_CHECK(r.body[0] == ID::posLiteralFromAtom(idgX));
00108       BOOST_CHECK(r.body[1] == ID::nafLiteralFromAtom(idhXX));
00109     }
00110   }
00111 }
00112 
00113 
00114 BOOST_AUTO_TEST_CASE(testHexParserConstraint) 
00115 {
00116   ProgramCtx ctx;
00117   ctx.setupRegistry(RegistryPtr(new Registry));
00118 
00119   std::stringstream ss;
00120   ss <<
00121     ":- g(X), not h(X,X)." << std::endl;
00122   InputProviderPtr ip(new InputProvider);
00123   ip->addStreamInput(ss, "testinput");
00124   ModuleHexParser parser;
00125   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00126 
00127     LOG_REGISTRY_PROGRAM(ctx);
00128 
00129   ID idgX = ctx.registry()->onatoms.getIDByString("g(X)");
00130   ID idhXX = ctx.registry()->onatoms.getIDByString("h(X,X)");
00131   BOOST_REQUIRE((idgX | idhXX) != ID_FAIL);
00132 
00133   BOOST_REQUIRE(ctx.idb.size() == 1);
00134   {
00135     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[0]);
00136     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_CONSTRAINT));
00137     BOOST_CHECK(r.weight == ID_FAIL);
00138     BOOST_CHECK(r.level == ID_FAIL);
00139     BOOST_CHECK(r.head.size() == 0);
00140     BOOST_REQUIRE(r.body.size() == 2);
00141     {
00142       BOOST_CHECK(r.body[0] == ID::posLiteralFromAtom(idgX));
00143       BOOST_CHECK(r.body[1] == ID::nafLiteralFromAtom(idhXX));
00144     }
00145   }
00146 }
00147 
00148 #warning Weak constraints currently not implemented, here is a testcase for them
00149 #if 0
00150 BOOST_AUTO_TEST_CASE(testHexParserWeakConstraint) 
00151 {
00152   ProgramCtx ctx;
00153   ctx.setupRegistry(RegistryPtr(new Registry));
00154 
00155   std::stringstream ss;
00156   ss <<
00157     ":~ g(X), not h(X,X)." << std::endl <<
00158     ":~ g(X). [X:4]";
00159   InputProviderPtr ip(new InputProvider);
00160   ip->addStreamInput(ss, "testinput");
00161   ModuleHexParser parser;
00162   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00163 
00164     LOG_REGISTRY_PROGRAM(ctx);
00165 
00166   ID idX = ctx.registry()->terms.getIDByString("X");
00167   ID id1 = ID::termFromInteger(1);
00168   ID id4 = ID::termFromInteger(4);
00169   ID idgX = ctx.registry()->onatoms.getIDByString("g(X)");
00170   ID idhXX = ctx.registry()->onatoms.getIDByString("h(X,X)");
00171   BOOST_REQUIRE((idX | id1 | id4 | idgX | idhXX) != ID_FAIL);
00172 
00173   BOOST_REQUIRE(ctx.idb.size() == 2);
00174   {
00175     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[0]);
00176     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_WEAKCONSTRAINT));
00177     BOOST_CHECK(r.weight == id1);
00178     BOOST_CHECK(r.level == id1);
00179     BOOST_CHECK(r.head.size() == 0);
00180     BOOST_REQUIRE(r.body.size() == 2);
00181     {
00182       BOOST_CHECK(r.body[0] == ID::posLiteralFromAtom(idgX));
00183       BOOST_CHECK(r.body[1] == ID::nafLiteralFromAtom(idhXX));
00184     }
00185   }
00186   {
00187     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[1]);
00188     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_WEAKCONSTRAINT));
00189     BOOST_CHECK(r.weight == idX);
00190     BOOST_CHECK(r.level == id4);
00191     BOOST_CHECK(r.head.size() == 0);
00192     BOOST_REQUIRE(r.body.size() == 1);
00193     {
00194       BOOST_CHECK(r.body[0] == ID::posLiteralFromAtom(idgX));
00195     }
00196   }
00197 }
00198 #endif
00199 
00200 #warning reenable true negation
00201 #if 0
00202 BOOST_AUTO_TEST_CASE(testHexParserTrueNegation) 
00203 {
00204   ProgramCtx ctx;
00205   ctx.setupRegistry(RegistryPtr(new Registry));
00206 
00207   std::stringstream ss;
00208   ss <<
00209     "a. -b. -b :- a, -b, not -b, not a." << std::endl;
00210   InputProviderPtr ip(new InputProvider);
00211   ip->addStreamInput(ss, "testinput");
00212   ModuleHexParser parser;
00213   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00214 
00215     LOG_REGISTRY_PROGRAM(ctx);
00216 
00217   ID ida = ctx.registry()->ogatoms.getIDByString("a");
00218   ID idmb = ctx.registry()->ogatoms.getIDByString("-b");
00219   BOOST_REQUIRE((ida | idmb) != ID_FAIL);
00220 
00221   // TODO: the following will become a bitset check
00222   BOOST_REQUIRE(ctx.edb.size() == 2);
00223   {
00224     BOOST_CHECK(ctx.edb[0] == ida);
00225     BOOST_CHECK(ctx.edb[1] == idmb);
00226   }
00227 
00228   BOOST_REQUIRE(ctx.idb.size() == 1);
00229   {
00230     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[0]);
00231     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR));
00232     BOOST_CHECK(r.weight == ID_FAIL);
00233     BOOST_CHECK(r.level == ID_FAIL);
00234     BOOST_REQUIRE(r.head.size() == 1);
00235     {
00236       BOOST_CHECK(r.head[0] == idmb);
00237     }
00238     BOOST_REQUIRE(r.body.size() == 4);
00239     {
00240       BOOST_CHECK(r.body[0] == ID::posLiteralFromAtom(ida));
00241       BOOST_CHECK(r.body[1] == ID::posLiteralFromAtom(idmb));
00242       BOOST_CHECK(r.body[2] == ID::nafLiteralFromAtom(idmb));
00243       BOOST_CHECK(r.body[3] == ID::nafLiteralFromAtom(ida));
00244     }
00245   }
00246 }
00247 #endif
00248 
00249 BOOST_AUTO_TEST_CASE(testHexParserBuiltinPredicates) 
00250 {
00251   ProgramCtx ctx;
00252   ctx.setupRegistry(RegistryPtr(new Registry));
00253 
00254   std::stringstream ss;
00255   ss <<
00256     ":- X != 4, X < Y, >=(X,Y), #int(X).";
00257   InputProviderPtr ip(new InputProvider);
00258   ip->addStreamInput(ss, "testinput");
00259   ModuleHexParser parser;
00260   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00261 
00262     LOG_REGISTRY_PROGRAM(ctx);
00263 
00264   ID idX = ctx.registry()->terms.getIDByString("X");
00265   ID idY = ctx.registry()->terms.getIDByString("Y");
00266   ID id4 = ID::termFromInteger(4);
00267   ID idne = ID::termFromBuiltin(ID::TERM_BUILTIN_NE);
00268   ID idlt = ID::termFromBuiltin(ID::TERM_BUILTIN_LT);
00269   ID idge = ID::termFromBuiltin(ID::TERM_BUILTIN_GE);
00270   ID idint = ID::termFromBuiltin(ID::TERM_BUILTIN_INT);
00271   BOOST_REQUIRE((idX | idY | id4 | idne | idlt | idge | idint) != ID_FAIL);
00272 
00273   BOOST_REQUIRE(ctx.idb.size() == 1);
00274   {
00275     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[0]);
00276     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_CONSTRAINT));
00277     BOOST_CHECK(r.weight == ID_FAIL);
00278     BOOST_CHECK(r.level == ID_FAIL);
00279     BOOST_CHECK(r.head.size() == 0);
00280     BOOST_REQUIRE(r.body.size() == 4);
00281     {
00282       ID idlit = r.body[0];
00283       BOOST_CHECK(idlit.isLiteral());
00284       BOOST_CHECK(idlit.isBuiltinAtom());
00285       const BuiltinAtom& at = ctx.registry()->batoms.getByID(idlit);
00286       BOOST_CHECK(ID(at.kind,0).isBuiltinAtom());
00287       BOOST_REQUIRE(at.tuple.size() == 3);
00288       BOOST_CHECK(at.tuple[0] == idne);
00289       BOOST_CHECK(at.tuple[1] == idX);
00290       BOOST_CHECK(at.tuple[2] == id4);
00291     }
00292     {
00293       ID idlit = r.body[1];
00294       BOOST_CHECK(idlit.isLiteral());
00295       BOOST_CHECK(idlit.isBuiltinAtom());
00296       const BuiltinAtom& at = ctx.registry()->batoms.getByID(idlit);
00297       BOOST_CHECK(ID(at.kind,0).isBuiltinAtom());
00298       BOOST_REQUIRE(at.tuple.size() == 3);
00299       BOOST_CHECK(at.tuple[0] == idlt);
00300       BOOST_CHECK(at.tuple[1] == idX);
00301       BOOST_CHECK(at.tuple[2] == idY);
00302     }
00303     {
00304       ID idlit = r.body[2];
00305       BOOST_CHECK(idlit.isLiteral());
00306       BOOST_CHECK(idlit.isBuiltinAtom());
00307       const BuiltinAtom& at = ctx.registry()->batoms.getByID(idlit);
00308       BOOST_CHECK(ID(at.kind,0).isBuiltinAtom());
00309       BOOST_REQUIRE(at.tuple.size() == 3);
00310       BOOST_CHECK(at.tuple[0] == idge);
00311       BOOST_CHECK(at.tuple[1] == idX);
00312       BOOST_CHECK(at.tuple[2] == idY);
00313     }
00314     {
00315       ID idlit = r.body[3];
00316       BOOST_CHECK(idlit.isLiteral());
00317       BOOST_CHECK(idlit.isBuiltinAtom());
00318       const BuiltinAtom& at = ctx.registry()->batoms.getByID(idlit);
00319       BOOST_CHECK(ID(at.kind,0).isBuiltinAtom());
00320       BOOST_REQUIRE(at.tuple.size() == 2);
00321       BOOST_CHECK(at.tuple[0] == idint);
00322       BOOST_CHECK(at.tuple[1] == idX);
00323     }
00324   }
00325 }
00326 
00327 BOOST_AUTO_TEST_CASE(testHexParserExternalAtoms) 
00328 {
00329   ProgramCtx ctx;
00330   ctx.setupRegistry(RegistryPtr(new Registry));
00331 
00332   std::stringstream ss;
00333   ss <<
00334     ":- &foo[a,b,X](b,X,4).";
00335   InputProviderPtr ip(new InputProvider);
00336   ip->addStreamInput(ss, "testinput");
00337   ModuleHexParser parser;
00338   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00339 
00340     LOG_REGISTRY_PROGRAM(ctx);
00341 
00342   ID ida = ctx.registry()->terms.getIDByString("a");
00343   ID idb = ctx.registry()->terms.getIDByString("b");
00344   ID idX = ctx.registry()->terms.getIDByString("X");
00345   ID id4 = ID::termFromInteger(4);
00346   ID idfoo = ctx.registry()->terms.getIDByString("foo");
00347   BOOST_REQUIRE((ida | idb | idX | id4 | idfoo) != ID_FAIL);
00348 
00349   BOOST_REQUIRE(ctx.idb.size() == 1);
00350   {
00351     const Rule& r = ctx.registry()->rules.getByID(ctx.idb[0]);
00352     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_CONSTRAINT | ID::PROPERTY_RULE_EXTATOMS));
00353     BOOST_CHECK(r.weight == ID_FAIL);
00354     BOOST_CHECK(r.level == ID_FAIL);
00355     BOOST_CHECK(r.head.size() == 0);
00356     BOOST_REQUIRE(r.body.size() == 1);
00357     {
00358       ID idlit = r.body[0];
00359       BOOST_CHECK(idlit.isLiteral());
00360       BOOST_CHECK(idlit.isExternalAtom());
00361       const ExternalAtom& at = ctx.registry()->eatoms.getByID(idlit);
00362       BOOST_CHECK(ID(at.kind,0).isExternalAtom());
00363       BOOST_CHECK(at.predicate == idfoo);
00364       BOOST_REQUIRE(at.inputs.size() == 3);
00365       BOOST_CHECK(at.inputs[0] == ida);
00366       BOOST_CHECK(at.inputs[1] == idb);
00367       BOOST_CHECK(at.inputs[2] == idX);
00368       BOOST_REQUIRE(at.tuple.size() == 3);
00369       BOOST_CHECK(at.tuple[0] == idb);
00370       BOOST_CHECK(at.tuple[1] == idX);
00371       BOOST_CHECK(at.tuple[2] == id4);
00372     }
00373   }
00374 }
00375