#include "buchi.h" #include <brick-string.h> #if OPT_LTL3BA #include <external/ltl3ba/ltl3ba.h> #endif using namespace divine; #if OPT_LTL3BA // ltl3ba does not have the proper interface void reinit(); int tl_main( std::string &argv ); extern int tl_det_m; extern int tl_sim_r; extern int tl_print; std::vector< Buchi::DNFClause > Buchi::gclause; int Buchi::ltl3ba_parse( std::string ltl ) { LTL_parse_t parse; LTL_formul_t F; parse.nacti( ltl ); if ( !parse.syntax_check( F ) ) { std::cerr << "Error: Syntax error in LTL formula: '" << ltl << "'." << std::endl; return -1; } F = F.negace(); std::stringstream strF; strF << F; ltl = strF.str(); // run ltl3ba reinit(); tl_det_m = 1; // try to determinize tl_sim_r = 1; // simulation reduction tl_print = 0; // do not print anything return tl_main( ltl ); // returns zero if successful } void Buchi::ltl3ba_finalize() { // Normally, bdd_done() would be called here, but that causes heap corruption in the bdd library if it is used again } BState *Buchi::nodeBegin() { return get_buchi_states()->prv; } BState *Buchi::nodeEnd() { return get_buchi_states(); } bool Buchi::isAccepting( BState* s ) { return s->final == get_buchi_accept(); } bool Buchi::isInitial( BState* s ) { return s->id == -1; } void Buchi::next( BState*& s ) { s = s->prv; } int Buchi::getId( BState* s ) { return s->incoming; } void Buchi::assignId( BState* s, int id ) { s->incoming = id; } int Buchi::getEdgeCount( BState* s ) { return s->trans->size(); } int Buchi::parseEdge( BState* s, int i ) { auto iter = s->trans->begin(); std::advance( iter, i ); gclause.clear(); if ( iter->second == bdd_false() ); // impossible edge else if ( iter->second == bdd_true() ) // always enabled gclause.push_back( DNFClause() ); else // one or more conditional edges bdd_allsat( iter->second, allsatHandler ); return getId( iter->first ); } void Buchi::allsatHandler( char* varset, int size ) { gclause.push_back( DNFClause() ); for ( int v = 0; v < size; v++ ) { if ( varset[v] < 0 ) continue; // varset[v] == 0 means negation gclause.back().push_back( std::make_pair( varset[v] > 0, get_buchi_symbol( v ) ) ); } } #endif void Buchi::buildEmpty() { nodes.resize( 1 ); nodes[ 0 ].isAcc = false; nodes[ 0 ].tr.resize( 1 ); nodes[ 0 ].tr[ 0 ] = std::make_pair( 0, 0 ); initId = 0; } bool Buchi::readLTLFile( const std::string& fname, std::vector< std::string >& props, std::map< std::string, std::string >& defs ) { std::fstream file( fname, std::fstream::in ); if ( !file.is_open() ) return false; brick::string::ERegexp def( "^[ \t]*#define ([^ \t]+)[ \t]+(.*)", 3 ); brick::string::ERegexp prop( "^[ \t]*#property (.*)", 2 ); while ( file.good() ) { std::string line; getline( file, line ); if ( def.match( line ) ) defs[ def[1] ] = def[2]; if ( prop.match( line ) ) props.push_back( prop[1] ); } return !props.empty(); } std::ostream& Buchi::printAutomaton( std::ostream& o, const std::string& property, const std::map< std::string, std::string >& defs ) { Buchi buchi; std::vector< std::string > guards ( 1 ); buchi.build( property, [ &guards, &defs ]( const Buchi::DNFClause& clause ) -> int { if ( clause.empty() ) return 0; guards.push_back( std::string() ); for ( auto lit = clause.begin(); lit != clause.end(); ++lit ) { auto found = defs.find( lit->second ); const std::string& strLit = ( found == defs.end() ) ? lit->second : found->second; // substitute definitions if ( !lit->first ) guards.back() += "!"; guards.back() += strLit; if ( lit + 1 != clause.end() ) guards.back() += " && "; } return guards.size() - 1; }); o << "\tstates q0"; for ( unsigned int i = 1; i < buchi.size(); ++i ) o << ", q" << i; o << ";\n\tinit q" << buchi.getInitial(); o << ";\n\taccepting "; bool first = true; for ( unsigned int i = 0; i < buchi.size(); ++i ) { if ( buchi.isAccepting( i ) ) { if ( first ) o << "q"; else o << ", q"; o << i; first = false; } } o << ";\n\ttrans\n"; first = true; for ( unsigned int i = 0; i < buchi.size(); ++i ) { for ( auto tr = buchi.transitions( i ).begin(); tr != buchi.transitions( i ).end(); ++tr ) { if ( !first ) o << ",\n"; first = false; o << "\t\tq" << i << " -> q" << tr->first; if ( tr->second ) o << " {guard " << guards[ tr->second ] << "}"; else o << " {}"; } } o << ";\n"; return o; }