Import of lbtt 1.1.0

This commit is contained in:
Alexandre Duret-Lutz 2004-07-07 16:40:50 +00:00
parent 15618b84ea
commit d7b3d97422
49 changed files with 13388 additions and 5404 deletions

View file

@ -1,3 +1,744 @@
2004-07-07 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* Version 1.1.0 released.
2004-07-06 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* configure.ac: Make detection of the need for obstack.h
compilation workaround with glibc 2.3.2 more accurate.
Remove check for single_client_alloc.
* src/LbttAlloc.h: Remove conditional definition of
the ALLOC macro.
* src/UserCommandReader.cc: Remove workaround for
compilation with gcc 2.95.
2004-07-02 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* doc/texinfo.tex: New upstream version.
* doc/lbtt.texi: Update to edition 1.1.0.
* NEWS: Update.
2004-07-02 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/UserCommandReader.cc (parseCommand): Recognize
`implementations' and `translators' as aliases of the
`algorithms' command.
* src/UserCommands.cc (printCommandHelp): List
`implementations' and `translators' as aliases of the
`algorithms' command.
2004-06-30 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/Configuration.h (CommandLineOptionType): Rearrange the
values to list constants with an explicit character value
first. Change the value of OPT_VERSION to `V'.
* src/Configuration.cc (Configuration::read): Treat the single-
character option `V' as an alias of the `--version' option.
(Configuration::showCommandLineHelp): Describe the `-V' option.
* src/translate.cc (main): Rename the single character option
`v' to `V'.
2004-06-29 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/BuchiAutomaton.h (BuchiAutomaton::regularize)
(BuchiAutomaton::intersect): Remove.
(BuchiAutomaton::BuchiTransition::print(_, _, _)): Override
the corresponding virtual function in parent class explicitly.
* src/BuchiAutomaton.cc (BuchiAutomaton::regularize)
(BuchiAutomaton::intersect): Remove.
2004-05-31 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/LtlFormula.h: Do not include the map header. Include the
set header instead.
(LtlFormula::refcount): New variable.
(LtlFormula::formula_storage): Change type to a set of
pointers to LtlFormulas.
(LtlFormula::LtlFormula): Initialize `this->refcount' to 1. Do
not initialize `info_flags' explicitly (this is always done in
subclasses).
(LtlFormula::destruct): Update the reference counts of formulas
directly.
(LtlFormula::clone, LtlFormula::insertToStorage): Likewise.
(Atom::Atom): Do not call parent class constructor explicitly.
(UnaryFormula<Operator>::UnaryFormula): Likewise.
(BinaryFormula<Operator>::BinaryFormula): Likewise.
* src/LtlFormula.cc: Update definition of the static member
`LtlFormula::formula_storage'.
* src/FormulaRandomizer.h: Include the map header.
2004-05-19 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* configure.ac (BIGUINT): Define as unsigned long long int
if the compiler supports it (unsigned long int otherwise).
* src/TestStatistics.h
(TestStatistics::total_number_of_buchi_states)
(TestStatistics::total_number_of_buchi_transitions)
(TestStatistics::total_number_of_acceptance_sets)
(TestStatistics::total_number_of_product_states)
(TestStatistics::total_number_of_product_transitions):
Change type to BIGUINT.
(TestStatistics::total_number_of_msccs): Remove.
(TestStatistics::TestStatistics): Remove initialization
of `total_number_of_msccs'.
* src/StatDisplay.cc (printCollectiveStats): Use BIGUINTs
for referencing total state, transition and acceptance set
counts.
2004-05-18 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/ProductAutomaton.h, src/ProductAutomaton.cc,
src/SccIterator.h: Remove. The functionality provided by
these files has been rearranged into more general product
computation and emptiness checking routines in:
* src/Product.h, src/SccCollection.h: New files.
* src/BuchiProduct.h, src/BuchiProduct.cc, src/StateSpaceProduct.h:
New files for providing specializations of the general product
computation operation applicable to Büchi automata and state
spaces.
* src/Makefile.am: Add BuchiProduct.h, BuchiProduct.cc,
Product.h, SccCollection.h and StateSpaceProduct.h to
lbtt_SOURCES.
Remove ProductAutomaton.h, ProductAutomaton.cc and
SccIterator.h from lbtt_SOURCES.
* src/Graph.h.in (Graph::EdgeContainerType, Graph::Path): New
type definitions.
(Graph::PathElement): New class.
* src/PathEvaluator.h (evaluate): Change prototype to accept
a path prefix and a cycle as parameters.
* src/PathEvaluator.cc (evaluate): Rewrite to support the
changed prototype.
* src/TestRoundInfo.h: Do not include the ProductAutomaton.h
header.
(TestRoundInfo::product_automaton): Remove.
(TestRoundInfo::TestRoundInfo): Remove initialization of
`product_automaton'.
* src/TestStatistics.h: Do not include the ProductAutomaton.h
header. Include the EdgeContainer.h and Graph.h headers.
(AutomatonStats::number_of_product_states): Change type to
Graph<GraphEdgeContainer>::size_type.
* src/main.cc (testLoop): Remove references to
`round_info.product_automaton' and `generateProductAutomaton'.
* src/TestOperations.h (generateProductAutomaton): Remove.
* src/TestOperations.cc: Include the BuchiProduct.h, Product.h,
SccCollection.h and StateSpaceProduct.h headers. Do not
include the ProductAutomaton.h and SccIterator.h headers.
Define static members of
Product<BuchiProduct> and Product<StateSpaceProduct>.
(generateProductAutomaton): Remove.
(performEmptinessCheck): Display output messages from the
removed `generateProductAutomaton' function here. Do the
same for updating product automaton statistics. Use the
Product interface for constructing the product and checking
it for emptiness.
(performBuchiIntersectionCheck): Use the Product interface
for constructing the intersection of Büchi automata and
checking it for emptiness.
* src/UserCommandReader.cc: Do not include the
ProductAutomaton.h header.
(executeUserCommands): Remove the variables `product_automaton'
and `last_computed_product_automaton'.
* src/UserCommands.h: Do not include the ProductAutomaton.h
header. Include the EdgeContainer.h, Graph.h and Product.h
headers.
(computeProductAutomaton): Remove.
(synchronizePrefixAndCycle): Remove.
(printCrossComparisonAnalysisResults): Remove
`product_automaton' and `last_product_automaton' from
prototype.
(printPath): Change the types of `prefix' and `cycle' to
constant references to StateSpace::Path objects.
(printAcceptingCycle). Expect also a prefix and cycle of a
state space as parameters. Represent the path segments as
constant references to {BuchiAutomaton,StateSpace}::Path
objects.
* src/UserCommands.cc: Include the BuchiProduct.h, Product.h
and StateSpaceProduct.h headers.
(computeProductAutomaton): Remove.
(synchronizePrefixAndCycle): Remove.
(printCrossComparisonAnalysisResults): Update parameter list and
documentation. Use the Product interface for constructing and
analyzing a witness for the nonemptiness of a product automaton.
(printAutomatonAnalysisResults): Use the Product interface
for constructing and analyzing a witness for the nonemptiness
of the intersection of two Büchi automata.
(printPath): Update parameter list and documentation. Standardize
the output to resemble that produced by printAcceptingCycle.
(printAcceptingCycle): Update parameter list and documentation.
Display all relevant information about an accepting execution
of a Büchi automaton.
2004-05-18 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* configure.ac (YACC): Do not add `-d' here.
* src/Makefile.am: Rearrange to make future updates easier.
(BUILT_SOURCES): New variable.
(AM_YFLAGS): New variable for adding the `-d' flag to be
passed to YACC.
Move Config-parse.h and NeverClaim-parse.h from
EXTRA_lbtt_SOURCES and EXTRA_lbtt_translate_SOURCES to
BUILT_SOURCES.
Thanks to Alexandre Duret-Lutz for patches.
2004-05-13 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* configure.ac: Add checks for the sys/times.h and sys/wait.h
headers. Add checks for the strerror, mkstemp, open, read, write,
close, popen, pclose, pipe, fork, execvp, getpid, waitpid, alarm,
sigaction, sigprocmask, sigemptyset, sigaddset, times, sysconf,
and strsignal library functions. Remove check for the return type
of signal.
2004-05-13 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/NeverClaim-lex.ll: Add %option nounput to avoid a
compiler warning.
* src/ExternalTranslator.h: Include the TempFsysName.h header.
(ExternalTranslator::TempFileObject): Remove.
(ExternalTranslator::registerTempFileObject): Change
prototype to match that of TempFsysName::allocate.
(ExternalTranslator::temporary_file_objects): Change to a
stack of pointers to TempFsysName objects.
* src/ExternalTranslator.cc
(ExternalTranslator::registerTempFileObject): Use the
TempFsysName interface for creating temporary names.
(ExternalTranslator::translate): Handle temporary file names
as C-style strings.
(ExternalTranslator::TempFileObject): Remove.
* src/translate.cc: Make `translator' a static variable.
(signalHandler): Delete `translator' if necessary to remove
any temporary files before aborting. Restore the default
signal handler using sigaction.
(installSignalHandler): New function.
(main): Fix the number of dashes in the descriptions of
single-character command line options.
Install handler for signals that terminate the
process.
* src/Makefile.am: Add TempFsysName.h and TempFsysName.cc to
lbtt_translate_SOURCES.
2004-05-12 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/Graph.h.in (Graph<EdgeContainer>::Edge) Fix return
type of targetNode() and the type of the `target_node'
variable to allow compilation with gcc 3.4.0.
(Graph<EdgeContainer>::stats): Fix type definition of
`result' to allow compilation with gcc 3.4.0.
* src/FormulaWriter.h: Include the LtlFormula.h header
to allow compilation with gcc 3.4.0. Remove forward
declarations of class LtlFormula and class Atom.
2004-03-18 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/UserCommandReader.cc (executeUserCommands): Print a
newline after each nonempty input line regardless of whether
the line consists only of an external command or not. Don't
print a newline after piping the output of a command to an
external program. Print a newline after the output of a
command. Do not interpret failures when writing to pipe as
errors to allow external programs to ignore some of the input.
* src/UserCommands.cc (printAlgorithmList)
(printCrossComparisonAnalysisResults)
(printConsistencyAnalysisResults, printAutomatonAnalysisResults)
(printAcceptingCycle, printBuchiAutomaton, evaluateFormula)
(printCommandHelp, printInconsistencies, printStateSpace):
Remove extra newlines from the end of output.
* src/StatDisplay.cc (printBuchiIntersectionCheckStats):
Remove extra newlines from the end of output.
* src/TestOperations.cc (performBuchiIntersectionCheck): Print
a newline after the results to transcript file and to console
in verbosity modes >= 3.
2004-03-17 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/BuchiAutomaton.h: Include the cstdlib header.
Fix description of the BuchiAutomaton class.
(BuchiAutomaton::connect): Add parameters for the acceptance
sets associated with a transition.
(BuchiAutomaton::BuchiTransition::BuchiTransition): Add
parameters for the acceptance sets associated with a transition.
Remove copy constructor.
(BuchiAutomaton::BuchiTransition::print): Remove default values
for arguments. Add parameter for the number of acceptance sets
associated with a transition.
(BuchiAutomaton::BuchiTransition::acceptanceSets) New functions.
(BuchiAutomaton::BuchiTransition::acceptance_sets): New
variable.
* src/BuchiAutomaton.cc
(BuchiAutomaton::BuchiAutomaton(const BuchiAutomaton&): Copy
also the acceptance sets of each transition.
(BuchiAutomaton::operator=): Copy also the acceptance sets of
each transition.
(BuchiAutomaton::regularize): Handle also acceptance sets on
transitions.
(BuchiAutomaton::read): Update description. Accept automata with
acceptance sets on states and/or transitions.
(BuchiAutomaton::intersect): Take care of acceptance sets
associated with transitions when forming the intersection of two
automata.
(BuchiAutomaton::print): Change output to refer to "acceptance
sets" instead of "sets of accepting states". Pass the number of
acceptance sets to BuchiAutomaton::BuchiTransition::print when
displaying the automaton in dot format.
(BuchiAutomaton::BuchiTransition::print): List the acceptance
sets associated with each transition in all output modes.
(BuchiAutomaton::BuchiState::print): Pass the number of
acceptance sets to BuchiAutomaton::BuchiTransition::print.
2004-03-15 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/UserCommands.h (printFormula): Change prototype to accept
the vector of input tokens as an additional parameter.
* src/UserCommands.cc (printFormula): Accept the vector of
input tokens as an additional parameter. Use the optional
parameter "nnf" or "normal" to choose the display mode.
Display only the formula to accommodate feeding the output (if
redirected to a file) back to lbtt using the --formulafile
command line option.
(printCommandHelp): Update the description of the `formula'
command.
* src/UserCommandReader.cc (executeUserCommands): Accept one
optional parameter for the `formula' command. Pass the input
tokens as an additional parameter in the printFormula call.
Print an additional newline after the call if the output is
not redirected to a file.
2004-03-12 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/Exception.h: Include the istream header.
(Exceptional_istream::get, Exceptional_istream::read): New
functions.
* src/Ltl-parse.yy: New file.
* src/LtlFormula.h (parseFormula): Declare.
(LtlFormula::read(istream&)): Read the formula by calling
parseFormula (provided by Ltl-parse.yy).
(LtlFormula::read(Exceptional_istream&)): Remove.
* src/LtlFormula.cc (LtlFormula::read(Exceptional_istream&)):
Remove.
* src/Makefile.am: Add Ltl-parse.yy to lbtt_SOURCES and
lbtt_translate_SOURCES.
2004-03-08 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/TempFsysName.h, src/TempFsysName.cc New files.
* src/Makefile.am: Add TempFsysName.h and TempFsysName.cc to
lbtt_SOURCES.
* src/TestRoundInfo.h: Include the TempFsysName.h header.
(TestRoundInfo::formula_file_name[])
(TestRoundInfo::automaton_file_name)
(TestRoundInfo::{cout,cerr}_capture_file): Change type to
TempFsysName*.
(TestRoundInfo::TestRoundInfo): Initialize temporary file
name pointers to 0.
* src/main.cc: Include the TempFsysName.h header.
(allocateTempFilenames, deallocateTempFilenames): New functions.
(abortHandler): New signal handler.
(installSignalHandler): New function.
(testLoop): Do not explicitly remove the temporary formula files.
(main): Use the above functions for allocating and deallocating
names for temporary files. Handle signals that terminate the
process by cleaning up temporary files before aborting; however,
for SIGINT, do this only if user breaks are not handled by lbtt.
* src/TestOperations.h (removeFile): Rename as truncateFile.
* src/TestOperations.cc: Include the TempFsysName.h header.
(removeFile): Rename as truncateFile; truncate file instead of
removing it.
(writeFormulaeToFiles): Use the TempFsysName interface for
referring to the names of temporary files.
(generateBuchiAutomaton): Truncate all temporary files before
exec'ing an external process. Use the TempFsysName interface
for referring to the names of temporary files.
* src/ExternalTranslator.cc: Include the cstring header.
(ExternalTranslator::TempFileObject::TempFileObject): Use
mkstemp instead of tmpnam to allocate a name for a temporary
file.
2004-03-08 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/StringUtil.h (findInQuotedString): New function prototype.
* src/StringUtil.cc (findInQuotedString): New function.
* src/UserCommandReader.cc (executeUserCommands):
[HAVE_READLINE] Add the input line to history before extracting
the external command from the line.
Ignore white space within quotes when splitting input line into
tokens.
Move parsing the algorithm identifiers given for the
`buchianalysis' command to
src/UserCommands.cc (printAutomatonAnalysisResults).
(parseRedirection): Explicitly unquote the file name.
* src/UserCommands.h: Include the map and the IntervalList.h
headers.
(parseAlgorithmId, parseAlgorithmIdList): New function prototypes.
(printAutomatonAnalysisResults): Change function prototype to
accept a list of tokens instead of two algorithm identifiers.
* src/ProductAutomaton.h: Include the string header. Rewrite
the friend declaration of
UserCommands::printAutomatonAnalysisResults.
* src/UserCommands.cc (parseAlgorithmId, parseAlgorithmIdList):
New functions.
(printCrossComparisonAnalysisResults)
(printConsistencyAnalysisResults): Parse algorithm identifier
using the parseAlgorithmId function.
(printAutomatonAnalysisResults): Parse algorithm identifiers
using the parseAlgorithmId function. Throw a CommandErrorException
in the case one of the algorithm identifiers refers to lbtt's
internal model checking algorithm.
(printBuchiAutomaton): Parse algorithm identifier using the
parseAlgorithmId function. Throw a CommandErrorException in the
case the identifier refers to lbtt's internal model checking
algorithm.
(printCommandHelp): Do not treat the internal model checking
algorithm as a special case in command descriptions.
(evaluateFormula, printInconsistencies, printTestResults)
(printStateSpace, changeAlgorithmState): Parse lists of
algorithms and states using the parseAlgorithmIdList and the
StringUtil::parseIntervalList functions, respectively. Access the
numeric algorithm and state identifiers via IntervalLists. Make
error messages more consistent.
2004-03-07 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/StatDisplay.h: Include the IntervalList.h header.
(printStatTableHeader): New function prototype.
(printCrossComparisonStats, printBuchiIntersectionCheckStats):
Change the function prototypes to accept a reference to an
IntervalList for the algorithm identifiers.
* src/StatDisplay.cc (printStatTableHeader): New function.
* src/StatDisplay.cc (printBuchiAutomatonStats)
(printProductAutomatonStats, printAcceptanceCycleStats)
(printConsistencyCheckStats): Display statistics in a table in
verbosity mode <= 2.
(printCrossComparisonStats): Iterate over the set of algorithms
using an IntervalList. Do not handle the internal model checking
algorithm as a special case.
(printBuchiIntersectionCheckStats) Iterate over the set of
algorithms using an IntervalList. Skip the internal model
checking algorithm when displaying automata generation or
intersection check statistics.
(printAllStats): Display statistics in a table in verbosity
mode <= 2.
(printCollectiveStats): Skip the internal algorithm when
displaying the rows of the cross-comparison result table. Use
the changed semantics of Configuration::AlgorithmInformation
to find the name of an implementation.
* src/main.cc (testLoop): Display test statistics in a table in
verbosity modes 1 and 2.
* src/TestOperations.cc: Include the IntervalList.h header.
Remove inclusion of the TestStatistics.h header.
(generateBuchiAutomaton, generateProductAutomaton)
(performEmptinessCheck): Display the test statistics in a table
in verbosity modes 1 and 2.
(compareResults, performBuchiIntersectionCheck): Display the
result of the test also in verbosity mode 2. Show test statistics
using the changed semantics of
StatDisplay::printCrossComparisonStats and
StatDisplay::printBuchiIntersectionCheckStats.
(verifyFormulaOnPath, generateProductAutomaton)
(performEmptinessCheck, performBuchiIntersectionCheck): More
consistent error messages when the test is aborted.
* src/UserCommands.cc (evaluateFormula): Use the changed
semantics of Configuration::AlgorithmInformation to find the
name of an implementation.
(printTestResults): Display the test results using the changed
semantics of StatDisplay::printCrossComparisonStats and
StatDisplay::printBuchiIntersectionCheckStats.
2004-03-04 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/TestOperations.h (openFile(const char*, int&, int, int)):
New function prototype.
* src/TestOperations.cc: Include the csignal, cstring, cerrno,
[HAVE_SYS_TYPES_H] sys/types.h, [HAVE_SYS_STAT_H] sys/stat.h,
[HAVE_FCNTL_H] fcntl.h, and [HAVE_SYS_WAIT_H] sys/wait.h headers.
(timeout): New variable.
(timeoutHandler): New function.
(openFile(const char*, int&, int, int)): New function.
(verifyFormulaOnPath): Fix references to the internal model
checking algorithm.
(generateBuchiAutomaton): Execute external program using fork/exec
instead of `system' to improve the detection of the case when an
external program was terminated by a signal (the behavior of
"system" in the presence of signals varies between architectures).
Handle timeouts when running the external programs. Discard I/O
exceptions while displaying the stdout/stderr capture file.
(performBuchiIntersectionCheck): Skip the internal model checking
algorithm when iterating over algorithms.
2004-03-04 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/main.cc (breakHandler): Make function static and change
return type to void.
(testLoop): Do not add the internal model checking algorithm to
the list of implementations (it is done in Configuration::read).
Apply the internal model checking algorithm if it is enabled.
Otherwise skip the automata generation loop as it is not
applicable for this algorithm.
(main): Enable interrupt handler only if mandated by the program
configuration. Use sigaction instead of signal to register the
signal handler.
2004-03-04 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/Config-lex.ll, src/Config-parse.yy, src/Configuration.h,
src/Configuration.cc: Rewrite the configuration file parser to
allow reusing a common set of functions for changing the various
settings independently of whether the settings were given in the
configuration file or as command-line options. Rearrange the
structure of Configuration::AlgorithmInformation, remove the
"nopause" and "pauseonbreak" command line options (and make
"pause" an alias of "interactive"), recognize lists of
interactivity modes (with the new mode "onbreak") both in the
configuration file and command line, and add the new
configuration setting "translatortimeout". In more detail,
the changes are:
* src/Config-lex.ll: Do not include any standard headers. Add
%option nounput to suppress a compiler warning. Accept
"Implementation" or "Translator" as an alias of the Algorithm
block identifier. Do not accept newlines in "option = value"
strings. Do not interpret option values in the lexer. Make
specifying option values more flexible: quotes are now needed
only for values including white space. Both single and double
quotes may be used (as before, \ works as an escape character in
double quotes). Reject values with unmatched quotes. Remove the
getCharacter function (add rules for matching unknown tokens in
full).
* src/Config-parse.yy: Do not include the cstdio header. Add
namespace StringUtil to the current namespace.
([declarations]) Change %union declaration to make all semantic
values constant C-style strings. Remove tokens CFG_TRUTH_VALUE,
CFG_INTERACTIVITY_VALUE, CFG_FORMULA_MODE_VALUE,
CFG_STATESPACE_MODE_VALUE, CFG_PRODUCT_TYPE_VALUE, CFG_INTEGER,
CFG_REAL, CFG_INTEGER_INTERVAL and CFG_STRING_CONSTANT. Add
new token CFG_VALUE and nonterminal equals_value.
(algorithm_information): Replaced with `algorithm_name',
`algorithm_path', `algorithm_parameters' and `algorithm_enabled'.
(current_block_type, current_option_type): Removed.
(yyerror): Make parameter const. Remove the loop for reading the
remainder of the current token (the token is recognized in full
directly by the lexer). Remove error messages for all tokens in
the above list.
(checkIntegerRange, checkProbability, isLocked): Removed.
([grammar rule `equals_value']): New rule.
([grammar rules for the "Algorithm" configuration file section]):
Read the implementation information into `algorithm_name',
`algorithm_path', `algorithm_parameters' and `algorithm_enabled'.
Use the functions provided by the Configuration class to update
the configuration.
([grammar rules for the other configuration file sections]): Use
the functions provided by the Configuration class to update the
configuration. Remove the rules `formula_size' and
`statespace_size'.
* src/Configuration.h: Include the cstdio header. Add
declarations for variables and functions provided by the parser.
Declare yyparse() as a friend.
(Configuration::AlgorithmInformation::path_to_program)
(Configuration::IntPair, Configuration::locked_options)
(Configuration::GENERATION_RANGE, Configuration::PRIORITY_RANGE)
(Configuration::PROPOSITION_COUNT_RANGE)
(Configuration::FORMULA_SIZE_RANGE)
(Configuration::FORMULA_MAX_SIZE_RANGE)
(Configuration::STATESPACE_SIZE_RANGE)
(Configuration::STATESPACE_MAX_SIZE_RANGE)
(Configuration::OPT_NOCOMPARISONTEST)
(Configuration::OPT_NOCONSISTENCYTEST)
(Configuration::OPT_NOINTERSECTIONTEST)
(Configuration::OPT_NOABBREVIATEDOPERATORS)
(Configuration::OPT_PAUSE, Configuration::OPT_NOPAUSE)
(Configuration::OPT_PAUSEONERROR):
Remove.
(Configuration::AlgorithmInformation::extra_parameters): Redefine
as `char** parameters'.
(Configuration::AlgorithmInformation::num_parameters)
(Configuration::GlobalConfiguration::handle_breaks)
(Configuration::GlobalConfiguration::translator_timeout)
(Configuration::algorithm_names: New variables.
(Configuration::IntegerRange): Change the type of lower and upper
bounds to unsigned long int. Make `error_message' const.
(Configuration::DEFAULT_RANGE, Configuration::RANDOM_SEED_RANGE)
(Configuration::ATOMIC_PRIORITY_RANGE)
(Configuration::OPERATOR_PRIORITY_RANGE): New IntegerRange
declarations.
(Configuration::OPT_TRANSLATORTIMEOUT): New OPT_ constant.
(Configuration::registerAlgorithm, Configuration::readProbability)
(Configuration::readSize, Configuration::readTruthValue)
(Configuration::readInteractivity, Configuration::readProductType)
(Configuration::readFormulaMode, Configuration::readStateSpaceMode)
(Configuration::readTranslatorTimeout): New function
prototypes.
(Configuration::isInternalAlgorithm): New function.
(Configuration::readInteger): New template function.
* src/Configuration.cc: Do not include the cstdio and
Config-parse.h headers. Include the IntervalList.h header. Remove
declarations for checkIntegerRange and checkProbability. Move
remaining extern declarations to Configuration.h.
(Configuration::GENERATION_RANGE, Configuration::PRIORITY_RANGE)
(Configuration::PROPOSITION_COUNT_RANGE)
(Configuration::FORMULA_SIZE_RANGE)
(Configuration::FORMULA_MAX_SIZE_RANGE)
(Configuration::STATESPACE_SIZE_RANGE)
(Configuration::STATESPACE_MAX_SIZE_RANGE)
(Configuration::parseCommandLineInteger): Remove.
(Configuration::DEFAULT_RANGE, Configuration::RANDOM_SEED_RANGE)
(Configuration::ATOMIC_PRIORITY_RANGE)
(Configuration::OPERATOR_PRIORITY_RANGE): New IntegerRange
definitions.
(Configuration::ROUND_COUNT_RANGE): Change upper bound to
ULONG_MAX.
(Configuration::~Configuration): Use the changed semantics
of Configuration::AlgorithmInformation.
(Configuration::read): The
--{comparison,consistency,intersection}{test,check} and
--abbreviatedoperators command line options now take an optional
argument.
The options
--no{{comparison,consistency,intersection}{test,check},
abbreviatedoperators} return the same OPT_ constant as the
corresponding positive option.
The --interactive and --pause options take an optional argument.
Remove the --nopause and --pauseonerror command line options.
Store the command line parameters into a vector of <opttype,arg>
pairs (preprocess the special options --configfile, --formulafile,
--help, --logfile, --showconfig, --showoperatordistribution,
--skip and --version; preprocess also the options accepting an
optional argument). Then read the configuration file. Add the
internal model checking algorithm to the set of algorithms if
necessary here instead of in src/main.cc (testLoop). Finally
process the parameter vector again to override any settings made
in the configuration file.
Use the new functions for modifying the configuration.
Allow symbolic algorithm identifiers for the options --enable
and --disable.
Make error messages more consistent.
Exit with the status 2 if an unknown command line option was
encountered or an argument for an option was missing.
(Configuration::print): Tell whether the user break handler is
enabled; tell also the value of the timeout for translators.
(Configuration::algorithmString): Use the new structure of
Configuration::AlgorithmInformation.
(Configuration::showCommandLineHelp): Rewrite the descriptions of
the --{comparison,consistency,intersection}test,
--abbreviatedoperators, --interactive and --pause command line
options. Correct typos in the description of the
--abbreviatedoperators option. Remove descriptions of the
--nopause and --pauseonerror options.
(Configuration::reset): Initialize the values of
`global_options.handle_breaks' and
`global_options.translator_timeout' to false and 0, respectively.
(Configuration::registerAlgorithm): New function for adding a
new implementation to the configuration. The names of
implementations should be unique and different from the reserved
name "lbtt".
(Configuration::readProbability, Configuration::readSize)
(Configuration::readTruthValue, Configuration::readInteractivity)
(Configuration::readProductType, Configuration::readFormulaMode)
(Configuration::readStateSpaceMode)
(Configuration::readTranslatorTimeout): New functions. The
interactivity can now be specified using a comma-separated list
of modes that may include the new keyword "onbreak".
2004-03-02 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/StringUtil.h (toLowerCase, unquoteString)
(substituteInQuotedString, parseTime): New function prototypes.
(QuoteMode): New enumeration type.
* src/StringUtil.cc: Include the cctype header.
(toLowerCase, interpretSpecialCharacters, unquoteString)
(substituteInQuotedString, parseTime): New functions.
2004-02-19 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/TestRoundInfo.h (TestRoundInfo::all_tests_successful): New
variable.
(TestRoundInfo::TestRoundInfo): Initialize the value of
all_tests_successful to true.
* src/main.cc (testLoop): Update the value of
round_info.all_tests_successful to indicate the occurrence of an
error. Use the value of this variable as return value from
testLoop.
(main): Return 1 if an error occurred during testing. Return 2 if
there was an error in program configuration; remove extra space
after colon in output. Return 3 if an unexpected exception
occurred. In this case print an additional newline before the
error message.
2004-02-19 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/StringUtil.h: Include the IntervalList.h header.
(IntervalStringType): New enumeration type for describing the
boundedness of interval strings.
(parseInterval): New function prototype. Renamed the old prototype
to `parseIntervalList'.
* src/StringUtil.cc: Include the climits header.
(parseNumber): Be more strict about ensuring that the numbers are
positive.
(parseInterval): New function for parsing interval strings.
(parseIntervalList): Use the `parseInterval' function as a
subroutine when parsing a list of intervals. Add a parameter for
optionally storing tokens not recognized as intervals into a
vector of strings. Store the result into an IntervalList. Throw an
IntervalRangeException if an interval does not fit within the
given bounds.
2004-02-18 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/IntervalList.h, src/IntervalList.cc: New files.
* src/Makefile.am: Add IntervalList.h and IntervalList.cc to
lbtt_SOURCES.
2004-02-17 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/TestOperations.cc (writeFormulaeToFiles): Make the order of
debugging messages (verbosity level 5) more consistent.
2004-02-15 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/DispUtil.h (printText): Move function declarations to their
correct place (out of struct StreamFormatting).
2004-02-15 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* configure.ac: Require Autoconf 2.59.
Remove use of deprecated macros.
--with-readline-prefix, --with-readline-includes,
--with-readline-libs: New options.
2004-02-13 Heikki Tauriainen <heikki.tauriainen@hut.fi> 2004-02-13 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* src/BitArray.{h,cc}, src/BuchiAutomaton.{h,cc}, * src/BitArray.{h,cc}, src/BuchiAutomaton.{h,cc},
@ -12,6 +753,8 @@
src/translate.{h,cc}, src/UserCommandReader.{h,cc}, src/translate.{h,cc}, src/UserCommandReader.{h,cc},
src/UserCommands.{h,cc}: Remove all #pragmas. src/UserCommands.{h,cc}: Remove all #pragmas.
* Version 1.0.3 released.
2004-02-12 Heikki Tauriainen <heikki.tauriainen@hut.fi> 2004-02-12 Heikki Tauriainen <heikki.tauriainen@hut.fi>
* doc/texinfo.tex: New upstream version. * doc/texinfo.tex: New upstream version.

View file

@ -1,4 +1,4 @@
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc. Foundation, Inc.
This file is free documentation; the Free Software Foundation gives This file is free documentation; the Free Software Foundation gives

132
lbtt/NEWS
View file

@ -1,4 +1,4 @@
lbtt NEWS -- history of user-visible changes. 13 Feb 2004 lbtt NEWS -- history of user-visible changes. 7 Jul 2004
Copyright (C) 2004 Heikki Tauriainen Copyright (C) 2004 Heikki Tauriainen
Permission is granted to anyone to make or distribute verbatim copies Permission is granted to anyone to make or distribute verbatim copies
@ -12,6 +12,136 @@ Copyright (C) 2004 Heikki Tauriainen
Please send bug reports to <heikki.tauriainen@hut.fi>. Please send bug reports to <heikki.tauriainen@hut.fi>.
Version 1.1.0
* File formats
- The file format for automata description files has changed to
accommodate automata with acceptance conditions on both states
and transitions. The old format for automata remains supported
with the restriction that each guard formula of a transition
should be followed by a newline (with optional preceding white
space).
- In addition to the prefix format for LTL formulas, the input
files used with the `--formulafile' command line option may now
contain formulas in a variety of other formats, such as in the
infix format used by lbtt for log messages, together with formats
used by some LTL-to-Büchi translator implementations (Spin,
LTL2BA, LTL2AUT, Temporal Massage Parlor, Wring, Spot, LBT).
These formats can also be used for guard formulas in automaton
description files (however, lbtt still uses the prefix format in
the input files for the translators).
Thanks to Alexandre Duret-Lutz for useful suggestions for
enhancements.
* Support for symbolic names of implementations
- Beside the numeric identifiers of implementations, lbtt now
accepts also the symbolic names of implementations (as defined in
a configuration file) as parameters for command line options and
internal commands. Consequently, the names of implementations
defined in the configuration file have to be unique.
- The name `lbtt' is now reserved for lbtt's internal model checking
algorithm and cannot be used as a name for an implementation in
the configuration file.
* User commands
- For consistency, numeric intervals in state or implementation
identifier lists can now be specified using either - or ... as a
separator between the bounds of the interval.
- The user command `formula' now accepts an additional parameter
(`normal' or `nnf') for choosing whether to display a formula in
the form in which it was generated or in negation normal form.
- The internal model checking algorithm is now referred to with the
keyword "lbtt" instead of "p" as was the case with previous
versions of lbtt. The internal model checking algorithm can now be
enabled or disabled similarly to the external translators.
- The `consistencyanalysis' and `buchianalysis' commands now show
more information about the accepting runs of Büchi automata to
help examining the runs. (Because of this change, the runs and
witnesses may be longer than in previous versions of lbtt.)
- The `implementations' and `translators' commands are now recognized
as synonyms of the `algorithms' command.
* Configuration files
- Quotes are no longer required for enclosing string values
containing no white space.
- Numeric intervals in formula or state space sizes can now be
specified using either - or ... as a separator between the bounds
of the interval.
- The keywords "Implementation" and "Translator" are now recognized
as synonyms of the "Algorithm" block identifier.
* User interrupts
Keyboard interrupt handling is now enabled only at explicit request
(if not enabled, lbtt simply aborts on keyboard interrupts). The
interrupt handler is enabled by combining the keyword `onbreak' with
any of the three standard interactivity modes (`always', `never', or
`onerror') in the arguments for the `GlobalOptions.Interactive'
configuration file option or the `--interactive' command line option.
For example, use the command line option
`--interactive=onerror,onbreak' to pause testing in case of an error
or on a user interrupt.
* Command line options
- The `--pause' command line option now works identically to the
`--interactive' option.
- The command-line options `--nopause' and `--pauseonerror' are no
longer supported. Use the `--interactive' or the `--pause'
option instead with an optional argument of a comma-separated list
of interactivity modes (`always', `never', `onerror', `onbreak').
* Timeouts
lbtt now supports specifying a time (in wall-clock time) after
which the execution of a translator is aborted if it has not yet
produced a result. The timeout can be set using either the new
configuration file option `GlobalOptions.TranslatorTimeout' or the
equivalent command line option `--translatortimeout'. Both options
require a parameter of the form [hours]h[minutes]min[seconds]s; for
example, use the command line option `--translatortimeout=1h30min'
to set the timeout at one hour and thirty minutes.
* Reporting
- lbtt now reports test statistics also in verbosity modes 1 and 2.
The output of the user command `results' also reflects the active
verbosity mode more accurately.
- lbtt now exits with status 0 only if no test failures were
detected; otherwise the exit status is either 1 (at least
one failure occurred), 2 (error in program configuration or
command line parameters) or 3 (lbtt exited due to an internal
error).
* Internal changes
Due to the changes in the supported file formats, this version
includes a rewrite of the product computation and emptiness checking
algorithms. As this is a major internal change, any information about
unexpected changes in the stability (*) of the tool is welcomed at the
e-mail address given above.
(*) Unfortunately, the above changes in the source code are known to
cause build problems with GCC 2.95. Therefore, this compiler is no
longer officially supported for building the tool.
---------------------------------------------------------------------------
Version 1.0.3 Version 1.0.3
* This release fixes several compilation issues with GNU libc 2.3.2 * This release fixes several compilation issues with GNU libc 2.3.2

View file

@ -1,14 +1,14 @@
lbtt version 1.0.3 lbtt version 1.1.0
------------------ ------------------
lbtt is a tool for testing programs that translate formulas lbtt is a tool for testing programs that translate formulas
expressed in propositional linear temporal logic (LTL) into expressed in propositional linear temporal logic (LTL) into
Büchi automata. The goal of the tool is to assist in the Büchi automata. The goal of the tool is to assist implementing
correct implementation of LTL-to-Büchi translation algorithms LTL-to-Büchi translation algorithms correctly by providing an
by providing an automated testing environment for LTL-to-Büchi automated testing environment for LTL-to-B@"uchi translators.
translators. Additionally, the testing environment can be used Additionally, the testing environment can be used for very basic
for very basic profiling of different LTL-to-Büchi translators profiling of different LTL-to-Büchi translators to evaluate their
to evaluate their performance. performance.
The latest version of the program is available at The latest version of the program is available at
<http://www.tcs.hut.fi/Software/lbtt/>. <http://www.tcs.hut.fi/Software/lbtt/>.

View file

@ -1,11 +1,11 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ([2.53]) AC_PREREQ([2.59])
AC_INIT([lbtt], [1.0.3], [heikki.tauriainen@hut.fi]) AC_INIT([lbtt], [1.1.0], [heikki.tauriainen@hut.fi])
AC_REVISION([Revision: 1.3]) AC_REVISION([Revision: 1.4])
AC_CONFIG_SRCDIR([src/main.cc]) AC_CONFIG_SRCDIR([src/main.cc])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AM_CONFIG_HEADER([config.h])
@ -18,35 +18,68 @@ AC_PROG_CXXCPP
AM_PROG_LEX AM_PROG_LEX
AC_PROG_YACC AC_PROG_YACC
YACC="${YACC} -d"
# Check whether the user has explicitly disabled support for the GNU readline
# Check whether the user has explicitly disabled the test for the availability # library.
# of the GNU readline library.
readline=yes readline=yes
readline_includedir=
readline_libdir=
AC_ARG_WITH([readline], AC_ARG_WITH(
[AC_HELP_STRING([--without-readline], [readline],
[disable check for the GNU readline library])], [AS_HELP_STRING(
[--without-readline],
[disable support for the GNU readline library (default enable)])],
[if test x"${withval}" = xno; then readline=no; fi]) [if test x"${withval}" = xno; then readline=no; fi])
AC_ARG_WITH(
[readline-prefix],
[AS_HELP_STRING(
[--with-readline-prefix=DIR],
[location where GNU readline is installed (optional)])],
[readline_includedir="${withval}/include"
readline_libdir="${withval}/lib"])
AC_ARG_WITH(
[readline-includes],
[AS_HELP_STRING(
[--with-readline-includes=DIR],
[location where GNU readline headers are installed (optional)])],
[readline_includedir="${withval}"])
AC_ARG_WITH(
[readline-libs],
[AS_HELP_STRING(
[--with-readline-libs=DIR],
[location where GNU readline libraries are installed (optional)])],
[readline_libdir="${withval}"])
old_CPPFLAGS=${CPPFLAGS}
old_LDFLAGS=${LDFLAGS}
if test -n "${readline_includedir}"; then
CPPFLAGS="${CPPFLAGS} -I${readline_includedir}"
fi
if test -n "${readline_libdir}"; then
LDFLAGS="${LDFLAGS} -L${readline_libdir}"
fi
# Check for the availability of headers. # Check for the availability of headers.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([libintl.h fcntl.h sys/times.h])
AC_HEADER_SYS_WAIT
# Check for the availability of the GNU readline headers. # Check for the availability of the GNU readline headers.
if test "${readline}" = yes; then if test "${readline}" = yes; then
rl_history_h="readline/history.h" rl_history_h="readline/history.h"
rl_readline_h="readline/readline.h" rl_readline_h="readline/readline.h"
AC_CHECK_HEADERS([${rl_history_h} ${rl_readline_h}], AC_CHECK_HEADERS([${rl_history_h} ${rl_readline_h}], [], [readline=no])
[],
[readline=no])
fi fi
AC_LANG([C++]) AC_LANG([C++])
@ -55,23 +88,34 @@ AC_LANG([C++])
# version of this header that cannot be compiled using g++; enable a workaround # version of this header that cannot be compiled using g++; enable a workaround
# if necessary. # if necessary.
AC_CHECK_HEADERS([obstack.h], AC_CHECK_HEADERS(
[obstack.h],
[AC_MSG_CHECKING([whether obstack.h compilation workaround is needed]) [AC_MSG_CHECKING([whether obstack.h compilation workaround is needed])
AC_TRY_COMPILE([#include <obstack.h>], old_cxxflags=${CXXFLAGS}
[#if __GLIBC__ == 2 && __GLIBC_MINOR__ == 3 CXXFLAGS="${CXXFLAGS} -Werror"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <obstack.h>]],
[[
#ifdef __GLIBC__ == 2 && __GLIBC_MINOR__ = 3
obstack_alloc(0, 0); obstack_alloc(0, 0);
#endif], #endif
]])],
[AC_MSG_RESULT([no])], [AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes]) [AC_MSG_RESULT([yes])
AC_DEFINE([GLIBC_OBSTACK_WORKAROUND], AC_DEFINE(
[GLIBC_OBSTACK_WORKAROUND],
[1], [1],
[Define to 1 to enable an obstack.h C++ compilation workaround for GNU libc 2.3.])])]) [Define to 1 to enable an obstack.h C++ compilation workaround for GNU libc 2.3.])])
CXXFLAGS=${old_cxxflags}])
# Check for the availablility of the sstream or strstream header. # Check for the availablility of the sstream or strstream header.
AC_CHECK_HEADERS([sstream], AC_CHECK_HEADERS(
[sstream],
[], [],
[AC_CHECK_HEADERS([strstream], [AC_CHECK_HEADERS(
[strstream],
[], [],
[AC_MSG_ERROR([missing one or more standard C++ headers])])]) [AC_MSG_ERROR([missing one or more standard C++ headers])])])
@ -86,28 +130,33 @@ AC_CHECK_HEADERS([sstream],
AC_MSG_CHECKING([for slist]) AC_MSG_CHECKING([for slist])
for slist_header in slist ext/slist no; do for slist_header in slist ext/slist no; do
if test "${slist_header}" != no; then if test "${slist_header}" != no; then
AC_TRY_CPP([#include <${slist_header}>], [break]) AC_PREPROC_IFELSE(
[AC_LANG_SOURCE([[#include <${slist_header}>]])],
[break])
fi fi
done done
# Try to determine the C++ namespace in which the class slist resides. # Try to determine the C++ namespace in which the class slist resides.
# (For example, GCC versions 3.1, 3.1.1 and 3.2 put slist into the # (For example, GCC versions >= 3.1 put slist into the __gnu_cxx namespace.)
# __gnu_cxx namespace.)
if test "${slist_header}" != no; then if test "${slist_header}" != no; then
for slist_namespace in std __gnu_cxx error; do for slist_namespace in std __gnu_cxx error; do
if test "${slist_namespace}" != error; then if test "${slist_namespace}" != error; then
AC_TRY_LINK([#include <${slist_header}>], AC_COMPILE_IFELSE(
[${slist_namespace}::slist<int> s;], [AC_LANG_PROGRAM(
[[#include <${slist_header}>]],
[[${slist_namespace}::slist<int> s;]])],
[break]) [break])
fi fi
done done
if test "${slist_namespace}" != error; then if test "${slist_namespace}" != error; then
AC_MSG_RESULT([header <${slist_header}>, typename ${slist_namespace}::slist]) AC_MSG_RESULT([header <${slist_header}>, typename ${slist_namespace}::slist])
AC_DEFINE([HAVE_SLIST], AC_DEFINE(
[HAVE_SLIST],
[1], [1],
[Define to 1 if you have the <slist> or <ext/slist> header file.]) [Define to 1 if you have the <slist> or <ext/slist> header file.])
AC_DEFINE_UNQUOTED([SLIST_NAMESPACE], AC_DEFINE_UNQUOTED(
[SLIST_NAMESPACE],
[${slist_namespace}], [${slist_namespace}],
[Define as the name of the C++ namespace containing slist.]) [Define as the name of the C++ namespace containing slist.])
AC_SUBST([INCLUDE_SLIST_HEADER], ["#include <${slist_header}>"]) AC_SUBST([INCLUDE_SLIST_HEADER], ["#include <${slist_header}>"])
@ -119,26 +168,21 @@ fi
if test "${slist_header}" = no; then if test "${slist_header}" = no; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
# Check for the availability of the single_client_alloc memory allocator
# available in some compilers supporting the SGI extensions to the Standard
# template library (for example, pre-3.0 versions of gcc). This check is not
# needed if no suitable slist header was found above, since in that case the
# compiler does not support the SGI extensions.
else
AC_MSG_CHECKING([for single_client_alloc])
AC_TRY_LINK([#include <${slist_header}>],
[using namespace std;
${slist_namespace}::slist<int, single_client_alloc> s;],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_SINGLE_CLIENT_ALLOC],
[1],
[Define if your C++ compiler supports the single_client_allocator memory allocator.])],
[AC_MSG_RESULT([no])])
fi fi
AC_LANG(C) AC_LANG(C)
AC_CHECK_TYPES(
[unsigned long long int],
[AC_DEFINE(
[BIGUINT],
[unsigned long long int],
[Define to an unsigned integer type supported by your compiler.])],
[AC_DEFINE(
[BIGUINT],
[unsigned long int],
[Define to an unsigned integer type supported by your compiler.])])
AC_C_CONST AC_C_CONST
AC_C_INLINE AC_C_INLINE
@ -146,12 +190,14 @@ AC_C_INLINE
# Checks for library functions. # Checks for library functions.
AC_TYPE_SIGNAL AC_CHECK_FUNCS(
AC_CHECK_FUNCS([mkdir strchr strtod strtol strtoul getopt_long isatty]) [strchr strtod strtol strtoul strerror mkdir mkstemp open read write close popen pclose pipe fork execvp getpid waitpid alarm sigaction sigprocmask sigemptyset sigaddset times sysconf],
[],
[AC_MSG_ERROR([missing one of the library functions required for compilation])])
AC_CHECK_FUNCS([strsignal isatty getopt_long])
if test x"${ac_cv_func_getopt_long}" = xno; then if test x"${ac_cv_func_getopt_long}" = xno; then
AC_LIBOBJ([getopt]) AC_LIBOBJ([getopt])
AC_LIBOBJ([getopt1]) AC_LIBOBJ([getopt1])
AC_CHECK_HEADERS([libintl.h])
AC_CHECK_FUNCS([memset]) AC_CHECK_FUNCS([memset])
fi fi
@ -163,16 +209,21 @@ if test "${readline}" = yes; then
for READLINELIBS in "-lreadline" "-lreadline -lcurses" "-lreadline -ltermcap" error; do for READLINELIBS in "-lreadline" "-lreadline -lcurses" "-lreadline -ltermcap" error; do
if test "${READLINELIBS}" != error; then if test "${READLINELIBS}" != error; then
LIBS="${oldlibs} ${READLINELIBS}" LIBS="${oldlibs} ${READLINELIBS}"
AC_TRY_LINK([#include <stdio.h> AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdio.h>
#include <${rl_history_h}> #include <${rl_history_h}>
#include <${rl_readline_h}>], #include <${rl_readline_h}>
[using_history(); readline(""); add_history("");], ]],
[[using_history(); readline(""); add_history("");]])],
[break]) [break])
fi fi
done done
LIBS=${oldlibs} LIBS=${oldlibs}
if test "${READLINELIBS}" != error; then if test "${READLINELIBS}" != error; then
AC_DEFINE([HAVE_READLINE], AC_DEFINE(
[HAVE_READLINE],
[1], [1],
[Define if you have the GNU readline library.]) [Define if you have the GNU readline library.])
AC_SUBST([READLINELIBS]) AC_SUBST([READLINELIBS])
@ -180,23 +231,32 @@ if test "${readline}" = yes; then
else else
AC_MSG_RESULT([no suitable libraries found, readline support disabled]) AC_MSG_RESULT([no suitable libraries found, readline support disabled])
READLINELIBS="" READLINELIBS=""
readline=no
fi fi
fi fi
if test "${readline}" = no; then
CPPFLAGS=${old_CPPFLAGS}
LDFLAGS=${old_LDFLAGS}
fi
# Check for the availability of the `rand48' family of random number # Check for the availability of the `rand48' family of random number
# generation functions. # generation functions.
have_rand48=yes have_rand48=yes
AC_CHECK_FUNCS([srand48 lrand48 seed48], AC_CHECK_FUNCS(
[srand48 lrand48 seed48],
[], [],
[have_rand48=no [have_rand48=no
AC_CHECK_FUNCS([rand srand], AC_CHECK_FUNCS(
[rand srand],
[], [],
[AC_MSG_ERROR([missing library functions for random number generation])])]) [AC_MSG_ERROR([missing library functions for random number generation])])])
if test "${have_rand48}" = yes; then if test "${have_rand48}" = yes; then
AC_DEFINE([HAVE_RAND48], AC_DEFINE(
[HAVE_RAND48],
[1], [1],
[Define if you have the `rand48' family of random number generation functions.]) [Define if you have the `rand48' family of random number generation functions.])
fi fi

File diff suppressed because it is too large Load diff

View file

@ -92,7 +92,9 @@ BuchiAutomaton::BuchiAutomaton(const BuchiAutomaton& automaton) :
++transition) ++transition)
connect(state, connect(state,
static_cast<const BuchiTransition*>(*transition)->targetNode(), static_cast<const BuchiTransition*>(*transition)->targetNode(),
static_cast<const BuchiTransition*>(*transition)->guard()); static_cast<const BuchiTransition*>(*transition)->guard(),
static_cast<const BuchiTransition*>(*transition)
->acceptanceSets());
operator[](state).acceptanceSets().copy(automaton[state].acceptanceSets(), operator[](state).acceptanceSets().copy(automaton[state].acceptanceSets(),
number_of_acceptance_sets); number_of_acceptance_sets);
@ -129,7 +131,9 @@ BuchiAutomaton& BuchiAutomaton::operator=(const BuchiAutomaton& automaton)
++transition) ++transition)
connect(state, connect(state,
static_cast<const BuchiTransition*>(*transition)->targetNode(), static_cast<const BuchiTransition*>(*transition)->targetNode(),
static_cast<const BuchiTransition*>(*transition)->guard()); static_cast<const BuchiTransition*>(*transition)->guard(),
static_cast<const BuchiTransition*>(*transition)
->acceptanceSets());
operator[](state).acceptanceSets().copy operator[](state).acceptanceSets().copy
(automaton[state].acceptanceSets(), number_of_acceptance_sets); (automaton[state].acceptanceSets(), number_of_acceptance_sets);
@ -190,113 +194,13 @@ BuchiAutomaton::size_type BuchiAutomaton::expand(size_type node_count)
return nodes.size() - 1; return nodes.size() - 1;
} }
/* ========================================================================= */
BuchiAutomaton* BuchiAutomaton::regularize() const
/* ----------------------------------------------------------------------------
*
* Description: Converts a generalized Büchi automaton (i.e., an automaton
* with any number of accepting state sets) into an automaton
* with only one set of accepting states.
*
* Arguments: None.
*
* Returns: A pointer to an equivalent BuchiAutomaton with exactly one
* set of accepting states.
*
* ------------------------------------------------------------------------- */
{
/*
* If `this' automaton already has exactly one set of accepting states,
* return a copy of `this' automaton.
*/
if (number_of_acceptance_sets == 1)
return new BuchiAutomaton(*this);
/*
* Otherwise construct the result using a depth-first search in `this'
* automaton.
*/
typedef pair<size_type, unsigned long int> ExpandedState;
BuchiAutomaton* result_automaton = new BuchiAutomaton(0, 0, 1);
if (empty())
return result_automaton;
stack<ExpandedState, deque<ExpandedState, ALLOC(ExpandedState) > >
states_to_process;
map<ExpandedState, size_type, less<ExpandedState>, ALLOC(size_type) >
state_mapping;
const GraphEdgeContainer* transitions;
size_type result_source_state, result_target_state;
map<ExpandedState, size_type, less<ExpandedState>, ALLOC(size_type) >
::const_iterator check_state;
ExpandedState state = make_pair(initial_state, 0);
states_to_process.push(state);
state_mapping[state] = result_automaton->expand();
while (!states_to_process.empty())
{
state = states_to_process.top();
states_to_process.pop();
result_source_state = state_mapping[state];
transitions = &operator[](state.first).edges();
if (number_of_acceptance_sets == 0
|| operator[](state.first).acceptanceSets().test(state.second))
{
if (state.second == 0)
(*result_automaton)[result_source_state].acceptanceSets().setBit(0);
if (number_of_acceptance_sets > 0)
{
++state.second;
state.second %= number_of_acceptance_sets;
}
}
for (GraphEdgeContainer::const_iterator transition = transitions->begin();
transition != transitions->end();
++transition)
{
state.first = (*transition)->targetNode();
check_state = state_mapping.find(state);
if (check_state == state_mapping.end())
{
result_target_state = result_automaton->expand();
state_mapping[state] = result_target_state;
states_to_process.push(state);
}
else
result_target_state = check_state->second;
result_automaton->connect(result_source_state, result_target_state,
static_cast<const BuchiTransition*>
(*transition)->guard());
}
}
return result_automaton;
}
/* ========================================================================= */ /* ========================================================================= */
void BuchiAutomaton::read(istream& input_stream) void BuchiAutomaton::read(istream& input_stream)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Reads an automaton description (which may represent a * Description: Reads an automaton description (which may represent a
* generalized Büchi automaton) from a stream and stores it * generalized Büchi automaton) from a stream and stores it
* into the automaton object, converting it to a regular * into the automaton object.
* Büchi automaton if necessary.
* *
* Argument: input_stream -- A reference to an input stream. * Argument: input_stream -- A reference to an input stream.
* *
@ -312,20 +216,63 @@ void BuchiAutomaton::read(istream& input_stream)
try try
{ {
/* /* Read the number of states in the generalized Büchi automaton. */
* Read in the number of states in the generalized Büchi automaton.
*/
einput_stream >> number_of_states; einput_stream >> number_of_states;
/* /* If the automaton is empty, do nothing. */
* If the automaton is empty, do nothing.
*/
if (number_of_states == 0) if (number_of_states == 0)
return; return;
einput_stream >> number_of_acceptance_sets; /*
* Determine the number and placement of acceptance sets.
* (Acceptance sets are described using strings described by the regular
* expression [0-9]+(s|S|t|T)*, where the [0-9]+ part corresponds to the
* number of the sets, and the (s|S|t|T)* part corresponds to the
* placement of the sets -- s or S for states, t or T for transitions.
* To retain compatibility with lbtt 1.0.x, the acceptance set placement
* defaults to acceptance sets on states if is not given explicitly.)
*/
bool acceptance_sets_on_states = false;
bool acceptance_sets_on_transitions = false;
string tok;
einput_stream >> tok;
string::size_type s_pos = string::npos;
string::size_type t_pos = string::npos;
string::size_type pos = tok.find_first_not_of("0123456789");
if (pos == 0)
throw AutomatonParseException
("invalid specification for acceptance sets");
number_of_acceptance_sets = strtoul(tok.substr(0, pos).c_str(), 0, 10);
for ( ; pos < tok.length(); ++pos)
{
if (tok[pos] == 's' || tok[pos] == 'S')
{
s_pos = pos;
acceptance_sets_on_states = true;
}
else if (tok[pos] == 't' || tok[pos] == 'T')
{
t_pos = pos;
acceptance_sets_on_transitions = true;
}
else
throw AutomatonParseException
("invalid specification for acceptance sets");
}
if (s_pos == string::npos && t_pos == string::npos)
{
acceptance_sets_on_states = true;
acceptance_sets_on_transitions = false;
}
BitArray acc_sets(number_of_acceptance_sets);
/* /*
* Allocate space for the regular Büchi automaton that will be constructed * Allocate space for the regular Büchi automaton that will be constructed
@ -446,6 +393,8 @@ void BuchiAutomaton::read(istream& input_stream)
operator[](current_state).acceptanceSets().clear operator[](current_state).acceptanceSets().clear
(number_of_acceptance_sets); (number_of_acceptance_sets);
if (acceptance_sets_on_states)
{
while (1) while (1)
{ {
einput_stream >> acceptance_set_mapping.first; einput_stream >> acceptance_set_mapping.first;
@ -471,11 +420,14 @@ void BuchiAutomaton::read(istream& input_stream)
operator[](current_state).acceptanceSets().setBit(acceptance_set); operator[](current_state).acceptanceSets().setBit(acceptance_set);
} }
}
/* /*
* Process the transitions from the state to other states. Read a * Process the transitions from the state to other states. Read a
* target state id and add a mapping for it in the translation table if * target state id and add a mapping for it in the translation table if
* necessary. Then, read the propositional formula guarding the * necessary. If the automaton is allowed to have acceptance sets
* associated with transitions, read an additional list of acceptance
* sets. Finally, read the propositional formula guarding the
* transition and connect the current state to the target using the * transition and connect the current state to the target using the
* guard formula. * guard formula.
*/ */
@ -501,6 +453,42 @@ void BuchiAutomaton::read(istream& input_stream)
state_mapping.second++; state_mapping.second++;
} }
acc_sets.clear(number_of_acceptance_sets);
/*
* If automata with acceptance sets on transitions are accepted, read
* the acceptance sets associated with the transition.
*/
if (acceptance_sets_on_transitions)
{
while (1)
{
einput_stream >> acceptance_set_mapping.first;
if (acceptance_set_mapping.first == -1)
break;
acceptance_set_finder =
acceptance_set_map.insert(acceptance_set_mapping);
if (!acceptance_set_finder.second)
acceptance_set = (acceptance_set_finder.first)->second;
else
{
if (acceptance_set_mapping.second >= number_of_acceptance_sets)
throw AutomatonParseException("number of acceptance sets "
"does not match automaton state "
"definitions");
acceptance_set = acceptance_set_mapping.second;
++acceptance_set_mapping.second;
}
acc_sets.setBit(acceptance_set);
}
}
try try
{ {
guard = ::Ltl::LtlFormula::read(input_stream); guard = ::Ltl::LtlFormula::read(input_stream);
@ -516,7 +504,7 @@ void BuchiAutomaton::read(istream& input_stream)
throw AutomatonParseException("illegal operators in guard formula"); throw AutomatonParseException("illegal operators in guard formula");
} }
connect(current_state, neighbor_state, guard); connect(current_state, neighbor_state, guard, acc_sets);
} }
processed_states.setBit(current_state); processed_states.setBit(current_state);
@ -544,297 +532,6 @@ void BuchiAutomaton::read(istream& input_stream)
} }
} }
/* ========================================================================= */
BuchiAutomaton* BuchiAutomaton::intersect
(const BuchiAutomaton& a1, const BuchiAutomaton& a2,
map<size_type, StateIdPair, less<size_type>, ALLOC(StateIdPair) >*
intersection_state_mapping)
/* ----------------------------------------------------------------------------
*
* Description: Computes the intersection of two Büchi automata and returns
* a pointer to the intersection of the two automata.
*
* Arguments: a1, a2 -- References to two constant
* Büchi automata.
* intersection_state_mapping -- An (optional) pointer to a
* map which can be used to find
* out the state identifiers of
* the original automata to
* which a particular state in
* the intersection corresponds.
*
* Returns: A newly allocated BuchiAutomaton representing the
* intersection of the two automata.
*
* ------------------------------------------------------------------------- */
{
if (intersection_state_mapping != 0)
intersection_state_mapping->clear();
/*
* If either of the original automata is empty, the intersection is also
* empty.
*/
if (a1.empty() || a2.empty())
return new BuchiAutomaton(0, 0, 0);
BuchiAutomaton* automaton;
/*
* Determine the number of acceptance sets in the intersection.
*/
const bool a1_has_no_acceptance_sets = (a1.number_of_acceptance_sets == 0);
const bool a2_has_no_acceptance_sets = (a2.number_of_acceptance_sets == 0);
unsigned long int number_of_intersection_acceptance_sets;
if (a1_has_no_acceptance_sets && a2_has_no_acceptance_sets)
number_of_intersection_acceptance_sets = 0;
else
number_of_intersection_acceptance_sets = a1.number_of_acceptance_sets
+ a2.number_of_acceptance_sets;
automaton = new BuchiAutomaton(1, 0, number_of_intersection_acceptance_sets);
/*
* A stack for processing pairs of states of the original automata.
*/
stack<const StateIdPair*, deque<const StateIdPair*,
ALLOC(const StateIdPair*) > >
unprocessed_states;
/*
* `state_mapping' maps pairs of states of the original automata to the
* states of the new automaton.
*/
map<StateIdPair, size_type, less<StateIdPair>, ALLOC(size_type) >
state_mapping;
size_type first_free_id = 1; /* First free identifier for a
* new state in the intersection
* automaton.
*/
const StateIdPair* state_pair; /* Pointer to pair of two state
* identifiers of the original
* automata.
*/
size_type intersect_state; /* `Current' state in the
* intersection automaton.
*/
bool intersect_state_valid; /* True if the current state has
* been determined by using the
* mapping.
*/
BitArray* intersect_acceptance_sets; /* Pointers for accessing the */
const BitArray* acceptance_sets; /* acceptance sets of the new
* and the original automata.
*/
const GraphEdgeContainer* transitions1; /* Pointers for accessing the */
const GraphEdgeContainer* transitions2; /* transitions of the two
* original automata.
*/
::Ltl::LtlFormula* guard1; /* Pointers for accessing the */
::Ltl::LtlFormula* guard2; /* guard formulas of the */
::Ltl::LtlFormula* new_guard; /* transitions of the
* automata.
*/
/*
* Insert the initial state into the state mapping.
*/
state_mapping.insert(make_pair(make_pair(a1.initial_state, a2.initial_state),
0));
unprocessed_states.push(&(state_mapping.begin()->first));
/*
* Adjust the acceptance sets of the initial state of the intersection.
*/
intersect_acceptance_sets = &((*automaton)[0].acceptanceSets());
if (!a1_has_no_acceptance_sets)
{
acceptance_sets = &(a1[a1.initial_state].acceptanceSets());
for (unsigned long int accept_set = 0;
accept_set < a1.number_of_acceptance_sets;
accept_set++)
{
if (acceptance_sets->test(accept_set))
intersect_acceptance_sets->setBit(accept_set);
}
}
if (!a2_has_no_acceptance_sets)
{
acceptance_sets = &(a2[a2.initial_state].acceptanceSets());
for (unsigned long int accept_set = 0;
accept_set < a2.number_of_acceptance_sets;
accept_set++)
{
if (acceptance_sets->test(accept_set))
intersect_acceptance_sets->setBit(a1.number_of_acceptance_sets
+ accept_set);
}
}
/*
* Pop pairs of states of the two original automata until all states have
* been processed.
*/
try
{
while (!unprocessed_states.empty())
{
if (::user_break)
throw UserBreakException();
intersect_state_valid = false;
state_pair = unprocessed_states.top();
unprocessed_states.pop();
/*
* Loop through the transitions of the two original automata. If the
* conjunction of the guard formulae of any two transitions is
* satisfiable, insert a new transition into the intersection automaton.
* Create new states in the intersection automaton if necessary.
*/
transitions1 = &a1[state_pair->first].edges();
transitions2 = &a2[state_pair->second].edges();
for (GraphEdgeContainer::const_iterator tr1 = transitions1->begin();
tr1 != transitions1->end();
++tr1)
{
guard1 = &(static_cast<BuchiTransition*>(*tr1)->guard());
for (GraphEdgeContainer::const_iterator tr2 = transitions2->begin();
tr2 != transitions2->end();
++tr2)
{
guard2 = &(static_cast<BuchiTransition*>(*tr2)->guard());
new_guard = &Ltl::And::construct(*guard1, *guard2);
if (new_guard->satisfiable())
{
/*
* Determine the `current' state of the intersection automaton.
*/
if (!intersect_state_valid)
{
intersect_state = state_mapping[*state_pair];
intersect_state_valid = true;
}
/*
* Test whether the state pair pointed to by the two transitions
* is already in the intersection.
*/
pair<map<StateIdPair, size_type, less<StateIdPair>,
ALLOC(size_type) >::iterator, bool>
check_state;
check_state
= state_mapping.insert(make_pair(make_pair((*tr1)->targetNode(),
(*tr2)->targetNode()),
first_free_id));
if (check_state.second) /* insertion occurred? */
{
automaton->expand();
/*
* Determine the acceptance sets to which the new state in the
* intersection automaton belongs.
*/
intersect_acceptance_sets
= &((*automaton)[first_free_id].acceptanceSets());
if (!a1_has_no_acceptance_sets)
{
acceptance_sets = &(a1[check_state.first->first.first].
acceptanceSets());
for (unsigned long int accept_set = 0;
accept_set < a1.number_of_acceptance_sets;
accept_set++)
{
if (acceptance_sets->test(accept_set))
intersect_acceptance_sets->setBit(accept_set);
}
}
if (!a2_has_no_acceptance_sets)
{
acceptance_sets = &(a2[check_state.first->first.second].
acceptanceSets());
for (unsigned long int accept_set = 0;
accept_set < a2.number_of_acceptance_sets;
accept_set++)
{
if (acceptance_sets->test(accept_set))
intersect_acceptance_sets->setBit
(a1.number_of_acceptance_sets + accept_set);
}
}
/*
* Connect the `current' state of the intersection automaton to
* the new state.
*/
automaton->connect(intersect_state, first_free_id, new_guard);
first_free_id++;
unprocessed_states.push(&(check_state.first->first));
}
else
automaton->connect(intersect_state, check_state.first->second,
new_guard);
}
else
::Ltl::LtlFormula::destruct(new_guard);
}
}
}
if (intersection_state_mapping != 0)
{
for (map<StateIdPair, size_type, less<StateIdPair>, ALLOC(size_type) >
::const_iterator mapping = state_mapping.begin();
mapping != state_mapping.end();
++mapping)
intersection_state_mapping->insert(make_pair(mapping->second,
mapping->first));
}
}
catch (...)
{
delete automaton;
throw;
}
return automaton;
}
/* ========================================================================= */ /* ========================================================================= */
void BuchiAutomaton::print void BuchiAutomaton::print
(ostream& stream, const int indent, const GraphOutputFormat fmt) const (ostream& stream, const int indent, const GraphOutputFormat fmt) const
@ -876,7 +573,7 @@ void BuchiAutomaton::print
<< " transitions.\n" + string(indent, ' ') << " transitions.\n" + string(indent, ' ')
+ "The automaton has " + "The automaton has "
<< number_of_acceptance_sets << number_of_acceptance_sets
<< " sets of accepting states.\n" + string(indent, ' ') << " acceptance sets.\n" + string(indent, ' ')
+ "The reachable part of the automaton contains\n" + "The reachable part of the automaton contains\n"
+ string(indent + 4, ' ') + string(indent + 4, ' ')
<< reachable_part_statistics.first << reachable_part_statistics.first
@ -937,7 +634,8 @@ void BuchiAutomaton::print
++transition) ++transition)
{ {
estream << string(indent + 2, ' ') + 'n' << state; estream << string(indent + 2, ' ') + 'n' << state;
(*transition)->print(stream, indent, fmt); static_cast<const BuchiTransition*>(*transition)
->print(stream, indent, fmt, number_of_acceptance_sets);
estream << ";\n"; estream << ";\n";
} }
} }
@ -960,15 +658,22 @@ void BuchiAutomaton::print
/* ========================================================================= */ /* ========================================================================= */
void BuchiAutomaton::BuchiTransition::print void BuchiAutomaton::BuchiTransition::print
(ostream& stream, const int indent, const GraphOutputFormat fmt) const (ostream& stream, const int indent, const GraphOutputFormat fmt,
const unsigned long int number_of_acceptance_sets) const
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Writes information about a transition between two states of * Description: Writes information about a transition between two states of
* a Büchi automaton. * a Büchi automaton.
* *
* Arguments: stream -- A reference to an output stream. * Arguments: stream -- A reference to an output
* indent -- Number of spaces to leave to the left of output. * stream.
* fmt -- Determines the format of output. * indent -- Number of spaces to leave to
* the left of output.
* fmt -- Determines the format of
* output.
* number_of_acceptance_sets -- Number of acceptance sets in
* the automaton to which the
* transition belongs.
* *
* Returns: Nothing. * Returns: Nothing.
* *
@ -977,11 +682,9 @@ void BuchiAutomaton::BuchiTransition::print
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit); Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
if (fmt == NORMAL) if (fmt == NORMAL)
{
estream << string(indent, ' ') + "Transition to state " estream << string(indent, ' ') + "Transition to state "
<< targetNode() << targetNode()
<< " [ guard: " << *guard_formula << " ]\n"; << " [ acc.: ";
}
else if (fmt == DOT) else if (fmt == DOT)
{ {
string formula(StringUtil::toString(*guard_formula)); string formula(StringUtil::toString(*guard_formula));
@ -1002,9 +705,33 @@ void BuchiAutomaton::BuchiTransition::print
else else
estream << formula[i]; estream << formula[i];
} }
estream << "\",fontsize=10,fontname=\"Courier-Bold\"]";
estream << "\\n";
} }
estream << '{';
bool first_printed = false;
for (unsigned long int accept_set = 0;
accept_set < number_of_acceptance_sets;
++accept_set)
{
if (acceptance_sets[accept_set])
{
if (first_printed)
estream << ", ";
else
first_printed = true;
estream << accept_set;
}
}
estream << '}';
if (fmt == NORMAL)
estream << ", guard: " << *guard_formula << " ]\n";
else if (fmt == DOT)
estream << "\",fontsize=10,fontname=\"Courier-Bold\"]";
estream.flush(); estream.flush();
} }
@ -1069,7 +796,8 @@ void BuchiAutomaton::BuchiState::print
GraphEdgeContainer::const_iterator edge; GraphEdgeContainer::const_iterator edge;
for (edge = edges().begin(); edge != edges().end(); ++edge) for (edge = edges().begin(); edge != edges().end(); ++edge)
(*edge)->print(stream, indent); static_cast<const BuchiAutomaton::BuchiTransition*>(*edge)
->print(stream, indent, fmt, number_of_acceptance_sets);
} else } else
estream << string(indent, ' ') + "No transitions to other states.\n"; estream << string(indent, ' ') + "No transitions to other states.\n";

View file

@ -21,6 +21,7 @@
#define BUCHIAUTOMATON_H #define BUCHIAUTOMATON_H
#include <config.h> #include <config.h>
#include <cstdlib>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <string> #include <string>
@ -38,8 +39,7 @@ namespace Graph
/****************************************************************************** /******************************************************************************
* *
* A class for representing Büchi automata with a single set of accepting * A class for representing generalized Büchi automata.
* states.
* *
*****************************************************************************/ *****************************************************************************/
@ -139,15 +139,19 @@ public:
void connect /* Connects two states */ void connect /* Connects two states */
(const size_type father, /* of the automaton with */ (const size_type father, /* of the automaton with */
const size_type child); /* an unguarded const size_type child); /* an unguarded
* transition. * transition with no
* associated acceptance
* sets.
*/ */
void connect /* Connects two states */ void connect /* Connects two states */
(const size_type father, const size_type child, /* of the automaton with */ (const size_type father, const size_type child, /* of the automaton with */
::Ltl::LtlFormula& guard); /* a transition guarded */ ::Ltl::LtlFormula& guard, /* a transition guarded */
void connect /* by a propositional */ const BitArray& acc_sets); /* by a propositional */
(const size_type father, const size_type child, /* formula. */ void connect /* formula. */
::Ltl::LtlFormula* guard); (const size_type father, const size_type child,
::Ltl::LtlFormula* guard,
const BitArray& acc_sets);
/* `disconnect' inherited from Graph<GraphEdgeContainer> */ /* `disconnect' inherited from Graph<GraphEdgeContainer> */
@ -167,12 +171,6 @@ public:
* automaton. * automaton.
*/ */
BuchiAutomaton* regularize() const; /* Converts a generalized
* automaton to an
* automaton with one set
* of accepting states.
*/
void read(istream& input_stream); /* Reads the automaton void read(istream& input_stream); /* Reads the automaton
* from a stream. * from a stream.
*/ */
@ -185,13 +183,6 @@ public:
* `fmt' argument). * `fmt' argument).
*/ */
static BuchiAutomaton* intersect /* Computes the */
(const BuchiAutomaton& a1, /* intersection of two */
const BuchiAutomaton& a2, /* Büchi automata. */
map<size_type, StateIdPair,
less<size_type>, ALLOC(StateIdPair) >*
intersection_state_mapping = 0);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class AutomatonParseException; /* Class for reporting class AutomatonParseException; /* Class for reporting
@ -227,14 +218,12 @@ class BuchiAutomaton::BuchiTransition : public Graph<GraphEdgeContainer>::Edge
public: public:
BuchiTransition /* Constructor. */ BuchiTransition /* Constructor. */
(const size_type target, (const size_type target,
::Ltl::LtlFormula* formula); ::Ltl::LtlFormula* formula,
const BitArray& acc_sets,
unsigned long int num_acc_sets);
~BuchiTransition(); /* Destructor. */ ~BuchiTransition(); /* Destructor. */
private:
public:
/* `targetNode' inherited from Graph<GraphEdgeContainer>::Edge */ /* `targetNode' inherited from Graph<GraphEdgeContainer>::Edge */
bool enabled /* These functions test */ bool enabled /* These functions test */
@ -250,14 +239,24 @@ public:
* guarding the transition. * guarding the transition.
*/ */
void print /* Writes information */ BitArray& acceptanceSets(); /* Returns the */
(ostream& stream = cout, /* about the transition */ const BitArray& acceptanceSets() const; /* acceptance sets
const int indent = 0, /* to a stream in */ * associated with the
const GraphOutputFormat fmt = NORMAL) const; /* various formats * the transition.
* (determined by the
* `fmt' argument).
*/ */
void print /* Writes information */
(ostream& stream, /* about the transition */
const int indent, /* (as a plain graph */
const GraphOutputFormat fmt) const; /* edge) to a stream. */
void print /* Writes information */
(ostream& stream, /* about the transition */
const int indent, /* to a stream in */
const GraphOutputFormat fmt, /* various formats */
const unsigned long int /* (determined by the */
number_of_acceptance_sets) const; /* `fmt' argument). */
private: private:
BuchiTransition(const BuchiTransition&); /* Prevent copying and */ BuchiTransition(const BuchiTransition&); /* Prevent copying and */
BuchiTransition& operator= /* assignment of */ BuchiTransition& operator= /* assignment of */
@ -281,6 +280,11 @@ private:
* formula guarding the * formula guarding the
* transition. * transition.
*/ */
BitArray acceptance_sets; /* Acceptance sets
* associated with the
* transition.
*/
}; };
@ -372,7 +376,8 @@ inline void BuchiAutomaton::connect
* *
* Description: Connects two states of a BuchiAutomaton to each other with an * Description: Connects two states of a BuchiAutomaton to each other with an
* unguarded transition (actually, a transition with a guard * unguarded transition (actually, a transition with a guard
* that is always true). * that is always true) with an empty set of acceptance
* conditions.
* *
* Arguments: father -- Source state identifier. * Arguments: father -- Source state identifier.
* child -- Target state identifier. * child -- Target state identifier.
@ -381,12 +386,15 @@ inline void BuchiAutomaton::connect
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
connect(father, child, &(::Ltl::True::construct())); BitArray acc_sets(number_of_acceptance_sets);
acc_sets.clear(number_of_acceptance_sets);
connect(father, child, &(::Ltl::True::construct()), acc_sets);
} }
/* ========================================================================= */ /* ========================================================================= */
inline void BuchiAutomaton::connect inline void BuchiAutomaton::connect
(const size_type father, const size_type child, ::Ltl::LtlFormula& guard) (const size_type father, const size_type child, ::Ltl::LtlFormula& guard,
const BitArray& acc_sets)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Connects two states of a BuchiAutomaton to each other, using * Description: Connects two states of a BuchiAutomaton to each other, using
@ -397,17 +405,20 @@ inline void BuchiAutomaton::connect
* child -- Target state. * child -- Target state.
* guard -- A reference to an LtlFormula (a propositional * guard -- A reference to an LtlFormula (a propositional
* formula) guarding the transition. * formula) guarding the transition.
* acc_sets -- A reference to a BitArray giving the
* acceptance sets associated with the transition.
* *
* Returns: Nothing. * Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
connect(father, child, guard.clone()); connect(father, child, guard.clone(), acc_sets);
} }
/* ========================================================================= */ /* ========================================================================= */
inline void BuchiAutomaton::connect inline void BuchiAutomaton::connect
(const size_type father, const size_type child, ::Ltl::LtlFormula* guard) (const size_type father, const size_type child, ::Ltl::LtlFormula* guard,
const BitArray& acc_sets)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Connects two states of a BuchiAutomaton to each other, using * Description: Connects two states of a BuchiAutomaton to each other, using
@ -417,14 +428,17 @@ inline void BuchiAutomaton::connect
* Arguments: father -- Source state. * Arguments: father -- Source state.
* child -- Target state. * child -- Target state.
* guard -- A pointer to an LtlFormula (a propositional * guard -- A pointer to an LtlFormula (a propositional
* formula) guarding the transition. The transition * formula) guarding the transition. The
* will "own" the guard formula. * transition will "own" the guard formula.
* acc_sets -- A reference to a BitArray giving the acceptance
* sets associated with the transition.
* *
* Returns: Nothing. * Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
BuchiTransition* new_buchi_transition = new BuchiTransition(child, guard); BuchiTransition* new_buchi_transition
= new BuchiTransition(child, guard, acc_sets, number_of_acceptance_sets);
try try
{ {
@ -512,39 +526,28 @@ inline istream& operator>>(istream& stream, BuchiAutomaton& automaton)
/* ========================================================================= */ /* ========================================================================= */
inline BuchiAutomaton::BuchiTransition::BuchiTransition inline BuchiAutomaton::BuchiTransition::BuchiTransition
(const size_type target, ::Ltl::LtlFormula* formula) : (const size_type target, ::Ltl::LtlFormula* formula,
Edge(target), guard_formula(formula) const BitArray& acc_sets, unsigned long int num_acc_sets) :
Edge(target), guard_formula(formula), acceptance_sets(num_acc_sets)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Constructor for class BuchiAutomaton::BuchiTransition. * Description: Constructor for class BuchiAutomaton::BuchiTransition.
* Initializes a new transition to a BuchiState, guarded by an * Initializes a new transition to a BuchiState, guarded by an
* LtlFormula (which is actually a propositional formula). * LtlFormula (which is actually a propositional formula).
* *
* Arguments: target -- Identifier of the target state of the automaton. * Arguments: target -- Identifier of the target state of the
* automaton.
* formula -- A pointer to a propositional formula guarding * formula -- A pointer to a propositional formula guarding
* the transition. * the transition.
* acc_sets -- A reference to a constant BitArray containing
* the acceptance sets associated with the
* transition.
* *
* Returns: Nothing. * Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
} acceptance_sets.copy(acc_sets, num_acc_sets);
/* ========================================================================= */
inline BuchiAutomaton::BuchiTransition::BuchiTransition
(const BuchiTransition& transition) :
Edge(transition), guard_formula(transition.guard_formula->clone())
/* ----------------------------------------------------------------------------
*
* Description: Copy constructor for class BuchiAutomaton::BuchiTransition.
* Creates a copy of a BuchiTransition object.
*
* Arguments: transition -- BuchiTransition to be copied.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
} }
/* ========================================================================= */ /* ========================================================================= */
@ -688,6 +691,59 @@ inline ::Ltl::LtlFormula& BuchiAutomaton::BuchiTransition::guard() const
return *guard_formula; return *guard_formula;
} }
/* ========================================================================= */
inline BitArray& BuchiAutomaton::BuchiTransition::acceptanceSets()
/* ----------------------------------------------------------------------------
*
* Description: Returns the acceptance sets associated with a
* BuchiTransition.
*
* Arguments: None.
*
* Returns: A reference to the BitArray storing the acceptance sets
* associated with the transition.
*
* ------------------------------------------------------------------------- */
{
return acceptance_sets;
}
/* ========================================================================= */
inline const BitArray& BuchiAutomaton::BuchiTransition::acceptanceSets() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the acceptance sets associated with a
* BuchiTransition.
*
* Arguments: None.
*
* Returns: A constant reference to the BitArray storing the acceptance
* sets associated with the transition.
*
* ------------------------------------------------------------------------- */
{
return acceptance_sets;
}
/* ========================================================================= */
inline void BuchiAutomaton::BuchiTransition::print
(ostream& stream, const int indent, const GraphOutputFormat fmt) const
/* ----------------------------------------------------------------------------
*
* Description: Writes information about a transition (as a plain graph edge
* without any associated information) to a stream.
*
* Arguments: stream -- A reference to an output stream.
* indent -- Number of spaces to leave to the left of output.
* fmt -- Determines the output format of the transition.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Graph<GraphEdgeContainer>::Edge::print(stream, indent, fmt);
}
/****************************************************************************** /******************************************************************************

98
lbtt/src/BuchiProduct.cc Normal file
View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 "BuchiProduct.h"
namespace Graph
{
/******************************************************************************
*
* Static member definitions for class BuchiProduct.
*
*****************************************************************************/
map< ::Ltl::LtlFormula*, BuchiProduct::SatisfiabilityMapping,
less< ::Ltl::LtlFormula*>, ALLOC(BuchiProduct::SatisfiabilityMapping) >
BuchiProduct::sat_cache;
/******************************************************************************
*
* Function definitions for class BuchiProduct.
*
*****************************************************************************/
/* ========================================================================= */
bool BuchiProduct::synchronizable
(const Graph<GraphEdgeContainer>::Edge& transition_1,
const Graph<GraphEdgeContainer>::Edge& transition_2)
/* ----------------------------------------------------------------------------
*
* Description: Tests whether two transitions of two Büchi automata are
* synchronizable by checking whether the conjunction of their
* guard formulas is satisfiable.
*
* Arguments: transition_1, -- Constant references to the transitions.
* transition_2
*
* Returns: true iff the transitions are synchronizable. The result is
* also stored into `this->sat_cache' for later reference.
*
* ------------------------------------------------------------------------- */
{
using ::Ltl::LtlFormula;
using ::Ltl::And;
LtlFormula* guard_1 = &static_cast<const BuchiAutomaton::BuchiTransition&>
(transition_1).guard();
LtlFormula* guard_2 = &static_cast<const BuchiAutomaton::BuchiTransition&>
(transition_2).guard();
if (guard_2 > guard_1)
{
LtlFormula* swap_guard = guard_2;
guard_2 = guard_1;
guard_1 = swap_guard;
}
map<LtlFormula*, SatisfiabilityMapping, less<LtlFormula*>,
ALLOC(SatisfiabilityMapping) >::iterator
sat_cache_element = sat_cache.find(guard_1);
if (sat_cache_element == sat_cache.end())
sat_cache_element = sat_cache.insert
(make_pair(guard_1, SatisfiabilityMapping())).first;
else
{
SatisfiabilityMapping::const_iterator sat_result
= sat_cache_element->second.find(guard_2);
if (sat_result != sat_cache_element->second.end())
return sat_result->second;
}
LtlFormula* f = &And::construct(*guard_1, *guard_2);
const bool result = f->satisfiable();
LtlFormula::destruct(f);
sat_cache_element->second.insert(make_pair(guard_2, result));
return result;
}
}

512
lbtt/src/BuchiProduct.h Normal file
View file

@ -0,0 +1,512 @@
/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 BUCHIPRODUCT_H
#define BUCHIPRODUCT_H
#include <config.h>
#include <deque>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "BitArray.h"
#include "BuchiAutomaton.h"
#include "EdgeContainer.h"
#include "Graph.h"
#include "LtlFormula.h"
using namespace std;
namespace Graph
{
/******************************************************************************
*
* A class with operations for checking the intersection of two Büchi automata
* (represented as two BuchiAutomaton objects) for emptiness.
*
*****************************************************************************/
class BuchiProduct
{
public:
BuchiProduct /* Constructor. */
(const Graph<GraphEdgeContainer>& a1,
const Graph<GraphEdgeContainer>& a2);
/* default copy constructor */
~BuchiProduct(); /* Destructor. */
/* default assignment operator */
bool empty() const; /* Tells whether the
* intersection of the
* Büchi automata
* associated with the
* product object is
* (trivially) empty.
*/
unsigned long int numberOfAcceptanceSets() const; /* Tells the number of
* acceptance sets in the
* intersection of the
* automata associated with
* the object.
*/
const BuchiAutomaton::BuchiState& firstComponent /* Mappings between an */
(const Graph<GraphEdgeContainer>::size_type /* intersection state */
state_id) const; /* identifier and states */
const BuchiAutomaton::BuchiState& secondComponent /* of the underlying */
(const Graph<GraphEdgeContainer>::size_type /* automata. */
state_id) const;
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Node& state1, /* sets associated with */
const Graph<GraphEdgeContainer>::Node& state2, /* a pair of states into */
BitArray& acceptance_sets) const; /* a collection of sets. */
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Edge& /* sets associated with */
transition1, /* a pair of */
const Graph<GraphEdgeContainer>::Edge& /* transitions into a */
transition2, /* collection of sets. */
BitArray& acceptance_sets) const;
void validateEdgeIterators /* Ensures that a pair */
(const Graph<GraphEdgeContainer>::Node& /* of transition */
state_1, /* iterators points to a */
const Graph<GraphEdgeContainer>::Node& /* transition beginning */
state_2, /* from a given state in */
GraphEdgeContainer::const_iterator& /* the intersection of */
transition_1, /* two Büchi automata. */
GraphEdgeContainer::const_iterator&
transition_2);
void incrementEdgeIterators /* Updates a pair of */
(const Graph<GraphEdgeContainer>::Node& /* transition iterators */
state_1, /* to make them point to */
const Graph<GraphEdgeContainer>::Node& /* the "next" transition */
state_2, /* starting from a given */
GraphEdgeContainer::const_iterator& /* state in the */
transition_1, /* intersection of two */
GraphEdgeContainer::const_iterator& /* Büchi automata. */
transition_2);
static void clearSatisfiabilityCache(); /* Clears information about
* the satisfiability of
* the guards of product
* transitions.
*/
private:
void mergeAcceptanceInformation /* Bitwise or between */
(const BitArray& sets1, const BitArray& sets2, /* two "component" */
BitArray& result) const; /* acceptance set
* vectors and a result
* vector.
*/
bool synchronizable /* Tests whether a pair */
(const Graph<GraphEdgeContainer>::Edge& /* of transitions of two */
transition_1, /* Büchi automata is */
const Graph<GraphEdgeContainer>::Edge& /* synchronizable. */
transition_2);
const BuchiAutomaton& automaton_1; /* Automata associated */
const BuchiAutomaton& automaton_2; /* with the BuchiProduct */
/* object. */
const unsigned long int /* Number of acceptance */
number_of_acceptance_sets; /* sets in the
* intersection of the
* automata.
*/
typedef map< ::Ltl::LtlFormula*, bool, /* Type definition for */
less< ::Ltl::LtlFormula*>, /* storing information */
ALLOC(bool) > /* about the */
SatisfiabilityMapping; /* satisfiability of the
* guards of product
* transitions.
*/
static map< ::Ltl::LtlFormula*, /* Result cache for */
SatisfiabilityMapping, /* satisfiability tests. */
less< ::Ltl::LtlFormula*>,
ALLOC(SatisfiabilityMapping) >
sat_cache;
};
/******************************************************************************
*
* Inline function definitions for class BuchiProduct.
*
*****************************************************************************/
/* ========================================================================= */
inline BuchiProduct::BuchiProduct
(const Graph<GraphEdgeContainer>& a1, const Graph<GraphEdgeContainer>& a2) :
automaton_1(static_cast<const BuchiAutomaton&>(a1)),
automaton_2(static_cast<const BuchiAutomaton&>(a2)),
number_of_acceptance_sets(static_cast<const BuchiAutomaton&>(a1)
.numberOfAcceptanceSets()
+ static_cast<const BuchiAutomaton&>(a2)
.numberOfAcceptanceSets())
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class BuchiProduct. Initializes a new object
* with operations for checking the emptiness of two Büchi
* automata.
*
* Arguments: a1, a2 -- Constant references to two
* Graph<GraphEdgeContainer> objects, assumed to be
* BüchiAutomaton objects to which to apply the
* operations.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline BuchiProduct::~BuchiProduct()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class BuchiProduct.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline bool BuchiProduct::empty() const
/* ----------------------------------------------------------------------------
*
* Description: Tells whether the intersection of the Büchi automata
* associated with a BuchiProduct object is (trivially) empty.
*
* Arguments: None.
*
* Returns: true iff either of the automata associated with the
* BuchiProduct object is (trivially) empty (i.e., whether
* either of the automata has no states).
*
* ------------------------------------------------------------------------- */
{
return (automaton_1.empty() || automaton_2.empty());
}
/* ========================================================================= */
inline unsigned long int BuchiProduct::numberOfAcceptanceSets() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the number of acceptance sets in the intersection of
* the two Büchi automata associated with a BuchiProduct object.
*
* Arguments: None.
*
* Returns: The number of acceptance sets in the intersection.
*
* ------------------------------------------------------------------------- */
{
return number_of_acceptance_sets;
}
/* ========================================================================= */
inline const BuchiAutomaton::BuchiState& BuchiProduct::firstComponent
(const Graph<GraphEdgeContainer>::size_type state_id) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing states of the "first" component
* automaton in the intersection of two Büchi automata.
*
* Argument: state_id -- Identifier of a state in the component
* automaton.
*
* Returns: A constant reference to a state in the component automaton.
*
* ------------------------------------------------------------------------- */
{
return automaton_1[state_id];
}
/* ========================================================================= */
inline const BuchiAutomaton::BuchiState& BuchiProduct::secondComponent
(const Graph<GraphEdgeContainer>::size_type state_id) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing states of the "second" component
* automaton in the intersection of two Büchi automata.
*
* Argument: state_id -- Identifier of a state in the component
* automaton.
*
* Returns: A constant reference to a state in the component automaton.
*
* ------------------------------------------------------------------------- */
{
return automaton_2[state_id];
}
/* ========================================================================= */
inline void BuchiProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Node& state1,
const Graph<GraphEdgeContainer>::Node& state2,
BitArray& acceptance_sets) const
/* ----------------------------------------------------------------------------
*
* Description: Merges the acceptance sets associated with a pair of states
* of two Büchi automata into a collection of sets.
*
* Arguments: state1, state2 -- Constant references to the states of the
* automata.
* acceptance_sets -- A reference to a BitArray for storing
* the result. The BitArray is assumed to
* have capacity for
* `this->number_of_acceptance_sets' bits.
*
* Returns: Nothing. Let n=`this->automaton_1.numberOfAcceptanceSets()';
* after the operation, `acceptance_sets[i] = true' holds if
* either
* 0 <= i < n and
* `state1.acceptanceSets().test(i) == true'
* or 0 <= i - n < `this->automaton_2.numberOfAcceptanceSets()'
* and `state2.acceptanceSets().test(i - n) == true'.
*
* ------------------------------------------------------------------------- */
{
mergeAcceptanceInformation
(static_cast<const BuchiAutomaton::BuchiState&>(state1).acceptanceSets(),
static_cast<const BuchiAutomaton::BuchiState&>(state2).acceptanceSets(),
acceptance_sets);
}
/* ========================================================================= */
inline void BuchiProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Edge& transition1,
const Graph<GraphEdgeContainer>::Edge& transition2,
BitArray& acceptance_sets) const
/* ----------------------------------------------------------------------------
*
* Description: Merges the acceptance sets associated with a pair of
* transitions of two Büchi automata into a collection of
* acceptance sets.
*
* Arguments: transition1, -- Constant references to the transitions
* transition2 of the automata.
* acceptance_sets -- A reference to a BitArray for storing
* the result. The BitArray is assumed to
* have capacity for
* `this->number_of_acceptance_sets' bits.
*
* Returns: Nothing. Let n=`this->automaton_1.numberOfAcceptanceSets()';
* after the operation, `acceptance_sets[i] = true' holds if
* either
* 0 <= i < n and
* `transition1.acceptanceSets().test(i) == true'
* or 0 <= i - n < `this->automaton_2.numberOfAcceptanceSets()'
* and `transition2.acceptanceSets().test(i - n) == true'.
*
* ------------------------------------------------------------------------- */
{
mergeAcceptanceInformation
(static_cast<const BuchiAutomaton::BuchiTransition&>(transition1)
.acceptanceSets(),
static_cast<const BuchiAutomaton::BuchiTransition&>(transition2)
.acceptanceSets(),
acceptance_sets);
}
/* ========================================================================= */
inline void BuchiProduct::mergeAcceptanceInformation
(const BitArray& sets1, const BitArray& sets2, BitArray& result) const
/* ----------------------------------------------------------------------------
*
* Description: Bitwise or between two acceptance set vectors and a result
* vector.
*
* Arguments: sets1, -- Constant references to two BitArrays having (at
* sets2 least) capacities
* `automaton_1.numberOfAcceptanceSets()' and
* `automaton_2.numberOfAcceptanceSets()',
* respectively.
* result -- A BitArray for storing the result, assumed to
* have room for at least
* `this->number_of_acceptance_sets' bits.
*
* Returns: Nothing. Let n=`this->automaton_1.numberOfAcceptanceSets()';
* after the operation, `result[i] = true' holds if
* either
* 0 <= i < n and `sets1[i] == true'
* or 0 <= i - n < `this->automaton_2.numberOfAcceptanceSets()'
* and `sets2[i - n] == true'.
*
* ------------------------------------------------------------------------- */
{
const unsigned long int shift
= automaton_1.numberOfAcceptanceSets();
unsigned long int acceptance_set;
for (acceptance_set = 0; acceptance_set < shift; ++acceptance_set)
{
if (sets1[acceptance_set])
result.setBit(acceptance_set);
}
for ( ; acceptance_set < number_of_acceptance_sets; ++acceptance_set)
{
if (sets2[acceptance_set - shift])
result.setBit(acceptance_set);
}
}
/* ========================================================================= */
inline void BuchiProduct::validateEdgeIterators
(const Graph<GraphEdgeContainer>::Node& state_1,
const Graph<GraphEdgeContainer>::Node& state_2,
GraphEdgeContainer::const_iterator& transition_1,
GraphEdgeContainer::const_iterator& transition_2)
/* ----------------------------------------------------------------------------
*
* Description: Checks whether a pair of transition iterators corresponds to
* a transition beginning from a state in the intersection of
* two Büchi automata; if this is not the case, increments the
* iterators to make them point to a valid transition beginning
* from the state in the intersection (or to the "end" of the
* collection of transitions beginning from the state if no
* valid transition can be found by incrementing the iterators).
*
* Arguments: state_1, -- These variables determine the state in
* state_2 the intersection automaton; `state_1' and
* `state_2' should both be references to
* BuchiAutomaton::BuchiState objects.
* transition_1, -- References to the transition iterators.
* transition_2 Initially, `transition_1' and
* `transition_2' should point to two
* transitions starting from `state_1' and
* `state_2', respectively.
*
* Returns: Nothing. Upon return, `transition_1' and `transition_2' will
* either equal `state_1.edges().end()' and
* `state_2.edges().end()', respectively, or they will point to
* a pair of transitions beginning from `state_1' and `state_2'
* such that this pair of transitions corresponds to a
* transition starting from the intersection state determined by
* `state_1' and `state_2'.
*
* ------------------------------------------------------------------------- */
{
const GraphEdgeContainer& transitions_1 = state_1.edges();
const GraphEdgeContainer& transitions_2 = state_2.edges();
if (transition_1 == transitions_1.end())
{
transition_2 = transitions_2.end();
return;
}
if (transition_2 == transitions_2.end())
{
transition_1 = transitions_1.end();
return;
}
if (!synchronizable(**transition_1, **transition_2))
incrementEdgeIterators(state_1, state_2, transition_1, transition_2);
}
/* ========================================================================= */
inline void BuchiProduct::incrementEdgeIterators
(const Graph<GraphEdgeContainer>::Node& state_1,
const Graph<GraphEdgeContainer>::Node& state_2,
GraphEdgeContainer::const_iterator& transition_1,
GraphEdgeContainer::const_iterator& transition_2)
/* ----------------------------------------------------------------------------
*
* Description: Increments a pair of transition iterators to point to the
* "next" transition beginning from a state in the intersection
* of two Büchi automata. If no "next" transition exists, makes
* the iterators point to the "end" of the collection of
* transitions beginning from the state.
*
* Arguments: state_1, -- These variables determine the state in
* state_2 the intersection automaton; `state_1' and
* `state_2' should both be references to
* BuchiAutomaton::BuchiState objects.
* transition_1, -- References to the transition iterators.
* transition_2 Initially, `transition_1' and
* `transition_2' should point to two
* transitions starting from `state_1' and
* `state_2', respectively.
*
* Returns: Nothing. Upon return, `transition_1' and `transition_2' will
* either equal `state_1.edges().end()' and
* `state_2.edges().end()', respectively, or they will point to
* a pair of transitions beginning from `state_1' and `state_2'
* such that this pair of transitions corresponds to a
* transition starting from the intersection state determined by
* `state_1' and `state_2'.
*
* ------------------------------------------------------------------------- */
{
const GraphEdgeContainer& transitions_1 = state_1.edges();
const GraphEdgeContainer& transitions_2 = state_2.edges();
do
{
++transition_2;
if (transition_2 == transitions_2.end())
{
++transition_1;
if (transition_1 == transitions_1.end())
return;
transition_2 = transitions_2.begin();
}
}
while (!synchronizable(**transition_1, **transition_2));
}
/* ========================================================================= */
inline void BuchiProduct::clearSatisfiabilityCache()
/* ----------------------------------------------------------------------------
*
* Description: Clears information about the satisfiability of the guard
* formulas of product transitions.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
sat_cache.clear();
}
}
#endif /* !BUCHIPRODUCT_H */

View file

@ -19,11 +19,6 @@
%{ %{
#include <config.h> #include <config.h>
#include <cmath>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <string>
#include "Configuration.h" #include "Configuration.h"
#include "Config-parse.h" #include "Config-parse.h"
@ -34,225 +29,102 @@ extern int config_file_line_number;
%option case-insensitive %option case-insensitive
%option never-interactive %option never-interactive
%option noyywrap %option noyywrap
%option nounput
%x ATTR EQ VAL
SQSTR [^\'\n]*
DQSTR ([^\"\\\n]|\\.)*
UQC [^\'\"\\ \t\n]
UQSTR ({UQC}+|\\.)({UQC}*|\\.)*
OKVAL \'{SQSTR}\'|\"{DQSTR}\"|{UQSTR}
%% %%
[ \t]* { /* Skip whitespace. */ } <*>[ \t]* { /* Skip whitespace everywhere. */ }
"#"[^\n]* { /* Skip comments. */ } <*>"#".*$ { /* Skip comments everywhere. */ }
"\n" { /* Skip newlines, but update the line number. */ <INITIAL,ATTR>"\n" { /* Skip newlines, but update the line number. */
config_file_line_number++; config_file_line_number++;
} }
"{" { return CFG_LBRACE; } "{" { BEGIN(ATTR); return CFG_LBRACE; }
"}" { return CFG_RBRACE; }
"=" { return CFG_EQUALS; }
algorithm { return CFG_ALGORITHM; }
enabled { return CFG_ENABLED; }
name { return CFG_NAME; }
parameters { return CFG_PARAMETERS; }
path { return CFG_PROGRAMPATH; }
algorithm|implementation|translator { return CFG_ALGORITHM; }
globaloptions { return CFG_GLOBALOPTIONS; } globaloptions { return CFG_GLOBALOPTIONS; }
comparisoncheck { return CFG_COMPARISONTEST; }
comparisontest { return CFG_COMPARISONTEST; }
consistencycheck { return CFG_CONSISTENCYTEST; }
consistencytest { return CFG_CONSISTENCYTEST; }
interactive { return CFG_INTERACTIVE; }
intersectioncheck { return CFG_INTERSECTIONTEST; }
intersectiontest { return CFG_INTERSECTIONTEST; }
modelcheck { return CFG_MODELCHECK; }
rounds { return CFG_ROUNDS; }
verbosity { return CFG_VERBOSITY; }
statespaceoptions { return CFG_STATESPACEOPTIONS; } statespaceoptions { return CFG_STATESPACEOPTIONS; }
edgeprobability { return CFG_EDGEPROBABILITY; }
propositions { return CFG_PROPOSITIONS; }
size { return CFG_SIZE; }
truthprobability { return CFG_TRUTHPROBABILITY; }
changeinterval { return CFG_CHANGEINTERVAL; }
randomseed { return CFG_RANDOMSEED; }
formulaoptions { return CFG_FORMULAOPTIONS; } formulaoptions { return CFG_FORMULAOPTIONS; }
abbreviatedoperators { return CFG_ABBREVIATEDOPERATORS; }
andpriority { return CFG_ANDPRIORITY; }
beforepriority { return CFG_BEFOREPRIORITY; }
defaultoperatorpriority { return CFG_DEFAULTOPERATORPRIORITY; }
equivalencepriority { return CFG_EQUIVALENCEPRIORITY; }
falsepriority { return CFG_FALSEPRIORITY; }
finallypriority { return CFG_FINALLYPRIORITY; }
generatemode { return CFG_GENERATEMODE; }
globallypriority { return CFG_GLOBALLYPRIORITY; }
implicationpriority { return CFG_IMPLICATIONPRIORITY; }
nextpriority { return CFG_NEXTPRIORITY; }
notpriority { return CFG_NOTPRIORITY; }
orpriority { return CFG_ORPRIORITY; }
outputmode { return CFG_OUTPUTMODE; }
propositionpriority { return CFG_PROPOSITIONPRIORITY; }
releasepriority { return CFG_RELEASEPRIORITY; }
strongreleasepriority { return CFG_STRONGRELEASEPRIORITY; }
truepriority { return CFG_TRUEPRIORITY; }
untilpriority { return CFG_UNTILPRIORITY; }
weakuntilpriority { return CFG_WEAKUNTILPRIORITY; }
xorpriority { return CFG_XORPRIORITY; }
true|yes { [^ \t\n]+ { return CFG_UNKNOWN; }
yylval.truth_value = true;
return CFG_TRUTH_VALUE; <ATTR>enabled { BEGIN(EQ); return CFG_ENABLED; }
<ATTR>name { BEGIN(EQ); return CFG_NAME; }
<ATTR>parameters { BEGIN(EQ); return CFG_PARAMETERS; }
<ATTR>path { BEGIN(EQ); return CFG_PROGRAMPATH; }
<ATTR>comparisoncheck { BEGIN(EQ); return CFG_COMPARISONTEST; }
<ATTR>comparisontest { BEGIN(EQ); return CFG_COMPARISONTEST; }
<ATTR>consistencycheck { BEGIN(EQ); return CFG_CONSISTENCYTEST; }
<ATTR>consistencytest { BEGIN(EQ); return CFG_CONSISTENCYTEST; }
<ATTR>interactive { BEGIN(EQ); return CFG_INTERACTIVE; }
<ATTR>intersectioncheck { BEGIN(EQ); return CFG_INTERSECTIONTEST; }
<ATTR>intersectiontest { BEGIN(EQ); return CFG_INTERSECTIONTEST; }
<ATTR>modelcheck { BEGIN(EQ); return CFG_MODELCHECK; }
<ATTR>rounds { BEGIN(EQ); return CFG_ROUNDS; }
<ATTR>translatortimeout { BEGIN(EQ); return CFG_TRANSLATORTIMEOUT; }
<ATTR>verbosity { BEGIN(EQ); return CFG_VERBOSITY; }
<ATTR>edgeprobability { BEGIN(EQ); return CFG_EDGEPROBABILITY; }
<ATTR>propositions { BEGIN(EQ); return CFG_PROPOSITIONS; }
<ATTR>size { BEGIN(EQ); return CFG_SIZE; }
<ATTR>truthprobability { BEGIN(EQ); return CFG_TRUTHPROBABILITY; }
<ATTR>changeinterval { BEGIN(EQ); return CFG_CHANGEINTERVAL; }
<ATTR>randomseed { BEGIN(EQ); return CFG_RANDOMSEED; }
<ATTR>abbreviatedoperators { BEGIN(EQ); return CFG_ABBREVIATEDOPERATORS; }
<ATTR>andpriority { BEGIN(EQ); return CFG_ANDPRIORITY; }
<ATTR>beforepriority { BEGIN(EQ); return CFG_BEFOREPRIORITY; }
<ATTR>defaultoperatorpriority {
BEGIN(EQ); return CFG_DEFAULTOPERATORPRIORITY;
}
<ATTR>equivalencepriority { BEGIN(EQ); return CFG_EQUIVALENCEPRIORITY; }
<ATTR>falsepriority { BEGIN(EQ); return CFG_FALSEPRIORITY; }
<ATTR>finallypriority { BEGIN(EQ); return CFG_FINALLYPRIORITY; }
<ATTR>generatemode { BEGIN(EQ); return CFG_GENERATEMODE; }
<ATTR>globallypriority { BEGIN(EQ); return CFG_GLOBALLYPRIORITY; }
<ATTR>implicationpriority { BEGIN(EQ); return CFG_IMPLICATIONPRIORITY; }
<ATTR>nextpriority { BEGIN(EQ); return CFG_NEXTPRIORITY; }
<ATTR>notpriority { BEGIN(EQ); return CFG_NOTPRIORITY; }
<ATTR>orpriority { BEGIN(EQ); return CFG_ORPRIORITY; }
<ATTR>outputmode { BEGIN(EQ); return CFG_OUTPUTMODE; }
<ATTR>propositionpriority { BEGIN(EQ); return CFG_PROPOSITIONPRIORITY; }
<ATTR>releasepriority { BEGIN(EQ); return CFG_RELEASEPRIORITY; }
<ATTR>strongreleasepriority { BEGIN(EQ); return CFG_STRONGRELEASEPRIORITY; }
<ATTR>truepriority { BEGIN(EQ); return CFG_TRUEPRIORITY; }
<ATTR>untilpriority { BEGIN(EQ); return CFG_UNTILPRIORITY; }
<ATTR>weakuntilpriority { BEGIN(EQ); return CFG_WEAKUNTILPRIORITY; }
<ATTR>xorpriority { BEGIN(EQ); return CFG_XORPRIORITY; }
<ATTR>"}" { BEGIN(INITIAL); return CFG_RBRACE; }
<ATTR>"="?[^= \t\n]* { return CFG_UNKNOWN; }
<EQ>"=" { BEGIN(VAL); return CFG_EQUALS; }
<EQ>. { return CFG_UNKNOWN; }
<VAL>\\|{OKVAL}+(\\)? {
yylval.value = yytext;
BEGIN(ATTR);
return CFG_VALUE;
} }
false|no { <VAL>{OKVAL}*(\'{SQSTR}|\"{DQSTR})(\\)? {
yylval.truth_value = false;
return CFG_TRUTH_VALUE;
}
always {
yylval.interactivity_value =
Configuration::ALWAYS;
return CFG_INTERACTIVITY_VALUE;
}
never {
yylval.interactivity_value =
Configuration::NEVER;
return CFG_INTERACTIVITY_VALUE;
}
onerror {
yylval.interactivity_value =
Configuration::ONERROR;
return CFG_INTERACTIVITY_VALUE;
}
normal {
yylval.formula_mode_value =
Configuration::NORMAL;
return CFG_FORMULA_MODE_VALUE;
}
nnf {
yylval.formula_mode_value = Configuration::NNF;
return CFG_FORMULA_MODE_VALUE;
}
local {
yylval.product_type_value = Configuration::LOCAL;
return CFG_PRODUCT_TYPE_VALUE;
}
global {
yylval.product_type_value =
Configuration::GLOBAL;
return CFG_PRODUCT_TYPE_VALUE;
}
randomgraph {
yylval.statespace_mode_value
= Configuration::RANDOMGRAPH;
return CFG_STATESPACE_MODE_VALUE;
}
randomconnectedgraph {
yylval.statespace_mode_value
= Configuration::RANDOMCONNECTEDGRAPH;
return CFG_STATESPACE_MODE_VALUE;
}
randompath {
yylval.statespace_mode_value
= Configuration::RANDOMPATH;
return CFG_STATESPACE_MODE_VALUE;
}
enumeratedpath {
yylval.statespace_mode_value
= Configuration::ENUMERATEDPATH;
return CFG_STATESPACE_MODE_VALUE;
}
"-"?[0-9]+"...""-"?[0-9]+ {
char* dot_ptr;
yylval.integer_interval.min
= strtol(yytext, &dot_ptr, 10);
if (yylval.integer_interval.min == LONG_MIN
|| yylval.integer_interval.min == LONG_MAX)
throw Configuration::ConfigurationException throw Configuration::ConfigurationException
(config_file_line_number, (config_file_line_number,
"integer out of range"); "unmatched quotes");
dot_ptr += 3;
yylval.integer_interval.max
= strtol(dot_ptr, 0, 10);
if (yylval.integer_interval.max == LONG_MIN
|| yylval.integer_interval.max == LONG_MAX)
throw Configuration::ConfigurationException
(config_file_line_number,
"integer out of range");
return CFG_INTEGER_INTERVAL;
}
"-"?[0-9]+ {
yylval.integer = strtol(yytext, 0, 10);
if (yylval.integer == LONG_MIN
|| yylval.integer == LONG_MAX)
throw Configuration::ConfigurationException
(config_file_line_number,
"integer out of range");
return CFG_INTEGER;
}
"-"?[0-9]*"."[0-9]+ {
yylval.real = strtod(yytext, 0);
if (yylval.real == HUGE_VAL
|| yylval.real == -HUGE_VAL)
throw Configuration::ConfigurationException
(config_file_line_number,
"real number out of range");
return CFG_REAL;
}
\"([^\n\"\\]*(\\[^\n])?)*\" {
unsigned long int len = strlen(yytext);
bool escape = false;
yylval.str = new string;
for (unsigned long int i = 1; i < len - 1; i++)
{
if (!escape && yytext[i] == '\\')
escape = true;
else
{
escape = false;
(*yylval.str) += yytext[i];
}
}
return CFG_STRING_CONSTANT;
}
. {
return CFG_UNKNOWN;
} }
<EQ,VAL>"\n" { return CFG_UNKNOWN; }
%% %%
/* ========================================================================= */
int getCharacter()
/* ----------------------------------------------------------------------------
*
* Description: Reads the next character from the lexer input stream.
*
* Arguments: None.
*
* Returns: The next character in the lexer input stream or EOF if there
* are no more characters to read.
*
* ------------------------------------------------------------------------- */
{
return yyinput();
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@
#define CONFIGURATION_H #define CONFIGURATION_H
#include <config.h> #include <config.h>
#include <cstdio>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <set> #include <set>
@ -35,8 +36,6 @@
using namespace std; using namespace std;
/****************************************************************************** /******************************************************************************
* *
* A class for storing program configuration information. * A class for storing program configuration information.
@ -69,15 +68,23 @@ public:
* string. * string.
*/ */
bool isInternalAlgorithm(unsigned long int id) /* Tests whether a given */
const; /* algorithm identifier
* refers to lbtt's
* internal model
* checking algorithm.
*/
static void showCommandLineHelp /* Prints the list of */ static void showCommandLineHelp /* Prints the list of */
(const char* program_name); /* command line options. */ (const char* program_name); /* command line options. */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
enum InteractionMode {NEVER, ALWAYS, ONERROR}; /* Enumeration constants enum InteractionMode {NEVER, ALWAYS, ONERROR, /* Enumeration constants */
* affecting the behaviour ONBREAK}; /* affecting the
* of the program as * behavior of the
* regards user control. * program as regards
* user control.
*/ */
enum FormulaMode {NORMAL, NNF}; /* Enumeration constants enum FormulaMode {NORMAL, NNF}; /* Enumeration constants
@ -109,17 +116,21 @@ public:
* parameters). * parameters).
*/ */
{ {
string* name; /* Name of the algorithm. string name; /* Name of the algorithm.
*/ */
string* path_to_program; /* Path to the executable char** parameters; /* Command-line parameters
* required for running * required for running
* the algorithm. * the executable. See
* the documentation for
* the registerAlgorithm
* function (in
* Configuration.cc) for
* more information.
*/ */
string* extra_parameters; /* Additional command-line vector<string>::size_type num_parameters; /* Number of command-line
* parameters required for * parameters.
* running the executable.
*/ */
bool enabled; /* Determines whether the bool enabled; /* Determines whether the
@ -169,6 +180,12 @@ public:
* commands. * commands.
*/ */
bool handle_breaks; /* If true, pause testing
* also on interrupt
* signals instead of
* simply aborting.
*/
unsigned long int number_of_rounds; /* Number of test rounds. unsigned long int number_of_rounds; /* Number of test rounds.
*/ */
@ -278,6 +295,10 @@ public:
* formula generation * formula generation
* algorithms. * algorithms.
*/ */
unsigned int translator_timeout; /* Timeout (in seconds) for
* translators.
*/
}; };
struct FormulaConfiguration /* A structure for storing struct FormulaConfiguration /* A structure for storing
@ -360,6 +381,12 @@ public:
* the tests. * the tests.
*/ */
map<string, unsigned long int, less<string>, /* Mapping between */
ALLOC(unsigned long int) > /* algorithm names and */
algorithm_names; /* their numeric
* identifiers.
*/
GlobalConfiguration global_options; /* General configuration GlobalConfiguration global_options; /* General configuration
* information. * information.
*/ */
@ -376,15 +403,6 @@ public:
* algorithms. * algorithms.
*/ */
typedef pair<int, int> IntPair;
set<IntPair, less<IntPair>, ALLOC(IntPair) > /* Configuration options */
locked_options; /* the values of which
* should not be
* initialized from the
* configuration file.
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class ConfigurationException : public Exception /* A class for reporting class ConfigurationException : public Exception /* A class for reporting
@ -419,6 +437,9 @@ public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
private:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
struct IntegerRange /* Data structure for struct IntegerRange /* Data structure for
* representing integer- * representing integer-
* valued ranges of certain * valued ranges of certain
@ -426,11 +447,11 @@ public:
* options. * options.
*/ */
{ {
long int min; /* Lower bound. */ unsigned long int min; /* Lower bound. */
long int max; /* Upper bound. */ unsigned long int max; /* Upper bound. */
char* error_message; /* Error message to be const char* error_message; /* Error message to be
* displayed if the value * displayed if the value
* is not within the * is not within the
* specified range. * specified range.
@ -439,31 +460,30 @@ public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* /* Ranges for certain integer-valued configuration options. */
* Ranges for certain integer-valued configuration options.
*/
static const struct IntegerRange static const struct IntegerRange
VERBOSITY_RANGE, ROUND_COUNT_RANGE, GENERATION_RANGE, PRIORITY_RANGE, DEFAULT_RANGE, VERBOSITY_RANGE,
PROPOSITION_COUNT_RANGE, FORMULA_SIZE_RANGE, FORMULA_MAX_SIZE_RANGE, ROUND_COUNT_RANGE, RANDOM_SEED_RANGE,
STATESPACE_SIZE_RANGE, STATESPACE_MAX_SIZE_RANGE; ATOMIC_PRIORITY_RANGE, OPERATOR_PRIORITY_RANGE;
private: /* Command line options. */
enum CommandLineOptionType /* Command line options. */
{OPT_COMPARISONTEST = 10000, OPT_CONFIGFILE, enum CommandLineOptionType
{OPT_HELP = 'h', OPT_VERSION = 'V',
OPT_COMPARISONTEST = 10000, OPT_CONFIGFILE,
OPT_CONSISTENCYTEST, OPT_DISABLE, OPT_ENABLE, OPT_CONSISTENCYTEST, OPT_DISABLE, OPT_ENABLE,
OPT_FORMULACHANGEINTERVAL, OPT_FORMULAFILE, OPT_FORMULACHANGEINTERVAL,
OPT_FORMULARANDOMSEED, OPT_HELP = 'h', OPT_FORMULAFILE, OPT_FORMULARANDOMSEED,
OPT_GLOBALPRODUCT = 20000, OPT_INTERACTIVE, OPT_GLOBALPRODUCT, OPT_INTERACTIVE,
OPT_INTERSECTIONTEST, OPT_LOGFILE, OPT_INTERSECTIONTEST, OPT_LOGFILE,
OPT_MODELCHECK, OPT_NOCOMPARISONTEST, OPT_MODELCHECK, OPT_PROFILE, OPT_QUIET,
OPT_NOCONSISTENCYTEST, OPT_NOINTERSECTIONTEST, OPT_ROUNDS, OPT_SHOWCONFIG,
OPT_NOPAUSE, OPT_PAUSE, OPT_PAUSEONERROR, OPT_SHOWOPERATORDISTRIBUTION, OPT_SKIP,
OPT_PROFILE, OPT_QUIET, OPT_ROUNDS, OPT_STATESPACECHANGEINTERVAL,
OPT_SHOWCONFIG, OPT_SHOWOPERATORDISTRIBUTION, OPT_STATESPACERANDOMSEED,
OPT_SKIP, OPT_STATESPACECHANGEINTERVAL, OPT_TRANSLATORTIMEOUT, OPT_VERBOSITY,
OPT_STATESPACERANDOMSEED, OPT_VERBOSITY,
OPT_VERSION,
OPT_LOCALPRODUCT, OPT_LOCALPRODUCT,
@ -476,7 +496,6 @@ private:
OPT_FORMULAPROPOSITIONS, OPT_FORMULASIZE, OPT_FORMULAPROPOSITIONS, OPT_FORMULASIZE,
OPT_GENERATENNF, OPT_GLOBALLYPRIORITY, OPT_GENERATENNF, OPT_GLOBALLYPRIORITY,
OPT_IMPLICATIONPRIORITY, OPT_NEXTPRIORITY, OPT_IMPLICATIONPRIORITY, OPT_NEXTPRIORITY,
OPT_NOABBREVIATEDOPERATORS,
OPT_NOGENERATENNF, OPT_NOOUTPUTNNF, OPT_NOGENERATENNF, OPT_NOOUTPUTNNF,
OPT_NOTPRIORITY, OPT_ORPRIORITY, OPT_NOTPRIORITY, OPT_ORPRIORITY,
OPT_OUTPUTNNF, OPT_PROPOSITIONPRIORITY, OPT_OUTPUTNNF, OPT_PROPOSITIONPRIORITY,
@ -503,6 +522,8 @@ private:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
friend int yyparse();
Configuration(const Configuration& cfg); /* Prevent copying and */ Configuration(const Configuration& cfg); /* Prevent copying and */
Configuration& operator= /* assignment of */ Configuration& operator= /* assignment of */
(const Configuration& cfg); /* Configuration (const Configuration& cfg); /* Configuration
@ -514,10 +535,59 @@ private:
* to default values. * to default values.
*/ */
long int parseCommandLineInteger /* Converts an integer */ void registerAlgorithm /* Adds a new algorithm */
(const string& option, const string& value) /* to a string with */ (const string& name, const string& path, /* to the configuration. */
const; /* some additional const string& parameters, bool enabled,
* validity checks. const int block_begin_line);
template<typename T> /* Reads an integer, */
void readInteger /* checks that it is */
(T& target, const string& value, /* within given bounds */
const IntegerRange& range = DEFAULT_RANGE); /* and stores it into
* an unsigned integer
* type variable.
*/
void readProbability /* Reads a probability */
(double& target, const string& value); /* and stores it into
* a given variable of
* type double.
*/
void readSize(int valtype, const string& value); /* Initializes formula or
* state space size
* ranges from a given
* string.
*/
void readTruthValue /* Interprets a symbolic */
(bool& target, const string& value); /* truth value. */
void readInteractivity(const string& value); /* Interprets a symbolic
* interactivity mode.
*/
void readProductType(const string& value); /* Interprets a symbolic
* model checking mode.
*/
void readFormulaMode /* Interprets a symbolic */
(FormulaMode& target, const string& mode); /* formula mode.
*/
void readStateSpaceMode(const string& mode); /* Initializes
* `global_options.
* statespace_generation
* _mode' from a
* symbolic mode
* identifier.
*/
void readTranslatorTimeout(const string& value); /* Initializes
* `global_options.
* translator_timeout'
* from a symbolic time
* specification.
*/ */
double operatorProbability /* Computes the */ double operatorProbability /* Computes the */
@ -532,6 +602,97 @@ private:
/******************************************************************************
*
* Declarations for functions and variables provided by the parser.
*
*****************************************************************************/
extern int config_file_line_number; /* Number of the current
* line in the
* configuration file.
*/
extern int parseConfiguration /* Parser interface. */
(FILE*, Configuration&);
/******************************************************************************
*
* Inline function definitions for class Configuration.
*
*****************************************************************************/
/* ========================================================================= */
inline bool Configuration::isInternalAlgorithm(unsigned long int id) const
/* ----------------------------------------------------------------------------
*
* Description: Tests whether a given algorithm identifier refers to lbtt's
* internal model checking algorithm.
*
* Argument: id -- Identifier to test.
*
* Returns: True if `id' is the identifier of lbtt's internal model
* checking algorithm.
*
* ------------------------------------------------------------------------- */
{
return ((global_options.statespace_generation_mode & Configuration::PATH)
&& id == algorithms.size() - 1);
}
/******************************************************************************
*
* Template function definitions for class Configuration.
*
*****************************************************************************/
/* ========================================================================= */
template<typename T>
void Configuration::readInteger
(T& target, const string& value, const IntegerRange& range)
/* ----------------------------------------------------------------------------
*
* Description: Reads an integer and stores it into `target'.
*
* Arguments: target -- A reference to an unsigned integer type variable
* for storing the result.
* value -- The integer as a string.
* range -- A reference to a constant IntegerRange object
* giving the bounds for the value.
*
* Returns: Nothing; the result is stored into `target'. The function
* throws a ConfigurationException if `value' is not a valid
* integer within the bounds specified by `range'.
*
* ------------------------------------------------------------------------- */
{
string error;
unsigned long int val;
try
{
val = ::StringUtil::parseNumber(value);
}
catch (const ::StringUtil::NotANumberException&)
{
error = "`" + value + "' is not a valid nonnegative integer";
}
if (error.empty() && (val < range.min || val > range.max))
error = range.error_message;
if (!error.empty())
throw ConfigurationException(config_file_line_number, error);
target = val;
}
/****************************************************************************** /******************************************************************************
* *
* Inline function definitions for class Configuration::ConfigurationException. * Inline function definitions for class Configuration::ConfigurationException.

View file

@ -58,6 +58,16 @@ void printTextBlock /* Writes an indented */
* a stream. * a stream.
*/ */
bool printText /* "Verbosity-aware" */
(const char* text, /* functions for writing */
const int verbosity_threshold, /* text to standard */
const int indent); /* output. */
bool printText
(const string& text,
const int verbosity_threshold,
const int indent);
/****************************************************************************** /******************************************************************************
@ -78,16 +88,6 @@ struct StreamFormatting
* e.g. the justification * e.g. the justification
* of output. * of output.
*/ */
bool printText /* "Verbosity-aware" */
(const char* text, /* functions for writing */
const int verbosity_threshold, /* text to standard */
const int indent); /* output. */
bool printText
(const string& text,
const int verbosity_threshold,
const int indent);
}; };

View file

@ -23,6 +23,7 @@
#include <config.h> #include <config.h>
#include <string> #include <string>
#include <exception> #include <exception>
#include <istream>
#include <iostream> #include <iostream>
using namespace std; using namespace std;
@ -299,6 +300,16 @@ public:
template<class T> /* Operator for reading */ template<class T> /* Operator for reading */
Exceptional_istream &operator>>(T &t); /* from the stream. */ Exceptional_istream &operator>>(T &t); /* from the stream. */
Exceptional_istream& get(istream::char_type& C); /* Reads a character from
* the stream.
*/
Exceptional_istream& read /* Reads a given number */
(istream::char_type* buffer, streamsize count); /* of characters from
* the stream into a
* buffer.
*/
operator istream&(); /* Casts the exception- operator istream&(); /* Casts the exception-
* aware input stream into * aware input stream into
* a regular input stream. * a regular input stream.
@ -992,6 +1003,47 @@ inline Exceptional_istream::~Exceptional_istream()
{ {
} }
/* ========================================================================= */
inline Exceptional_istream& Exceptional_istream::get(istream::char_type& c)
/* ----------------------------------------------------------------------------
*
* Description: Reads a character from the input stream.
*
* Argument: c -- A reference to a character to extract.
*
* Returns: A reference to the stream.
*
* ------------------------------------------------------------------------- */
{
stream->get(c);
if (stream->rdstate() & exception_mask)
throw IOException("error reading from stream");
return *this;
}
/* ========================================================================= */
inline Exceptional_istream& Exceptional_istream::read
(istream::char_type* buffer, streamsize count)
/* ----------------------------------------------------------------------------
*
* Description: Reads a given number of characters from the stream into a
* buffer.
*
* Arguments: buffer -- A pointer to the buffer.
* count -- Number of characters to read.
*
* Returns: A reference to the stream.
*
* ------------------------------------------------------------------------- */
{
stream->read(buffer, count);
if (stream->rdstate() & exception_mask)
throw IOException("error reading from stream");
return *this;
}
/* ========================================================================= */ /* ========================================================================= */
inline Exceptional_istream::operator istream&() inline Exceptional_istream::operator istream&()
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------

View file

@ -20,6 +20,7 @@
#include <config.h> #include <config.h>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
@ -62,25 +63,30 @@ ExternalTranslator::~ExternalTranslator()
} }
/* ========================================================================= */ /* ========================================================================= */
ExternalTranslator::TempFileObject& const char* ExternalTranslator::registerTempFileObject
ExternalTranslator::registerTempFileObject (const string& filename, const TempFsysName::NameType type,
(const string& filename, TempFileObject::Type type) const bool literal)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Registers a temporary file or directory such that it will be * Description: Registers a temporary file or directory such that it will be
* automatically deleted when the ExternalTranslator object is * automatically deleted when the ExternalTranslator object is
* destroyed. * destroyed.
* *
* Arguments: filename -- Name of the temporary file or directory. * Arguments: filename -- Name of the temporary file or directory. If
* empty, a new name will be created.
* type -- Type of the object (TempFileObject::FILE or * type -- Type of the object (TempFileObject::FILE or
* TempFileObject::DIRECTORY). * TempFileObject::DIRECTORY).
* literal -- Tells whether the file name should be
* interpreted literally.
* *
* Returns: A reference to the file object. * Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
temporary_file_objects.push(new TempFileObject(filename, type)); TempFsysName* name = new TempFsysName;
return *temporary_file_objects.top(); name->allocate(filename.c_str(), type, literal);
temporary_file_objects.push(name);
return name->get();
} }
/* ========================================================================= */ /* ========================================================================= */
@ -99,19 +105,19 @@ void ExternalTranslator::translate
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
TempFileObject& external_program_input_file = registerTempFileObject(); const char* external_program_input_file
= registerTempFileObject("lbtt-translate");
TempFileObject& external_program_output_file = registerTempFileObject(); const char* external_program_output_file
= registerTempFileObject("lbtt-translate");
string translated_formula; string translated_formula;
translateFormula(formula, translated_formula); translateFormula(formula, translated_formula);
ofstream input_file; ofstream input_file;
input_file.open(external_program_input_file.getName().c_str(), input_file.open(external_program_input_file, ios::out | ios::trunc);
ios::out | ios::trunc);
if (!input_file.good()) if (!input_file.good())
throw FileCreationException(string("`") throw FileCreationException(string("`") + external_program_input_file
+ external_program_input_file.getName()
+ "'"); + "'");
Exceptional_ostream einput_file(&input_file, ios::failbit | ios::badbit); Exceptional_ostream einput_file(&input_file, ios::failbit | ios::badbit);
@ -121,96 +127,11 @@ void ExternalTranslator::translate
input_file.close(); input_file.close();
string command_line = string(command_line_arguments[2]) string command_line = string(command_line_arguments[2])
+ commandLine(external_program_input_file.getName(), + commandLine(external_program_input_file,
external_program_output_file.getName()); external_program_output_file);
if (!execSuccess(system(command_line.c_str()))) if (!execSuccess(system(command_line.c_str())))
throw ExecFailedException(command_line_arguments[2]); throw ExecFailedException(command_line_arguments[2]);
parseAutomaton(external_program_output_file.getName(), filename); parseAutomaton(external_program_output_file, filename);
}
/******************************************************************************
*
* Function definitions for class ExternalTranslator::TempFileObject.
*
*****************************************************************************/
/* ========================================================================= */
ExternalTranslator::TempFileObject::TempFileObject
(const string& filename, Type t)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class TempFileObject. Creates a temporary
* file or a directory and tests whether it can really be
* written to (if not, a FileCreationException is thrown).
*
* Arguments: filename -- Name of the temporary file or directory.
* If the filename is an empty string, the
* filename is obtained by a call to tmpnam(3).
* t -- Type of the object (TempFileObject::FILE or
* TempFileObject::DIRECTORY).
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (filename.empty())
{
char tempname[L_tmpnam + 1];
if (tmpnam(tempname) == 0)
throw FileCreationException("a temporary file");
name = tempname;
}
else
name = filename;
if (t == FILE)
{
ofstream tempfile;
tempfile.open(name.c_str(), ios::out | ios::trunc);
if (!tempfile.good())
throw FileCreationException("a temporary file");
tempfile.close();
}
else
{
if (mkdir(name.c_str(), 0700) != 0)
throw FileCreationException("a temporary directory");
}
type = t;
}
/* ========================================================================= */
ExternalTranslator::TempFileObject::~TempFileObject()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class TempFileObject. Deletes the file or
* the directory associated with the object (displays a warning
* if this fails).
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (remove(name.c_str()) != 0)
{
string msg("error removing temporary ");
if (type == TempFileObject::FILE)
msg += "file";
else
msg += "directory";
msg += " `" + name + "'";
printWarning(msg);
}
} }

View file

@ -33,6 +33,7 @@
#include "Exception.h" #include "Exception.h"
#include "LtlFormula.h" #include "LtlFormula.h"
#include "translate.h" #include "translate.h"
#include "TempFsysName.h"
#include "TranslatorInterface.h" #include "TranslatorInterface.h"
/****************************************************************************** /******************************************************************************
@ -98,13 +99,21 @@
* from the names of the input/output files. Each of these files should be * from the names of the input/output files. Each of these files should be
* "registered" before calling the external program with the function * "registered" before calling the external program with the function
* *
* void registerTempFileObject * const char* registerTempFileObject
* (const string& filename, TempFileObject::Type t) * (const string& filename, const TempFsysName::NameType t,
* const bool literal)
* *
* where `filename' is the full name of the temporary file and `t' is a type * where `filename' is the prefix of a temporary file name, `t' is a type
* of the object (TempFileObject::FILE or TempFileObject::DIRECTORY). * of the object (TempFsysName::FILE or TempFsysName::DIRECTORY), and
* `literal' specifies whether `filename' should be interpreted literally or
* not (if not, `filename' will be treated as a suggestion for the name
* of the temporary file). If the name is to be interpreted literally,
* `filename' should contain the full path name of the temporary file to be
* created. In all cases, the function returns the full path name of the
* temporary file or directory, or it throws an IOException (defined in
* Exception.h) if the creation fails.
* *
* All files or directories registered using this function will then be * All files or directories registered using this function will be
* automatically deleted after the translation is finished or aborted. * automatically deleted after the translation is finished or aborted.
* The files or directories will be deleted in the reverse order of * The files or directories will be deleted in the reverse order of
* registration, i.e., the most recently registered file/directory will be * registration, i.e., the most recently registered file/directory will be
@ -115,55 +124,15 @@
class ExternalTranslator : public TranslatorInterface class ExternalTranslator : public TranslatorInterface
{ {
public: public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class TempFileObject /* A class for storing */
{ /* information about */
public: /* temporary files and
* directories.
*/
enum Type {FILE, DIRECTORY}; /* Types for a temporary
* file object.
*/
TempFileObject /* Constructor. */
(const string& filename = "", Type t = FILE);
~TempFileObject(); /* Destructor. */
const string& getName() const; /* Returns the filename
* associated with the
* object.
*/
Type getType() const; /* Returns the type of
* the object.
*/
private:
string name; /* Name of the file object.
*/
Type type; /* Type of the file object.
*/
TempFileObject(const TempFileObject&); /* Prevent copying and */
TempFileObject& operator= /* assignment of */
(const TempFileObject&); /* TempFileObjects. */
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ExternalTranslator(); /* Constructor. */ ExternalTranslator(); /* Constructor. */
~ExternalTranslator(); /* Destructor. */ ~ExternalTranslator(); /* Destructor. */
TempFileObject& registerTempFileObject /* Registers a temporary */ const char* registerTempFileObject /* Registers a temporary */
(const string& filename = "", /* file or directory */ (const string& filename = "", /* file or directory */
TempFileObject::Type /* such that it will be */ const TempFsysName::NameType /* such that it will be */
t = TempFileObject::FILE); /* automatically deleted t = TempFsysName::FILE, /* automatically deleted */
* when the translation const bool literal = false); /* when the translation
* is complete. * is complete.
*/ */
@ -205,17 +174,12 @@ private:
* objects. * objects.
*/ */
stack<TempFileObject*, /* Stack for storing */ stack<TempFsysName*, /* Stack for storing */
deque<TempFileObject*, /* temporary file */ deque<TempFsysName*, /* temporary file */
ALLOC(TempFileObject*) > > /* information. */ ALLOC(TempFsysName*) > > /* information. */
temporary_file_objects; temporary_file_objects;
friend class KecWrapper; /* Friend declarations. */ friend class SpinWrapper; /* Friend declarations. */
friend class Ltl2AutWrapper;
friend class Ltl2BaWrapper;
friend class ProdWrapper;
friend class SpinWrapper;
friend class WringWrapper;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@ -316,46 +280,6 @@ inline bool ExternalTranslator::execSuccess(int exitcode)
/******************************************************************************
*
* Inline function definitions for class ExternalTranslator::TempFileObject.
*
*****************************************************************************/
/* ========================================================================= */
inline const string& ExternalTranslator::TempFileObject::getName() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the name associated with the
* ExternalTranslator::TempFileObject.
*
* Arguments: None.
*
* Returns: The name associated with the object.
*
* ------------------------------------------------------------------------- */
{
return name;
}
/* ========================================================================= */
inline ExternalTranslator::TempFileObject::Type
ExternalTranslator::TempFileObject::getType() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the type of the ExternalTranslator::TempFileObject.
*
* Arguments: None.
*
* Returns: The type associated with the object.
*
* ------------------------------------------------------------------------- */
{
return type;
}
/****************************************************************************** /******************************************************************************
* *
* Inline function definitions for class * Inline function definitions for class

View file

@ -21,6 +21,7 @@
#define FORMULARANDOMIZER_H #define FORMULARANDOMIZER_H
#include <config.h> #include <config.h>
#include <map>
#include <vector> #include <vector>
#include <utility> #include <utility>
#include "LbttAlloc.h" #include "LbttAlloc.h"

View file

@ -21,13 +21,11 @@
#define FORMULAWRITER_H #define FORMULAWRITER_H
#include "Exception.h" #include "Exception.h"
#include "LtlFormula.h"
namespace Ltl namespace Ltl
{ {
class LtlFormula;
class Atom;
/****************************************************************************** /******************************************************************************
* *
* A function template class for writing the formula to a stream. * A function template class for writing the formula to a stream.

View file

@ -186,6 +186,10 @@ public:
* graph nodes. * graph nodes.
*/ */
class PathElement; /* A class for representing
* (node, edge) pairs
*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
protected: protected:
@ -205,6 +209,14 @@ public:
* the graph nodes. * the graph nodes.
*/ */
typedef EdgeContainer EdgeContainerType; /* Type definition for
* containers of graph
* edges.
*/
typedef deque<PathElement, ALLOC(PathElement) > /* Type definition for */
Path; /* paths in a graph. */
typedef pair<size_type, size_type> StateIdPair; /* Type definition for a typedef pair<size_type, size_type> StateIdPair; /* Type definition for a
* pair of state * pair of state
* identifiers in a graph. * identifiers in a graph.
@ -323,8 +335,8 @@ public:
/* default assignment operator */ /* default assignment operator */
Graph<EdgeContainer>::size_type targetNode() /* Returns the index of */ size_type targetNode() const; /* Returns the index of */
const; /* the target node of /* the target node of
* the directed edge. * the directed edge.
*/ */
@ -353,7 +365,7 @@ protected:
*/ */
private: private:
Graph<EdgeContainer>::size_type target_node; /* Identifier of the edge's size_type target_node; /* Identifier of the edge's
* target node. * target node.
*/ */
}; };
@ -404,6 +416,62 @@ protected:
/******************************************************************************
*
* A template class for representing (node identifier, edge) pairs in a graph.
*
*****************************************************************************/
template <class EdgeContainer>
class Graph<EdgeContainer>::PathElement
{
public:
explicit PathElement /* Constructors. */
(const typename Graph<EdgeContainer>::size_type
n,
const typename Graph<EdgeContainer>::Edge*
e = 0);
PathElement
(const typename Graph<EdgeContainer>::size_type
n,
const typename Graph<EdgeContainer>::Edge& e);
/* default copy constructor */
~PathElement(); /* Destructor. */
/* default assignment operator */
size_type node() const; /* Returns the identifier
* of the node associated
* with the path element.
*/
bool hasEdge() const; /* Tells whether there is
* an edge associated with
* the path element.
*/
const Edge& edge() const; /* Returns the edge
* associated with the
* path element.
*/
private:
typename Graph<EdgeContainer>::size_type node_id; /* Identifier of the node
* associated with the path
* element.
*/
const typename Graph<EdgeContainer>::Edge* /* Pointer to the edge */
edge_pointer; /* associated with the
* path element.
*/
};
/****************************************************************************** /******************************************************************************
* *
* An exception class for reporting errors when indexing graph nodes. * An exception class for reporting errors when indexing graph nodes.
@ -924,7 +992,7 @@ Graph<EdgeContainer>::stats() const
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
pair<Graph<EdgeContainer>::size_type, unsigned long int> result; pair<size_type, unsigned long int> result;
result.first = nodes.size(); result.first = nodes.size();
result.second = 0; result.second = 0;
@ -1468,6 +1536,128 @@ void Graph<EdgeContainer>::Node::print
/******************************************************************************
*
* Inline function definitions for template class
* Graph<EdgeContainer>::PathElement.
*
*****************************************************************************/
/* ========================================================================= */
template <class EdgeContainer>
inline Graph<EdgeContainer>::PathElement::PathElement
(const typename Graph<EdgeContainer>::size_type n,
const typename Graph<EdgeContainer>::Edge* e) :
node_id(n), edge_pointer(e)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class Graph<EdgeContainer>::PathElement.
* Creates a (node identifier, edge) pair from a node identifier
* and a pointer to an edge.
*
* Arguments: n -- Numeric identifier of a graph node.
* e -- A constant pointer to a graph edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class EdgeContainer>
inline Graph<EdgeContainer>::PathElement::PathElement
(const typename Graph<EdgeContainer>::size_type n,
const typename Graph<EdgeContainer>::Edge& e) :
node_id(n), edge_pointer(&e)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class Graph<EdgeContainer>::PathElement.
* Creates a (node identifier, edge) pair from a node identifier
* and an edge.
*
* Arguments: n -- Numeric identifier of a graph node.
* e -- A constant reference to a graph edge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class EdgeContainer>
inline Graph<EdgeContainer>::PathElement::~PathElement()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class Graph<EdgeContainer>::PathElement.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
template <class EdgeContainer>
inline typename Graph<EdgeContainer>::size_type
Graph<EdgeContainer>::PathElement::node() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the identifier of the node associated with a
* Graph<EdgeContainer>::PathElement object.
*
* Arguments: None.
*
* Returns: Identifier of the node associated with the object.
*
* ------------------------------------------------------------------------- */
{
return node_id;
}
/* ========================================================================= */
template <class EdgeContainer>
inline bool Graph<EdgeContainer>::PathElement::hasEdge() const
/* ----------------------------------------------------------------------------
*
* Description: Tells whether there is an edge associated with a
* Graph<EdgeContainer>::PathElement object.
*
* Arguments: None.
*
* Returns: true iff there is an edge associated with the object.
*
* ------------------------------------------------------------------------- */
{
return (edge != 0);
}
/* ========================================================================= */
template <class EdgeContainer>
inline const typename Graph<EdgeContainer>::Edge&
Graph<EdgeContainer>::PathElement::edge() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the edge associated with a
* Graph<EdgeContainer>::PathElement object. The function
* assumes that there is such an edge; it is an error to call
* this function for a PathElement object `element' for which
* `element.hasEdge() == false'.
*
* Arguments: None.
*
* Returns: The edge associated with the object.
*
* ------------------------------------------------------------------------- */
{
return *edge_pointer;
}
/****************************************************************************** /******************************************************************************
* *
* Inline function definitions for class NodeIndexException. * Inline function definitions for class NodeIndexException.

187
lbtt/src/IntervalList.cc Normal file
View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 "IntervalList.h"
#include "StringUtil.h"
/******************************************************************************
*
* Function definitions for class IntervalList.
*
*****************************************************************************/
/* ========================================================================= */
void IntervalList::merge(unsigned long int min, unsigned long int max)
/* ----------------------------------------------------------------------------
*
* Description: Merges a new interval with a list of intervals.
*
* Arguments: min, max -- Upper and lower bound of the new interval.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (min > max)
return;
list<Interval, ALLOC(Interval) >::iterator interval;
for (interval = intervals.begin();
interval != intervals.end() && interval->second + 1 < min;
++interval)
;
if (interval == intervals.end())
{
intervals.insert(interval, make_pair(min, max));
return;
}
if (interval->first <= min && max <= interval->second)
return;
if (max + 1 < interval->first)
{
intervals.insert(interval, make_pair(min, max));
return;
}
if (min < interval->first)
interval->first = min;
if (interval->second < max)
{
interval->second = max;
list<Interval, ALLOC(Interval) >::iterator interval2 = interval;
++interval2;
while (interval2 != intervals.end()
&& interval2->first <= interval->second + 1)
{
if (interval->second < interval2->second)
interval->second = interval2->second;
list<Interval, ALLOC(Interval) >::iterator interval_to_erase = interval2;
++interval2;
intervals.erase(interval_to_erase);
}
}
}
/* ========================================================================= */
void IntervalList::remove(unsigned long int min, unsigned long int max)
/* ----------------------------------------------------------------------------
*
* Description: Removes a closed interval from an interval list.
*
* Arguments: min, max -- Bounds for the interval to remove.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (min > max)
return;
list<Interval, ALLOC(Interval) >::iterator interval;
for (interval = intervals.begin();
interval != intervals.end() && interval->second < min;
++interval)
;
while (interval != intervals.end())
{
if (max < interval->first) /* min <= max < imin <= imax */
return;
if (interval->first < min)
{
if (max < interval->second) /* imin < min <= max < imax */
{
intervals.insert(interval, make_pair(interval->first, min - 1));
interval->first = max + 1;
return;
}
interval->second = min - 1; /* imin < min <= imax <= max */
++interval;
}
else if (max < interval->second) /* min <= imin <= max < imax */
{
interval->first = max + 1;
return;
}
else /* min <= imin <= imax <= max */
{
list<Interval, ALLOC(Interval) >::iterator interval_to_erase = interval;
++interval;
intervals.erase(interval_to_erase);
}
}
}
/* ========================================================================= */
bool IntervalList::covers(unsigned long int min, unsigned long int max) const
/* ----------------------------------------------------------------------------
*
* Description: Test whether an interval list covers a given interval.
*
* Arguments: min, max -- Upper and lower bound for the interval to test.
*
* Returns: True if the IntervalList covers the given interval.
*
* ------------------------------------------------------------------------- */
{
if (min > max)
return true; /* empty interval is always covered */
list<Interval, ALLOC(Interval) >::const_iterator interval;
for (interval = intervals.begin();
interval != intervals.end() && min > interval->second;
++interval)
;
if (interval == intervals.end())
return false;
return (min >= interval->first && max <= interval->second);
}
/* ========================================================================= */
string IntervalList::toString() const
/* ----------------------------------------------------------------------------
*
* Description: Converts the interval list to a string.
*
* Arguments: None.
*
* Returns: A string listing the intervals in the interval list.
*
* ------------------------------------------------------------------------- */
{
string s;
for (list<Interval, ALLOC(Interval) >::const_iterator
interval = intervals.begin();
interval != intervals.end();
++interval)
{
if (interval != intervals.begin())
s += ',';
s += StringUtil::toString(interval->first) + "..."
+ StringUtil::toString(interval->second);
}
return s;
}

499
lbtt/src/IntervalList.h Normal file
View file

@ -0,0 +1,499 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 INTERVALLIST_H
#define INTERVALLIST_H
#include <config.h>
#include <list>
#include <string>
#include <utility>
#include "LbttAlloc.h"
using namespace std;
/******************************************************************************
*
* The IntervalList class represents a list of disjoint closed intervals
* formed from pairs of unsigned long integers. The class supports merging
* a new interval with a list of intervals, removing an interval from a list
* of intervals and checking whether the interval list covers a given element
* (or a given interval). The elements of the intervals can also be accessed
* in increasing order via IntervalList::const_iterator.
*
*****************************************************************************/
class IntervalList
{
private:
typedef pair<unsigned long int,
unsigned long int>
Interval;
public:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class const_iterator /* A class for iterating */
{ /* over the elements of */
/* an IntervalList. */
public:
const_iterator(); /* Constructor. */
/* default copy constructor */
~const_iterator(); /* Destructor. */
/* default assignment operator */
bool operator==(const const_iterator& it) /* Comparison operators. */
const;
bool operator!=(const const_iterator& it)
const;
unsigned long int operator*() const; /* Dereference operator. */
unsigned long int operator++(); /* Prefix increment. */
unsigned long int operator++(int); /* Postfix increment. */
private:
const list<Interval, ALLOC(Interval) >* /* The interval list */
interval_list; /* associated with the */
/* iterator. */
list<Interval, ALLOC(Interval) > /* An iterator pointing */
::const_iterator interval; /* at the current */
/* interval list. */
unsigned long int element; /* Element currently
* pointed to by the
* iterator.
*/
friend class IntervalList;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
IntervalList(); /* Constructor. */
~IntervalList(); /* Destructor. */
/* default copy constructor */
/* default assignment operator */
void merge(unsigned long int element); /* Merges a point interval
* with the list of
* intervals.
*/
void merge /* Merges a new interval */
(unsigned long int min, unsigned long int max); /* with the list of
* intervals.
*/
void remove(unsigned long int element); /* Removes an element from
* the list of intervals.
*/
void remove /* Removes an interval */
(unsigned long int min, unsigned long int max); /* from the list of
* intervals.
*/
bool covers(unsigned long int element) const; /* Tests whether the
* interval list covers an
* element.
*/
bool covers /* Tests whether the */
(unsigned long int min, unsigned long int max) /* interval list covers */
const; /* an interval. */
const_iterator begin() const; /* Returns an iterator to
* the beginning of the
* interval list.
*/
const_iterator end() const; /* Returns an iterator to
* the end of the interval
* list.
*/
typedef const_iterator iterator; /* The interval list
* cannot be modified with
* iterators.
*/
typedef list<Interval, ALLOC(Interval) > /* Size type. */
::size_type size_type;
size_type size() const; /* Tell the number of
* disjoint intervals in
* the interval list.
*/
size_type max_size() const; /* Tell the maximum
* allowable number of
* disjoint intervals in
* the interval list.
*/
bool empty() const; /* Tell whether the
* interval list is empty.
*/
void clear(); /* Makes the interval list
* empty.
*/
string toString() const; /* Converts the interval
* list to a string.
*/
private:
list<Interval, ALLOC(Interval) > intervals; /* List of intervals. */
friend class const_iterator;
};
/******************************************************************************
*
* Inline function definitions for class IntervalList.
*
*****************************************************************************/
/* ========================================================================= */
inline IntervalList::IntervalList()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class IntervalList. Creates an empty list of
* intervals.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline IntervalList::~IntervalList()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class IntervalList.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline void IntervalList::merge(unsigned long int element)
/* ----------------------------------------------------------------------------
*
* Description: Merges an element (a point interval) with an IntervalList.
*
* Arguments: element -- Element to merge.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
merge(element, element);
}
/* ========================================================================= */
inline bool IntervalList::covers(unsigned long int element) const
/* ----------------------------------------------------------------------------
*
* Description: Tests whether an interval list covers an element.
*
* Arguments: element -- Element to test.
*
* Returns: True if the IntervalList covers the element.
*
* ------------------------------------------------------------------------- */
{
return covers(element, element);
}
/* ========================================================================= */
inline IntervalList::size_type IntervalList::size() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the number of disjoint intervals in an IntervalList.
*
* Arguments: None.
*
* Returns: Number of disjoint intervals in the IntervalList.
*
* ------------------------------------------------------------------------- */
{
return intervals.size();
}
/* ========================================================================= */
inline IntervalList::size_type IntervalList::max_size() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the maximum allowable number of disjoint intervals in
* an IntervalList.
*
* Arguments: None.
*
* Returns: Maximum allowable number of disjoint intervals in the
* IntervalList.
*
* ------------------------------------------------------------------------- */
{
return intervals.max_size();
}
/* ========================================================================= */
inline bool IntervalList::empty() const
/* ----------------------------------------------------------------------------
*
* Description: Tells whether an IntervalList is empty.
*
* Arguments: None.
*
* Returns: True if the IntervalList is empty.
*
* ------------------------------------------------------------------------- */
{
return intervals.empty();
}
/* ========================================================================= */
inline void IntervalList::clear()
/* ----------------------------------------------------------------------------
*
* Description: Makes an IntervalList empty.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
intervals.clear();
}
/* ========================================================================= */
inline IntervalList::const_iterator IntervalList::begin() const
/* ----------------------------------------------------------------------------
*
* Description: Returns an IntervalList::const_iterator pointing to the
* beginning of an IntervalList.
*
* Arguments: None.
*
* Returns: An IntervalList::const_iterator pointing to the beginning of
* the IntervalList.
*
* ------------------------------------------------------------------------- */
{
const_iterator it;
it.interval_list = &this->intervals;
it.interval = intervals.begin();
if (it.interval != intervals.end())
it.element = it.interval->first;
else
it.element = 0;
return it;
}
/* ========================================================================= */
inline IntervalList::const_iterator IntervalList::end() const
/* ----------------------------------------------------------------------------
*
* Description: Returns an IntervalList::const_iterator pointing to the end
* of an IntervalList.
*
* Arguments: None.
*
* Returns: An IntervalList::const_iterator pointing to the end of the
* IntervalList.
*
* ------------------------------------------------------------------------- */
{
const_iterator it;
it.interval_list = &this->intervals;
it.interval = intervals.end();
it.element = 0;
return it;
}
/******************************************************************************
*
* Inline function definitions for class IntervalList::const_iterator.
*
*****************************************************************************/
/* ========================================================================= */
inline IntervalList::const_iterator::const_iterator()
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline IntervalList::const_iterator::~const_iterator()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline bool IntervalList::const_iterator::operator==
(const const_iterator& it) const
/* ----------------------------------------------------------------------------
*
* Description: Equality test for two IntervalList::const_iterators. Two
* IntervalList::const_iterators are equal if and only if they
* point to the same interval of an interval list and the same
* element in the interval.
*
* Argument: it -- A constant reference to another
* IntervalList::const_iterator.
*
* Returns: Result of the equality test (a truth value).
*
* ------------------------------------------------------------------------- */
{
return (interval_list == it.interval_list && interval == it.interval
&& element == it.element);
}
/* ========================================================================= */
inline bool IntervalList::const_iterator::operator!=
(const const_iterator& it) const
/* ----------------------------------------------------------------------------
*
* Description: Inequality test for two IntervalList::const_iterators. Two
* IntervalList::const_iterators are not equal if and only if
* they point to different intervals of an interval list or to
* different elements of the same interval in the list.
*
* Argument: it -- A constant reference to another
* IntervalList::const_iterator.
*
* Returns: Result of the inequality test (a truth value).
*
* ------------------------------------------------------------------------- */
{
return (interval_list != it.interval_list || interval != it.interval
|| element != it.element);
}
/* ========================================================================= */
inline unsigned long int IntervalList::const_iterator::operator*() const
/* ----------------------------------------------------------------------------
*
* Description: Dereferencing operator for IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: The element currently pointed to by the iterator.
*
* ------------------------------------------------------------------------- */
{
return element;
}
/* ========================================================================= */
inline unsigned long int IntervalList::const_iterator::operator++()
/* ----------------------------------------------------------------------------
*
* Description: Prefix increment operator for IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: The element following the "current" element in the interval
* list.
*
* ------------------------------------------------------------------------- */
{
if (element == interval->second)
{
++interval;
if (interval != interval_list->end())
element = interval->first;
else
element = 0;
}
else
++element;
return element;
}
/* ========================================================================= */
inline unsigned long int IntervalList::const_iterator::operator++(int)
/* ----------------------------------------------------------------------------
*
* Description: Postfix increment operator for IntervalList::const_iterator.
*
* Arguments: None.
*
* Returns: The "current" element in the interval list.
*
* ------------------------------------------------------------------------- */
{
unsigned long int current_element = element;
if (element == interval->second)
{
++interval;
if (interval != interval_list->end())
element = interval->first;
else
element = 0;
}
else
++element;
return current_element;
}
#endif /* INTERVALLIST_H */

View file

@ -22,11 +22,7 @@
#include <config.h> #include <config.h>
#ifdef HAVE_SINGLE_CLIENT_ALLOC
#define ALLOC(typename) single_client_alloc
#else
#define ALLOC(typename) allocator<typename> #define ALLOC(typename) allocator<typename>
#endif /* HAVE_SINGLE_CLIENT_ALLOC */
#ifdef HAVE_OBSTACK_H #ifdef HAVE_OBSTACK_H

610
lbtt/src/Ltl-parse.yy Normal file
View file

@ -0,0 +1,610 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 <config.h>
#include <cctype>
#include <climits>
#include <cstring>
#include <istream>
#include <set>
#include "Exception.h"
#include "LbttAlloc.h"
#include "LtlFormula.h"
using namespace Ltl;
/******************************************************************************
*
* Variables and functions used for parsing an LTL formula.
*
*****************************************************************************/
static Exceptional_istream* estream; /* Pointer to input stream.
*/
static LtlFormula* result; /* This variable stores the
* result after a call to
* ltl_parse.
*/
static std::set<LtlFormula*, less<LtlFormula*>, /* Intermediate results. */
ALLOC(LtlFormula*) > /* (This set is used */
intermediate_results; /* for keeping track of
* the subformulas of a
* partially constructed
* formula in case the
* memory allocated for
* the subformulas needs
* to be freed because
* of a parse error.)
*/
static int ltl_lex(); /* The lexical scanner. */
/******************************************************************************
*
* Function for reporting parse errors.
*
*****************************************************************************/
static void ltl_error(const char*)
{
throw LtlFormula::ParseErrorException("error parsing LTL formula");
}
/******************************************************************************
*
* Function for updating the set of intermediate results.
*
*****************************************************************************/
inline LtlFormula* newFormula(LtlFormula& f)
{
intermediate_results.insert(&f);
return &f;
}
%}
%name-prefix="ltl_"
/******************************************************************************
*
* Declarations for terminal and nonterminal symbols used in the grammar rules
* below.
*
*****************************************************************************/
%union {
class LtlFormula* formula;
}
/* Uninterpreted symbols. */
%token LTLPARSE_LPAR LTLPARSE_RPAR LTLPARSE_FALSE LTLPARSE_TRUE
LTLPARSE_UNKNOWN
/* Atomic propositions. */
%token <formula> LTLPARSE_ATOM
/* Operators. */
%nonassoc LTLPARSE_UNTIL LTLPARSE_RELEASE LTLPARSE_WEAK_UNTIL
LTLPARSE_STRONG_RELEASE LTLPARSE_BEFORE
%left LTLPARSE_IMPLY LTLPARSE_EQUIV LTLPARSE_XOR
%left LTLPARSE_OR
%left LTLPARSE_AND
%nonassoc LTLPARSE_NOT LTLPARSE_NEXT LTLPARSE_FINALLY LTLPARSE_GLOBALLY
%nonassoc LTLPARSE_EQUALS
/* Compound formulas. */
%type <formula> formula atomic_formula unary_formula prefix_op_formula
binary_formula prefix_b_formula infix_b_formula
/******************************************************************************
*
* Grammar rule definitions.
*
*****************************************************************************/
%%
ltl_formula: formula
{ result = $1; }
;
formula: atomic_formula
{ $$ = $1; }
| unary_formula
{ $$ = $1; }
| binary_formula
{ $$ = $1; }
| LTLPARSE_LPAR formula LTLPARSE_RPAR
{ $$ = $2; }
;
atomic_formula: LTLPARSE_ATOM
{ $$ = $1; }
| LTLPARSE_ATOM LTLPARSE_EQUALS LTLPARSE_FALSE
{
intermediate_results.erase($1);
$$ = newFormula(Not::construct($1));
}
| LTLPARSE_ATOM LTLPARSE_EQUALS LTLPARSE_TRUE
{ $$ = $1; }
| LTLPARSE_FALSE
{ $$ = newFormula(False::construct()); }
| LTLPARSE_TRUE
{ $$ = newFormula(True::construct()); }
;
unary_formula: LTLPARSE_NOT formula
{
intermediate_results.erase($2);
$$ = newFormula(Not::construct($2));
}
| LTLPARSE_NEXT formula
{
intermediate_results.erase($2);
$$ = newFormula(Next::construct($2));
}
| LTLPARSE_FINALLY formula
{
intermediate_results.erase($2);
$$ = newFormula(Finally::construct($2));
}
| LTLPARSE_GLOBALLY formula
{
intermediate_results.erase($2);
$$ = newFormula(Globally::construct($2));
}
;
prefix_op_formula: atomic_formula
{ $$ = $1; }
| unary_formula
{ $$ = $1; }
| prefix_b_formula
{ $$ = $1; }
| LTLPARSE_LPAR formula LTLPARSE_RPAR
{ $$ = $2; }
;
binary_formula: prefix_b_formula
{ $$ = $1; }
| infix_b_formula
{ $$ = $1; }
;
prefix_b_formula: LTLPARSE_AND prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(And::construct($2, $3));
}
| LTLPARSE_OR prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Or::construct($2, $3));
}
| LTLPARSE_IMPLY prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Imply::construct($2, $3));
}
| LTLPARSE_EQUIV prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Equiv::construct($2, $3));
}
| LTLPARSE_XOR prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Xor::construct($2, $3));
}
| LTLPARSE_UNTIL prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Until::construct($2, $3));
}
| LTLPARSE_RELEASE prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(V::construct($2, $3));
}
| LTLPARSE_WEAK_UNTIL prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(WeakUntil::construct($2, $3));
}
| LTLPARSE_STRONG_RELEASE prefix_op_formula
prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(StrongRelease::construct($2, $3));
}
| LTLPARSE_BEFORE prefix_op_formula prefix_op_formula
{
intermediate_results.erase($2);
intermediate_results.erase($3);
$$ = newFormula(Before::construct($2, $3));
}
;
infix_b_formula: formula LTLPARSE_AND formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(And::construct($1, $3));
}
| formula LTLPARSE_OR formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Or::construct($1, $3));
}
| formula LTLPARSE_IMPLY formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Imply::construct($1, $3));
}
| formula LTLPARSE_EQUIV formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Equiv::construct($1, $3));
}
| formula LTLPARSE_XOR formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Xor::construct($1, $3));
}
| formula LTLPARSE_UNTIL formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Until::construct($1, $3));
}
| formula LTLPARSE_RELEASE formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(V::construct($1, $3));
}
| formula LTLPARSE_WEAK_UNTIL formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(WeakUntil::construct($1, $3));
}
| formula LTLPARSE_STRONG_RELEASE formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(StrongRelease::construct($1, $3));
}
| formula LTLPARSE_BEFORE formula
{
intermediate_results.erase($1);
intermediate_results.erase($3);
$$ = newFormula(Before::construct($1, $3));
}
;
%%
/******************************************************************************
*
* Helper function for reading lexical tokens from a stream.
*
*****************************************************************************/
static inline size_t matchCharactersFromStream
(istream& stream, char* chars)
{
size_t num_matched;
for (num_matched = 0; *chars != '\0' && stream.peek() == *chars; ++chars)
{
stream.ignore(1);
++num_matched;
}
return num_matched;
}
/******************************************************************************
*
* Main interface to the parser.
*
*****************************************************************************/
namespace Ltl
{
/* ========================================================================= */
LtlFormula* parseFormula(istream& stream)
/* ----------------------------------------------------------------------------
*
* Description: Parses an LTL formula from a stream. The formula should be
* in one of the formats used by the tools lbtt 1.0.x (both
* prefix and infix form), Spin/Temporal Massage Parlor/LTL2BA,
* LTL2AUT or Wring 1.1.0 (actually, the grammar is basically
* a combination of the grammars of the above tools with the
* exception that propositions should always be written in the
* form `pN' for some integer N; in principle, it is possible to
* use a mixed syntax for the formula). The input should be
* terminated with a newline.
*
* Argument: stream -- A reference to the input stream.
*
* Returns: A pointer to the formula. The function throws an
* LtlFormula::ParseErrorException if the syntax is incorrect,
* or an IOException in case of an end-of-file or another I/O
* error.
*
* ------------------------------------------------------------------------- */
{
Exceptional_istream es(&stream, ios::badbit | ios::failbit | ios::eofbit);
estream = &es;
intermediate_results.clear();
try
{
ltl_parse();
}
catch (...)
{
for (std::set<LtlFormula*, less<LtlFormula*>, ALLOC(LtlFormula*) >
::const_iterator f = intermediate_results.begin();
f != intermediate_results.end();
++f)
LtlFormula::destruct(*f);
throw;
}
return result;
}
}
/******************************************************************************
*
* The lexical scanner.
*
*****************************************************************************/
static int ltl_lex()
{
char c;
std::istream& stream = static_cast<istream&>(*estream);
do
{
estream->get(c);
}
while (isspace(c) && c != '\n');
switch (c)
{
case '\n' : return 0;
case '(' :
return (matchCharactersFromStream(stream, ")") == 1
? LTLPARSE_NEXT
: LTLPARSE_LPAR);
case ')' : return LTLPARSE_RPAR;
case 'f' :
switch (matchCharactersFromStream(stream, "alse"))
{
case 0 : case 4 :
return LTLPARSE_FALSE;
default:
break;
}
return LTLPARSE_UNKNOWN;
case '0' : return LTLPARSE_FALSE;
case 't' :
switch (matchCharactersFromStream(stream, "rue"))
{
case 0 : case 3 :
return LTLPARSE_TRUE;
default :
return LTLPARSE_UNKNOWN;
}
case 'T' :
return (matchCharactersFromStream(stream, "RUE") == 3
? LTLPARSE_TRUE
: LTLPARSE_UNKNOWN);
case '1' : return LTLPARSE_TRUE;
case '!' : case '~' : return LTLPARSE_NOT;
case '&' :
matchCharactersFromStream(stream, "&");
return LTLPARSE_AND;
case '/' :
return (matchCharactersFromStream(stream, "\\") == 1
? LTLPARSE_AND
: LTLPARSE_UNKNOWN);
case '*' : return LTLPARSE_AND;
case '|' :
matchCharactersFromStream(stream, "|");
return LTLPARSE_OR;
case '\\' :
return (matchCharactersFromStream(stream, "/") == 1
? LTLPARSE_OR
: LTLPARSE_UNKNOWN);
case '+' : return LTLPARSE_OR;
case '=' :
return (matchCharactersFromStream(stream, ">") == 1
? LTLPARSE_IMPLY
: LTLPARSE_EQUALS);
case '-' :
return (matchCharactersFromStream(stream, ">") == 1
? LTLPARSE_IMPLY
: LTLPARSE_UNKNOWN);
case 'i' : return LTLPARSE_IMPLY;
case '<' :
if (matchCharactersFromStream(stream, ">") == 1)
return LTLPARSE_FINALLY;
return (matchCharactersFromStream(stream, "->") == 2
|| matchCharactersFromStream(stream, "=>") == 2
? LTLPARSE_EQUIV
: LTLPARSE_UNKNOWN);
case 'e' : return LTLPARSE_EQUIV;
case 'x' :
return (matchCharactersFromStream(stream, "or") == 2
? LTLPARSE_XOR
: LTLPARSE_UNKNOWN);
case '^' : return LTLPARSE_XOR;
case 'X' : return LTLPARSE_NEXT;
case 'U' : return LTLPARSE_UNTIL;
case 'V' : case 'R' : return LTLPARSE_RELEASE;
case 'W' : return LTLPARSE_WEAK_UNTIL;
case 'M' : return LTLPARSE_STRONG_RELEASE;
case 'B' : return LTLPARSE_BEFORE;
case 'F' :
switch (matchCharactersFromStream(stream, "ALSE"))
{
case 0 :
return LTLPARSE_FINALLY;
case 4 :
return LTLPARSE_FALSE;
default :
return LTLPARSE_UNKNOWN;
}
case '[' :
return (matchCharactersFromStream(stream, "]") == 1
? LTLPARSE_GLOBALLY
: LTLPARSE_UNKNOWN);
case 'G' : return LTLPARSE_GLOBALLY;
case 'p' :
{
long int id = 0;
bool id_ok = false;
int ch = stream.peek();
while (ch >= '0' && ch <= '9')
{
id_ok = true;
estream->get(c);
if (LONG_MAX / 10 < id)
throw LtlFormula::ParseErrorException
("error parsing LTL formula (proposition identifier out of "
"range)");
id *= 10;
id += (c - '0');
ch = stream.peek();
}
if (id_ok)
{
ltl_lval.formula = newFormula(Atom::construct(id));
return LTLPARSE_ATOM;
}
return LTLPARSE_UNKNOWN;
}
default : return LTLPARSE_UNKNOWN;
}
}

View file

@ -24,9 +24,8 @@
namespace Ltl namespace Ltl
{ {
map<LtlFormula*, unsigned long int, /* Shared storage for */ set<LtlFormula*, LtlFormula::ptr_less, /* Shared storage for */
LtlFormula::ptr_less, /* LTL formulae. */ ALLOC(LtlFormula*) > /* LTL formulae. */
ALLOC(unsigned long int) >
LtlFormula::formula_storage; LtlFormula::formula_storage;
unsigned long int /* Upper limit for the */ unsigned long int /* Upper limit for the */
@ -38,8 +37,6 @@ unsigned long int /* Upper limit for the */
* truth assignment). * truth assignment).
*/ */
/****************************************************************************** /******************************************************************************
* *
* Function for obtaining the infix symbol associated with a given * Function for obtaining the infix symbol associated with a given
@ -875,193 +872,6 @@ Bitset LtlFormula::findPropositionalModel(long int max_atom) const
return model; return model;
} }
/* ========================================================================= */
LtlFormula* LtlFormula::read(Exceptional_istream& stream)
/* ----------------------------------------------------------------------------
*
* Description: Recursively constructs an LtlFormula by parsing input from an
* exception-aware input stream.
*
* Argument: stream -- A reference to an exception-aware input stream.
*
* Returns: The constructed LtlFormula.
*
* ------------------------------------------------------------------------- */
{
string token;
LtlFormula* formula;
try
{
stream >> token;
}
catch (const IOException&)
{
if (static_cast<istream&>(stream).eof())
throw ParseErrorException("error parsing LTL formula (unexpected end of "
"input)");
else
throw ParseErrorException("error parsing LTL formula (I/O error)");
}
if (token[0] == 'p')
{
if (token.length() == 1)
throw ParseErrorException("error parsing LTL formula (unrecognized "
"token: `" + token + "')");
long int id;
char* endptr;
id = strtol(token.c_str() + 1, &endptr, 10);
if (*endptr != '\0' || id < 0 || id == LONG_MIN || id == LONG_MAX)
throw ParseErrorException("error parsing LTL formula (unrecognized "
"token: `" + token + "')");
formula = &Atom::construct(id);
}
else
{
if (token.length() > 1)
throw ParseErrorException("error parsing LTL formula (unrecognized "
"token: `" + token + "')");
switch (token[0])
{
case LTL_TRUE :
formula = &True::construct();
break;
case LTL_FALSE :
formula = &False::construct();
break;
case LTL_NEGATION :
case LTL_NEXT :
case LTL_FINALLY :
case LTL_GLOBALLY :
{
LtlFormula* g = read(stream);
try
{
switch (token[0])
{
case LTL_NEGATION :
formula = &Not::construct(g);
break;
case LTL_NEXT :
formula = &Next::construct(g);
break;
case LTL_FINALLY :
formula = &Finally::construct(g);
break;
default : /* LTL_GLOBALLY */
formula = &Globally::construct(g);
break;
}
}
catch (...)
{
LtlFormula::destruct(g);
throw;
}
break;
}
case LTL_CONJUNCTION :
case LTL_DISJUNCTION :
case LTL_IMPLICATION :
case LTL_EQUIVALENCE :
case LTL_XOR :
case LTL_UNTIL :
case LTL_V :
case LTL_WEAK_UNTIL :
case LTL_STRONG_RELEASE :
case LTL_BEFORE :
{
LtlFormula* g = read(stream);
LtlFormula* h;
try
{
h = read(stream);
}
catch (...)
{
LtlFormula::destruct(g);
throw;
}
try
{
switch (token[0])
{
case LTL_CONJUNCTION :
formula = &And::construct(g, h);
break;
case LTL_DISJUNCTION :
formula = &Or::construct(g, h);
break;
case LTL_IMPLICATION :
formula = &Imply::construct(g, h);
break;
case LTL_EQUIVALENCE :
formula = &Equiv::construct(g, h);
break;
case LTL_XOR :
formula = &Xor::construct(g, h);
break;
case LTL_UNTIL :
formula = &Until::construct(g, h);
break;
case LTL_V :
formula = &V::construct(g, h);
break;
case LTL_WEAK_UNTIL :
formula = &WeakUntil::construct(g, h);
break;
case LTL_STRONG_RELEASE :
formula = &StrongRelease::construct(g, h);
break;
default : /* LTL_BEFORE */
formula = &Before::construct(g, h);
break;
}
}
catch (...)
{
LtlFormula::destruct(g);
LtlFormula::destruct(h);
throw;
}
break;
}
default :
throw ParseErrorException("error parsing LTL formula (unrecognized "
"token: `" + token + "')");
}
}
return formula;
}
/* ========================================================================= */ /* ========================================================================= */
void LtlFormula::print(Exceptional_ostream& estream, OutputMode mode) const void LtlFormula::print(Exceptional_ostream& estream, OutputMode mode) const
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------

View file

@ -23,7 +23,7 @@
#include <config.h> #include <config.h>
#include <deque> #include <deque>
#include <iostream> #include <iostream>
#include <map> #include <set>
#include <stack> #include <stack>
#include <string> #include <string>
#include "LbttAlloc.h" #include "LbttAlloc.h"
@ -188,13 +188,6 @@ public:
* input stream. * input stream.
*/ */
static LtlFormula* read /* Constructs an */
(Exceptional_istream& stream); /* LtlFormula by parsing
* input from an
* exception-aware input
* stream.
*/
void print /* Writes the formula to */ void print /* Writes the formula to */
(ostream& stream = cout, /* an output stream. */ (ostream& stream = cout, /* an output stream. */
OutputMode mode = LTL_INFIX) const; OutputMode mode = LTL_INFIX) const;
@ -250,6 +243,10 @@ protected:
unsigned int is_constant : 1; /* operators and atomic */ unsigned int is_constant : 1; /* operators and atomic */
} info_flags; /* propositions. */ } info_flags; /* propositions. */
unsigned long int refcount; /* Number of references to
* `this' LtlFormula.
*/
static LtlFormula& /* Updates the shared */ static LtlFormula& /* Updates the shared */
insertToStorage(LtlFormula* f); /* formula storage with insertToStorage(LtlFormula* f); /* formula storage with
* a new formula. * a new formula.
@ -288,8 +285,8 @@ private:
* formula. * formula.
*/ */
static map<LtlFormula*, unsigned long int, /* Shared storage for */ static set<LtlFormula*, ptr_less, /* Shared storage for */
ptr_less, ALLOC(unsigned long int) > /* LTL formulae. */ ALLOC(LtlFormula*) > /* LTL formulae. */
formula_storage; formula_storage;
static unsigned long int /* Upper limit for the */ static unsigned long int /* Upper limit for the */
@ -330,6 +327,16 @@ private:
/******************************************************************************
*
* Interface to the formula parser.
*
*****************************************************************************/
extern LtlFormula* parseFormula(istream& stream);
/****************************************************************************** /******************************************************************************
* *
* A class for atomic propositions. * A class for atomic propositions.
@ -1076,7 +1083,7 @@ typedef BinaryFormula<LtlBefore> Before;
*****************************************************************************/ *****************************************************************************/
/* ========================================================================= */ /* ========================================================================= */
inline LtlFormula::LtlFormula() inline LtlFormula::LtlFormula() : refcount(1)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Constructor for class LtlFormula. Initializes the attributes * Description: Constructor for class LtlFormula. Initializes the attributes
@ -1088,8 +1095,6 @@ inline LtlFormula::LtlFormula()
* *
* --------------------------------------------------------------------------*/ * --------------------------------------------------------------------------*/
{ {
info_flags.is_propositional = 0;
info_flags.is_constant = 0;
} }
/* ========================================================================= */ /* ========================================================================= */
@ -1122,14 +1127,9 @@ inline void LtlFormula::destruct(LtlFormula* f)
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
map<LtlFormula*, unsigned long int, LtlFormula::ptr_less, if (--f->refcount == 0)
ALLOC(unsigned long int) >::iterator
deleter;
deleter = formula_storage.find(f);
if (--deleter->second == 0)
{ {
formula_storage.erase(deleter); formula_storage.erase(f);
delete f; delete f;
} }
} }
@ -1147,7 +1147,7 @@ inline LtlFormula* LtlFormula::clone()
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
formula_storage.find(this)->second++; ++refcount;
return this; return this;
} }
@ -1241,8 +1241,7 @@ inline LtlFormula* LtlFormula::read(istream& stream)
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
Exceptional_istream estream(&stream, ios::badbit | ios::failbit); return parseFormula(stream);
return read(estream);
} }
/* ========================================================================= */ /* ========================================================================= */
@ -1303,8 +1302,6 @@ inline Exceptional_ostream& operator<<
return stream; return stream;
} }
/* ========================================================================= */ /* ========================================================================= */
inline LtlFormula& LtlFormula::insertToStorage(LtlFormula* f) inline LtlFormula& LtlFormula::insertToStorage(LtlFormula* f)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -1317,19 +1314,16 @@ inline LtlFormula& LtlFormula::insertToStorage(LtlFormula* f)
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
map<LtlFormula*, unsigned long int, LtlFormula::ptr_less, set<LtlFormula*, ptr_less, ALLOC(LtlFormula*) >::iterator inserter
ALLOC(unsigned long int) >::iterator = formula_storage.find(f);
inserter;
inserter = formula_storage.find(f);
if (inserter != formula_storage.end()) if (inserter != formula_storage.end())
{ {
delete f; delete f;
inserter->second++; ++(*inserter)->refcount;
return *(inserter->first); return **inserter;
} }
formula_storage.insert(make_pair(f, 1)); formula_storage.insert(f);
return *f; return *f;
} }
@ -1571,8 +1565,7 @@ inline Atom& Atom::construct(long int a)
} }
/* ========================================================================= */ /* ========================================================================= */
inline Atom::Atom(long int a) : inline Atom::Atom(long int a) : atom(a)
LtlFormula(), atom(a)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Constructor for class Atom. Creates a new propositional atom. * Description: Constructor for class Atom. Creates a new propositional atom.
@ -1886,8 +1879,7 @@ inline UnaryFormula<Operator>& UnaryFormula<Operator>::construct(LtlFormula& f)
/* ========================================================================= */ /* ========================================================================= */
template<class Operator> template<class Operator>
inline UnaryFormula<Operator>::UnaryFormula(LtlFormula* f) : inline UnaryFormula<Operator>::UnaryFormula(LtlFormula* f) : subformula(f)
LtlFormula(), subformula(f)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Constructs an LTL formula with a unary operator. * Description: Constructs an LTL formula with a unary operator.
@ -2189,7 +2181,7 @@ BinaryFormula<Operator>::construct(LtlFormula& f1, LtlFormula* f2)
/* ========================================================================= */ /* ========================================================================= */
template<class Operator> template<class Operator>
inline BinaryFormula<Operator>::BinaryFormula(LtlFormula* f1, LtlFormula* f2) : inline BinaryFormula<Operator>::BinaryFormula(LtlFormula* f1, LtlFormula* f2) :
LtlFormula(), subformula1(f1), subformula2(f2) subformula1(f1), subformula2(f2)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Constructs a binary LTL formula. * Description: Constructs a binary LTL formula.

View file

@ -1,22 +1,90 @@
BUILT_SOURCES = Config-parse.h NeverClaim-parse.h
AM_YFLAGS = -d
bin_PROGRAMS = lbtt lbtt-translate bin_PROGRAMS = lbtt lbtt-translate
lbtt_SOURCES = BitArray.h Bitset.h BitArray.cc BuchiAutomaton.h \ lbtt_SOURCES = \
BuchiAutomaton.cc Config-parse.yy Config-lex.ll Configuration.h \ BitArray.h \
Configuration.cc DispUtil.h DispUtil.cc EdgeContainer.h Exception.h \ Bitset.h \
FormulaRandomizer.h FormulaRandomizer.cc FormulaWriter.h LbttAlloc.h \ BitArray.cc \
LtlFormula.h LtlFormula.cc main.cc PathEvaluator.h PathEvaluator.cc \ BuchiAutomaton.h \
PathIterator.h PathIterator.cc ProductAutomaton.h ProductAutomaton.cc \ BuchiAutomaton.cc \
Random.h SccIterator.h SharedTestData.h StatDisplay.h StatDisplay.cc \ BuchiProduct.h \
StateSpace.h StateSpace.cc StateSpaceRandomizer.h StateSpaceRandomizer.cc \ BuchiProduct.cc \
StringUtil.h StringUtil.cc TestOperations.h TestOperations.cc TestRoundInfo.h \ Config-parse.yy \
TestStatistics.h TestStatistics.cc UserCommandReader.h UserCommandReader.cc \ Config-lex.ll \
UserCommands.h UserCommands.cc Configuration.h \
EXTRA_lbtt_SOURCES = gnu-getopt.h Config-parse.h Configuration.cc \
DispUtil.h \
DispUtil.cc \
EdgeContainer.h \
Exception.h \
FormulaRandomizer.h \
FormulaRandomizer.cc \
FormulaWriter.h \
IntervalList.h \
IntervalList.cc \
LbttAlloc.h \
LtlFormula.h \
LtlFormula.cc \
Ltl-parse.yy \
main.cc \
PathEvaluator.h \
PathEvaluator.cc \
PathIterator.h \
PathIterator.cc \
Product.h \
Random.h \
SccCollection.h \
SharedTestData.h \
StatDisplay.h \
StatDisplay.cc \
StateSpace.h \
StateSpace.cc \
StateSpaceProduct.h \
StateSpaceRandomizer.h \
StateSpaceRandomizer.cc \
StringUtil.h \
StringUtil.cc \
TempFsysName.h \
TempFsysName.cc \
TestOperations.h \
TestOperations.cc \
TestRoundInfo.h \
TestStatistics.h \
TestStatistics.cc \
UserCommandReader.h \
UserCommandReader.cc \
UserCommands.h \
UserCommands.cc
EXTRA_lbtt_SOURCES = gnu-getopt.h
lbtt_LDADD = @LIBOBJS@ @READLINELIBS@ lbtt_LDADD = @LIBOBJS@ @READLINELIBS@
lbtt_translate_SOURCES = BitArray.h BitArray.cc Exception.h \ lbtt_translate_SOURCES = \
ExternalTranslator.h ExternalTranslator.cc FormulaWriter.h LbttAlloc.h \ BitArray.h \
LbtWrapper.h LtlFormula.h LtlFormula.cc NeverClaim-parse.yy NeverClaim-lex.ll \ BitArray.cc \
NeverClaimAutomaton.h NeverClaimAutomaton.cc SpinWrapper.h SpinWrapper.cc \ Exception.h \
StringUtil.h StringUtil.cc translate.h translate.cc TranslatorInterface.h ExternalTranslator.h \
EXTRA_lbtt_translate_SOURCES = gnu-getopt.h NeverClaim-parse.h ExternalTranslator.cc \
FormulaWriter.h \
IntervalList.h \
IntervalList.cc \
LbttAlloc.h \
LbtWrapper.h \
LtlFormula.h \
LtlFormula.cc \
Ltl-parse.yy \
NeverClaim-parse.yy \
NeverClaim-lex.ll \
NeverClaimAutomaton.h \
NeverClaimAutomaton.cc \
SpinWrapper.h \
SpinWrapper.cc \
StringUtil.h \
StringUtil.cc \
TempFsysName.h \
TempFsysName.cc \
translate.h \
translate.cc \
TranslatorInterface.h
EXTRA_lbtt_translate_SOURCES = gnu-getopt.h
lbtt_translate_LDADD = @LIBOBJS@ lbtt_translate_LDADD = @LIBOBJS@

View file

@ -30,6 +30,7 @@ extern int current_neverclaim_line_number;
%option never-interactive %option never-interactive
%option noyywrap %option noyywrap
%option nounput
%% %%

View file

@ -61,26 +61,25 @@ void PathEvaluator::reset()
/* ========================================================================= */ /* ========================================================================= */
bool PathEvaluator::evaluate bool PathEvaluator::evaluate
(const LtlFormula& formula, const StateSpace& statespace, (const LtlFormula& formula, const StateSpace::Path& prefix,
const vector<StateSpace::size_type, ALLOC(StateSpace::size_type) >& const StateSpace::Path& cycle, const StateSpace& statespace)
states_on_path,
StateSpace::size_type loop_state)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Evaluates an LTL formula in a state space in which the states * Description: Evaluates an LTL formula in a path formed from a prefix and
* are connected into a non-branching sequence that ends in a * an infinitely repeating cycle of states in a state space.
* loop.
* *
* Arguments: formula -- Formula to be evaluated. * Arguments: formula -- Formula to be evaluated.
* statespace -- State space from which the path is * prefix -- A StateSpace::Path object corresponding to
* extracted. * the prefix of the path. Only the state
* states_on_path -- Mapping between states in the path and * identifiers in the path elements are used;
* the states in `statespace' such that * the function will not require `prefix' to
* `statespace[states_on_path[i]]' * actually represent a path in `statespace'.
* corresponds to the ith state of the path. * cycle -- A StateSpace::Path object corresponding to
* loop_state -- Number of the state in the path to which * the infinitely repeating cycle. Only the
* the ``last'' state of the path is * state identifiers in the path elements are
* connected. * relevant.
* statespace -- State space to which the state identifiers in
* `path' and `cycle' refer.
* *
* Returns: `true' if and only if the LTL formula holds in the path. * Returns: `true' if and only if the LTL formula holds in the path.
* *
@ -88,13 +87,21 @@ bool PathEvaluator::evaluate
{ {
reset(); reset();
if (states_on_path.empty() || loop_state >= states_on_path.size()) if (cycle.empty())
return false; return false;
current_formula = &formula; current_formula = &formula;
current_path = &statespace; current_path = &statespace;
current_loop_state = loop_state; current_loop_state = prefix.size();
path_states = states_on_path; path_states.reserve(prefix.size() + cycle.size());
for (StateSpace::Path::const_iterator state = prefix.begin();
state != prefix.end();
++state)
path_states.push_back(state->node());
for (StateSpace::Path::const_iterator state = cycle.begin();
state != cycle.end();
++state)
path_states.push_back(state->node());
return eval(); return eval();
} }

View file

@ -54,11 +54,11 @@ public:
bool evaluate /* Tests whether an */ bool evaluate /* Tests whether an */
(const LtlFormula& formula, /* LtlFormula holds in a */ (const LtlFormula& formula, /* LtlFormula holds in a */
const StateSpace& statespace, /* state space. */ const StateSpace::Path& prefix, /* path described by a */
const vector<StateSpace::size_type, const StateSpace::Path& cycle, /* prefix and a cycle of */
ALLOC(StateSpace::size_type) >& const StateSpace& statespace); /* states from a state
states_on_path, * space.
StateSpace::size_type loop_state); */
bool evaluate /* Same as above. */ bool evaluate /* Same as above. */
(const LtlFormula& formula, (const LtlFormula& formula,

2936
lbtt/src/Product.h Normal file

File diff suppressed because it is too large Load diff

1174
lbtt/src/SccCollection.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@
#include <string> #include <string>
#include "DispUtil.h" #include "DispUtil.h"
#include "Exception.h" #include "Exception.h"
#include "IntervalList.h"
#include "SharedTestData.h" #include "SharedTestData.h"
#include "StatDisplay.h" #include "StatDisplay.h"
#include "StringUtil.h" #include "StringUtil.h"
@ -33,6 +34,47 @@ using namespace ::DispUtil;
using namespace ::SharedTestData; using namespace ::SharedTestData;
using namespace ::StringUtil; using namespace ::StringUtil;
/* ========================================================================= */
void printStatTableHeader(ostream& stream, int indent)
/* ----------------------------------------------------------------------------
*
* Description: Displays a table header for test statistics (used in
* verbosity mode 2).
*
* Arguments: stream -- A reference to the output stream to which the
* header should be written.
* indent -- Number of spaces to leave on the left of the
* output.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
int num_dashes = 39;
estream << string(indent, ' ') + " # F Elapsed Büchi Büchi Acc.";
if (configuration.global_options.do_cons_test
|| configuration.global_options.do_comp_test)
{
num_dashes += 31;
estream << " Product Product Acc.";
if (configuration.global_options.do_cons_test)
{
num_dashes += 3;
estream << " CC";
}
}
estream << '\n' + string(indent + 10, ' ')
+ "time states trans. sets";
if (configuration.global_options.do_cons_test
|| configuration.global_options.do_comp_test)
estream << " states trans. cycles";
estream << "\n" + string(indent, ' ') + string(num_dashes, '-') + '\n';
estream.flush();
}
/* ========================================================================= */ /* ========================================================================= */
void printBuchiAutomatonStats void printBuchiAutomatonStats
(ostream& stream, int indent, (ostream& stream, int indent,
@ -48,7 +90,7 @@ void printBuchiAutomatonStats
* Arguments: stream -- A reference to the output stream to which the * Arguments: stream -- A reference to the output stream to which the
* information should be written. * information should be written.
* indent -- Number of spaces to leave on the left of the * indent -- Number of spaces to leave on the left of the
* output. * output in verbosity modes >= 3.
* algorithm -- Identifier of the algorithm used for * algorithm -- Identifier of the algorithm used for
* generating the automaton. * generating the automaton.
* result_id -- Selects between the automata constructed from * result_id -- Selects between the automata constructed from
@ -63,6 +105,37 @@ void printBuchiAutomatonStats
const AutomatonStats& automaton_stats = const AutomatonStats& automaton_stats =
test_results[algorithm].automaton_stats[result_id]; test_results[algorithm].automaton_stats[result_id];
if (configuration.global_options.verbosity <= 2)
{
if (!automaton_stats.buchiAutomatonComputed())
estream << " N/A N/A N/A N/A";
else
{
if (automaton_stats.buchi_generation_time >= 0.0)
{
changeStreamFormatting(stream, 9, 2, ios::fixed | ios::right);
estream << automaton_stats.buchi_generation_time;
restoreStreamFormatting(stream);
}
else
estream << " N/A";
estream << ' ';
changeStreamFormatting(stream, 9, 0, ios::right);
estream << automaton_stats.number_of_buchi_states;
restoreStreamFormatting(stream);
estream << ' ';
changeStreamFormatting(stream, 9, 0, ios::right);
estream << automaton_stats.number_of_buchi_transitions;
restoreStreamFormatting(stream);
estream << ' ';
changeStreamFormatting(stream, 4, 0, ios::right);
estream << automaton_stats.number_of_acceptance_sets;
restoreStreamFormatting(stream);
}
estream << ' ';
}
else
{
estream << string(indent, ' '); estream << string(indent, ' ');
if (!automaton_stats.buchiAutomatonComputed()) if (!automaton_stats.buchiAutomatonComputed())
@ -92,6 +165,8 @@ void printBuchiAutomatonStats
} }
estream << '\n'; estream << '\n';
}
estream.flush(); estream.flush();
} }
@ -110,7 +185,7 @@ void printProductAutomatonStats
* Arguments: stream -- A reference to the output stream to which the * Arguments: stream -- A reference to the output stream to which the
* information should be written. * information should be written.
* indent -- Number of spaces to leave on the left of the * indent -- Number of spaces to leave on the left of the
* output. * output in verbosity modes >= 3.
* algorithm -- Identifier of the algorithm used for * algorithm -- Identifier of the algorithm used for
* generating the product automaton. * generating the product automaton.
* result_id -- Selects between the automata constructed from * result_id -- Selects between the automata constructed from
@ -125,6 +200,24 @@ void printProductAutomatonStats
const AutomatonStats& automaton_stats = const AutomatonStats& automaton_stats =
test_results[algorithm].automaton_stats[result_id]; test_results[algorithm].automaton_stats[result_id];
if (configuration.global_options.verbosity <= 2)
{
if (!automaton_stats.productAutomatonComputed())
estream << " N/A N/A";
else
{
changeStreamFormatting(stream, 11, 0, ios::right);
estream << automaton_stats.number_of_product_states;
restoreStreamFormatting(stream);
estream << ' ';
changeStreamFormatting(stream, 11, 0, ios::right);
estream << automaton_stats.number_of_product_transitions;
restoreStreamFormatting(stream);
}
estream << ' ';
}
else
{
estream << string(indent, ' '); estream << string(indent, ' ');
if (!automaton_stats.productAutomatonComputed()) if (!automaton_stats.productAutomatonComputed())
@ -144,7 +237,8 @@ void printProductAutomatonStats
changeStreamFormatting(stream, 0, 2, ios::fixed); changeStreamFormatting(stream, 0, 2, ios::fixed);
estream << static_cast<double> estream << static_cast<double>
(automaton_stats.number_of_product_states) (automaton_stats.number_of_product_states)
/ static_cast<double>(automaton_stats.number_of_buchi_states) / static_cast<double>
(automaton_stats.number_of_buchi_states)
/ static_cast<double>(round_info.statespace->size()) / static_cast<double>(round_info.statespace->size())
* 100.0; * 100.0;
restoreStreamFormatting(stream); restoreStreamFormatting(stream);
@ -162,6 +256,8 @@ void printProductAutomatonStats
} }
estream << '\n'; estream << '\n';
}
estream.flush(); estream.flush();
} }
@ -181,7 +277,7 @@ void printAcceptanceCycleStats
* Arguments: stream -- A reference to the output stream to which the * Arguments: stream -- A reference to the output stream to which the
* information should be written. * information should be written.
* indent -- Number of spaces to leave on the left of the * indent -- Number of spaces to leave on the left of the
* output. * output in verbosity mode >= 3.
* algorithm -- Identifier of the algorithm used for * algorithm -- Identifier of the algorithm used for
* computing the Büchi automaton whose accepting * computing the Büchi automaton whose accepting
* cycles are to be considered. * cycles are to be considered.
@ -197,6 +293,20 @@ void printAcceptanceCycleStats
const AutomatonStats& automaton_stats = const AutomatonStats& automaton_stats =
test_results[algorithm].automaton_stats[result_id]; test_results[algorithm].automaton_stats[result_id];
if (configuration.global_options.verbosity <= 2)
{
if (!automaton_stats.emptiness_check_performed)
estream << " N/A";
else
{
changeStreamFormatting(stream, 6, 0, ios::right);
estream << automaton_stats.emptiness_check_result.count();
restoreStreamFormatting(stream);
}
estream << ' ';
}
else
{
estream << string(indent, ' '); estream << string(indent, ' ');
if (!automaton_stats.emptiness_check_performed) if (!automaton_stats.emptiness_check_performed)
@ -232,6 +342,8 @@ void printAcceptanceCycleStats
} }
estream << '\n'; estream << '\n';
}
estream.flush(); estream.flush();
} }
@ -249,7 +361,7 @@ void printConsistencyCheckStats
* Arguments: stream -- A reference to an output stream to which the * Arguments: stream -- A reference to an output stream to which the
* information should be written. * information should be written.
* indent -- Number of spaces to leave on the left of the * indent -- Number of spaces to leave on the left of the
* output. * output in verbosity mode >= 3.
* algorithm -- Identifier of the algorithm whose consistency * algorithm -- Identifier of the algorithm whose consistency
* check result should be displayed. * check result should be displayed.
* *
@ -260,6 +372,25 @@ void printConsistencyCheckStats
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit); Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
const AlgorithmTestResults& test_result = test_results[algorithm]; const AlgorithmTestResults& test_result = test_results[algorithm];
if (configuration.global_options.verbosity <= 2)
{
switch (test_result.consistency_check_result)
{
case -1 :
estream << "NA";
break;
case 0 :
estream << " F";
break;
default:
estream << " P";
break;
}
}
else
{
estream << string(indent, ' '); estream << string(indent, ' ');
if (test_result.consistency_check_result == -1) if (test_result.consistency_check_result == -1)
@ -291,14 +422,14 @@ void printConsistencyCheckStats
} }
estream << '\n'; estream << '\n';
}
estream.flush(); estream.flush();
} }
/* ========================================================================= */ /* ========================================================================= */
void printCrossComparisonStats void printCrossComparisonStats
(ostream& stream, int indent, (ostream& stream, int indent, const IntervalList& algorithms)
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Displays information about the model checking result cross- * Description: Displays information about the model checking result cross-
@ -309,51 +440,46 @@ void printCrossComparisonStats
* information should be written. * information should be written.
* indent -- Number of spaces to leave on the left of the * indent -- Number of spaces to leave on the left of the
* output. * output.
* algorithm -- If less than the number of algorithms, show * algorithms -- A reference to a constant IntervalList
* only the results for the algorithm with this * storing the numeric identifiers of the
* identifier. * algorithms for which the statistics should
* be shown.
* *
* Returns: Nothing. * Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit); Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
bool no_errors_to_report = true; bool no_errors_to_report = true, nothing_to_report = true;
if (algorithm < configuration.algorithms.size()
&& !configuration.algorithms[algorithm].enabled)
{
estream << string(indent, ' ') + "not performed\n\n";
estream.flush();
return;
}
estream << string(indent, ' ') + "result:";
const AutomatonStats* alg_1_pos_results; const AutomatonStats* alg_1_pos_results;
const AutomatonStats* alg_1_neg_results; const AutomatonStats* alg_1_neg_results;
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type for (IntervalList::const_iterator alg_1 = algorithms.begin();
alg_1 = 0; alg_1 != algorithms.end();
alg_1 < test_results.size(); ++alg_1)
alg_1++)
{ {
alg_1_pos_results = &test_results[alg_1].automaton_stats[0]; alg_1_pos_results = &test_results[*alg_1].automaton_stats[0];
alg_1_neg_results = &test_results[alg_1].automaton_stats[1]; alg_1_neg_results = &test_results[*alg_1].automaton_stats[1];
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
alg_2 = alg_1 + 1; alg_2 = 0;
alg_2 < test_results.size(); alg_2 < round_info.number_of_translators;
alg_2++) alg_2++)
{ {
if ((algorithm >= configuration.algorithms.size() if (*alg_1 != alg_2
|| alg_1 == algorithm && (alg_2 > *alg_1 || !algorithms.covers(alg_2))
|| alg_2 == algorithm) && configuration.algorithms[*alg_1].enabled
&& configuration.algorithms[alg_1].enabled
&& configuration.algorithms[alg_2].enabled) && configuration.algorithms[alg_2].enabled)
{ {
bool pos_test, neg_test; bool pos_test, neg_test;
if (nothing_to_report)
{
nothing_to_report = false;
estream << string(indent, ' ') + "result:";
}
for (int counter = 0; counter < 2; counter++) for (int counter = 0; counter < 2; counter++)
{ {
if (counter == 0) if (counter == 0)
@ -381,34 +507,25 @@ void printCrossComparisonStats
else else
estream << "-) "; estream << "-) ";
estream << ' '; estream << " " + configuration.algorithmString(*alg_1) + ", "
if (alg_1 == round_info.number_of_translators) + configuration.algorithmString(alg_2);
estream << "lbtt";
else
estream << configuration.algorithmString(alg_1);
estream << ", ";
if (alg_2 == round_info.number_of_translators)
estream << "lbtt";
else
estream << configuration.algorithmString(alg_2);
} }
} }
} }
} }
} }
if (no_errors_to_report) if (nothing_to_report)
estream << string(indent, ' ') + "not performed";
else if (no_errors_to_report)
estream << string(20, ' ') + "no failures detected"; estream << string(20, ' ') + "no failures detected";
estream << "\n\n"; estream << "\n\n";
estream.flush(); estream.flush();
} }
/* ========================================================================= */ /* ========================================================================= */
void printBuchiIntersectionCheckStats void printBuchiIntersectionCheckStats
(ostream& stream, int indent, (ostream& stream, int indent, const IntervalList& algorithms)
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Displays information about the Büchi automaton intersection * Description: Displays information about the Büchi automaton intersection
@ -419,51 +536,47 @@ void printBuchiIntersectionCheckStats
* information should be written. * information should be written.
* indent -- Number of spaces to leave on the left of the * indent -- Number of spaces to leave on the left of the
* output. * output.
* algorithm -- If less than the number of algorithms, show * algorithms -- A reference to a constant IntervalList
* only the results for the algorithm with this * storing the numeric identifiers of the
* identifier. * algorithms for which the statistics should
* be shown.
* *
* Returns: Nothing. * Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit); Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
bool no_errors_to_report = true; bool no_errors_to_report = true, nothing_to_report = true;
if (algorithm < round_info.number_of_translators
&& !configuration.algorithms[algorithm].enabled)
{
estream << string(indent, ' ') + "not performed\n\n";
estream.flush();
return;
}
estream << string(indent, ' ') + "result:";
const AutomatonStats* alg_1_pos_results; const AutomatonStats* alg_1_pos_results;
const AutomatonStats* alg_1_neg_results; const AutomatonStats* alg_1_neg_results;
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type for (IntervalList::const_iterator alg_1 = algorithms.begin();
alg_1 = 0; alg_1 != algorithms.end();
alg_1 < round_info.number_of_translators; ++alg_1)
alg_1++)
{ {
alg_1_pos_results = &test_results[alg_1].automaton_stats[0]; alg_1_pos_results = &test_results[*alg_1].automaton_stats[0];
alg_1_neg_results = &test_results[alg_1].automaton_stats[1]; alg_1_neg_results = &test_results[*alg_1].automaton_stats[1];
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
alg_2 = alg_1; alg_2 = 0;
alg_2 < round_info.number_of_translators; alg_2 < round_info.number_of_translators;
alg_2++) alg_2++)
{ {
if ((algorithm >= round_info.number_of_translators if (configuration.algorithms[*alg_1].enabled
|| alg_1 == algorithm && configuration.algorithms[alg_2].enabled
|| alg_2 == algorithm) && (alg_2 >= *alg_1 || !algorithms.covers(alg_2))
&& configuration.algorithms[alg_1].enabled && !configuration.isInternalAlgorithm(*alg_1)
&& configuration.algorithms[alg_2].enabled) && !configuration.isInternalAlgorithm(alg_2))
{ {
bool pos_test, neg_test; bool pos_test, neg_test;
if (nothing_to_report)
{
nothing_to_report = false;
estream << string(indent, ' ') + "result:";
}
for (int counter = -1; counter < 1; counter++) for (int counter = -1; counter < 1; counter++)
{ {
pos_test = (alg_1_pos_results->buchi_intersection_check_stats[alg_2] pos_test = (alg_1_pos_results->buchi_intersection_check_stats[alg_2]
@ -478,7 +591,7 @@ void printBuchiIntersectionCheckStats
estream << string(counter == -1 ? "N/A " : "failed") + ' '; estream << string(counter == -1 ? "N/A " : "failed") + ' ';
if (alg_1 != alg_2) if (*alg_1 != alg_2)
{ {
estream << '('; estream << '(';
if (pos_test) if (pos_test)
@ -489,9 +602,9 @@ void printBuchiIntersectionCheckStats
else else
estream << " "; estream << " ";
estream << ' ' + configuration.algorithmString(alg_1); estream << ' ' + configuration.algorithmString(*alg_1);
if (alg_1 != alg_2) if (*alg_1 != alg_2)
{ {
estream << ", ("; estream << ", (";
if (pos_test) if (pos_test)
@ -507,10 +620,11 @@ void printBuchiIntersectionCheckStats
} }
} }
if (no_errors_to_report) if (nothing_to_report)
estream << string(indent, ' ') + "not performed";
else if (no_errors_to_report)
estream << string(20, ' ') + "no failures detected"; estream << string(20, ' ') + "no failures detected";
estream << "\n";
estream << "\n\n";
estream.flush(); estream.flush();
} }
@ -537,22 +651,37 @@ void printAllStats
{ {
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit); Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
if (configuration.global_options.verbosity >= 3)
estream << string(indent, ' ') + configuration.algorithmString(algorithm) estream << string(indent, ' ') + configuration.algorithmString(algorithm)
+ '\n'; + '\n';
estream.flush();
for (int counter = 0; counter < 2; counter++) for (int counter = 0; counter < 2; counter++)
{
if (configuration.global_options.verbosity <= 2)
{
if (counter == 1)
estream << '\n';
estream << string(indent, ' ');
changeStreamFormatting(stream, 2, 0, ios::right);
estream << algorithm << ' ';
restoreStreamFormatting(stream);
estream << (counter == 0 ? '+' : '-') << ' ';
}
else
{ {
estream << string(indent + 2, ' ') estream << string(indent + 2, ' ')
+ (counter == 0 ? "Positive" : "Negated") + " formula:\n" + (counter == 0 ? "Positive" : "Negated") + " formula:\n"
+ string(indent + 4, ' ') + "Büchi automaton:\n"; + string(indent + 4, ' ') + "Büchi automaton:\n";
}
printBuchiAutomatonStats(stream, indent + 6, algorithm, counter); printBuchiAutomatonStats(stream, indent + 6, algorithm, counter);
if (configuration.global_options.do_comp_test if (configuration.global_options.do_comp_test
|| configuration.global_options.do_cons_test) || configuration.global_options.do_cons_test)
{ {
if (configuration.global_options.verbosity >= 3)
estream << string(indent + 4, ' ') + "Product automaton:\n"; estream << string(indent + 4, ' ') + "Product automaton:\n";
printProductAutomatonStats(stream, indent + 6, algorithm, counter); printProductAutomatonStats(stream, indent + 6, algorithm, counter);
if (configuration.global_options.verbosity >= 3)
estream << string(indent + 4, ' ') + "Accepting cycles:\n"; estream << string(indent + 4, ' ') + "Accepting cycles:\n";
printAcceptanceCycleStats(stream, indent + 6, algorithm, counter); printAcceptanceCycleStats(stream, indent + 6, algorithm, counter);
} }
@ -560,6 +689,7 @@ void printAllStats
if (configuration.global_options.do_cons_test) if (configuration.global_options.do_cons_test)
{ {
if (configuration.global_options.verbosity >= 3)
estream << string(indent + 2, ' ') + "Result consistency check:\n"; estream << string(indent + 2, ' ') + "Result consistency check:\n";
printConsistencyCheckStats(stream, indent + 4, algorithm); printConsistencyCheckStats(stream, indent + 4, algorithm);
} }
@ -626,10 +756,8 @@ void printCollectiveCrossComparisonStats
break; break;
default : default :
if (configuration.global_options.statespace_generation_mode if (configuration.isInternalAlgorithm(algorithm_x)
& Configuration::PATH || configuration.isInternalAlgorithm(algorithm_y))
&& (algorithm_x == round_info.number_of_translators
|| algorithm_y == round_info.number_of_translators))
{ {
estream << string(21, ' '); estream << string(21, ' ');
return; return;
@ -951,8 +1079,11 @@ void printCollectiveStats(ostream& stream, int indent)
algorithm < round_info.number_of_translators; algorithm < round_info.number_of_translators;
++algorithm) ++algorithm)
{ {
if (configuration.isInternalAlgorithm(algorithm))
continue;
estream << '\n' + string((i > 0 ? 4 : 2) + indent, ' ') estream << '\n' + string((i > 0 ? 4 : 2) + indent, ' ')
+ *(configuration.algorithms[algorithm].name) + '\n'; + configuration.algorithms[algorithm].name + '\n';
switch (i) switch (i)
{ {
@ -965,14 +1096,14 @@ void printCollectiveStats(ostream& stream, int indent)
unsigned long int failures_to_compute_automaton; unsigned long int failures_to_compute_automaton;
unsigned long int automaton_count; unsigned long int automaton_count;
unsigned long int number_of_successful_instances; unsigned long int number_of_successful_instances;
unsigned long int total_number_of_states; BIGUINT total_number_of_states;
unsigned long int total_number_of_transitions; BIGUINT total_number_of_transitions;
const TestStatistics& stats = final_statistics[algorithm]; const TestStatistics& stats = final_statistics[algorithm];
estream << string(2 + indent, ' ') estream << string(2 + indent, ' ')
+ string(configuration.algorithms[algorithm].name + string(configuration.algorithms[algorithm].name.
->length(), '='); length(), '=');
for (int k = 0; k < 2; k++) for (int k = 0; k < 2; k++)
{ {
@ -1117,7 +1248,7 @@ void printCollectiveStats(ostream& stream, int indent)
if (k == 0) if (k == 0)
{ {
unsigned long int total_number_of_acceptance_sets; BIGUINT total_number_of_acceptance_sets;
double buchi_generation_time; double buchi_generation_time;
estream << '\n' + string(22 + indent, ' ') estream << '\n' + string(22 + indent, ' ')
@ -1350,7 +1481,7 @@ void printCollectiveStats(ostream& stream, int indent)
if (algorithm_x + i < number_of_algorithms) if (algorithm_x + i < number_of_algorithms)
{ {
algorithm_name = algorithm_name =
(*(configuration.algorithms[algorithm_x + i].name)).substr(0, 20); configuration.algorithms[algorithm_x + i].name.substr(0, 20);
estream << "| " + algorithm_name estream << "| " + algorithm_name
+ string(21 - algorithm_name.length(), ' '); + string(21 - algorithm_name.length(), ' ');
} }
@ -1360,6 +1491,9 @@ void printCollectiveStats(ostream& stream, int indent)
for (algorithm_y = 0; algorithm_y < number_of_algorithms; for (algorithm_y = 0; algorithm_y < number_of_algorithms;
algorithm_y++) algorithm_y++)
{ {
if (configuration.isInternalAlgorithm(algorithm_y))
continue;
estream << "\n " + ind + string(26, '-'); estream << "\n " + ind + string(26, '-');
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
@ -1370,7 +1504,7 @@ void printCollectiveStats(ostream& stream, int indent)
estream << '+'; estream << '+';
algorithm_name algorithm_name
= (*(configuration.algorithms[algorithm_y].name)).substr(0, 20); = configuration.algorithms[algorithm_y].name.substr(0, 20);
bool algorithm_name_printed = false; bool algorithm_name_printed = false;
legend = 1; legend = 1;

View file

@ -42,6 +42,11 @@ extern Configuration configuration;
namespace StatDisplay namespace StatDisplay
{ {
void printStatTableHeader /* Displays a table */
(ostream& stream, int indent); /* header for test
* statistics.
*/
void printBuchiAutomatonStats /* Displays information */ void printBuchiAutomatonStats /* Displays information */
(ostream& stream, /* about a Büchi */ (ostream& stream, /* about a Büchi */
int indent, /* automaton. */ int indent, /* automaton. */
@ -74,17 +79,15 @@ void printConsistencyCheckStats /* Displays the result */
algorithm); algorithm);
void printCrossComparisonStats /* Displays information */ void printCrossComparisonStats /* Displays information */
(ostream& stream, /* about the model */ (ostream& stream, int indent, /* about the model */
int indent, /* checking result */ const IntervalList& algorithms); /* checking result */
vector<AlgorithmTestResults, /* cross-comparison */ /* cross-comparison */
ALLOC(AlgorithmTestResults) >::size_type /* check. */ /* check. */
algorithm);
void printBuchiIntersectionCheckStats /* Displays the results */ void printBuchiIntersectionCheckStats /* Displays the results */
(ostream& stream, int indent, /* of the Büchi automata */ (ostream& stream, int indent, /* of the Büchi automata */
vector<AlgorithmTestResults, /* intersection */ const IntervalList& algorithms); /* intersection */
ALLOC(AlgorithmTestResults) >::size_type /* emptiness checks. */ /* emptiness checks. */
algorithm);
void printAllStats /* A shorthand for */ void printAllStats /* A shorthand for */
(ostream& stream, /* showing all the */ (ostream& stream, /* showing all the */

View file

@ -0,0 +1,430 @@
/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 STATESPACEPRODUCT_H
#define STATESPACEPRODUCT_H
#include <config.h>
#include "BitArray.h"
#include "BuchiAutomaton.h"
#include "EdgeContainer.h"
#include "Graph.h"
#include "StateSpace.h"
using namespace std;
namespace Graph
{
/******************************************************************************
*
* A class with operations for checking the product of a Büchi automaton and
* a state space for emptiness.
*
*****************************************************************************/
class StateSpaceProduct
{
public:
StateSpaceProduct /* Constructor. */
(const Graph<GraphEdgeContainer>& a,
const Graph<GraphEdgeContainer>& s);
/* default copy constructor */
~StateSpaceProduct(); /* Destructor. */
/* default assignment operator */
bool empty() const; /* Tells whether the
* product of a Büchi
* automaton and a state
* space is (trivially)
* empty.
*/
unsigned long int numberOfAcceptanceSets() const; /* Tells the number of
* acceptance sets in a
* Büchi automaton in its
* product with a state
* space.
*/
const BuchiAutomaton::BuchiState& firstComponent /* Mappings between a */
(const Graph<GraphEdgeContainer>::size_type /* product state */
state_id) const; /* identifier and */
const StateSpace::State& secondComponent /* states of the Büchi */
(const Graph<GraphEdgeContainer>::size_type /* automaton and the */
state_id) const; /* state space forming
* the product.
*/
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Node& state, /* sets associated with */
const Graph<GraphEdgeContainer>::Node&, /* a state in the Büchi */
BitArray& acceptance_sets) const; /* automaton into a
* collection of sets.
*/
void mergeAcceptanceInformation /* Merges the acceptance */
(const Graph<GraphEdgeContainer>::Edge& /* sets associated with */
buchi_transition, /* a transition in the */
const Graph<GraphEdgeContainer>::Edge&, /* Büchi automaton into */
BitArray& acceptance_sets) const; /* a collection of sets. */
void validateEdgeIterators /* Ensures that a pair */
(const Graph<GraphEdgeContainer>::Node& /* of transition */
buchi_state, /* iterators points to a */
const Graph<GraphEdgeContainer>::Node& /* transition beginning */
system_state, /* from a given state in */
GraphEdgeContainer::const_iterator& /* the product of a */
buchi_transition, /* Büchi automaton and */
GraphEdgeContainer::const_iterator& /* a state space. */
system_transition) const;
void incrementEdgeIterators /* Updates a pair of */
(const Graph<GraphEdgeContainer>::Node& /* transition iterators */
buchi_state, /* to make them point to */
const Graph<GraphEdgeContainer>::Node& /* the "next" transition */
system_state, /* starting from a given */
GraphEdgeContainer::const_iterator& /* state in the product */
buchi_transition, /* of a Büchi automaton */
GraphEdgeContainer::const_iterator& /* and a state space. */
system_transition) const;
private:
const BuchiAutomaton& buchi_automaton; /* Büchi automaton
* associated with the
* product.
*/
const StateSpace& statespace; /* State space associated
* with the product.
*/
};
/******************************************************************************
*
* Inline function definitions for class StateSpaceProduct.
*
*****************************************************************************/
/* ========================================================================= */
inline StateSpaceProduct::StateSpaceProduct
(const Graph<GraphEdgeContainer>& a, const Graph<GraphEdgeContainer>& s) :
buchi_automaton(static_cast<const BuchiAutomaton&>(a)),
statespace(static_cast<const StateSpace&>(s))
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class StateSpaceProduct. Initializes a new
* object with operations for checking the emptiness of the
* product of a Büchi automaton and a state space.
*
* Arguments: a -- A constant reference to a Graph<GraphEdgeContainer>
* object, assumed to be a BuchiAutomaton.
* s -- A constant reference to a Graph<GraphEdgeContainer>
* object, assumed to be a StateSpace.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline StateSpaceProduct::~StateSpaceProduct()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class StateSpaceProduct.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline bool StateSpaceProduct::empty() const
/* ----------------------------------------------------------------------------
*
* Description: Tells whether the product of `this->buchi_automaton' and
* `this->statespace' is (trivially) empty.
*
* Arguments: None.
*
* Returns: true iff either the Büchi automaton or the state space has
* no states.
*
* ------------------------------------------------------------------------- */
{
return (buchi_automaton.empty() || statespace.empty());
}
/* ========================================================================= */
inline unsigned long int StateSpaceProduct::numberOfAcceptanceSets() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the number of acceptance sets in the Büchi automaton
* associated with a StateSpaceProduct object.
*
* Arguments: None.
*
* Returns: The number of acceptance sets in the automaton.
*
* ------------------------------------------------------------------------- */
{
return buchi_automaton.numberOfAcceptanceSets();
}
/* ========================================================================= */
inline const BuchiAutomaton::BuchiState& StateSpaceProduct::firstComponent
(const Graph<GraphEdgeContainer>::size_type state_id) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing states in the Büchi automaton
* associated with a StateSpaceProduct object.
*
* Argument: state_id -- Identifier of a state in the automaton.
*
* Returns: A constant reference to a state in the automaton.
*
* ------------------------------------------------------------------------- */
{
return buchi_automaton[state_id];
}
/* ========================================================================= */
inline const StateSpace::State& StateSpaceProduct::secondComponent
(const Graph<GraphEdgeContainer>::size_type state_id) const
/* ----------------------------------------------------------------------------
*
* Description: Function for accessing states in the state space associated
* with a StateSpaceProduct object.
*
* Argument: state_id -- Identifier of a state in the state space.
*
* Returns: A constant reference to a state in the state space.
*
* ------------------------------------------------------------------------- */
{
return statespace[state_id];
}
/* ========================================================================= */
inline void StateSpaceProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Node& state,
const Graph<GraphEdgeContainer>::Node&, BitArray& acceptance_sets) const
/* ----------------------------------------------------------------------------
*
* Description: Merges the acceptance sets associated with a state of a Büchi
* automaton into a collection of sets.
*
* Arguments: state -- A constant reference to a state in the
* automaton.
* acceptance_sets -- A reference to a BitArray for storing
* the result. The BitArray should have
* capacity for (at least)
* `this->buchi_automaton
* .numberOfAcceptanceSets()' bits.
* (The second argument is needed to allow the class
* StateSpaceProduct to be used for instantiating the Product
* template; see file Product.h.)
*
* Returns: Nothing. After the operation, `acceptance_sets[i] == true'
* holds if `state.acceptanceSets().test(i) == true' for all
* 0 <= i < `this->buchi_automaton.numberOfAcceptanceSets()'.
*
* ------------------------------------------------------------------------- */
{
acceptance_sets.bitwiseOr
(static_cast<const BuchiAutomaton::BuchiState&>(state).acceptanceSets(),
numberOfAcceptanceSets());
}
/* ========================================================================= */
inline void StateSpaceProduct::mergeAcceptanceInformation
(const Graph<GraphEdgeContainer>::Edge& buchi_transition,
const Graph<GraphEdgeContainer>::Edge&, BitArray& acceptance_sets) const
/* ----------------------------------------------------------------------------
*
* Description: Merges the acceptance sets associated with a transition of a
* Büchi automaton into a collection of sets.
*
* Arguments: transition -- A constant reference to a transition in
* the automaton.
* acceptance_sets -- A reference to a BitArray for storing
* the result. The BitArray should have
* capacity for (at least)
* `this->buchi_automaton
* .numberOfAcceptanceSets()' bits.
* (The second argument is needed to allow the class
* StateSpaceProduct to be used for instantiating the Product
* template; see file Product.h.)
*
* Returns: Nothing. After the operation, `acceptance_sets[i] == true'
* holds if `transition.acceptanceSets().test(i) == true' for
* all
* 0 <= i < `this->buchi_automaton.numberOfAcceptanceSets()'.
*
* ------------------------------------------------------------------------- */
{
acceptance_sets.bitwiseOr
(static_cast<const BuchiAutomaton::BuchiTransition&>(buchi_transition)
.acceptanceSets(),
numberOfAcceptanceSets());
}
/* ========================================================================= */
inline void StateSpaceProduct::validateEdgeIterators
(const Graph<GraphEdgeContainer>::Node& buchi_state,
const Graph<GraphEdgeContainer>::Node& system_state,
GraphEdgeContainer::const_iterator& buchi_transition,
GraphEdgeContainer::const_iterator& system_transition) const
/* ----------------------------------------------------------------------------
*
* Description: Checks whether a pair of transition iterators corresponds to
* a transition beginning from a state in the product of a Büchi
* automaton and a state space; if this is not the case, makes
* the iterators point to a valid transition beginning from the
* product state (or to the "end" of the collection of
* transitions beginning from the product state if no valid
* transition can be found by incrementing the iterators).
*
* Arguments: buchi_state, -- These variables determine the state
* system_state, in the product; `buchi_state' and
* `system_state' should be references to
* states in `this->buchi_automaton' and
* `this->statespace', respectively.
* buchi_transition, -- References to the transition
* system_transition iterators. It is assumed that
* `buchi_transition' and
* `system_transition' initially point to
* two transitions starting from
* `buchi_state' and `system_state',
* respectively.
*
* Returns: Nothing. Upon return, `buchi_transition' and
* `system_transition' will either equal
* `buchi_state.edges().end()' and `system_state.edges().end()',
* respectively, or they will point to a pair of transitions
* beginning from `buchi_state' and `system_state' such that
* this pair of transitions corresponds to a transition starting
* from the product state determined by `buchi_state' and
* `system_state'.
*
* ------------------------------------------------------------------------- */
{
const GraphEdgeContainer& buchi_transitions = buchi_state.edges();
const GraphEdgeContainer& system_transitions = system_state.edges();
if (buchi_transition == buchi_transitions.end())
{
system_transition = system_transitions.end();
return;
}
if (system_transition == system_transitions.end())
{
buchi_transition = buchi_transitions.end();
return;
}
while (!static_cast<const BuchiAutomaton::BuchiTransition*>
(*buchi_transition)->enabled
(static_cast<const StateSpace::State&>(system_state)
.positiveAtoms(),
statespace.numberOfPropositions()))
{
++buchi_transition;
if (buchi_transition == buchi_transitions.end())
{
system_transition = system_transitions.end();
return;
}
}
system_transition = system_transitions.begin();
}
/* ========================================================================= */
inline void StateSpaceProduct::incrementEdgeIterators
(const Graph<GraphEdgeContainer>::Node& buchi_state,
const Graph<GraphEdgeContainer>::Node& system_state,
GraphEdgeContainer::const_iterator& buchi_transition,
GraphEdgeContainer::const_iterator& system_transition) const
/* ----------------------------------------------------------------------------
*
* Description: Increments a pair of transition iterators to point to the
* "next" transition beginning from a state in the product of a
* Büchi automaton and a state space. If no "next" transition
* exists, makes the iterators point to the "end" of the
* collection of transitions beginning from the product state.
*
* Arguments: buchi_state, -- These variables determine the state
* system_state, in the product; `buchi_state' and
* `system_state' should be references to
* states in `this->buchi_automaton' and
* `this->statespace', respectively.
* buchi_transition, -- References to the transition
* system_transition iterators. It is assumed that
* `buchi_transition' and
* `system_transition' initially point to
* two transitions starting from
* `buchi_state' and `system_state',
* respectively.
*
* Returns: Nothing. Upon return, `buchi_transition' and
* `system_transition' will either equal
* `buchi_state.edges().end()' and `system_state.edges().end()',
* respectively, or they will point to a pair of transitions
* beginning from `buchi_state' and `system_state' such that
* this pair of transitions corresponds to a transition starting
* from the product state determined by `buchi_state' and
* `system_state'.
*
* ------------------------------------------------------------------------- */
{
const GraphEdgeContainer& buchi_transitions = buchi_state.edges();
const GraphEdgeContainer& system_transitions = system_state.edges();
++system_transition;
if (system_transition == system_transitions.end())
{
do
{
++buchi_transition;
if (buchi_transition == buchi_transitions.end())
return;
}
while (!static_cast<const BuchiAutomaton::BuchiTransition*>
(*buchi_transition)->enabled
(static_cast<const StateSpace::State&>(system_state)
.positiveAtoms(),
statespace.numberOfPropositions()));
system_transition = system_transitions.begin();
}
}
}
#endif /* !STATESPACEPRODUCT_H */

View file

@ -18,6 +18,8 @@
*/ */
#include <config.h> #include <config.h>
#include <cctype>
#include <climits>
#include <cstdlib> #include <cstdlib>
#include "StringUtil.h" #include "StringUtil.h"
@ -100,6 +102,211 @@ void sliceString
while (last_non_slicechar_pos != s.npos && last_slicechar_pos != s.npos); while (last_non_slicechar_pos != s.npos && last_slicechar_pos != s.npos);
} }
/* ========================================================================= */
string toLowerCase(const string& s)
/* ----------------------------------------------------------------------------
*
* Description: Converts a string to lower case.
*
* Argument: s -- String to process.
*
* Returns: The string in lower case.
*
* ------------------------------------------------------------------------- */
{
string result;
for (string::size_type pos = 0; pos < s.length(); ++pos)
result += tolower(s[pos]);
return result;
}
/* ========================================================================= */
bool interpretSpecialCharacters(const char c, bool& escape, char& quotechar)
/* ----------------------------------------------------------------------------
*
* Description: Updates the values of `escape' and `quotechar' based on their
* original values and the value of `c'. Used for scanning
* through a string possibly containing quotes and escaped
* characters.
*
* Arguments: c -- A character.
* escape -- A truth value telling whether `c' was escaped.
* quotechar -- 0 == `c' was read outside of quotes.
* `'' == `c' was read inside single quotes.
* `"' == `c' was read inside double quotes.
*
* Returns: True if `c' had a special meaning (for example, if it was a
* begin/end quote character) in the state determined by the
* original values of `escape' and `quotechar'.
*
* ------------------------------------------------------------------------- */
{
if (escape)
{
escape = false;
return false;
}
switch (c)
{
case '\\' :
if (quotechar != '\'')
{
escape = true;
return true;
}
break;
case '\'' : case '"' :
if (quotechar == 0)
{
quotechar = c;
return true;
}
else if (c == quotechar)
{
quotechar = 0;
return true;
}
break;
default :
break;
}
return false;
}
/* ========================================================================= */
string unquoteString(const string& s)
/* ----------------------------------------------------------------------------
*
* Description: Removes (unescaped) single and double quotes and escape
* characters from a string.
*
* Argument: s -- String to process.
*
* Returns: A string with the quotes and escape characters removed.
*
* ------------------------------------------------------------------------- */
{
string result;
char quotechar = 0;
bool escape = false;
for (string::size_type pos = 0; pos < s.size(); ++pos)
{
if (!interpretSpecialCharacters(s[pos], escape, quotechar))
result += s[pos];
}
return result;
}
/* ========================================================================= */
string::size_type findInQuotedString
(const string& s, const string& chars, QuoteMode type)
/* ----------------------------------------------------------------------------
*
* Description: Finds a character in a string (respecting quotes).
*
* Arguments: s -- String to process.
* chars -- A sting of characters to be searched in `s'.
* type -- The extent of the search.
* GLOBAL - Apply the search to the entire
* string.
* INSIDE_QUOTES - Restrict the search to
* unescaped characters between
* quotes.
* OUTSIDE_QUOTES - Restrict the search to
* unescaped characters outside
* quotes.
*
* Returns: If `s' contains one of the characters in `chars' in a part
* of the string that matches `type', the position of the
* character in `s', and string::npos otherwise.
*
* ------------------------------------------------------------------------- */
{
char quotechar = 0;
bool escape = false;
for (string::size_type pos = 0; pos < s.size(); ++pos)
{
if ((type == GLOBAL || (!escape &&
((type == INSIDE_QUOTES && quotechar != 0)
|| (type == OUTSIDE_QUOTES && quotechar == 0))))
&& chars.find_first_of(s[pos]) != string::npos)
return pos;
interpretSpecialCharacters(s[pos], escape, quotechar);
}
return string::npos;
}
/* ========================================================================= */
string substituteInQuotedString
(const string& s, const string& chars, const string& substitutions,
QuoteMode type)
/* ----------------------------------------------------------------------------
*
* Description: Substitutes characters in a string with other characters.
*
* Arguments: s -- String to process.
* chars -- A string of characters, each of which
* should be substituted in `s' with the
* character at the corresponding
* position of the string `substitutions'.
* substitutions -- Characters to substitute. The length of
* this string should equal the length of
* `chars'.
* type -- The extent of substitution.
* GLOBAL - Apply the substitutions
* globally (the default).
* INSIDE_QUOTES - Apply the substitutions
* to unescaped characters
* only inside quotes that
* have not been escaped
* with a backslash.
* OUTSIDE_QUOTES - Apply the substitutions
* to unescaped characters
* only outside quotes
* that have not been
* escaped with a
* backslash.
* It is not recommended to substitute the
* special characters ', " and \ with other
* characters if they have special meaning in
* `s'.
*
* Returns: A string with the substitutions.
*
* ------------------------------------------------------------------------- */
{
string result;
char quotechar = 0;
bool escape = false;
for (string::size_type pos = 0; pos < s.size(); ++pos)
{
char c = s[pos];
if (type == GLOBAL || (!escape &&
((type == INSIDE_QUOTES && quotechar != 0)
|| (type == OUTSIDE_QUOTES && quotechar == 0))))
{
string::size_type subst_pos = chars.find_first_of(c);
if (subst_pos != string::npos)
c = substitutions[subst_pos];
}
result += c;
interpretSpecialCharacters(s[pos], escape, quotechar);
}
return result;
}
/* ========================================================================= */ /* ========================================================================= */
unsigned long int parseNumber(const string& number_string) unsigned long int parseNumber(const string& number_string)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -115,9 +322,11 @@ unsigned long int parseNumber(const string& number_string)
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
char* endptr; char* endptr;
unsigned long int number = strtoul(number_string.c_str(), &endptr, 10); unsigned long int number = strtoul(number_string.c_str(), &endptr, 10);
if (*endptr != '\0') if (*endptr != '\0' || number_string.empty()
|| number_string.find_first_of("-") != string::npos)
throw NotANumberException("expected a nonnegative integer, got `" throw NotANumberException("expected a nonnegative integer, got `"
+ number_string + "'"); + number_string + "'");
@ -125,98 +334,254 @@ unsigned long int parseNumber(const string& number_string)
} }
/* ========================================================================= */ /* ========================================================================= */
void parseInterval int parseInterval
(const string& token, (const string& token, unsigned long int& min, unsigned long int& max)
set<unsigned long int, less<unsigned long int>, ALLOC(unsigned long int) >&
number_set,
unsigned long int min, unsigned long int max)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Parses a string for a list of number intervals, storing all * Description: Reads the lower and upper bound from an "interval string"
* the numbers into a set. * into two unsigned long integer variables.
* *
* Arguments: token -- A reference to a constant string containing * Arguments: token -- A reference to a constant "interval string" of
* the list of intervals. A legal list of * the format
* intervals has the following syntax: * <interval string>
* ::= "*" // 0
* | <ulong> // 1
* | <sep><ulong> // 2
* | <ulong><sep> // 3
* | <ulong><sep><ulong> // 4
* where <ulong> is an unsigned long integer (not
* containing a minus sign), and <sep> is either
* "-" or "...". The meaning of the various cases
* is as follows:
* 0 All integers between 0 and ULONG_MAX.
* 1 A point interval consisting of a single
* value.
* 2 An interval from 0 to a given upper
* bound.
* 3 An interval from a given lower bound to
* ULONG_MAX.
* 4 A bounded interval.
* min, max -- References to two unsigned long integers for
* storing the lower and upper bound of the
* interval.
* *
* <interval_list> * Returns: A value telling the type of the specified interval, which is
* ::= <number> * a bitwise or of the values LEFT_BOUNDED and RIGHT_BOUNDED
* | '*' // all numbers in the * depending on which bounds were given explicitly for the
* // interval * interval. (The lower and upper bounds of the interval itself
* // [min, max] * are stored in the variables `min' and `max', respectively.)
* | '-'<number> // all numbers in the * The function will throw a NotANumberException if the
* // interval * interval string is of an invalid format.
* // [min, number]
* | <number>'-' // all numbers in the
* // interval
* // [number, max]
* | <number>'-'<number>
* | <interval_list>','<interval_list>
*
* number_set -- A reference to a set of unsigned long
* integers for storing the result.
* min -- Minimum bound for the numbers.
* max -- Maximum bound for the numbers.
*
* Note: `min' and `max' are only used to determine the limits
* for only partially defined intervals. The check that
* the explicitly specified values in the interval list
* are within these bounds is left to the caller when
* examining the result set.
*
* Returns: Nothing.
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
vector<string, ALLOC(string) > intervals; unsigned long int tmp_min = 0;
unsigned long int tmp_max = ULONG_MAX;
int interval_type = UNBOUNDED;
sliceString(token, ",", intervals); if (token != "*")
string::size_type dash_pos; {
string::size_type pos(token.find_first_of("-"));
if (pos == string::npos)
pos = token.find("...");
string value(token.substr(0, pos));
number_set.clear(); if (!value.empty())
{
tmp_min = parseNumber(value);
if (pos == string::npos)
tmp_max = tmp_min;
interval_type |= LEFT_BOUNDED;
}
if (pos != string::npos)
value = token.substr(pos + (token[pos] == '-' ? 1 : 3));
if (!value.empty())
{
tmp_max = parseNumber(value);
interval_type |= RIGHT_BOUNDED;
}
else if (!(interval_type & LEFT_BOUNDED))
throw NotANumberException("invalid format for interval");
}
min = tmp_min;
max = tmp_max;
return interval_type;
}
/* ========================================================================= */
void parseIntervalList
(const string& token, IntervalList& intervals, unsigned long int min,
unsigned long int max, vector<string, ALLOC(string) >* extra_tokens)
/* ----------------------------------------------------------------------------
*
* Description: Parses a string of number intervals into an IntervalList.
*
* Arguments: token -- A reference to a constant comma-separated
* list of interval strings (see documentation
* for the parseInterval function).
* intervals -- A reference to an IntervalList to be used
* for storing the result.
* min -- Absolute lower bound for the numbers.
* Numbers lower than this bound will not be
* stored in the result set.
* max -- Absolute upper bound for the numbers.
* Numbers greater than this bound will not be
* stored in the result set.
* extra_tokens -- If not 0, all tokens that cannot be
* recognized as valid interval strings will
* be stored in the vector of strings to which
* this variable points. Otherwise the
* function will throw a NotANumberException.
*
* Returns: Nothing. Throws an IntervalRangeException if any of the
* intervals in the list does not fit in the closed range
* [min,max].
*
* ------------------------------------------------------------------------- */
{
vector<string, ALLOC(string) > interval_strings;
int interval_type;
intervals.clear();
sliceString(token, ",", interval_strings);
for (vector<string, ALLOC(string) >::const_iterator for (vector<string, ALLOC(string) >::const_iterator
interval = intervals.begin(); i = interval_strings.begin();
interval != intervals.end(); i != interval_strings.end();
++interval) ++i)
{ {
if (*interval == "*") unsigned long int i_start, i_end;
try
{ {
for (unsigned long int i = min; i <= max; i++) interval_type = parseInterval(*i, i_start, i_end);
number_set.insert(i); }
catch (const NotANumberException&)
{
if (extra_tokens != 0)
{
extra_tokens->push_back(*i);
continue;
}
else
throw;
}
if (interval_type & LEFT_BOUNDED)
{
if (i_start < min || i_start > max)
throw IntervalRangeException(i_start);
}
else if (i_start < min)
i_start = min;
if (interval_type & RIGHT_BOUNDED)
{
if (i_end < min || i_end > max)
throw IntervalRangeException(i_end);
}
else if (i_end > max)
i_end = max;
intervals.merge(i_start, i_end);
}
}
/* ========================================================================= */
void parseTime
(const string& time_string, unsigned long int& hours,
unsigned long int& minutes, unsigned long int& seconds)
/* ----------------------------------------------------------------------------
*
* Description: Parses a "time string", i.e., a string of the form
* ([0-9]+"h")([0-9]+"min")?([0-9]+"s")?
* | ([0-9]+"min")([0-9]+"s")?
* | ([0-9]+"s")
* (where 'h', 'min' and 's' correspond to hours, minutes and
* seconds, respectively) and stores the numbers into three
* unsigned long integers. The case of the unit symbols is not
* relevant.
*
* Arguments: time_string -- String to process.
* hours -- A reference to an unsigned long integer for
* storing the number of hours.
* minutes -- A reference to an unsigned long integer for
* storing the number of minutes.
* seconds -- A reference to an unsigned long integer for
* storing the number of seconds.
*
* Time components left unspecified in `time_string' will get
* the value 0.
*
* Returns: Nothing. Throws an Exception if the given string is not of
* the correct format.
*
* ------------------------------------------------------------------------- */
{
bool hours_present = false, minutes_present = false, seconds_present = false;
hours = minutes = seconds = 0;
if (time_string.empty())
throw Exception("invalid time format");
string::size_type pos1 = 0;
string s;
while (pos1 < time_string.length())
{
string::size_type pos2 = time_string.find_first_not_of("0123456789", pos1);
if (pos2 >= time_string.length())
throw Exception("invalid time format");
unsigned long int val;
try
{
val = parseNumber(time_string.substr(pos1, pos2 - pos1));
}
catch (const NotANumberException&)
{
throw Exception("invalid time format");
}
switch (tolower(time_string[pos2]))
{
case 'h' :
if (hours_present || minutes_present || seconds_present)
throw Exception("invalid time format");
hours_present = true;
hours = val;
break;
case 'm' :
if (minutes_present
|| seconds_present
|| pos2 + 2 >= time_string.length()
|| tolower(time_string[pos2 + 1]) != 'i'
|| tolower(time_string[pos2 + 2]) != 'n')
throw Exception("invalid time format");
minutes_present = true;
minutes = val;
pos2 += 2;
break;
case 's' :
if (seconds_present)
throw Exception("invalid time format");
seconds_present = true;
seconds = val;
break;
default : /* 's' */
throw Exception("invalid time format");
break; break;
} }
dash_pos = (*interval).find_first_of("-"); pos1 = pos2 + 1;
if (dash_pos == (*interval).npos)
number_set.insert(parseNumber(*interval));
else
{
if (dash_pos == 0)
{
unsigned long int number = parseNumber((*interval).substr(1));
for (unsigned long int i = min; i <= number; i++)
number_set.insert(i);
}
else if (dash_pos == (*interval).length() - 1)
{
unsigned long int number =
parseNumber((*interval).substr(0, (*interval).length() - 1));
for (unsigned long int i = number; i <= max; i++)
number_set.insert(i);
}
else
{
unsigned long int min_bound =
parseNumber((*interval).substr(0, dash_pos));
unsigned long int max_bound =
parseNumber((*interval).substr(dash_pos + 1));
for (unsigned long int i = min_bound; i <= max_bound; i++)
number_set.insert(i);
}
}
} }
} }

View file

@ -31,6 +31,7 @@
#include <vector> #include <vector>
#include "LbttAlloc.h" #include "LbttAlloc.h"
#include "Exception.h" #include "Exception.h"
#include "IntervalList.h"
using namespace std; using namespace std;
@ -62,17 +63,65 @@ void sliceString /* Breaks a string into */
* separators. * separators.
*/ */
string toLowerCase(const string& s); /* Converts a string to
* lower case.
*/
string unquoteString(const string& s); /* Removes unescaped quotes
* from a string and
* interprets escaped
* characters.
*/
enum QuoteMode {GLOBAL, INSIDE_QUOTES, /* Enumeration type used */
OUTSIDE_QUOTES}; /* for controlling the
* behavior of the
* substitute function.
*/
string::size_type findInQuotedString /* Finds a character in */
(const string& s, const string& chars, /* a string (respecting */
QuoteMode type = GLOBAL); /* quotes). */
string substituteInQuotedString /* Replaces characters */
(const string& s, const string& chars, /* in a string with */
const string& substitutions, /* other characters. */
QuoteMode type = GLOBAL);
unsigned long int parseNumber /* Converts a string to */ unsigned long int parseNumber /* Converts a string to */
(const string& number_string); /* an unsigned long (const string& number_string); /* an unsigned long
* integer. * integer.
*/ */
void parseInterval /* Converts a string of */ enum IntervalStringType {UNBOUNDED = 0, /* Type for an interval */
LEFT_BOUNDED = 1, /* string (see the */
RIGHT_BOUNDED = 2}; /* documentation of
* the parseInterval
* function in
* StringUtil.cc).
*/
int parseInterval /* Reads the lower and */
(const string& token, /* upper bounds from a */
unsigned long int& min, /* "number interval */
unsigned long int& max); /* string" into two
* unsigned long integer
* variables.
*/
void parseIntervalList /* Converts a list of */
(const string& token, /* number intervals to */ (const string& token, /* number intervals to */
set<unsigned long int, less<unsigned long int>, /* the corresponding set */ IntervalList& intervals, /* the set of unsigned */
ALLOC(unsigned long int) >& number_set, /* of unsigned long */ unsigned long int min, /* long integers */
unsigned long int min, /* integers. */ unsigned long int max, /* corresponding to the */
unsigned long int max); vector<string, ALLOC(string) >* extra_tokens /* union of the */
= 0); /* intervals. */
void parseTime /* Parses a time string. */
(const string& time_string,
unsigned long int& hours,
unsigned long int& minutes,
unsigned long int& seconds);
@ -133,6 +182,38 @@ public:
/******************************************************************************
*
* A class for reporting "out of range" errors for numbers when parsing
* intervals.
*
*****************************************************************************/
class IntervalRangeException : public Exception
{
public:
IntervalRangeException /* Constructor. */
(const unsigned long int number,
const string& message = "number out of range");
/* default copy constructor */
~IntervalRangeException() throw(); /* Destructor. */
IntervalRangeException& operator= /* Assignment operator. */
(const IntervalRangeException& e);
unsigned long int getNumber() const; /* Returns the number
* associated with the
* exception object.
*/
private:
const unsigned long int invalid_number;
};
/****************************************************************************** /******************************************************************************
* *
* Inline function definitions for class NotANumberException. * Inline function definitions for class NotANumberException.
@ -189,6 +270,82 @@ inline NotANumberException& NotANumberException::operator=
return *this; return *this;
} }
/******************************************************************************
*
* Inline function definitions for class IntervalRangeException.
*
*****************************************************************************/
/* ========================================================================= */
inline IntervalRangeException::IntervalRangeException
(const unsigned long int number, const string& message) :
Exception(message), invalid_number(number)
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class IntervalRangeException. Creates an
* exception object.
*
* Arguments: number -- A constant unsigned long integer specifying a
* number that does not fit in an interval.
* message -- A reference to a constant string containing an
* error message.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline IntervalRangeException::~IntervalRangeException() throw()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class IntervalRangeException.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline unsigned long int IntervalRangeException::getNumber() const
/* ----------------------------------------------------------------------------
*
* Description: Returns the number associated with the IntervalRangeException
* object.
*
* Arguments: None.
*
* Returns: The number associated with the object.
*
* ------------------------------------------------------------------------- */
{
return invalid_number;
}
/* ========================================================================= */
inline IntervalRangeException& IntervalRangeException::operator=
(const IntervalRangeException& e)
/* ----------------------------------------------------------------------------
*
* Description: Assignment operator for class IntervalRangeException.
* Copies the contents of an exception object to another.
*
* Arguments: e -- A reference to a constant IntervalRangeException.
*
* Returns: A reference to the object assigned to.
*
* ------------------------------------------------------------------------- */
{
Exception::operator=(e);
return *this;
}
} }
#endif /* !STRINGUTIL_H */ #endif /* !STRINGUTIL_H */

125
lbtt/src/TempFsysName.cc Normal file
View file

@ -0,0 +1,125 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 <config.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#include <string>
#include "Exception.h"
#include "StringUtil.h"
#include "TempFsysName.h"
/******************************************************************************
*
* Number of generated temporary names.
*
*****************************************************************************/
unsigned long int TempFsysName::number_of_allocated_names = 0;
/******************************************************************************
*
* Function definitions for class TempFsysName.
*
*****************************************************************************/
/* ========================================================================= */
const char* TempFsysName::allocate
(const char* prefix, const NameType t, const bool literal)
/* ----------------------------------------------------------------------------
*
* Description: Associates a TempFsysName object with a temporary name. (As
* a side effect, the function actually creates an empty
* temporary file or a directory to reserve the name in the file
* system. The file or directory should never be removed
* explicitly; it is removed automatically when the TempFsysName
* object is destroyed or another call is made to
* `this->allocate'.)
*
* Arguments: prefix -- Pointer to a C-style string containing a prefix
* for the temporary name (empty by default). If
* `literal == true', `prefix' (if nonempty) is
* assumed to contain the full path for the
* temporary file or directory; otherwise the
* function will reserve a temporary name in the
* `P_tmpdir' directory. This name will consist
* of the value of `prefix' (if nonempty), followed
* by the current value of
* `TempFsysName::number_of_allocated_names' and
* the current process id, separated by dots.
* t -- Determines the type of the name (file or a
* directory).
* literal -- See above.
*
* Returns: A pointer to a constant C-style string containing the
* temporary name. The function throws an IOException if the
* name allocation or the file or directory creation fails.
*
* ------------------------------------------------------------------------- */
{
releaseName();
using ::StringUtil::toString;
string tempname;
try
{
if (!literal || strlen(prefix) == 0)
{
tempname = toString(P_tmpdir) + "/";
if (strlen(prefix))
tempname += string(prefix) + ".";
tempname += toString(number_of_allocated_names) + "."
+ toString(getpid());
++number_of_allocated_names;
}
else
tempname = prefix;
name = new char[tempname.length() + 1];
strcpy(name, tempname.c_str());
}
catch (const bad_alloc&)
{
name = 0;
throw IOException
("unable to allocate a temporary name in the file system");
}
type = t;
if (t == FILE)
{
int fd = open(name, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
if (fd == -1)
throw IOException("unable to create a temporary file");
close(fd);
}
else if (mkdir(name, S_IRWXU) == -1)
throw IOException("unable to create a temporary directory");
return name;
}

157
lbtt/src/TempFsysName.h Normal file
View file

@ -0,0 +1,157 @@
/*
* Copyright (C) 2004
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* 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 TEMPFSYSNAME_H
#define TEMPFSYSNAME_H
#include <config.h>
#include <cstdio>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
/******************************************************************************
*
* A class for temporary file system names.
*
*****************************************************************************/
class TempFsysName
{
public:
TempFsysName(); /* Constructor. */
~TempFsysName(); /* Destructor. */
enum NameType { FILE, DIRECTORY }; /* Types of temporary
* file system names.
*/
const char* allocate /* Allocates a name */
(const char* prefix = "", /* in the file system. */
const NameType t = FILE,
const bool literal = false);
const char* get() const; /* Tells the name. */
private:
TempFsysName(const TempFsysName&); /* Prevent copying and */
TempFsysName& operator=(const TempFsysName&); /* assignment of
* TempFsysName objects.
*/
void releaseName(); /* Frees a name in the file
* system.
*/
char* name; /* Temporary name. */
NameType type; /* Tells whether the name
* refers to a file or a
* directory.
*/
static unsigned long int /* Counter for the */
number_of_allocated_names; /* number of generated
* temporary names.
*/
};
/******************************************************************************
*
* Inline function definitions for class TempFsysName.
*
*****************************************************************************/
/* ========================================================================= */
inline TempFsysName::TempFsysName() : name(static_cast<char*>(0))
/* ----------------------------------------------------------------------------
*
* Description: Constructor for class TempFsysName.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
}
/* ========================================================================= */
inline TempFsysName::~TempFsysName()
/* ----------------------------------------------------------------------------
*
* Description: Destructor for class TempFsysName.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
releaseName();
}
/* ========================================================================= */
inline const char* TempFsysName::get() const
/* ----------------------------------------------------------------------------
*
* Description: Tells the name associated with the TempFsysName object.
*
* Arguments: None.
*
* Returns: A pointer to a constant C-style string containing the name
* associated with the TempFsysName object. If the TempFsysName
* object has not yet been (successfully) associated with a file
* using TempFsysName::allocate, this pointer has the value 0.
*
* ------------------------------------------------------------------------- */
{
return name;
}
/* ========================================================================= */
inline void TempFsysName::releaseName()
/* ----------------------------------------------------------------------------
*
* Description: Deallocates the memory reserved for `this->name' and frees
* the name also in the file system by removing the file or
* directory associated with the object. If the name
* is associated with a directory, the directory is assumed to
* be empty.
*
* Arguments: None.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
if (name == static_cast<char*>(0))
return;
if (type == FILE)
remove(name);
else
rmdir(name);
delete[] name;
name = 0;
}
#endif /* !TEMPFSYSNAME_H */

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
#include "Configuration.h" #include "Configuration.h"
#include "Exception.h" #include "Exception.h"
#include "StateSpace.h" #include "StateSpace.h"
#include "TestStatistics.h"
using namespace std; using namespace std;
@ -53,7 +54,11 @@ void openFile /* Opens a file for */
(const char* filename, ofstream& stream, /* writing. */ (const char* filename, ofstream& stream, /* writing. */
ios::openmode mode, int indent = 0); ios::openmode mode, int indent = 0);
void removeFile /* Removes a file. */ void openFile /* Opens a file for */
(const char* filename, int& fd, int flags, /* input/output using */
int indent = 0); /* file descriptors. */
void truncateFile /* Truncates a file. */
(const char* filename, int indent = 0); (const char* filename, int indent = 0);
void printFileContents /* Displays the contents */ void printFileContents /* Displays the contents */
@ -97,13 +102,6 @@ void generateBuchiAutomaton /* Generates a B
* for the conversion. * for the conversion.
*/ */
void generateProductAutomaton /* Computes the */
(int f, /* synchronous product */
vector<Configuration::AlgorithmInformation, /* of a Büchi automaton */
ALLOC(Configuration::AlgorithmInformation) > /* and a state space. */
::size_type
algorithm_id);
void performEmptinessCheck /* Performs an emptiness */ void performEmptinessCheck /* Performs an emptiness */
(int f, /* check on a product */ (int f, /* check on a product */
vector<Configuration::AlgorithmInformation, /* automaton. */ vector<Configuration::AlgorithmInformation, /* automaton. */

View file

@ -28,9 +28,9 @@
#include "LbttAlloc.h" #include "LbttAlloc.h"
#include "Exception.h" #include "Exception.h"
#include "LtlFormula.h" #include "LtlFormula.h"
#include "ProductAutomaton.h"
#include "PathIterator.h" #include "PathIterator.h"
#include "StateSpace.h" #include "StateSpace.h"
#include "TempFsysName.h"
using namespace std; using namespace std;
@ -90,6 +90,10 @@ public:
* current round. * current round.
*/ */
bool all_tests_successful; /* True if no errors have
* occurred during testing.
*/
bool skip; /* True if the current bool skip; /* True if the current
* round is to be skipped. * round is to be skipped.
*/ */
@ -122,11 +126,6 @@ public:
* paths as state spaces. * paths as state spaces.
*/ */
const Graph::ProductAutomaton* product_automaton; /* Pointer to the product
* automaton used in the
* current test round.
*/
unsigned long int real_emptiness_check_size; /* Number of states in the unsigned long int real_emptiness_check_size; /* Number of states in the
* state space where the * state space where the
* emptiness check should * emptiness check should
@ -181,10 +180,10 @@ public:
* formula. * formula.
*/ */
char formula_file_name[2][L_tmpnam + 1]; /* Storage space for the */ TempFsysName* formula_file_name[2]; /* Names for temporary */
char automaton_file_name[L_tmpnam + 1]; /* names of several */ TempFsysName* automaton_file_name; /* files. */
char cout_capture_file[L_tmpnam + 1]; /* temporary files. */ TempFsysName* cout_capture_file;
char cerr_capture_file[L_tmpnam + 1]; TempFsysName* cerr_capture_file;
private: private:
TestRoundInfo(const TestRoundInfo& info); /* Prevent copying and */ TestRoundInfo(const TestRoundInfo& info); /* Prevent copying and */
@ -206,14 +205,15 @@ private:
inline TestRoundInfo::TestRoundInfo() : inline TestRoundInfo::TestRoundInfo() :
cout(&std::cout, ios::failbit | ios::badbit), number_of_translators(0), cout(&std::cout, ios::failbit | ios::badbit), number_of_translators(0),
current_round(1), next_round_to_run(1), next_round_to_stop(1), current_round(1), next_round_to_run(1), next_round_to_stop(1),
error_report_round(0), error(false), skip(false), abort(false), error_report_round(0), error(false), all_tests_successful(true),
num_generated_statespaces(0), total_statespace_states(0), skip(false), abort(false), num_generated_statespaces(0),
total_statespace_transitions(0), num_processed_formulae(0), total_statespace_states(0), total_statespace_transitions(0),
fresh_statespace(false), statespace(0), path_iterator(0), num_processed_formulae(0), fresh_statespace(false), statespace(0),
product_automaton(0), real_emptiness_check_size(0), path_iterator(0), real_emptiness_check_size(0),
next_round_to_change_statespace(1), next_round_to_change_formula(1), next_round_to_change_statespace(1), next_round_to_change_formula(1),
fresh_formula(false), formulae(4, static_cast<class ::Ltl::LtlFormula*>(0)), fresh_formula(false), formulae(4, static_cast<class ::Ltl::LtlFormula*>(0)),
formula_in_file(2, false) formula_in_file(2, false), automaton_file_name(0), cout_capture_file(0),
cerr_capture_file(0)
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* *
* Description: Constructor for class TestRoundInfo. Creates a new * Description: Constructor for class TestRoundInfo. Creates a new
@ -225,6 +225,7 @@ inline TestRoundInfo::TestRoundInfo() :
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
formula_file_name[0] = formula_file_name[1] = 0;
} }
/* ========================================================================= */ /* ========================================================================= */

View file

@ -23,16 +23,16 @@
#include <config.h> #include <config.h>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "EdgeContainer.h"
#include "Graph.h"
#include "LbttAlloc.h" #include "LbttAlloc.h"
#include "BuchiAutomaton.h" #include "BuchiAutomaton.h"
#include "Configuration.h" #include "Configuration.h"
#include "ProductAutomaton.h"
#include "StateSpace.h" #include "StateSpace.h"
using namespace std; using namespace std;
using Graph::BuchiAutomaton; using Graph::BuchiAutomaton;
using Graph::StateSpace; using Graph::StateSpace;
using Graph::ProductAutomaton;
/****************************************************************************** /******************************************************************************
* *
@ -107,7 +107,7 @@ struct AutomatonStats
* Büchi automaton. * Büchi automaton.
*/ */
ProductAutomaton::size_type /* Number of stats in a */ ::Graph::Graph<GraphEdgeContainer>::size_type /* Number of stats in a */
number_of_product_states; /* product automaton. */ number_of_product_states; /* product automaton. */
unsigned long int number_of_product_transitions; /* Number of transitions in unsigned long int number_of_product_transitions; /* Number of transitions in
@ -270,29 +270,21 @@ struct TestStatistics
* checks performed. * checks performed.
*/ */
unsigned long int /* Total number of */ BIGUINT total_number_of_buchi_states[2]; /* Total number of states
total_number_of_buchi_states[2]; /* states in all the
* generated Büchi
* automata.
*/
unsigned long int /* Total number of */
total_number_of_buchi_transitions[2]; /* transitions in all
* the generated Büchi
* automata.
*/
unsigned long int /* Total number of sets */
total_number_of_acceptance_sets[2]; /* of accepting states
* in all the generated * in all the generated
* Büchi automata. * Büchi automata.
*/ */
unsigned long int /* Total number of */ BIGUINT total_number_of_buchi_transitions[2]; /* Total number of
total_number_of_msccs[2]; /* maximal strongly * transitions in all
* connected components * the generated Büchi
* in the generated * automata.
* Büchi automata. */
BIGUINT total_number_of_acceptance_sets[2]; /* Total number of sets of
* accepting states in all
* the generated Büchi
* automata.
*/ */
double total_buchi_generation_time[2]; /* Total time used when double total_buchi_generation_time[2]; /* Total time used when
@ -300,14 +292,13 @@ struct TestStatistics
* automata. * automata.
*/ */
unsigned long int /* Total number of */ BIGUINT total_number_of_product_states[2]; /* Total number of states
total_number_of_product_states[2]; /* states in all the * in all the generated
* generated product * product automata.
* automata.
*/ */
unsigned long int /* Total number of */ BIGUINT total_number_of_product_transitions[2]; /* Total number of
total_number_of_product_transitions[2]; /* transitions in all the * transitions in all the
* generated product * generated product
* automata. * automata.
*/ */
@ -556,7 +547,6 @@ inline TestStatistics::TestStatistics
total_number_of_buchi_states[i] = 0; total_number_of_buchi_states[i] = 0;
total_number_of_buchi_transitions[i] = 0; total_number_of_buchi_transitions[i] = 0;
total_number_of_acceptance_sets[i] = 0; total_number_of_acceptance_sets[i] = 0;
total_number_of_msccs[i] = 0;
total_number_of_product_states[i] = 0; total_number_of_product_states[i] = 0;
total_number_of_product_transitions[i] = 0; total_number_of_product_transitions[i] = 0;
total_buchi_generation_time[i] = 0.0; total_buchi_generation_time[i] = 0.0;

View file

@ -28,7 +28,6 @@
#include <strstream> #include <strstream>
#endif /* HAVE_SSTREAM */ #endif /* HAVE_SSTREAM */
#include "DispUtil.h" #include "DispUtil.h"
#include "ProductAutomaton.h"
#include "SharedTestData.h" #include "SharedTestData.h"
#include "StatDisplay.h" #include "StatDisplay.h"
#include "StringUtil.h" #include "StringUtil.h"
@ -118,9 +117,6 @@ void executeUserCommands()
{ {
#endif /* HAVE_READLINE */ #endif /* HAVE_READLINE */
ProductAutomaton* product_automaton = 0;
pair<unsigned long int, bool> last_computed_product_automaton;
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
while (1) while (1)
@ -170,35 +166,50 @@ void executeUserCommands()
} }
#endif /* HAVE_ISATTY */ #endif /* HAVE_ISATTY */
external_command = "";
string::size_type pipe_pos = input_line.find_first_of('|');
if (pipe_pos != string::npos)
{
string::size_type nonspace_pos
= input_line.find_first_not_of(" \t", pipe_pos + 1);
if (nonspace_pos != string::npos)
{
external_command = input_line.substr(nonspace_pos);
input_line = input_line.substr(0, pipe_pos);
}
}
sliceString(input_line, " \t", input_tokens);
user_break = false;
if (!input_tokens.empty())
{
#ifdef HAVE_READLINE #ifdef HAVE_READLINE
if (line != static_cast<char*>(0)) /* line may be 0 on EOF */ if (line != static_cast<char*>(0) /* line may be 0 on EOF */
&& input_line.find_first_not_of(" \t") != string::npos)
{ {
add_history(line); add_history(line);
free(line); free(line);
} }
#endif /* HAVE_READLINE */ #endif /* HAVE_READLINE */
/*
* If the input line contains an unescaped pipe symbol ('|') outside
* quotes, extract an external command from the line.
*/
external_command = "";
string::size_type pos
= findInQuotedString(input_line, "|", OUTSIDE_QUOTES);
if (pos != string::npos)
{
string::size_type nonspace_pos
= input_line.find_first_not_of(" \t", pos + 1);
if (nonspace_pos != string::npos)
{
external_command = input_line.substr(nonspace_pos);
input_line = input_line.substr(0, pos);
}
}
sliceString(substituteInQuotedString(input_line, " \t", "\n\n",
OUTSIDE_QUOTES),
"\n",
input_tokens);
user_break = false;
if (!input_tokens.empty() || !external_command.empty())
{
round_info.cout << '\n'; round_info.cout << '\n';
round_info.cout.flush(); round_info.cout.flush();
}
if (!input_tokens.empty())
{
token = parseCommand(input_tokens[0]); token = parseCommand(input_tokens[0]);
if (token == CONTINUE || token == SKIP) if (token == CONTINUE || token == SKIP)
@ -406,8 +417,7 @@ void executeUserCommands()
case BUCHIANALYZE : case BUCHIANALYZE :
verifyArgumentCount(input_tokens, 2, 2); verifyArgumentCount(input_tokens, 2, 2);
printAutomatonAnalysisResults(*output_stream, indent, printAutomatonAnalysisResults(*output_stream, indent,
parseNumber(input_tokens[1]), input_tokens);
parseNumber(input_tokens[2]));
if (output_file != 0) if (output_file != 0)
round_info.cout << " Büchi automaton intersection emptiness " round_info.cout << " Büchi automaton intersection emptiness "
"check analysis"; "check analysis";
@ -430,8 +440,8 @@ void executeUserCommands()
break; break;
case FORMULA : case FORMULA :
verifyArgumentCount(input_tokens, 0, 0); verifyArgumentCount(input_tokens, 0, 1);
printFormula(*output_stream, indent, formula_type); printFormula(*output_stream, indent, formula_type, input_tokens);
if (output_file != 0) if (output_file != 0)
round_info.cout << string(" ") + (formula_type round_info.cout << string(" ") + (formula_type
? "Formula" ? "Formula"
@ -458,8 +468,7 @@ void executeUserCommands()
case RESULTANALYZE : case RESULTANALYZE :
verifyArgumentCount(input_tokens, 2, 3); verifyArgumentCount(input_tokens, 2, 3);
printCrossComparisonAnalysisResults printCrossComparisonAnalysisResults
(*output_stream, indent, formula_type, input_tokens, (*output_stream, indent, formula_type, input_tokens);
product_automaton, last_computed_product_automaton);
if (output_file != 0) if (output_file != 0)
round_info.cout << " Model checking result cross-comparison " round_info.cout << " Model checking result cross-comparison "
"analysis"; "analysis";
@ -501,8 +510,8 @@ void executeUserCommands()
break; break;
default : default :
throw CommandErrorException("Unknown command (`" throw CommandErrorException("Unknown command (`" + input_tokens[0]
+ input_tokens[0] + "')."); + "').");
} }
if (output_string != 0) if (output_string != 0)
@ -513,21 +522,17 @@ void executeUserCommands()
FILE* output_pipe = popen(external_command.c_str(), "w"); FILE* output_pipe = popen(external_command.c_str(), "w");
if (output_pipe == NULL) if (output_pipe == NULL)
throw ExecFailedException(external_command); throw ExecFailedException(external_command);
int status = fputs(outstring.c_str(), output_pipe); fputs(outstring.c_str(), output_pipe);
if (status != EOF)
fflush(output_pipe);
pclose(output_pipe); pclose(output_pipe);
round_info.cout << '\n';
round_info.cout.flush();
if (status == EOF)
throw IOException("Error writing to pipe.");
} }
else if (output_file != 0) else
{ {
if (output_file != 0)
round_info.cout << string(redirection_info.second round_info.cout << string(redirection_info.second
? " appended" ? " appended"
: " written") : " written")
+ " to `" + redirection_info.first + "'.\n\n"; + " to `" + redirection_info.first + "'.\n";
round_info.cout << '\n';
round_info.cout.flush(); round_info.cout.flush();
} }
} }
@ -560,16 +565,6 @@ void executeUserCommands()
} }
} }
if (product_automaton != 0)
{
::DispUtil::printText
("<cleaning up memory allocated for product automaton>", 4, 2);
delete product_automaton;
::DispUtil::printText(" ok\n", 4);
}
#ifdef HAVE_READLINE #ifdef HAVE_READLINE
} }
catch (...) catch (...)
@ -597,19 +592,6 @@ TokenType parseCommand(const string& token)
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
{ {
/*
* gcc versions prior to version 3 do not conform to the C++ standard in their
* support for the string::compare functions. Use a macro to fix this if
* necessary.
*/
#ifdef __GNUC__
#if __GNUC__ < 3
#define compare(start,end,str,dummy) compare(str,start,end)
#endif
#endif
TokenType token_type = UNKNOWN; TokenType token_type = UNKNOWN;
string::size_type len = token.length(); string::size_type len = token.length();
bool ambiguous = false; bool ambiguous = false;
@ -706,8 +688,19 @@ TokenType parseCommand(const string& token)
break; break;
case 'i' : case 'i' :
if (token.compare(1, len - 1, "nconsistencies", len - 1) == 0) if (len < 2)
ambiguous = true;
else if (token[1] == 'm')
{
if (token.compare(2, len - 2, "plementations", len - 2) == 0)
token_type = ALGORITHMS;
}
else if (token[1] == 'n')
{
if (token.compare(2, len - 2, "consistencies", len - 2) == 0)
token_type = INCONSISTENCIES; token_type = INCONSISTENCIES;
}
break; break;
case 'q' : case 'q' :
@ -787,6 +780,11 @@ TokenType parseCommand(const string& token)
} }
break; break;
case 't' :
if (token.compare(1, len - 1, "ranslators", len - 1) == 0)
token_type = ALGORITHMS;
break;
case 'v' : case 'v' :
if (token.compare(1, len - 1, "erbosity", len - 1) == 0) if (token.compare(1, len - 1, "erbosity", len - 1) == 0)
token_type = VERBOSITY; token_type = VERBOSITY;
@ -797,12 +795,6 @@ TokenType parseCommand(const string& token)
throw CommandErrorException("Ambiguous command."); throw CommandErrorException("Ambiguous command.");
return token_type; return token_type;
#ifdef __GNUC__
#if __GNUC__ < 3
#undef compare
#endif
#endif
} }
/* ========================================================================= */ /* ========================================================================= */
@ -867,13 +859,13 @@ pair<string, bool> parseRedirection
if (token.length() > 2) if (token.length() > 2)
{ {
append = true; append = true;
filename = token.substr(2); filename = unquoteString(token.substr(2));
input_tokens.pop_back(); input_tokens.pop_back();
} }
} }
else else
{ {
filename = token.substr(1); filename = unquoteString(token.substr(1));
input_tokens.pop_back(); input_tokens.pop_back();
} }
} }
@ -882,10 +874,9 @@ pair<string, bool> parseRedirection
{ {
string& token = *(input_tokens.rbegin() + 1); string& token = *(input_tokens.rbegin() + 1);
if (token[0] == '>' && (token.length() == 1 if (token == ">" || token == ">>")
|| (token.length() == 2 && token[1] == '>')))
{ {
filename = input_tokens.back(); filename = unquoteString(input_tokens.back());
append = (token.length() == 2); append = (token.length() == 2);
input_tokens.pop_back(); input_tokens.pop_back();
input_tokens.pop_back(); input_tokens.pop_back();
@ -921,8 +912,7 @@ bool parseFormulaType(vector<string, ALLOC(string) >& input_tokens)
{ {
formula_type = (input_tokens[1] != "-"); formula_type = (input_tokens[1] != "-");
if (input_tokens[1].length() == 1 if (input_tokens[1] == "+" || input_tokens[1] == "-")
&& (input_tokens[1][0] == '+' || input_tokens[1][0] == '-'))
input_tokens.erase(input_tokens.begin()); input_tokens.erase(input_tokens.begin());
} }

File diff suppressed because it is too large Load diff

View file

@ -23,13 +23,17 @@
#include <config.h> #include <config.h>
#include <deque> #include <deque>
#include <iostream> #include <iostream>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <utility> #include <utility>
#include "LbttAlloc.h" #include "LbttAlloc.h"
#include "BuchiAutomaton.h" #include "BuchiAutomaton.h"
#include "Configuration.h" #include "Configuration.h"
#include "ProductAutomaton.h" #include "EdgeContainer.h"
#include "Graph.h"
#include "IntervalList.h"
#include "Product.h"
#include "StateSpace.h" #include "StateSpace.h"
using namespace std; using namespace std;
@ -45,38 +49,26 @@ extern Configuration configuration;
namespace UserCommands namespace UserCommands
{ {
void computeProductAutomaton /* Computes a product */ unsigned long int parseAlgorithmId /* Parses an */
(ProductAutomaton*& product_automaton, /* automaton. */ (const string& id); /* implementation
const BuchiAutomaton& buchi_automaton, * identifier.
pair<unsigned long int, bool>& last_automaton, */
const pair<unsigned long int, bool>&
new_automaton); void parseAlgorithmId /* Parses a list of */
(const string& ids, IntervalList& algorithms); /* implementation
* identifiers.
*/
void printAlgorithmList /* Displays a list of */ void printAlgorithmList /* Displays a list of */
(ostream& stream, int indent); /* algorithms used in (ostream& stream, int indent); /* algorithms used in
* the tests. * the tests.
*/ */
void synchronizePrefixAndCycle /* Synchronizes a prefix */
(deque<Graph::Graph<GraphEdgeContainer> /* with a cycle in a */
::size_type, /* sequence of graph */
ALLOC(Graph::Graph<GraphEdgeContainer> /* state identifiers. */
::size_type) >&
prefix,
deque<Graph::Graph<GraphEdgeContainer>
::size_type,
ALLOC(Graph::Graph<GraphEdgeContainer>
::size_type) >&
cycle);
void printCrossComparisonAnalysisResults /* Analyzes a */ void printCrossComparisonAnalysisResults /* Analyzes a */
(ostream& stream, int indent, /* contradiction between */ (ostream& stream, int indent, /* contradiction between */
bool formula_type, /* test results of two */ bool formula_type, /* test results of two */
const vector<string, ALLOC(string) >& /* implementations. */ const vector<string, ALLOC(string) >& /* implementations. */
input_tokens, input_tokens);
ProductAutomaton*& product_automaton,
pair<unsigned long int, bool>&
last_product_automaton);
void printConsistencyAnalysisResults /* Analyzes a */ void printConsistencyAnalysisResults /* Analyzes a */
(ostream& stream, int indent, /* contradicition in the */ (ostream& stream, int indent, /* contradicition in the */
@ -87,19 +79,15 @@ void printConsistencyAnalysisResults /* Analyzes a */
void printAutomatonAnalysisResults /* Analyzes a */ void printAutomatonAnalysisResults /* Analyzes a */
(ostream& stream, int indent, /* contradiction in the */ (ostream& stream, int indent, /* contradiction in the */
unsigned long int algorithm1, /* Büchi automata */ const vector<string, ALLOC(string) >& /* Büchi automata */
unsigned long int algorithm2); /* intersection input_tokens); /* intersection
* emptiness check. * emptiness check.
*/ */
void printPath /* Displays information */ void printPath /* Displays information */
(ostream& stream, int indent, /* about a single */ (ostream& stream, int indent, /* about a single */
const deque<StateSpace::size_type, /* system execution. */ const StateSpace::Path& prefix, /* system execution. */
ALLOC(StateSpace::size_type) >& const StateSpace::Path& cycle,
prefix,
const deque<StateSpace::size_type,
ALLOC(StateSpace::size_type) >&
cycle,
const StateSpace& path); const StateSpace& path);
void printAcceptingCycle /* Displays information */ void printAcceptingCycle /* Displays information */
@ -108,13 +96,12 @@ void printAcceptingCycle /* Displays information */
ALLOC(Configuration::AlgorithmInformation) > ALLOC(Configuration::AlgorithmInformation) >
::size_type ::size_type
algorithm_id, algorithm_id,
const deque<StateSpace::size_type, const BuchiAutomaton::Path& aut_prefix,
ALLOC(StateSpace::size_type) >& const BuchiAutomaton::Path& aut_cycle,
prefix, const BuchiAutomaton& automaton,
const deque<StateSpace::size_type, const StateSpace::Path& path_prefix,
ALLOC(StateSpace::size_type) >& const StateSpace::Path& path_cycle,
cycle, const StateSpace& statespace);
const BuchiAutomaton& automaton);
void printBuchiAutomaton /* Displays information */ void printBuchiAutomaton /* Displays information */
(ostream& stream, int indent, /* about a Büchi */ (ostream& stream, int indent, /* about a Büchi */
@ -129,7 +116,9 @@ void evaluateFormula /* Displays information */
void printFormula /* Displays a formula */ void printFormula /* Displays a formula */
(ostream& stream, int indent, /* used for testing. */ (ostream& stream, int indent, /* used for testing. */
bool formula_type); bool formula_type,
const vector<string, ALLOC(string) >&
input_tokens);
void printCommandHelp /* Displays help about */ void printCommandHelp /* Displays help about */
(ostream& stream, int indent, /* user commands. */ (ostream& stream, int indent, /* user commands. */

View file

@ -36,6 +36,7 @@
#include "Random.h" #include "Random.h"
#include "SharedTestData.h" #include "SharedTestData.h"
#include "StatDisplay.h" #include "StatDisplay.h"
#include "TempFsysName.h"
#include "TestOperations.h" #include "TestOperations.h"
#include "TestRoundInfo.h" #include "TestRoundInfo.h"
#include "TestStatistics.h" #include "TestStatistics.h"
@ -43,17 +44,6 @@
using namespace std; using namespace std;
/******************************************************************************
*
* Handler for the SIGINT signal.
*
*****************************************************************************/
RETSIGTYPE breakHandler(int)
{
user_break = true;
}
/****************************************************************************** /******************************************************************************
@ -105,13 +95,120 @@ vector<TestStatistics, ALLOC(TestStatistics) > /* Overall test */
/******************************************************************************
*
* Functions for allocating and deallocating temporary file names.
*
*****************************************************************************/
static void allocateTempFilenames()
{
using SharedTestData::round_info;
round_info.formula_file_name[0] = new TempFsysName;
round_info.formula_file_name[0]->allocate("lbtt");
round_info.formula_file_name[1] = new TempFsysName;
round_info.formula_file_name[1]->allocate("lbtt");
round_info.automaton_file_name = new TempFsysName;
round_info.automaton_file_name->allocate("lbtt");
round_info.cout_capture_file = new TempFsysName;
round_info.cout_capture_file->allocate("lbtt");
round_info.cerr_capture_file = new TempFsysName;
round_info.cerr_capture_file->allocate("lbtt");
}
static void deallocateTempFilenames()
{
using SharedTestData::round_info;
if (round_info.formula_file_name[0] != 0)
{
delete round_info.formula_file_name[0];
round_info.formula_file_name[0] = 0;
}
if (round_info.formula_file_name[1] != 0)
{
delete round_info.formula_file_name[1];
round_info.formula_file_name[1] = 0;
}
if (round_info.automaton_file_name != 0)
{
delete round_info.automaton_file_name;
round_info.automaton_file_name = 0;
}
if (round_info.cout_capture_file != 0)
{
delete round_info.cout_capture_file;
round_info.cout_capture_file = 0;
}
if (round_info.cerr_capture_file != 0)
{
delete round_info.cerr_capture_file;
round_info.cerr_capture_file = 0;
}
}
/******************************************************************************
*
* Handler for the SIGINT signal.
*
*****************************************************************************/
static void breakHandler(int)
{
user_break = true;
}
/******************************************************************************
*
* Default handler for signals that terminate the process.
*
*****************************************************************************/
static void abortHandler(int signum)
{
deallocateTempFilenames();
struct sigaction s;
s.sa_handler = SIG_DFL;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(signum, &s, static_cast<struct sigaction*>(0));
raise(signum);
}
/******************************************************************************
*
* Function for installing signal handlers.
*
*****************************************************************************/
static void installSignalHandler(int signum, void (*handler)(int))
{
struct sigaction s;
sigaction(signum, static_cast<struct sigaction*>(0), &s);
if (s.sa_handler != SIG_IGN)
{
s.sa_handler = handler;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(signum, &s, static_cast<struct sigaction*>(0));
}
}
/****************************************************************************** /******************************************************************************
* *
* Test loop. * Test loop.
* *
*****************************************************************************/ *****************************************************************************/
void testLoop() bool testLoop()
{ {
using namespace DispUtil; using namespace DispUtil;
using namespace SharedTestData; using namespace SharedTestData;
@ -136,13 +233,6 @@ void testLoop()
? round_info.next_round_to_run ? round_info.next_round_to_run
: global_options.number_of_rounds + 1); : global_options.number_of_rounds + 1);
if (tmpnam(round_info.formula_file_name[0]) == 0
|| tmpnam(round_info.formula_file_name[1]) == 0
|| tmpnam(round_info.automaton_file_name) == 0
|| tmpnam(round_info.cout_capture_file) == 0
|| tmpnam(round_info.cerr_capture_file) == 0)
throw Exception("unable to allocate names for temporary files");
/* /*
* If a name for the error log file was given in the configuration, create * If a name for the error log file was given in the configuration, create
* the file. * the file.
@ -221,19 +311,6 @@ void testLoop()
formula_random_state[i] = static_cast<short int>(LRAND(0, LONG_MAX)); formula_random_state[i] = static_cast<short int>(LRAND(0, LONG_MAX));
#endif /* HAVE_RAND48 */ #endif /* HAVE_RAND48 */
/*
* If using paths as state spaces, include the internal model checking
* algorithm in the set of algorithms.
*/
if (global_options.statespace_generation_mode & Configuration::PATH)
{
Configuration::AlgorithmInformation lbtt_info
= {new string("lbtt"), new string(), new string(), true};
configuration.algorithms.push_back(lbtt_info);
}
/* /*
* Intialize the vector for storing the test results for each * Intialize the vector for storing the test results for each
* implementation and the vector for collecting overall test statistics for * implementation and the vector for collecting overall test statistics for
@ -271,21 +348,9 @@ void testLoop()
= (round_info.current_round < round_info.next_round_to_run); = (round_info.current_round < round_info.next_round_to_run);
if (!round_info.skip) if (!round_info.skip)
{ printText(string("Round ") + toString(round_info.current_round)
if (!printText(string("Round ") + toString(round_info.current_round) + " of " + toString(global_options.number_of_rounds) + "\n\n",
+ " of " + toString(global_options.number_of_rounds) 2);
+ "\n\n",
2))
{
if (global_options.verbosity == 1)
{
if (round_info.current_round > 1)
round_info.cout << ' ';
round_info.cout << round_info.current_round;
round_info.cout.flush();
}
}
}
try try
{ {
@ -399,7 +464,7 @@ void testLoop()
if (user_break) if (user_break)
{ {
printText("[User break]\n\n", 2, 4); printText("[User break]\n\n", 1, 4);
throw UserBreakException(); throw UserBreakException();
} }
@ -414,12 +479,17 @@ void testLoop()
if (global_options.statespace_generation_mode & Configuration::PATH if (global_options.statespace_generation_mode & Configuration::PATH
&& (global_options.do_cons_test || global_options.do_comp_test) && (global_options.do_cons_test || global_options.do_comp_test)
&& (!test_results[round_info.number_of_translators]. && (!test_results[round_info.number_of_translators - 1].
automaton_stats[0].emptiness_check_performed)) automaton_stats[0].emptiness_check_performed)
&& configuration.algorithms[round_info.number_of_translators - 1].
enabled)
verifyFormulaOnPath(); verifyFormulaOnPath();
if (!round_info.error) if (!round_info.error)
{ {
if (global_options.verbosity == 2)
::StatDisplay::printStatTableHeader(round_info.cout, 4);
unsigned long int num_enabled_implementations = 0; unsigned long int num_enabled_implementations = 0;
for (unsigned long int algorithm_id = 0; for (unsigned long int algorithm_id = 0;
@ -431,28 +501,43 @@ void testLoop()
num_enabled_implementations++; num_enabled_implementations++;
if (configuration.isInternalAlgorithm(algorithm_id))
continue;
printText(configuration.algorithmString(algorithm_id) + '\n', printText(configuration.algorithmString(algorithm_id) + '\n',
2, 4); 3, 4);
for (int counter = 0; counter < 2; counter++) for (int counter = 0; counter < 2; counter++)
{ {
if (user_break) if (user_break)
{ {
printText("[User break]\n\n", 2, 4); printText("[User break]\n\n", 1, 4);
throw UserBreakException(); throw UserBreakException();
} }
if (global_options.verbosity == 1
|| global_options.verbosity == 2)
{
if (counter == 1)
round_info.cout << '\n';
if (global_options.verbosity == 1)
round_info.cout << round_info.current_round << ' ';
else
round_info.cout << string(4, ' ');
changeStreamFormatting(cout, 2, 0, ios::right);
round_info.cout << algorithm_id << ' ';
restoreStreamFormatting(cout);
round_info.cout << (counter == 0 ? '+' : '-') << ' ';
round_info.cout.flush();
}
else
printText(string(counter == 1 ? "Negated" : "Positive") printText(string(counter == 1 ? "Negated" : "Positive")
+ " formula:\n", + " formula:\n",
2, 3,
6); 6);
try try
{ {
try
{
round_info.product_automaton = 0;
/* /*
* Generate a Büchi automaton using the current algorithm. * Generate a Büchi automaton using the current algorithm.
* `counter' determines the formula which is to be * `counter' determines the formula which is to be
@ -462,16 +547,8 @@ void testLoop()
generateBuchiAutomaton(counter, algorithm_id); generateBuchiAutomaton(counter, algorithm_id);
if (global_options.do_cons_test if (global_options.do_cons_test || global_options.do_comp_test)
|| global_options.do_comp_test)
{ {
/*
* Compute the product of the Büchi automaton with the
* state space.
*/
generateProductAutomaton(counter, algorithm_id);
/* /*
* Find the system states from which an accepting * Find the system states from which an accepting
* execution cycle can be reached by checking the product * execution cycle can be reached by checking the product
@ -479,33 +556,6 @@ void testLoop()
*/ */
performEmptinessCheck(counter, algorithm_id); performEmptinessCheck(counter, algorithm_id);
/*
* If a product automaton was computed in this test round
* (it might have not if the emptiness checking result was
* already available), release the memory allocated for
* the product automaton.
*/
if (round_info.product_automaton != 0)
{
printText("<deallocating memory>", 4, 8);
delete round_info.product_automaton;
round_info.product_automaton = 0;
printText(" ok\n", 4);
}
}
}
catch (...)
{
if (round_info.product_automaton != 0)
{
delete round_info.product_automaton;
round_info.product_automaton = 0;
}
throw;
} }
} }
catch (const BuchiAutomatonGenerationException&) catch (const BuchiAutomatonGenerationException&)
@ -541,7 +591,13 @@ void testLoop()
emptiness_check_performed) emptiness_check_performed)
performConsistencyCheck(algorithm_id); performConsistencyCheck(algorithm_id);
printText("\n", 2); printText("\n", 1);
}
if (global_options.verbosity == 2)
{
round_info.cout << '\n';
round_info.cout.flush();
} }
if (num_enabled_implementations > 0) if (num_enabled_implementations > 0)
@ -553,10 +609,7 @@ void testLoop()
* results obtained using the different algorithms. * results obtained using the different algorithms.
*/ */
if (num_enabled_implementations >= 2 if (num_enabled_implementations >= 2)
|| (num_enabled_implementations == 1
&& global_options.statespace_generation_mode
& Configuration::PATH))
compareResults(); compareResults();
} }
@ -592,24 +645,16 @@ void testLoop()
* the testing should be paused to wait for user commands. * the testing should be paused to wait for user commands.
*/ */
if (round_info.error)
round_info.all_tests_successful = false;
if (round_info.error if (round_info.error
&& global_options.interactive == Configuration::ONERROR) && global_options.interactive == Configuration::ONERROR)
round_info.next_round_to_stop = round_info.current_round; round_info.next_round_to_stop = round_info.current_round;
if (round_info.next_round_to_stop == round_info.current_round) if (round_info.next_round_to_stop == round_info.current_round)
{
if (global_options.verbosity == 1)
{
round_info.cout << '\n';
round_info.cout.flush();
}
::UserCommandInterface::executeUserCommands(); ::UserCommandInterface::executeUserCommands();
} }
}
for (int i = 0; i < 2; i++)
removeFile(round_info.formula_file_name[i], 2);
if (round_info.path_iterator != 0) if (round_info.path_iterator != 0)
delete round_info.path_iterator; delete round_info.path_iterator;
@ -661,11 +706,13 @@ void testLoop()
round_info.transcript_file.close(); round_info.transcript_file.close();
} }
if (global_options.verbosity >= 1) if (global_options.verbosity >= 2)
printCollectiveStats(cout, 0); printCollectiveStats(cout, 0);
if (round_info.formula_input_file.is_open()) if (round_info.formula_input_file.is_open())
round_info.formula_input_file.close(); round_info.formula_input_file.close();
return round_info.all_tests_successful;
} }
@ -689,14 +736,26 @@ int main(int argc, char* argv[])
cerr << ":" << configuration.global_options.cfg_filename << ":" cerr << ":" << configuration.global_options.cfg_filename << ":"
<< e.line_info; << e.line_info;
cerr << ":" << e.what() << endl; cerr << ":" << e.what() << endl;
exit(-1); exit(2);
} }
if (configuration.global_options.verbosity >= 3) if (configuration.global_options.verbosity >= 3)
configuration.print(cout); configuration.print(cout);
user_break = false; user_break = false;
signal(SIGINT, breakHandler);
installSignalHandler(SIGHUP, abortHandler);
installSignalHandler(SIGINT,
configuration.global_options.handle_breaks
? breakHandler
: abortHandler);
installSignalHandler(SIGQUIT, abortHandler);
installSignalHandler(SIGABRT, abortHandler);
installSignalHandler(SIGPIPE, abortHandler);
installSignalHandler(SIGALRM, abortHandler);
installSignalHandler(SIGTERM, abortHandler);
installSignalHandler(SIGUSR1, abortHandler);
installSignalHandler(SIGUSR2, abortHandler);
#ifdef HAVE_OBSTACK_H #ifdef HAVE_OBSTACK_H
obstack_alloc_failed_handler = &ObstackAllocator::failure; obstack_alloc_failed_handler = &ObstackAllocator::failure;
@ -708,18 +767,26 @@ int main(int argc, char* argv[])
try try
{ {
testLoop(); allocateTempFilenames();
if (!testLoop())
{
deallocateTempFilenames();
return 1;
}
} }
catch (const Exception& e) catch (const Exception& e)
{ {
cerr << argv[0] << ": " << e.what() << endl; deallocateTempFilenames();
exit(-1); cerr << endl << argv[0] << ": " << e.what() << endl;
exit(3);
} }
catch (const bad_alloc&) catch (const bad_alloc&)
{ {
cerr << argv[0] << ": out of memory" << endl; deallocateTempFilenames();
exit(-1); cerr << endl << argv[0] << ": out of memory" << endl;
exit(3);
} }
deallocateTempFilenames();
return 0; return 0;
} }

View file

@ -45,6 +45,17 @@ char** command_line_arguments;
/******************************************************************************
*
* Pointer to an object providing operations for translating a formula into an
* automaton.
*
*****************************************************************************/
static TranslatorInterface* translator = 0;
/****************************************************************************** /******************************************************************************
* *
* A function for showing warnings to the user. * A function for showing warnings to the user.
@ -60,21 +71,46 @@ void printWarning(const string& msg)
/****************************************************************************** /******************************************************************************
* *
* Signal handler for debugging purposes. * Handler for SIGINT, SIGQUIT, SIGABRT and SIGTERM.
* *
*****************************************************************************/ *****************************************************************************/
RETSIGTYPE signalHandler(int signal_number) static void signalHandler(int signal_number)
{ {
cerr << string(command_line_arguments[0]) + ": received signal " if (translator != 0)
<< signal_number delete translator;
<< endl; struct sigaction s;
signal(signal_number, SIG_DFL); s.sa_handler = SIG_DFL;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(signal_number, &s, static_cast<struct sigaction*>(0));
raise(signal_number); raise(signal_number);
} }
/******************************************************************************
*
* Function for installing signal handlers.
*
*****************************************************************************/
static void installSignalHandler(int signum)
{
struct sigaction s;
sigaction(signum, static_cast<struct sigaction*>(0), &s);
if (s.sa_handler != SIG_IGN)
{
s.sa_handler = signalHandler;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(signum, &s, static_cast<struct sigaction*>(0));
}
}
/****************************************************************************** /******************************************************************************
* *
* Main function. * Main function.
@ -83,7 +119,7 @@ RETSIGTYPE signalHandler(int signal_number)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
typedef enum {OPT_HELP = 'h', OPT_LBT, OPT_SPIN, OPT_VERSION = 'v'} typedef enum {OPT_HELP = 'h', OPT_LBT, OPT_SPIN, OPT_VERSION = 'V'}
OptionType; OptionType;
static OPTIONSTRUCT command_line_options[] = static OPTIONSTRUCT command_line_options[] =
@ -100,12 +136,10 @@ int main(int argc, char** argv)
opterr = 1; opterr = 1;
int opttype, option_index; int opttype, option_index;
TranslatorInterface* translator = 0;
do do
{ {
option_index = 0; option_index = 0;
opttype = getopt_long(argc, argv, "hv", command_line_options, opttype = getopt_long(argc, argv, "hV", command_line_options,
&option_index); &option_index);
switch (opttype) switch (opttype)
@ -115,8 +149,8 @@ int main(int argc, char** argv)
<< " [translator] [command line for translator] [formula " << " [translator] [command line for translator] [formula "
"file] [automaton file]\n" "file] [automaton file]\n"
"General options:\n" "General options:\n"
" --h, --help Show this help\n" " -h, --help Show this help\n"
" --v, --version Show version and exit\n\n" " -V, --version Show version and exit\n\n"
"Translator options:\n" "Translator options:\n"
" --lbt lbt\n" " --lbt lbt\n"
" --spin Spin\n" " --spin Spin\n"
@ -168,16 +202,15 @@ int main(int argc, char** argv)
int exitstatus = 0; int exitstatus = 0;
signal(SIGHUP, signalHandler); installSignalHandler(SIGHUP);
signal(SIGINT, signalHandler); installSignalHandler(SIGINT);
signal(SIGQUIT, signalHandler); installSignalHandler(SIGQUIT);
signal(SIGILL, signalHandler); installSignalHandler(SIGABRT);
signal(SIGABRT, signalHandler); installSignalHandler(SIGPIPE);
signal(SIGFPE, signalHandler); installSignalHandler(SIGALRM);
signal(SIGSEGV, signalHandler); installSignalHandler(SIGTERM);
signal(SIGPIPE, signalHandler); installSignalHandler(SIGUSR1);
signal(SIGALRM, signalHandler); installSignalHandler(SIGUSR2);
signal(SIGTERM, signalHandler);
::Ltl::LtlFormula* formula(0); ::Ltl::LtlFormula* formula(0);