diff --git a/agenerate2/src/agenerate.cpp b/agenerate2/src/agenerate.cpp index b2ed27a49deaf3dd06be06e9be96e78aef1e6782..ce3c41283176d293656ebdd7b4fe4b5980bc6c2e 100644 --- a/agenerate2/src/agenerate.cpp +++ b/agenerate2/src/agenerate.cpp @@ -14,22 +14,35 @@ #include <string/LinearString.h> #include <grammar/Grammar.h> #include <grammar/generate/GenerateUpToLength.h> +#include <grammar/generate/CockeYoungerKasami.h> #include <container/ObjectsSet.h> +#include <primitive/Bool.h> int main(int argc, char* argv[]) { try { TCLAP::CmdLine cmd("String generate from grammar", ' ', "0.01"); - TCLAP::ValueArg<unsigned> upto( "", "upto", "Generate all strings up to length", false, 5, "unsigned"); + std::vector<std::string> allowed; + allowed.push_back("upTo"); + allowed.push_back("CYK"); + TCLAP::ValuesConstraint<std::string> allowedVals( allowed ); + + TCLAP::ValueArg<std::string> type( "t", "type", "Run type", false, "accept", &allowedVals); + cmd.add( type ); + + TCLAP::ValueArg<unsigned> upto( "", "upto", "Generate all strings up to length", false, 5, "unsigned"); cmd.add( upto ); + TCLAP::ValueArg<std::string> string( "s", "string", "String from file", false, "-", "file"); + cmd.add( string ); + TCLAP::ValueArg<std::string> grammar( "g", "grammar", "Grammar to use", false, "-", "file"); cmd.add( grammar ); - TCLAP::SwitchArg measure( "m", "measure", "Measure times", false); + TCLAP::SwitchArg measure( "m", "measure", "Measure times", false); cmd.add( measure ); - TCLAP::SwitchArg verbose( "v", "verbose", "Be verbose", false); + TCLAP::SwitchArg verbose( "v", "verbose", "Be verbose", false); cmd.add( verbose ); cmd.parse(argc, argv); @@ -42,6 +55,15 @@ int main(int argc, char* argv[]) { std::chrono::measurements::start("Overal", std::chrono::measurements::Type::OVERALL); std::chrono::measurements::start("Input read", std::chrono::measurements::Type::AUXILARY); + std::deque<sax::Token> stringTokens; + if(string.isSet()) { + if(string.getValue() == "-") { + sax::SaxParseInterface::parseStdin(stringTokens); + } else { + sax::SaxParseInterface::parseFile(string.getValue(), stringTokens); + } + } + std::deque<sax::Token> grammarTokens; if(grammar.isSet()) { if(grammar.getValue() == "-") { @@ -53,7 +75,7 @@ int main(int argc, char* argv[]) { sax::SaxParseInterface::parseStdin(grammarTokens); } - if( upto.isSet() ) { + if( type.getValue() == "upTo" && upto.isSet() ) { grammar::Grammar grammar = alib::XmlDataFactory::fromTokens<grammar::Grammar>(grammarTokens); std::chrono::measurements::end(); @@ -64,6 +86,19 @@ int main(int argc, char* argv[]) { std::chrono::measurements::end(); std::chrono::measurements::start("Output write", std::chrono::measurements::Type::AUXILARY); + alib::XmlDataFactory::toStdout( res ); + } else if ( type.getValue() == "CYK" ) { + grammar::Grammar grammar = alib::XmlDataFactory::fromTokens<grammar::Grammar>(grammarTokens); + string::LinearString string = alib::XmlDataFactory::fromTokens<string::LinearString>(stringTokens); + + std::chrono::measurements::end(); + std::chrono::measurements::start("Algorithm", std::chrono::measurements::Type::MAIN); + + bool res = grammar::generate::CockeYoungerKasami::generate(grammar, string); + + std::chrono::measurements::end(); + std::chrono::measurements::start("Output write", std::chrono::measurements::Type::AUXILARY); + alib::XmlDataFactory::toStdout( res ); } else { throw exception::AlibException( "Invalid run type" ); diff --git a/alib2algo/src/grammar/generate/CockeYoungerKasami.cpp b/alib2algo/src/grammar/generate/CockeYoungerKasami.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f08df75f1b6af8f39b97eb1d884bdc20f5137583 --- /dev/null +++ b/alib2algo/src/grammar/generate/CockeYoungerKasami.cpp @@ -0,0 +1,92 @@ +/* + * CockeYoungerKasami.cpp + * + * Created on: 22. 3. 2014 + * Author: Jan Travnicek + */ + +#include "CockeYoungerKasami.h" +#include <common/GlobalData.h> + +namespace grammar { + +namespace generate { + +bool CockeYoungerKasami::generate( const grammar::CNF & grammar, const string::LinearString & string ) { + unsigned stringSize = string.getContent().size(); + + if(stringSize == 0 && grammar.getGeneratesEpsilon()) return true; + + std::vector<std::vector<std::set<alphabet::Symbol>>> data; + data.resize(stringSize); + for(unsigned i = 0; i < stringSize; i++) { + data[i].resize(stringSize - i); + } + + for(unsigned i = 0; i < stringSize; i++) { + for( const std::pair < alphabet::Symbol, std::set < std::variant < alphabet::Symbol, std::pair < alphabet::Symbol, alphabet::Symbol > > > > rule : grammar.getRules ( ) ) { + const alphabet::Symbol & lhs = rule.first; + + for( const std::variant < alphabet::Symbol, std::pair < alphabet::Symbol, alphabet::Symbol > > rhs : rule.second ) { + if( rhs.is< alphabet::Symbol >() && rhs.get< alphabet::Symbol >() == string.getContent()[i]) { + data[0][i].insert(lhs); + } + } + } + } + + for(unsigned i = 1; i < stringSize; i++) { + for(unsigned j = 0; j < stringSize - i; j++) { + std::set<alphabet::Symbol> & targetCell = data[i][j]; //Element to compute + + for(unsigned k = 0; k < i; k++) { + const std::set<alphabet::Symbol> & vertical = data[k][j]; + const std::set<alphabet::Symbol> & diagonal = data[i - 1 - k][j + 1 + k]; // Sources of data + + for(const alphabet::Symbol & verticalElement : vertical) { + for(const alphabet::Symbol & diagonalElement : diagonal) { + + for( const std::pair < alphabet::Symbol, std::set < std::variant < alphabet::Symbol, std::pair < alphabet::Symbol, alphabet::Symbol > > > > rule : grammar.getRules ( ) ) { + const alphabet::Symbol & lhs = rule.first; + + for( const std::variant < alphabet::Symbol, std::pair < alphabet::Symbol, alphabet::Symbol > > rhs : rule.second ) { + if( rhs.is< std::pair<alphabet::Symbol, alphabet::Symbol > >() ) { + const std::pair<alphabet::Symbol, alphabet::Symbol > rhsp = rhs.get< std::pair<alphabet::Symbol, alphabet::Symbol > >(); + + if(rhsp.first == verticalElement && rhsp.second == diagonalElement ) { + targetCell.insert(lhs); + } + } + } + + } + + } + } + + } + + } + } + + if ( common::GlobalData::verbose ) + for(const std::vector<std::set<alphabet::Symbol>> & row : data) { + for( const std::set<alphabet::Symbol>& element : row) { + std::clog << element << " "; + } + std::clog << std::endl; + } + + return data[stringSize - 1][0].count(grammar.getInitialSymbol()); +} + +auto CockeYoungerKasamiCNF = CockeYoungerKasami::RegistratorWrapper<bool, grammar::CNF>(CockeYoungerKasami::getInstance(), CockeYoungerKasami::generate); + +bool CockeYoungerKasami::generate(const grammar::Grammar& grammar, const string::LinearString & string) { + return getInstance().dispatch(grammar.getData(), string); +} + +} /* namespace generate */ + +} /* namespace grammar */ + diff --git a/alib2algo/src/grammar/generate/CockeYoungerKasami.h b/alib2algo/src/grammar/generate/CockeYoungerKasami.h new file mode 100644 index 0000000000000000000000000000000000000000..8f49af3a648ddce9b57de457923f008d91e69535 --- /dev/null +++ b/alib2algo/src/grammar/generate/CockeYoungerKasami.h @@ -0,0 +1,40 @@ +/* + * CockeYoungerKasami.h + * + * Created on: 22. 3. 2014 + * Author: Jan Travnicek + */ + +#ifndef COCKE_YOUNGER_KASAMI_H_ +#define COCKE_YOUNGER_KASAMI_H_ + +#include <common/multipleDispatch.hpp> + +#include <grammar/Grammar.h> +#include <grammar/ContextFree/CNF.h> +#include <string/LinearString.h> + +namespace grammar { + +namespace generate { + +/** + * Implements algorithms from Melichar, chapter 3.3 + */ +class CockeYoungerKasami : public std::SingleDispatchLastStaticParam<bool, grammar::GrammarBase, const string::LinearString &> { +public: + static bool generate( const grammar::Grammar & grammar, const string::LinearString & string ); + + static bool generate( const grammar::CNF & grammar, const string::LinearString & string ); + + static CockeYoungerKasami& getInstance() { + static CockeYoungerKasami res; + return res; + } +}; + +} /* namespace generate */ + +} /* namespace grammar */ + +#endif /* COCKE_YOUNGER_KASAMI_H_ */ diff --git a/examples2/grammar/contextFree1-4.txt b/examples2/grammar/contextFree1-4.txt new file mode 100644 index 0000000000000000000000000000000000000000..937ed0bfee9d59568ca51dc1278a86aa55581706 --- /dev/null +++ b/examples2/grammar/contextFree1-4.txt @@ -0,0 +1,10 @@ +CFG ( +{'A', 'B', 'C', 'D', 'E'}, +{'a', 'b'}, +{'A' -> 'b' | 'A' 'B' | 'a', +'B' -> 'A' 'C', +'C' -> 'a' 'E' 'D', +'D' -> 'a' | 'B' 'E', +'E' -> 'B' 'A' | 'b' | +}, +'E') diff --git a/tests.anormalize.sh b/tests.anormalize.sh index 52f990d9e6b7f0f93b3677fe88b422acc2134d00..4a8617fafa0ee2e85a924a2928f8dcc8db52ac52 100755 --- a/tests.anormalize.sh +++ b/tests.anormalize.sh @@ -57,7 +57,7 @@ function generateCFG { # $1 = command for conversion. Output of such command must be a grammar !! # $2 = original grammar function runTest2 { - GENERATED_STRINGS="./agenerate2 --upto $STRING_LENGHTS" + GENERATED_STRINGS="./agenerate2 -t upTo --upto $STRING_LENGHTS" OUT=`timeout $TESTCASE_TIMEOUT bash -c "diff <(cat $2 | $1 | $GENERATED_STRINGS ) <(cat $2 | $GENERATED_STRINGS)"` RET=$?