lbt-1.2.2/0002755000175000017500000000000010164617064013712 5ustar msmakelamsmakela00000000000000lbt-1.2.2/doc/0002755000175000017500000000000010163770337014461 5ustar msmakelamsmakela00000000000000lbt-1.2.2/doc/index.html0000644000175000017500000002507710163766517016474 0ustar msmakelamsmakela00000000000000 LBT: LTL to Bchi converter

LBT: LTL to Bchi conversion

This piece of software provides a C++ implementation for an algorithm that converts a linear temporal logic formula to a generalised Bchi automaton. The algorithm comes from

R. Gerth, D. Peled, Y. Vardi, and P. Wolper.
Simple on-the-fly automatic verification of linear temporal logic. PSTV'95, Fifteenth International Symposium on PROTOCOL SPECIFICATION, TESTING AND VERIFICATION, Warsaw, Poland, 1995.

The resulting automaton may be used, for instance, in model checking, where it represents a property to be verified from a model (e.g. a Petri net).

Copyright

The implementation is Copyright 1999 Mauno Rnkk <mauno.ronkko@cs.utu.fi>. The original copyright statement follows:

This product contains free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. These terms also apply to any hardware schemas and any other information presented in the www-pages below.

This product information is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This also applies to any hardware schemas and any other information described in the www-pages below. See the GNU General Public License for more details. You should be able to read the GNU General Public License via the above link; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Enhancements and packaging are 1999-2001,2004 Heikki Tauriainen <heikki.tauriainen@hut.fi>, and 2001,2002,2004 Marko Mkel <marko.makela@hut.fi>.

Interfacing the Translator

The translator is designed to be invoked as a subprocess. It parses a linear temporal logic from standard input and writes a corresponding generalised Bchi automaton to standard output, and exits. Both the input and output format are based on prefix notation that facilitate straightforward recursive-descent parsing.

Grammar Definitions

The grammar is presented in Backus-Naur Form, one grammar rule per line. Comments delimited by the symbols /* and */ are not part of the formal grammar. Non-terminal symbols are enclosed within single quotes or presented as Flex-style regular-expressions.

Input format for LTL formulae

Propositional operators

<f> ::= 't' /* true */
<f> ::= 'f' /* false */
<f> ::= 'p'[0-9]+ /* proposition */
<f> ::= '!' <f> /* negation */
<f> ::= '|' <f> <f> /* disjunction */
<f> ::= '&' <f> <f> /* conjunction */
<f> ::= 'i' <f> <f> /* implication: "i <f1> <f2>" is short-hand for "| ! <f1> <f2>" */
<f> ::= 'e' <f> <f> /* equivalence */
<f> ::= '^' <f> <f> /* exclusive disjunction (xor) */
<f> ::= [ \t\n\r\v\f] <f> /* white space is ignored */
<f> ::= <f> [ \t\n\r\v\f] /* white space is ignored */

Temporal operators

<f> ::= 'X' <f> /* next */
<f> ::= 'F' <f> /* finally, eventually */
<f> ::= 'G' <f> /* globally, henceforth */
<f> ::= 'U' <f> <f> /* until */
<f> ::= 'V' <f> <f> /* release */

Output format for generalised Bchi automata

<space> ::= [ \n]+
<gba> ::= [0-9]+ <space> [0-9]+ <states> /* first the number of states, then the number of acceptance sets (if 0, all states are accepting) */
<states> ::= /* empty */
<states> ::= <states> <space> <state>
<state> ::= [0-9]+ <space> <initial?> <space> <acceptance sets> '-1' <transitions> '-1' /* state identifiers can be arbitrary unsigned integers */
<initial?> ::= '0' /* not an initial state */
<initial?> ::= '1' /* initial state (exactly one state must be initial) */
<acceptance sets> ::= /* empty */
<acceptance sets> ::= <acceptance sets> [0-9]+ <space> /* acceptance set identifiers can be arbitrary unsigned integers */
<transitions> ::= /* empty */
<transitions> ::= <transitions> <space> <transition>
<transition> ::= [0-9]+ <space> 't' /* constantly enabled transition to a state */
<transition> ::= [0-9]+ <space> <gate> /* conditionally enabled transition to a state */
<gate> ::= 'p'[0-9]+ /* proposition */
<gate> ::= '!' <space> <gate> /* negation */
<gate> ::= '|' <space> <gate> <space> <gate> /* disjunction */
<gate> ::= '&' <space> <gate> <space> <gate> /* conjunction */

Note that currently LBT does not generate disjunctions on gate conditions. Also, the initial state is always numbered 0.

Visualising the Output

A simple tool, lbt2dot, converts the generalised Bchi automata descriptions output by the translator to a format viewable with GraphViz, a visualisation tool for directed graphs. Gate expressions are presented as edge labels, and state and acceptance set identifiers are presented as node labels. The node corresponding to the initial state is shaded.

Here is a sample run involving the filter: echo '! G p0' | lbt | lbt2dot | dotty -.
[Generalised Bchi Automaton of ! G p0]
In the picture above, constructed with the command echo '! G p0' | lbt | lbt2dot | dot -Tpng -Grankdir=LR -Nfontname=Verdana -Efontname=Verdana > notgp0.png, the automaton has 4 states, identified by the numbers 0, 2, 3, and 4. The initial state is 0, and there is one acceptance set, identified by the number 0. All states except states 0 and 4 belong to this acceptance set.

The above example illustrates that the translation generates unnecessary states. The algoritm never generates loops to the initial state. Clearly, this automaton could be reduced to two states with t-labeled self-loops:
[Optimised Generalised Bchi Automaton of ! G p0]

Obtaining the Code

You can download the code from http://www.tcs.hut.fi/maria/src/. You will need C and C++ compilers such as GCC for compiling the source code.

For the convenience of Windows users, we provide executable files that were compiled with gcc-2.95.2 configured as a cross-compiler for the mingw target platform.

lbt-1.2.2/doc/notgp0-opt.png0000644000175000017500000000223507457762107017206 0ustar msmakelamsmakela00000000000000PNG  IHDRsy 6PLTE???___iiiNNN444L*tRNS7IDATxۂ `qN-e!@"\T5XXGpF`3zO:1ւٙyz9j-S:a,Ry6PLTEߟ???___iiiNNN444ItRNS7cIDATx뚢0 aD=fw9Ҧ~̀kia%8|!C!C!>||>|Y!bc㫟 >D>||V!|G?|'çk=Y6]O>t= mპzzCQ0У > !bDL>D?!8LG|vO8\ fENΡ Χ|;@24^;kshX^_Χ+>̯~[s/U~X&]>]N8_zY.}:܌Y%ͧ6|8G@q;%|[3^iF@׿ͪDN^jEc|dا9D@ nox!1q_'O7|v zTxlakϐO@v,_~T+Z%ΎB&l|^ռ,85qG[/yJ}A|l$ 'u6'b·W8 Q Fz*׳]5O3"!Is^(RپipQ4|;=e(ZjYtv/r8w S&=I/=\"qDȶ%|)\>Ta^scK=~,[XF!ZKj^m\\XcsJĿO_Q.a{ѵw2bi6z9: #"7On<(&9'A|38?[˧RHwͭhǨyyy0Sv?R};ƸWR:k<Ad8>/n痼t}hs)9Oq䛋|5Giv,f眉OW~r}J:y9y0tnOC珉46|\6g*^IF=({ɧW}NT ~畘OwnO g|Z]>g|S6M骬o6Fup#1W?6 vA2|(*e20g'UP[,2&2$Uwf|}gOϸ7'Ҹ+ o7f07Ǯ†Ui\V]bha}g3 yqt?pl\z0Ǵih*=o!A,|kuд}{#}F _]˼jZiPʪ^Zr.;Ts}=MG7[u6$ٗDiABuǷ# iᛱ4 _a4Ŷt壨4)-:)vJfLwz^& -f,CVVɧbRbTOɞ'z/|1WR6ʧRbt4ޕk3A2mnnPel+kOO`iOv(],xR)iOV .9OO%`]>1cn on]OE@1d^W:9Ok >Sag|D~S>m76 >u@||\h&G*OOهW|xb|4mt0vD\&/ǿ"V8mqW D58_V|uEBide`2|Saيs|'D|*K>#tOZهSW|x>u>#'O|WD&t=6W!>||A'IENDB`lbt-1.2.2/lbt.10000644000175000017500000000460507334736531014566 0ustar msmakelamsmakela00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH LBT 1 "August 10, 2001" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME lbt \- LTL to B\(:uchi Translator .SH SYNOPSIS .B lbt .RI "< " formula.txt " > " automaton.txt .br .B lbt2dot .RI "< " automaton.txt " > " automaton.dot .SH DESCRIPTION This manual page documents briefly the .B lbt and .B lbt2dot commands. This manual page was written for the Debian GNU/Linux distribution because the original program does not have a manual page. Instead, it has documentation in HTML format; see below. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBlbt\fP is a filter that translates a linear temporal logic (LTL) formula to a corresponding generalized B\(:uchi automaton. The translation is based on the algorithm by Gerth, Peled and Vardi presented at PSTV'95, .IR "Simple on-the-fly automatic verification of linear temporal logic". Hardly any optimizations are implemented, and the generated automaton is often bigger than necessary. But on the other hand, it should always be correct. .br The filter \fBlbt2dot\fP can be used to translate Bchi automata from the \fBlbt\fP output format to GraphViz format for visualization. .SH EXAMPLE \fBecho\fP G p0 | \fBlbt\fP | \fBlbt2dot\fP | \fBdotty\fP - .SH SEE ALSO .BR dotty (1). .SH FILES .TP .I /usr/share/doc/lbt/html/index.html The real documentation for LBT. .SH AUTHOR This manual page was written by Marko M\(:akel\(:a , for the Debian GNU/Linux system (but may be used by others). The \fBlbt\fP program was written by .B Mauno R\(:onkk\(:o and .B Heikki Tauriainen, and it was optimized by .B Marko M\(:akel\(:a, who also wrote the \fBlbt2dot\fP filter. Please see the copyright file in .I /usr/share/doc/lbt for details. lbt-1.2.2/lbt2dot.10000755000175000017500000000000010130256353016171 2lbt.1ustar msmakelamsmakela00000000000000lbt-1.2.2/Doxyfile0000644000175000017500000000133307332442762015422 0ustar msmakelamsmakela00000000000000# Doxygen configuration file for lbt, much like a -*- makefile -*- PROJECT_NAME = LBT WARNINGS = YES HAVE_DOT = YES GRAPHICAL_HIERARCHY = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES INPUT = . FILE_PATTERNS = *.C *.h INCLUDE_PATH = ENABLE_PREPROCESSING = NO MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = NO FULL_PATH_NAMES = NO GENERATE_LATEX = NO COMPACT_LATEX = YES PDF_HYPERLINKS = YES PAPER_TYPE = a4 GENERATE_RTF = NO GENERATE_MAN = NO GENERATE_HTML = YES SEARCHENGINE = YES CGI_NAME = lbt CGI_URL = http://siphon.tcs.hut.fi/cgi-bin DOC_URL = http://siphon.tcs.hut.fi/lbt DOC_ABSPATH = /var/www/lbt BIN_ABSPATH = /usr/lib/cgi-bin lbt-1.2.2/Makefile0000644000175000017500000000315410163767752015364 0ustar msmakelamsmakela00000000000000# Installation directory prefix for Debian GNU/Linux DESTDIR = # Generic installation directory prefix PREFIX = $(DESTDIR)/usr # Where to put binaries on 'make install'? BINDIR = $(PREFIX)/bin # Where to put documentation on 'make install'? DOCDIR = $(PREFIX)/share/doc/lbt # Where to put manual pages on 'make installman'? MANDIR = $(PREFIX)/share/man/man1 # Installation commands INSTALLDIR = install -d INSTALLBIN = install INSTALLDATA = install -m 444 RM = rm -f # GCC (tested with 2.95.4 and 3.0.2) CXX=g++ CXXFLAGS=$(CFLAGS) -fno-exceptions -fno-rtti LDFLAGS= CC=gcc CFLAGS=-O3 -fomit-frame-pointer ## Compaq C++ V6.3-011 for Digital UNIX V4.0G (Rev. 1530) #CXX=cxx #CXXFLAGS=$(CFLAGS) -nocleanup -nortti #LDFLAGS= #CC=cc #CFLAGS=-arch host -tune host -assume trusted_short_alignment -assume noptrs_to_globals -compress -O5 -om -w1 -std strict_ansi_errors TARGETS = lbt lbt2dot LBTOBJS = Ltl.o LtlGraph.o BitVector.o lbt.o L2DOBJS = lbt2dot.o OBJS = $(LBTOBJS) $(L2DOBJS) MANPAGES = lbt.1 lbt2dot.1 all: $(TARGETS) clean: $(RM) $(OBJS) reallyclean: clean $(RM) $(TARGETS) install: $(TARGETS) $(INSTALLDIR) $(BINDIR) $(DOCDIR) $(INSTALLBIN) lbt lbt2dot $(BINDIR) $(INSTALLDATA) doc/* $(DOCDIR) installman: $(MANPAGES) $(INSTALLDIR) $(MANDIR) $(INSTALLDATA) $(MANPAGES) $(MANDIR) lbt: $(LBTOBJS) $(CXX) -o $@ $(LBTOBJS) $(LDFLAGS) lbt2dot: $(L2DOBJS) $(CC) -o $@ $(L2DOBJS) $(LDFLAGS) .C.o: $(CXX) $(CXXFLAGS) -c $< -o $@ .c.o: $(CC) $(CFLAGS) -c $< -o $@ .phony: all clean reallyclean install installman .SUFFIXES: .SUFFIXES: .C .c .o Ltl.o LtlGraph.o lbt.o: Ltl.h LtlGraph.h BitVector.h BitVector.o: BitVector.h lbt-1.2.2/BitVector.C0000644000175000017500000000017007354045137015716 0ustar msmakelamsmakela00000000000000// -*- c++ -*- /// @file BitVector.C #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "BitVector.h" lbt-1.2.2/Ltl.C0000644000175000017500000001405610130332251014536 0ustar msmakelamsmakela00000000000000// -*- c++ -*- /// @file Ltl.C /* * This file is based on code originally written by Mauno Rnkk, * Copyright 1998 Mauno Rnkk . * * Modifications by Heikki Tauriainen * and Marko Mkel . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "Ltl.h" #include "LtlGraph.h" #include Ltl::Store Ltl::m_store; class Ltl& Ltl::Store::insert (class Ltl& ltl) { std::pair::iterator,bool> p = m_set.insert (<l); if (!p.second) delete <l; else { // new formula: add it to the translation table unsigned num = m_set.size (); if (!(num & (num - 1))) { const class Ltl** table = new const class Ltl*[num << 1]; memcpy (table, m_table, (num - 1) * sizeof *m_table); delete[] m_table; m_table = table; } m_table[ltl.m_num = num - 1] = <l; } return **p.first; } bool Ltl::operator< (const class Ltl& other) const { if (getKind () < other.getKind ()) return true; if (other.getKind () < getKind ()) return false; switch (getKind ()) { case Atom: return static_cast(*this) < static_cast(other); case Constant: return static_cast(*this) < static_cast(other); case Junct: return static_cast(*this) < static_cast(other); case Iff: return static_cast(*this) < static_cast(other); case Future: return static_cast(*this) < static_cast(other); case Until: return static_cast(*this) < static_cast(other); } assert (false); return false; } void LtlAtom::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (!node.m_old[negClone ().m_num]) node.m_atomic.assign_true (m_num); else { to_expand.pop (); delete &node; } } void LtlConstant::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (!m_true) { to_expand.pop (); delete &node; } } void LtlJunct::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (m_con) { if (!node.m_old[m_left.m_num]) node.m_new.assign_true (m_left.m_num); if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); } else { class BitVector new_set (node.m_new); if (!node.m_old[m_left.m_num]) new_set.assign_true (m_left.m_num); if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, node.m_next)); } } void LtlIff::expand (class LtlGraphNode& node, std::stack& to_expand) const { class BitVector new_set (node.m_new); class Ltl& neg_left = m_left.negClone (); class Ltl& neg_right = m_right.negClone (); if (!node.m_old[m_left.m_num]) node.m_new.assign_true (m_left.m_num); if (!new_set[neg_left.m_num]) new_set.assign_true (neg_left.m_num); if (m_iff) { if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); if (!new_set[neg_right.m_num]) new_set.assign_true (neg_right.m_num); } else { if (!node.m_old[neg_right.m_num]) node.m_new.assign_true (neg_right.m_num); if (!new_set[m_right.m_num]) new_set.assign_true (m_right.m_num); } to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, node.m_next)); } void LtlUntil::expand (class LtlGraphNode& node, std::stack& to_expand) const { if (m_release) { if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); class BitVector new_set (node.m_new); if (!node.m_old[m_left.m_num]) node.m_new.assign_true (m_left.m_num); class BitVector next_set (node.m_next); next_set.assign_true (m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, next_set)); } else { class BitVector new_set (node.m_new); if (!node.m_old[m_left.m_num]) new_set.assign_true (m_left.m_num); if (!node.m_old[m_right.m_num]) node.m_new.assign_true (m_right.m_num); class BitVector next_set (node.m_next); next_set.assign_true (m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, next_set)); } } void LtlFuture::expand (class LtlGraphNode& node, std::stack& to_expand) const { switch (m_op) { case next: node.m_next.assign_true (m_formula.m_num); return; case finally: { class BitVector new_set (node.m_new); if (!node.m_old[m_formula.m_num]) new_set.assign_true (m_formula.m_num); to_expand.push (new class LtlGraphNode (node.m_incoming, new_set, node.m_old, node.m_atomic, node.m_next)); } break; case globally: if (!node.m_old[m_formula.m_num]) node.m_new.assign_true (m_formula.m_num); break; #ifndef NDEBUG default: assert (false); #endif // NDEBUG } node.m_next.assign_true (m_num); } lbt-1.2.2/LtlGraph.C0000644000175000017500000000506010130332251015513 0ustar msmakelamsmakela00000000000000// -*- c++ -*- /// @file LtlGraph.C /* * This file is based on code originally written by Mauno Rnkk, * Copyright 1998 Mauno Rnkk . * * Modifications by Heikki Tauriainen * and Marko Mkel . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __GNUC__ # pragma implementation #endif // __GNUC__ #include "LtlGraph.h" #include /// An empty formula set static const class BitVector e; LtlGraph::LtlGraph (const class Ltl& formula) : m_next (1), m_nodes () { std::stack nodes_to_expand; std::set incoming; incoming.insert (0); class BitVector new_set (formula.m_num + 1); new_set.assign_true (formula.m_num); nodes_to_expand.push (new class LtlGraphNode (incoming, new_set, e, e, e)); expand_next_node: while (!nodes_to_expand.empty ()) { class LtlGraphNode& node = *nodes_to_expand.top (); if (unsigned p = node.m_new.nonzero ()) { p--; node.m_old.assign_true (p); node.m_new.assign_false (p); Ltl::fetch (p).expand (node, nodes_to_expand); continue; } nodes_to_expand.pop (); // no new propositions: merge the node with the graph // search for an existing node having the same 'old' and 'next' sets for (iterator i = m_nodes.begin (); i != m_nodes.end (); i++) { if (i->second.m_old == node.m_old && i->second.m_next == node.m_next) { // merge the node with an existing one i->second.m_incoming.insert (node.m_incoming.begin(), node.m_incoming.end()); delete &node; goto expand_next_node; } } // a genuinely new node: insert it to the graph and expand further m_nodes.insert (std::pair (m_next, node)); std::set incoming; incoming.insert (m_next++); nodes_to_expand.push (new class LtlGraphNode (incoming, node.m_next, e, e, e)); delete &node; } } lbt-1.2.2/lbt.C0000644000175000017500000001577207356541216014615 0ustar msmakelamsmakela00000000000000/// @file lbt.C /// The main program of lbt /* * Copyright 2001 Heikki Tauriainen * Copyright 2001 Marko Mkel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** @mainpage LBT: LTL to Bchi Translator * @htmlonly * Please visit also the * LBT home page. * @endhtmlonly */ #include "LtlGraph.h" #include /** Read an LTL formula from standard input * @param negation flag: negate the formula * @return the parsed formula, or NULL on error */ static class Ltl* readFormula (bool negation) { int ch; class Ltl *left, *right; loop: while ((ch = getchar ()) == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\v' || ch == '\f'); switch (ch) { case 't': case 'f': return &LtlConstant::construct ((ch == 'f') == negation); case 'p': if (1 == scanf ("%u", &ch)) return &LtlAtom::construct (ch, negation); fputs ("error in proposition number\n", stderr); return 0; case '!': negation = !negation; goto loop; case '&': case '|': if ((left = readFormula (negation)) && (right = readFormula (negation))) return &LtlJunct::construct ((ch == '&') != negation, *left, *right); return 0; case 'i': if ((left = readFormula (!negation)) && (right = readFormula (negation))) return &LtlJunct::construct (negation, *left, *right); return 0; case 'e': case '^' : if ((left = readFormula (false)) && (right = readFormula (false))) return &LtlIff::construct ((ch == 'e') != negation, *left, *right); return 0; case 'X': return (left = readFormula (negation)) ? &LtlFuture::construct (LtlFuture::next, *left) : 0; case 'F': case 'G': return (left = readFormula (negation)) ? &LtlFuture::construct ((ch == 'F') == negation ? LtlFuture::globally : LtlFuture::finally, *left) : 0; case 'U': case 'V': if ((left = readFormula (negation)) && (right = readFormula (negation))) return &LtlUntil::construct ((ch == 'U') == negation, *left, *right); case EOF: fputs ("unexpected end of file while parsing formula\n", stderr); return 0; default: fprintf (stderr, "unknown character 0x%02x\n", ch); return 0; } } /** Display the gates for arcs leaving a specific Bchi automaton state * @param gba the generalized Bchi automaton * @param state the state whose successor arcs are to be displayed */ static void printGates (const class LtlGraph& gba, unsigned state) { for (LtlGraph::const_iterator n = gba.begin (); n != gba.end (); n++) { if (n->second.m_incoming.find (state) == const_cast&>(n->second.m_incoming).end ()) continue; const class BitVector& propositions = n->second.m_atomic; printf ("%u ", n->first); /** Previously encountered gate expression */ const class LtlAtom* gate = 0; for (unsigned i = propositions.nonzero (); i; ) { if (gate) printf (gate->isNegated () ? "& ! p%u " : "& p%u ", gate->getValue ()); gate = &static_cast(Ltl::fetch (i - 1)); if (i) i = propositions.findNext (i); } if (gate) printf (gate->isNegated () ? "! p%u\n" : "p%u\n", gate->getValue ()); else puts ("t"); } puts ("-1"); } /** Translate a formula and output the automaton to standard output * @param formula the formula to be translated */ static void translateFormula (const class Ltl& formula) { /** The generalized Bchi automaton */ class LtlGraph gba (formula); /** acceptance set number and proposition */ typedef std::pair acceptance_set_t; typedef std::map acceptance_map_t; acceptance_map_t acceptance_sets; /** number of states */ unsigned numStates = 0; /** iterator to states */ LtlGraph::const_iterator s; // construct the acceptance sets for (s = gba.begin (); s != gba.end (); s++) { numStates++; const class BitVector& temporal = s->second.m_old; for (unsigned i = temporal.nonzero (); i; ) { const class Ltl& f = Ltl::fetch (i - 1); switch (f.getKind ()) { case Ltl::Until: if (!static_cast(f).isRelease ()) acceptance_sets.insert (std::pair (&f, acceptance_set_t (acceptance_sets.size (), &static_cast (f).getRight ()))); break; case Ltl::Future: if (static_cast(f).getOp () == LtlFuture::finally) acceptance_sets.insert (std::pair (&f, acceptance_set_t (acceptance_sets.size (), &static_cast (f).getFormula ()))); break; default: break; } if (i) i = temporal.findNext (i); } } if (numStates) { printf ("%u %u", numStates + 1, acceptance_sets.size ()); puts ("\n0 1 -1"); printGates (gba, 0); } else puts ("0 0"); for (s = gba.begin (); s != gba.end (); s++) { printf ("%u 0", s->first); const class BitVector& temporal = s->second.m_old; // determine and display the acceptance sets the state belongs to for (acceptance_map_t::iterator a = acceptance_sets.begin (); a != acceptance_sets.end (); a++) { /** flag: does the state belong to the acceptance set? */ bool accepting = true; for (unsigned i = temporal.nonzero (); i; ) { const class Ltl* f = &Ltl::fetch (i - 1); if (f == a->second.second) { accepting = true; break; } else if (f == a->first) accepting = false; if (i) i = temporal.findNext (i); } if (accepting) printf (" %u", a->second.first); } puts (" -1"); printGates (gba, s->first); } } int main(int argc, char* argv[]) { if (argc > 1) { fputs ("usage: ", stderr); fputs (*argv, stderr); fputs (" < formula.txt > automaton.txt\n", stderr); return 1; } if (class Ltl* formula = readFormula (false)) { translateFormula (*formula); int ch; while ((ch = getchar ()) == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\v' || ch == '\f'); if (ch != EOF) { fputs ("ignoring extraneous input: '", stderr); do putc (ch, stderr); while ((ch = getchar ()) != EOF); fputs ("'\n", stderr); return 2; } } else return 2; return 0; } lbt-1.2.2/BitVector.h0000644000175000017500000001265707356544274016010 0ustar msmakelamsmakela00000000000000// -*- c++ -*- /// @file BitVector.h /* * Copyright 2001 Marko Mkel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef BITVECTOR_H_ # define BITVECTOR_H_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include # include /** Binary digit (bit) vector */ class BitVector { public: /** machine word */ typedef unsigned long word_t; /** Constructor * @param size number of elements in the vector */ explicit BitVector (unsigned size = 0) : m_size (0), m_allocated (1), m_bits (new word_t[1]) { *m_bits = 0; setSize (size); } /** Copy constructor */ explicit BitVector (const class BitVector& old) : m_size (old.m_size), m_allocated (old.m_allocated), m_bits (0) { memcpy (m_bits = new word_t[m_allocated], old.m_bits, m_allocated * sizeof (word_t)); } private: /** Assignment operator */ class BitVector& operator= (const class BitVector& old); public: /** Destructor */ ~BitVector () { delete[] m_bits; } /** Equality comparison * @param other other bit vector to compare this against * @return true if the bit vectors are identical, * treating missing bits as unset */ bool operator== (const class BitVector& other) const { unsigned tsize = getNumWords (m_size), osize = getNumWords (other.m_size); if (tsize < osize) { if (memcmp (m_bits, other.m_bits, tsize * sizeof (word_t))) return false; for (register const word_t* bits = other.m_bits + osize; bits-- > other.m_bits + tsize; ) if (*bits) return false; } else { if (memcmp (m_bits, other.m_bits, osize * sizeof (word_t))) return false; for (register const word_t* bits = m_bits + tsize; bits-- > m_bits + osize; ) if (*bits) return false; } return true; } /** Determine the number of words the specified amount of bits occupy */ static unsigned getNumWords (unsigned bits) { const unsigned bitsPerWord = CHAR_BIT * sizeof (word_t); return (bits + bitsPerWord - 1) / bitsPerWord; } /** Set the size of the vector * @param size the new size of the vector */ void setSize (unsigned size) { const unsigned numWords = getNumWords (size); if (m_allocated < numWords) { while (m_allocated < numWords) m_allocated <<= 1; word_t* bits = new word_t[m_allocated]; const unsigned init = getNumWords (m_size); memcpy (bits, m_bits, init * sizeof *m_bits); memset (bits + init, 0, (m_allocated - init) * sizeof *m_bits); delete[] m_bits; m_bits = bits; } m_size = size; } /** Determine the size of the vector * @return the size of the vector */ unsigned getSize () const { return m_size; } /** Read a binary digit * @param i zero-based index of the element * @return value of the ternary digit */ bool operator[] (unsigned i) const { return i < m_size && m_bits[i / (CHAR_BIT * sizeof (word_t))] & (word_t (1) << (i % (CHAR_BIT * sizeof (word_t)))); } /** Set a binary digit * @param i zero-based index of the element */ void assign_true (unsigned i) { if (i >= m_size) setSize (i + 1); m_bits[i / (CHAR_BIT * sizeof (word_t))] |= word_t (1) << (i % (CHAR_BIT * sizeof (word_t))); } /** Clear a binary digit * @param i zero-based index of the element */ void assign_false (unsigned i) { m_bits[i / (CHAR_BIT * sizeof (word_t))] &= ~(word_t (1) << (i % (CHAR_BIT * sizeof (word_t)))); } /** Determine whether the whole vector is filled with zero bits * @return 0 if all bits in the vector are clear; * index of a nonzero entry + 1 otherwise */ unsigned nonzero () const { if (!m_size) return 0; return findNext (0); } /** Find the next index at which there is a set bit * @param i the starting index (counting forward) * @return 0 if all following bits in the vector are clear; * index of the next nonzero entry + 1 otherwise */ unsigned findNext (unsigned i) const { if (i >= m_size) return 0; register const word_t* w = &m_bits[i / (CHAR_BIT * sizeof (word_t))]; register word_t bit = 1 << (i % (CHAR_BIT * sizeof (word_t))); if (*w >= bit) { // found in the same word do if (*w & bit) return i + 1; while (i++, bit <<= 1); } const word_t* const w_end = m_bits + getNumWords (m_size); // search in the remaining words while (++w < w_end) { if (!*w) continue; for (i = 1, bit = 1; !(*w & bit); bit <<= 1, i++); return i + (w - m_bits) * CHAR_BIT * sizeof (word_t); } return 0; } private: /** Number of elements in the vector */ unsigned m_size; /** Size of the allocated vector in words */ unsigned m_allocated; /** The vector */ word_t* m_bits; }; #endif // BITVECTOR_H_ lbt-1.2.2/Ltl.h0000644000175000017500000004154410130332251014605 0ustar msmakelamsmakela00000000000000// -*- c++ -*- /// @file Ltl.h /* * This file is based on code originally written by Mauno Rnkk, * Copyright 1998 Mauno Rnkk . * * Modifications by Heikki Tauriainen * and Marko Mkel . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef Ltl_h_ # define Ltl_h_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # ifdef DEBUG # include # endif // DEBUG # include # include /** Abstract base class for LTL formulae */ class Ltl { public: /// LTL formula comparator struct ltless { /// Lexicographic order of LTL formulae /// @param l1 pointer to first formula to compare /// @param l2 pointer to second formula to compare /// @return true if l1 is before l2 bool operator() (const class Ltl* l1, const class Ltl* l2) const { return *l1 < *l2; } }; private: /// Set of instantiated LTL formulae class Store { private: /// Set of LTL formulae std::set m_set; /// Table of LTL formulae, indexed by Ltl::m_num const class Ltl** m_table; /// Copy constructor Store (const class Store&); /// Assignment operator class Store& operator= (const class Store&); public: /// Constructor Store () : m_set (), m_table (0) {} /// Destructor ~Store () { delete[] m_table; for (std::set::iterator i = m_set.begin (); i != m_set.end (); i++) { delete *i; } } /// Insert a formula to the set class Ltl& insert (class Ltl& ltl); /// Translate a formula index to a formula reference /// @param f formula index to be translated /// @return the corresponding formula const class Ltl& fetch (unsigned f) const { return *m_table[f]; } }; static class Store m_store; friend class Store; public: /// Number of the LTL formula unsigned m_num; /// Constructor Ltl () : m_num (0) {} private: /// Copy constructor Ltl (const class Ltl& old); /// Assignment operator class Ltl& operator= (const class Ltl& old); protected: /// Destructor virtual ~Ltl () {} /// Reference registrator /// @param ltl formula to be registered /// @return an equivalent formula static class Ltl& insert (class Ltl& ltl) { return m_store.insert (ltl); } public: /// Translate a formula index to a formula reference /// @param f formula index to be translated /// @return the corresponding formula static const class Ltl& fetch (unsigned f) { return m_store.fetch (f); } /// Returns a clone of the negation of this Ltl formula. virtual class Ltl& negClone () const = 0; /// Formula kinds enum Kind { Atom, Constant, Junct, Iff, Future, Until }; /// Determine the kind of the formula virtual enum Kind getKind () const = 0; /// Less-than comparison bool operator< (const class Ltl& other) const; /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded virtual void expand (class LtlGraphNode& node, std::stack& to_expand) const = 0; # ifdef DEBUG /// Stream output virtual void display (FILE* out) const = 0; # endif // DEBUG }; /** LTL atom */ class LtlAtom : public Ltl { private: /// The proposition number unsigned m_value; /// Flag: is the proposition negated? bool m_negated; public: /// Constructor /// @param value proposition number /// @param negated flag: is the proposition negated? /// @return an LTL atom static class Ltl& construct (unsigned value, bool negated) { return insert (*new class LtlAtom (value, negated)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlAtom (m_value, !m_negated)); } private: /// Constructor LtlAtom (unsigned value, bool negated = false) : Ltl (), m_value (value), m_negated (negated) {} /// Copy constructor LtlAtom (const class LtlAtom& old); /// Assignment operator class LtlAtom& operator= (const class LtlAtom& old); protected: /// Destructor ~LtlAtom () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Atom; } /// Less-than comparison bool operator< (const class LtlAtom& other) const { return m_value < other.m_value || (m_value == other.m_value && m_negated < other.m_negated); } /// Determine whether the atom is negated bool isNegated () const { return m_negated; } /// Determine the value of the proposition unsigned getValue () const { return m_value; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { if (m_negated) fputs ("! ", out); fprintf (out, "p%u", m_value); } # endif // DEBUG }; /** LTL constants 'true' and 'false' */ class LtlConstant : public Ltl { private: /// The truth value of the constant bool m_true; public: /// Constructor /// @param true_ the constant 'true' or 'false' /// @return an LTL constant static class Ltl& construct (bool true_) { return insert (*new class LtlConstant (true_)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlConstant (!m_true)); } private: /// Constructor LtlConstant (bool true_) : Ltl (), m_true (true_) {} /// Copy constructor LtlConstant (const class LtlConstant& old); /// Assignment operator class LtlConstant& operator= (const class LtlConstant& old); protected: /// Destructor ~LtlConstant () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Constant; } /// Less-than comparison bool operator< (const class LtlConstant& other) const { return m_true < other.m_true; } /// Convert to truth value operator bool () const { return m_true; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { putc (m_true ? 't' : 'f', out); } # endif // DEBUG }; /** LTL conjunction and disjunction */ class LtlJunct : public Ltl { private: /// Flag: conjunction instead of disjunction? bool m_con; /// The left-hand-side sub-formula class Ltl& m_left; /// The right-hand-side sub-formula class Ltl& m_right; public: /// Optimizing constructor /// @param con flag: conjunction instead of disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula /// @return an equivalent formula static class Ltl& construct (bool con, class Ltl& l, class Ltl& r) { if (l.getKind () == Ltl::Constant) return bool (static_cast(l)) == con ? r : l; if (r.getKind () == Ltl::Constant) return bool (static_cast(r)) == con ? l : r; if (&l == &r) return l; return &l < &r ? insert (*new class LtlJunct (con, l, r)) : insert (*new class LtlJunct (con, r, l)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlJunct (!m_con, m_left.negClone (), m_right.negClone ())); } private: /// Constructor /// @param con flag: conjunction instead of disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula LtlJunct (bool con, class Ltl& l, class Ltl& r) : m_con (con), m_left (l), m_right (r) {} /// Copy constructor LtlJunct (const class LtlJunct& old); /// Assignment operator class LtlJunct& operator= (const class LtlJunct& old); protected: /// Destructor ~LtlJunct () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Junct; } /// Less-than comparison bool operator< (const class LtlJunct& other) const { if (m_con < other.m_con) return true; if (other.m_con < m_con) return false; if (&m_left < &other.m_left) return true; if (&other.m_left < &m_left) return false; return &m_right < &other.m_right; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { fputs (m_con ? "& " : "| ", out); m_left.display (out); putc (' ', out); m_right.display (out); } # endif // DEBUG }; /** LTL equivalence or exclusive disjunction */ class LtlIff : public Ltl { private: /// Flag: equivalence instead of exclusive disjunction? bool m_iff; /// The left-hand-side sub-formula class Ltl& m_left; /// The right-hand-side sub-formula class Ltl& m_right; public: /// Optimizing constructor /// @param iff flag: equivalence instead of exclusive disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula /// @return an equivalent formula static class Ltl& construct (bool iff, class Ltl& l, class Ltl& r) { if (l.getKind () == Ltl::Constant) return bool (static_cast(l)) == iff ? r : r.negClone (); if (r.getKind () == Ltl::Constant) return bool (static_cast(r)) == iff ? l : l.negClone (); if (&l == &r) return LtlConstant::construct (iff); return &l < &r ? insert (*new class LtlIff (iff, l, r)) : insert (*new class LtlIff (iff, r, l)); } /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlIff (!m_iff, m_left, m_right)); } private: /// Constructor /// @param iff flag: equivalence instead of exclusive disjunction /// @param l the left-hand-side formula /// @param r the right-hand-side formula LtlIff (bool iff, class Ltl& l, class Ltl& r) : m_iff (iff), m_left (l), m_right (r) {} /// Copy constructor LtlIff (const class LtlIff& old); /// Assignment operator class LtlIff& operator= (const class LtlIff& old); protected: /// Destructor ~LtlIff () {} public: /// Determine the kind of the formula enum Kind getKind () const {return Iff; } /// Less-than comparison bool operator< (const class LtlIff& other) const { if (m_iff < other.m_iff) return true; if (other.m_iff < m_iff) return false; if (&m_left < &other.m_left) return true; if (&other.m_left < &m_left) return false; return &m_right < &other.m_right; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { fputs (m_iff ? "e " : "^ ", out); m_left.display (out); putc (' ', out); m_right.display (out); } # endif // DEBUG }; /** LTL next-time, globally and finally formulae */ class LtlFuture : public Ltl { public: /// Operator kinds enum Op { next, globally, finally }; private: /// The operator enum Op m_op; /// The formula being quantified class Ltl& m_formula; public: /// Constructor /// @param op the operator /// @param f the formula /// @return an LTL future formula static class Ltl& construct (enum Op op, class Ltl& f) { return insert (*new class LtlFuture (op, f)); } /// Returns a clone of the negation of this formula. class Ltl& negClone () const { switch (m_op) { case next: break; case globally: return insert (*new class LtlFuture (finally, m_formula.negClone ())); case finally: return insert (*new class LtlFuture (globally, m_formula.negClone ())); } return insert (*new class LtlFuture (m_op, m_formula.negClone ())); } private: /// Constructor /// @param op the operator /// @param f the formula /// @param r the right-hand-side formula LtlFuture (enum Op op, class Ltl& f) : m_op (op), m_formula (f) {} /// Copy constructor LtlFuture (const class LtlFuture& old); /// Assignment operator class LtlFuture& operator= (const class LtlFuture& old); protected: /// Destructor ~LtlFuture () {} public: /// Determine the kind of the formula enum Kind getKind () const { return Future; } /// Less-than comparison bool operator< (const class LtlFuture& other) const { if (m_op < other.m_op) return true; if (other.m_op < m_op) return false; return &m_formula < &other.m_formula; } /// Get the temporal operator enum Op getOp () const { return m_op; } /// Get the subformula const class Ltl& getFormula () const { return m_formula; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { switch (m_op) { case next: putc ('X', out); break; case globally: putc ('G', out); break; case finally: putc ('F', out); break; } putc (' ', out); m_formula.display (out); } # endif // DEBUG }; /** LTL 'until' and 'release' operators */ class LtlUntil : public Ltl { private: /// Flag: release instead of until bool m_release; /// The left-hand-side sub-formula class Ltl& m_left; /// The right-hand-side sub-formula class Ltl& m_right; public: /// Constructor /// @param release flag: 'release' instead of 'until' /// @param l the left-hand-side formula /// @param r the right-hand-side formula /// @return an LTL formula static class Ltl& construct (bool release, class Ltl& l, class Ltl& r) { return insert (*new class LtlUntil (release, l, r)); } private: /// Constructor /// @param release flag: 'release' instead of 'until' /// @param l the left-hand-side formula /// @param r the right-hand-side formula LtlUntil (bool release, class Ltl& l, class Ltl& r) : m_release (release), m_left (l), m_right (r) {} /// Copy constructor LtlUntil (const class LtlUntil& old); /// Assignment operator class LtlUntil& operator= (const class LtlUntil& old); public: /// Destructor ~LtlUntil () {} /// Returns a clone of the negation of this Ltl formula. class Ltl& negClone () const { return insert (*new class LtlUntil (!m_release, m_left.negClone (), m_right.negClone ())); } /// Determine the kind of the formula enum Kind getKind () const { return Until; } /// Less-than comparison bool operator< (const class LtlUntil& other) const { if (m_release < other.m_release) return true; if (other.m_release < m_release) return false; if (&m_left < &other.m_left) return true; if (&other.m_left < &m_left) return false; return &m_right < &other.m_right; } /// Determine whether this is a release operator instead of until bool isRelease () const { return m_release; } /// Get the left-hand-side subformula const class Ltl& getLeft () const { return m_left; } /// Get the right-hand-side subformula const class Ltl& getRight () const { return m_right; } /// Implements operator/operand specific details of the expansion algorithm. /// @param node the node representing the formula /// @param to_expand stack of nodes to be expanded void expand (class LtlGraphNode& node, std::stack& to_expand) const; # ifdef DEBUG /// Stream output void display (FILE* out) const { fputs (m_release ? "V " : "U ", out); m_left.display (out); putc (' ', out); m_right.display (out); } # endif // DEBUG }; #endif // Ltl_h_ lbt-1.2.2/LtlGraph.h0000644000175000017500000000752610130332251015571 0ustar msmakelamsmakela00000000000000// -*- c++ -*- /// @file LtlGraph.h /* * This file is based on code originally written by Mauno Rnkk, * Copyright 1998 Mauno Rnkk . * * Modifications by Heikki Tauriainen * and Marko Mkel . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef LtlGraph_h_ # define LtlGraph_h_ # ifdef __GNUC__ # pragma interface # endif // __GNUC__ # include "Ltl.h" # include "BitVector.h" # include /** * A node in a graph representing an LTL formula. * * The graph itself is a set of nodes of this kind. * The LtlGraphNode class is merely a front end for the set representation. */ class LtlGraphNode { public: /// From which nodes can one come to this node. std::set m_incoming; /// A set of formulae to be processed. class BitVector m_new; /// A set of formulae that must hold, when this node is entered. class BitVector m_old; /// A set of atomic propositions that must hold, when this node is entered. class BitVector m_atomic; /// A set of formulae that must hold in immediate next nodes. class BitVector m_next; /// Default constructor LtlGraphNode () : m_incoming (), m_new (), m_old (), m_atomic (), m_next () {} /// Constructs a specific node. LtlGraphNode (const std::set& incoming, const class BitVector& neww, const class BitVector& old, const class BitVector& atomic, const class BitVector& next) : m_incoming (incoming), m_new (neww), m_old (old), m_atomic (atomic), m_next (next) {} /// Copy constructor LtlGraphNode (const class LtlGraphNode& node) : m_incoming (node.m_incoming), m_new (node.m_new), m_old (node.m_old), m_atomic (node.m_atomic), m_next (node.m_next) {} private: /// Assignment operator class LtlGraphNode& operator= (const class LtlGraphNode& node); public: /// Destructor ~LtlGraphNode () {} }; /** * Graph representation of a generalized Bchi automaton * corresponding to an LTL formula * * A LtlGraph is automatically constructed from a given * Ltl formula. All relevant information is fully stored to the * graph, so that the formula itself may well be destoyed right after * the conversion. The Ltl operators/operands provide themselves * the knowledge of how to be expanded into a LtlGraph. */ class LtlGraph { public: /*@{*/ /// Map from state numbers to graph nodes typedef std::map Map; /// Iterator to the map typedef Map::iterator iterator; /// Constant iterator to the map typedef Map::const_iterator const_iterator; /*@}*/ private: /// Next available state number unsigned m_next; /// Map from state numbers to graph nodes (0=initial state) std::map m_nodes; private: /// Copy constructor LtlGraph (const class LtlGraph& old); /// Assignment operator class LtlGraph& operator= (const class LtlGraph& other); public: /// Constructs a graph from a given LTL formula. LtlGraph (const class Ltl& formula); /// Destructor ~LtlGraph () {} /** @name Accessors to the graph nodes */ /*@{*/ const_iterator begin () const { return m_nodes.begin (); } const_iterator end () const { return m_nodes.end (); } /*@}*/ }; #endif // LtlGraph_h_ lbt-1.2.2/lbt2dot.c0000644000175000017500000000740507332461326015435 0ustar msmakelamsmakela00000000000000/** * @file lbt2dot.c * This filter converts an lbt-generated automaton to a GraphViz digraph * @author Marko.Makela@hut.fi (Marko Mkel) */ /* * * Copyright 2001 Marko Mkel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include /** Copy a gate condition from standard input to standard output * @return zero if everything is ok; nonzero on error */ static int parseGate (void) { int ch; loop: while (isspace (ch = fgetc (stdin))); fputc (ch, stdout); switch (ch) { case 't': case 'f': return 0; case '|': case '&': case 'i': case 'e': if (parseGate ()) return 1; case '!': goto loop; case 'p': if (1 != fscanf (stdin, "%d", &ch)) { fputs ("error in proposition number\n", stderr); return 1; } fprintf (stdout, "%d", ch); return 0; case EOF: fputs ("unexpected end of file while parsing formula\n", stderr); return 2; default: fprintf (stderr, "unknown character 0x%02x", ch); return 2; } } /** The main program * @param argc number of command-line arguments * @param argv the command-line arguments */ int main (int argc, char** argv) { /** State counter */ unsigned i; /** Generic number */ unsigned num; /** a character */ int ch; if (2 != fscanf (stdin, "%u%u", &i, &num)) { parseError: fputs ("error in automaton\n", stderr); semanticError: return 1; } fputs ("digraph g {\n", stdout); while (i--) { /** separator between acceptance set entries */ const char* separator = "\\n"; /** the state number */ unsigned state; /* read the state number and "initial state" flag */ if (2 != fscanf (stdin, "%u%u", &state, &num) || num > 1) goto parseError; fprintf (stdout, "%u", state); fputs ("[", stdout); if (num) /* initial state */ fputs ("style=filled,", stdout); fprintf (stdout, "label=\"%u", state); /* acceptance sets that the state belongs to */ for (;;) { while (isspace (ch = fgetc (stdin))); if (ch == '-') { if (1 != fscanf (stdin, "%u", &num) || 1 != num) { fputs ("unexpected data after '-'\n", stderr); goto semanticError; } break; } ungetc (ch, stdin); if (!isdigit (ch) || 1 != fscanf (stdin, "%u", &num)) goto parseError; fprintf (stdout, "%s%u", separator, num); separator = ","; } fputs ("\"];\n", stdout); /* transitions */ for (;;) { while (isspace (ch = fgetc (stdin))); if (ch == '-') { if (1 != fscanf (stdin, "%u", &num) || 1 != num) { fputs ("unexpected data after '-'\n", stderr); goto semanticError; } break; } ungetc (ch, stdin); if (!isdigit (ch) || 1 != fscanf (stdin, "%u", &num)) goto parseError; fprintf (stdout, "%u->%u[label=\"", state, num); if (parseGate ()) goto parseError; fputs ("\"];\n", stdout); } } fputs ("}\n", stdout); while (isspace (ch = fgetc (stdin))); if (ch != EOF) { fputs ("extraneous non-whitespace data at end of input\n", stderr); goto semanticError; } return 0; } lbt-1.2.2/ChangeLog0000644000175000017500000000274110164617064015466 0ustar msmakelamsmakela000000000000002004-12-29 Marko Mkel * NEWS: Release 1.2.2, 29th December 2004 2004-12-27 Marko Mkel * ChangeLog, NEWS: Moved up one level from doc/ChangeLog * Makefile: Merge with lbt 1.1.1 * NEWS, doc/index.html: Update for lbt 1.2.2 2004-09-03 Heikki Tauriainen * LtlGraph.h (LtlGraph::expand, LtlGraph::add): Remove. * LtlGraph.C: Include the header. (LtlGraph::LtlGraph): Use an explicit stack of pointers to unexpanded nodes (instead of recursion) to drive node expansion. Use STL operations for merging sets. (LtlGraph::expand): Remove. * Ltl.C (LtlAtom::expand, LtlConstant::expand, LtlJunct::expand) (LtlIff::expand, LtlUntil::expand, LtlFuture::expand): Adjust to make use of a stack of unexpanded nodes. Remove redundant state number arguments. * Ltl.h: Include the header. (Ltl::expand, LtlAtom::expand, LtlConstant::expand) (LtlJunct::expand, LtlIff::expand, LtlUntil::expand) (LtlFuture::expand): Adjust prototypes. 2002-04-19 Marko Mkel lbt 1.2.1 was released. * NEWS: Described these changes. * notgp0.png, notgp0-opt.png: Rendered with anti-aliased fonts. * index.html: Corrected a few minor errors in the grammar, and updated the address of Mauno Rnkk. 2001-10-03 Marko Mkel lbt 1.2 was released. * NEWS: Initial revision * BitVector.h, BitVector.C: Initial revision * Makefile: Added a few variable definitions lbt-1.2.2/NEWS0000644000175000017500000000467110164616751014421 0ustar msmakelamsmakela00000000000000LBT NEWS -- history of user-visible changes. 29th December 2004 Copyright 2001,2002,2004 Marko Mkel Copyright 2004 Heikki Tauriainen See the end for copying conditions. * LBT 1.2.2 and LBT 1.1.1 fix problems with run-time stack overflow (no user-visible changes) ** The use of recursion in previous versions of LBT may lead to a crash with large input formulae due to run-time stack overflow. LBT 1.1.1 and LBT 1.2.2 attempt to improve the robustness of the tool by replacing recursion with explicit stacks. The difference between LBT 1.1.1 and LBT 1.2.2 is the same as the difference between LBT 1.2 and LBT 1.1, i.e., LBT 1.2.2 may be more efficient on small input formulae. * LBT 1.2.1 improves the documentation only ** A few minor errors were corrected in the grammar description. ** The pictures of the automata were redrawn with anti-aliased fonts. * LBT 1.2 is an optimized release with no user-visible changes ** Formula sets are now maintained in bit vectors instead of Standard Template Library sets. This typically reduces the memory usage and improves the speed of the program. The generated automata should be of the same size as with LBT 1.1, but the acceptance sets for the states can be displayed in a slightly different order. * New operators in LBT 1.1 ** The equivalence and nonequivalence (exclusive or) operators are supported natively by the translation algorithm of LBT 1.1. When these operators are implemented in the core language, formulae that contain these operators can be expressed in a much more compact way. * LBT 1.0 ** A complete rewrite of the algorithms from Mauno Rnkk's LBT2BUCHI and Heikki Tauriainen's super_aasa_lbt. ** Common subformula elimination reduces the size of the generated automata. ---------------------------------------------------------------------- Copyright information: Copyright 2001,2002,2004 Marko Mkel Copyright 2004 Heikki Tauriainen Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the copyright notice and this permission notice are preserved, thus giving the recipient permission to redistribute in turn. Permission is granted to distribute modified versions of this document, or of portions of it, under the above conditions, provided also that they carry prominent notices stating who last changed them. Local variables: mode: outline paragraph-separate: "[ ]*$" end: