You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
845 lines
22 KiB
845 lines
22 KiB
/*
|
|
* This file is part of the program ltl2dstar (http://www.ltl2dstar.de/).
|
|
* Copyright (C) 2005-2007 Joachim Klein <j.klein@ltl2dstar.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
|
|
/** @file
|
|
* Implementation of LTL2DSTAR_Scheduler
|
|
*/
|
|
|
|
#include "LTL2DRA.hpp"
|
|
#include "LTL2DSTAR_Scheduler.hpp"
|
|
|
|
#include "DAUnionAlgorithm.hpp"
|
|
#include "DRAOptimizations.hpp"
|
|
|
|
#include "NBA2DRA.hpp"
|
|
#include "DRA2NBA.hpp"
|
|
|
|
#include "LTLSafetyAutomata.hpp"
|
|
|
|
#include "StutterSensitivenessInformation.hpp"
|
|
|
|
#include "common/TempFile.hpp"
|
|
#include "common/RunProgram.hpp"
|
|
#include "common/Exceptions.hpp"
|
|
|
|
#include <typeinfo>
|
|
#include <limits>
|
|
#include <algorithm>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <cstring>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/tokenizer.hpp>
|
|
|
|
/** Dummy namespace for the building blocks */
|
|
class LTL2DSTAR_Scheduler_Trees {
|
|
public:
|
|
class LTL2DSTAR_Tree_Start;
|
|
class LTL2DSTAR_Tree_Safra;
|
|
class LTL2DSTAR_Tree_Rabin;
|
|
class LTL2DSTAR_Tree_Streett;
|
|
class LTL2DSTAR_Tree_Union;
|
|
|
|
|
|
/** Base class for the building blocks for the scheduler */
|
|
class LTL2DSTAR_Tree {
|
|
public:
|
|
/** Type of a vector over the children */
|
|
typedef std::vector<LTL2DSTAR_Tree*> child_vector;
|
|
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
LTL2DSTAR_Tree(LTLFormula_ptr& ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
_ltl(ltl), _options(options), _sched(sched) {}
|
|
|
|
/** Destructor */
|
|
virtual ~LTL2DSTAR_Tree() {
|
|
for (child_vector::iterator it=children.begin();
|
|
it!=children.end();
|
|
++it) {
|
|
delete *it;
|
|
}
|
|
}
|
|
|
|
/** Print the tree on output stream */
|
|
virtual void printTree(std::ostream& out,
|
|
unsigned int level=0) {
|
|
for (unsigned int i=0;i<level;i++) {
|
|
out << " ";
|
|
}
|
|
out << typeid(*this).name() << " = " << this <<
|
|
"(" << _ltl.get() << ")" << "\n";
|
|
for (child_vector::iterator it=children.begin();
|
|
it!=children.end();
|
|
++it) {
|
|
(*it)->printTree(out, level+1);
|
|
}
|
|
}
|
|
|
|
/** Abstract virtual function for tree generation */
|
|
virtual void generateTree() = 0;
|
|
|
|
/** Estimate the size of the automaton */
|
|
virtual unsigned int guestimate() {
|
|
return 0;
|
|
}
|
|
|
|
/** Hook that is called after calculate() finishes */
|
|
virtual void hook_after_calculate() {};
|
|
|
|
/** Calculate the automaton for this building block, by default
|
|
* calculate the automata for the children and then choose the smallest. */
|
|
virtual void calculate(int level=0,
|
|
unsigned int limit=0) {
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << "Calculate ("<< level <<"): " << typeid(*this).name() << std::endl;
|
|
}
|
|
|
|
calculateChildren(level, limit);
|
|
|
|
bool first=true;
|
|
for (child_vector::iterator it=children.begin();
|
|
it!=children.end();
|
|
++it) {
|
|
if ((*it)->_automaton==0) {
|
|
continue;
|
|
}
|
|
|
|
if (first) {
|
|
_automaton=(*it)->_automaton;
|
|
_comment=(*it)->_comment;
|
|
} else {
|
|
if (_automaton->size() > (*it)->_automaton->size()) {
|
|
_automaton=(*it)->_automaton;
|
|
_comment=(*it)->_comment;
|
|
}
|
|
}
|
|
|
|
first=false;
|
|
}
|
|
|
|
hook_after_calculate();
|
|
}
|
|
|
|
/** Add a new child */
|
|
void addChild(LTL2DSTAR_Tree* child) {
|
|
if (child==0) {return;}
|
|
|
|
children.push_back(child);
|
|
}
|
|
|
|
/** Calculate the automata for the children */
|
|
void calculateChildren(int level=0,
|
|
unsigned int limit=0) {
|
|
if (_sched.flagOptLimits()) {
|
|
DRA_ptr _min_automaton;
|
|
unsigned int _min_size=0;
|
|
|
|
for (child_vector::iterator it=children.begin();
|
|
it!=children.end();
|
|
++it) {
|
|
unsigned int child_limit;
|
|
if (_min_size!=0) {
|
|
if (limit > 0) {
|
|
child_limit=(std::min)(_sched.calcLimit(_min_size), limit);
|
|
} else {
|
|
child_limit=_sched.calcLimit(_min_size);
|
|
}
|
|
} else {
|
|
child_limit=limit;
|
|
}
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << " Limit (with alpha) = " << child_limit << std::endl;
|
|
}
|
|
try {
|
|
(*it)->calculate(level+1, child_limit);
|
|
|
|
if ((*it)->_automaton.get()!=0) {
|
|
if (_min_size==0 ||
|
|
(*it)->_automaton->size() < _min_size) {
|
|
_min_automaton=(*it)->_automaton;
|
|
_min_size=_min_automaton->size();
|
|
} else {
|
|
// delete automaton as it is bigger
|
|
// than necessary
|
|
(*it)->_automaton.reset();
|
|
}
|
|
}
|
|
} catch (LimitReachedException& e) {
|
|
(*it)->_automaton.reset();
|
|
}
|
|
}
|
|
} else {
|
|
for (child_vector::iterator it=children.begin();
|
|
it!=children.end();
|
|
++it) {
|
|
(*it)->calculate(level+1, limit);
|
|
}
|
|
}
|
|
}
|
|
|
|
LTLFormula_ptr _ltl;
|
|
LTL2DSTAR_Options _options;
|
|
unsigned int priority;
|
|
DRA_ptr _automaton;
|
|
std::string _comment;
|
|
LTL2DSTAR_Scheduler& _sched;
|
|
|
|
std::vector<LTL2DSTAR_Tree*> children;
|
|
};
|
|
|
|
|
|
|
|
|
|
/** The root building block for the calculation of DRA/DSA */
|
|
class LTL2DSTAR_Tree_Start : public LTL2DSTAR_Tree {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
LTL2DSTAR_Tree_Start(LTLFormula_ptr ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
LTL2DSTAR_Tree(ltl, options, sched) {
|
|
generateTree();
|
|
}
|
|
|
|
/** Generate the tree */
|
|
virtual void generateTree() {
|
|
LTL2DSTAR_Tree_Rabin* rabin=0;
|
|
LTL2DSTAR_Tree_Streett* streett=0;
|
|
|
|
if (_options.automata==LTL2DSTAR_Options::RABIN ||
|
|
_options.automata==LTL2DSTAR_Options::RABIN_AND_STREETT) {
|
|
rabin=new LTL2DSTAR_Tree_Rabin(_ltl,
|
|
_options,
|
|
_sched);
|
|
}
|
|
|
|
if (_options.automata==LTL2DSTAR_Options::STREETT ||
|
|
_options.automata==LTL2DSTAR_Options::RABIN_AND_STREETT) {
|
|
streett=new LTL2DSTAR_Tree_Streett(_ltl->negate()->toPNF(),
|
|
_options,
|
|
_sched);
|
|
}
|
|
|
|
if (rabin!=0 && streett!=0) {
|
|
unsigned int rabin_est = rabin->guestimate();
|
|
unsigned int streett_est = streett->guestimate();
|
|
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << "NBA-Estimates: Rabin: "<<rabin_est <<
|
|
" Streett: " << streett_est << std::endl;
|
|
}
|
|
|
|
if (rabin_est <= streett_est) {
|
|
addChild(rabin);
|
|
addChild(streett);
|
|
} else {
|
|
addChild(streett);
|
|
addChild(rabin);
|
|
}
|
|
} else {
|
|
if (rabin!=0)
|
|
addChild(rabin);
|
|
if (streett!=0)
|
|
addChild(streett);
|
|
}
|
|
|
|
|
|
if (_options.opt_safra.stutter) {
|
|
StutterSensitivenessInformation::ptr stutter_information(new StutterSensitivenessInformation);
|
|
stutter_information->checkLTL(_ltl);
|
|
|
|
if (!stutter_information->isCompletelyInsensitive() && _options.opt_safra.partial_stutter_check) {
|
|
NBA_ptr nba, complement_nba;
|
|
if (rabin) {
|
|
nba=rabin->getNBA();
|
|
} else if (streett) {
|
|
nba=streett->getNBA();
|
|
}
|
|
|
|
if (rabin && streett) {
|
|
complement_nba=streett->getNBA();
|
|
}
|
|
|
|
if (!nba) {
|
|
stutter_information->checkPartial(*_ltl, _sched.getLTL2DRA());
|
|
} else if (!complement_nba) {
|
|
stutter_information->checkPartial(*nba, *_ltl->negate()->toPNF(), _sched.getLTL2DRA());
|
|
} else {
|
|
stutter_information->checkNBAs(*nba, *complement_nba);
|
|
}
|
|
}
|
|
|
|
if (rabin) {
|
|
rabin->setStutterInformation(stutter_information);
|
|
}
|
|
if (streett) {
|
|
streett->setStutterInformation(stutter_information);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/** A building block for the calculation of a Rabin automaton
|
|
* (via Safra, Scheck or Union) */
|
|
class LTL2DSTAR_Tree_Rabin : public LTL2DSTAR_Tree {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
|
|
LTL2DSTAR_Tree_Rabin(LTLFormula_ptr ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
LTL2DSTAR_Tree(ltl, options, sched),
|
|
_tree_normal(0), _tree_union(0) {
|
|
generateTree();
|
|
}
|
|
|
|
/** Estimate the size of the automaton (use the estimate of Safra's
|
|
* building block ) */
|
|
virtual unsigned int guestimate() {
|
|
if (_tree_normal!=0) {
|
|
return _tree_normal->guestimate();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** Hook after calculation */
|
|
virtual void hook_after_calculate() {
|
|
if (_tree_normal!=0 && _sched.flagStatNBA()) {
|
|
_comment = _comment + std::string("+NBAstd=")+
|
|
(boost::lexical_cast<std::string>(guestimate()));
|
|
}
|
|
}
|
|
|
|
/** Generate the tree */
|
|
virtual void generateTree() {
|
|
if (_options.scheck_path!="") {
|
|
if (LTL2DSTAR_Tree_Scheck::worksWith(*_ltl, _options.verbose_scheduler)) {
|
|
addChild(new LTL2DSTAR_Tree_Scheck(_ltl, _options, _sched));
|
|
|
|
}
|
|
// add stuff for path. check here
|
|
}
|
|
|
|
if (_options.allow_union &&
|
|
_ltl->getRootNode()->getType() == LTLNode::T_OR) {
|
|
_tree_union=new LTL2DSTAR_Tree_Union(_ltl, _options, _sched);
|
|
addChild(_tree_union);
|
|
}
|
|
|
|
|
|
if (!((_options.only_union && _options.allow_union) ||
|
|
(_options.only_safety && _options.safety))) {
|
|
_tree_normal=new LTL2DSTAR_Tree_Safra(_ltl, _options, _sched);
|
|
addChild(_tree_normal);
|
|
}
|
|
}
|
|
|
|
NBA_ptr getNBA() {
|
|
if (_tree_normal) {
|
|
return _tree_normal->getNBA();
|
|
}
|
|
return NBA_ptr((NBA_t*)0);
|
|
}
|
|
|
|
void setStutterInformation(StutterSensitivenessInformation::ptr stutter_information) {
|
|
_stutter_information=stutter_information;
|
|
if (_tree_normal) {
|
|
_tree_normal->setStutterInformation(_stutter_information);
|
|
}
|
|
|
|
if (_tree_union) {
|
|
_tree_union->setStutterInformation(_stutter_information);
|
|
}
|
|
}
|
|
private:
|
|
// memory will be freed by normal tree destructor
|
|
LTL2DSTAR_Tree_Safra *_tree_normal;
|
|
LTL2DSTAR_Tree_Union *_tree_union;
|
|
|
|
StutterSensitivenessInformation::ptr _stutter_information;
|
|
};
|
|
|
|
|
|
/** Building block for the translation from LTL to DRA using Safra's algorithm */
|
|
class LTL2DSTAR_Tree_Safra : public LTL2DSTAR_Tree {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
LTL2DSTAR_Tree_Safra(LTLFormula_ptr ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
LTL2DSTAR_Tree(ltl, options, sched) {
|
|
generateTree();
|
|
}
|
|
|
|
/** Generate the tree */
|
|
virtual void generateTree() {
|
|
}
|
|
|
|
/** Translate LTL -> NBA */
|
|
void generateNBA() {
|
|
if (_nba.get()==0) {
|
|
_nba = _sched.getLTL2DRA().ltl2nba(*_ltl);
|
|
}
|
|
}
|
|
|
|
NBA_ptr getNBA() {
|
|
generateNBA();
|
|
return _nba;
|
|
}
|
|
|
|
/** Estimate the size of the DRA (returns the size of the NBA) */
|
|
virtual unsigned int guestimate() {
|
|
generateNBA();
|
|
if (_nba.get()!=0) {
|
|
return _nba->size();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** Translate the LTL formula to DRA using Safra's algorithm */
|
|
virtual void calculate(int level, unsigned int limit) {
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << "Calculate ("<< level <<"): " << typeid(*this).name() << std::endl;
|
|
std::cerr << " Limit = " << limit << std::endl;
|
|
}
|
|
|
|
generateNBA();
|
|
|
|
if (_nba.get()==0) {
|
|
THROW_EXCEPTION(Exception, "Couldn't create NBA from LTL formula");
|
|
};
|
|
|
|
_automaton=_sched.getLTL2DRA().nba2dra(*_nba,
|
|
limit,
|
|
_options.detailed_states,
|
|
_stutter_information);
|
|
_comment=std::string("Safra[NBA=")+
|
|
boost::lexical_cast<std::string>(_nba->size())+
|
|
"]";
|
|
|
|
if (_options.optimizeAcceptance) {
|
|
_automaton->optimizeAcceptanceCondition();
|
|
}
|
|
|
|
if (_options.bisim) {
|
|
DRAOptimizations<DRA_t> dra_optimizer;
|
|
_automaton=dra_optimizer.optimizeBisimulation(*_automaton,
|
|
false,
|
|
_options.detailed_states,
|
|
false);
|
|
}
|
|
}
|
|
|
|
|
|
void setStutterInformation(StutterSensitivenessInformation::ptr stutter_information) {
|
|
_stutter_information=stutter_information;
|
|
}
|
|
private:
|
|
NBA_ptr _nba;
|
|
|
|
StutterSensitivenessInformation::ptr _stutter_information;
|
|
};
|
|
|
|
|
|
/** Generate DRA by using the union construction on two DRAs */
|
|
class LTL2DSTAR_Tree_Union : public LTL2DSTAR_Tree {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
|
|
LTL2DSTAR_Tree_Union(LTLFormula_ptr ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
LTL2DSTAR_Tree(ltl, options, sched), _left_tree(0), _right_tree(0) {
|
|
|
|
_left=
|
|
_ltl->getSubFormula(_ltl->getRootNode()->getLeft());
|
|
|
|
_right=
|
|
_ltl->getSubFormula(_ltl->getRootNode()->getRight());
|
|
|
|
generateTree();
|
|
}
|
|
|
|
/**
|
|
* Generate the tree
|
|
*/
|
|
virtual void generateTree() {
|
|
LTL2DSTAR_Options rec_opt=_options;
|
|
rec_opt.recursion();
|
|
_left_tree=new LTL2DSTAR_Tree_Rabin(_left, rec_opt, _sched);
|
|
addChild(_left_tree);
|
|
_right_tree=new LTL2DSTAR_Tree_Rabin(_right, rec_opt, _sched);
|
|
addChild(_right_tree);
|
|
}
|
|
|
|
/**
|
|
* Perform union construction
|
|
*/
|
|
virtual void calculate(int level, unsigned int limit) {
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << "Calculate ("<< level <<"): " << typeid(*this).name() << std::endl;
|
|
}
|
|
|
|
try {
|
|
children[0]->calculate(level+1, limit);
|
|
children[1]->calculate(level+1, limit);
|
|
} catch (LimitReachedException& e) {
|
|
_automaton.reset();
|
|
return;
|
|
}
|
|
|
|
if (children[0]->_automaton.get()==0 ||
|
|
children[1]->_automaton.get()==0) {
|
|
return;
|
|
}
|
|
|
|
bool union_trueloop=_sched.getLTL2DRA().getOptions().union_trueloop;
|
|
if (_sched.getLTL2DRA().getOptions().stutter) {
|
|
_automaton=DRA_t::calculateUnionStuttered(*children[0]->_automaton,
|
|
*children[1]->_automaton,
|
|
_stutter_information,
|
|
union_trueloop,
|
|
_options.detailed_states);
|
|
} else {
|
|
_automaton=DRA_t::calculateUnion(*children[0]->_automaton,
|
|
*children[1]->_automaton,
|
|
union_trueloop,
|
|
_options.detailed_states);
|
|
/* _automaton=DRAOperations::dra_union(*children[0]->_automaton,
|
|
*children[1]->_automaton,
|
|
union_trueloop,
|
|
_options.detailed_states); */
|
|
}
|
|
_comment=std::string("Union{")+
|
|
children[0]->_comment+","+
|
|
children[1]->_comment+"}";
|
|
|
|
if (_options.optimizeAcceptance) {
|
|
_automaton->optimizeAcceptanceCondition();
|
|
}
|
|
|
|
if (_options.bisim) {
|
|
DRAOptimizations<DRA_t> dra_optimizer;
|
|
_automaton=dra_optimizer.optimizeBisimulation(*_automaton,
|
|
false,
|
|
_options.detailed_states,
|
|
false);
|
|
}
|
|
|
|
hook_after_calculate();
|
|
}
|
|
|
|
|
|
void setStutterInformation(StutterSensitivenessInformation::ptr stutter_information) {
|
|
_stutter_information=stutter_information;
|
|
|
|
StutterSensitivenessInformation::ptr
|
|
left_stutter_info(new StutterSensitivenessInformation(*stutter_information));
|
|
StutterSensitivenessInformation::ptr
|
|
right_stutter_info(new StutterSensitivenessInformation(*stutter_information));
|
|
|
|
if (!stutter_information->isCompletelyInsensitive()) {
|
|
left_stutter_info->checkLTL(_left);
|
|
right_stutter_info->checkLTL(_right);
|
|
}
|
|
|
|
if (!left_stutter_info->isCompletelyInsensitive()) {
|
|
left_stutter_info->checkPartial(*_left_tree->getNBA(),
|
|
*_left->negate()->toPNF(),
|
|
_sched.getLTL2DRA());
|
|
}
|
|
|
|
if (!right_stutter_info->isCompletelyInsensitive()) {
|
|
right_stutter_info->checkPartial(*_right_tree->getNBA(),
|
|
*_right->negate()->toPNF(),
|
|
_sched.getLTL2DRA());
|
|
}
|
|
|
|
_left_tree->setStutterInformation(left_stutter_info);
|
|
_right_tree->setStutterInformation(right_stutter_info);
|
|
}
|
|
|
|
LTL2DSTAR_Tree_Rabin *_left_tree;
|
|
LTL2DSTAR_Tree_Rabin *_right_tree;
|
|
|
|
LTLFormula_ptr _left;
|
|
LTLFormula_ptr _right;
|
|
|
|
StutterSensitivenessInformation::ptr _stutter_information;
|
|
};
|
|
|
|
|
|
/**
|
|
* Generate Streett automaton by calculating the Rabin automaton
|
|
* for the negated formula
|
|
*/
|
|
class LTL2DSTAR_Tree_Streett : public LTL2DSTAR_Tree {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
|
|
LTL2DSTAR_Tree_Streett(LTLFormula_ptr ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
LTL2DSTAR_Tree(ltl, options, sched) {
|
|
generateTree();
|
|
}
|
|
|
|
/** Estimate automaton size (use estimate of Rabin building block) */
|
|
virtual unsigned int guestimate() {
|
|
if (children[0]!=0) {
|
|
return children[0]->guestimate();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
NBA_ptr getNBA() {
|
|
if (_tree_rabin) {
|
|
return _tree_rabin->getNBA();
|
|
}
|
|
return NBA_ptr((NBA_t*)0);
|
|
}
|
|
|
|
|
|
/** Generate tree */
|
|
virtual void generateTree() {
|
|
LTL2DSTAR_Options opt=_options;
|
|
opt.automata=LTL2DSTAR_Options::RABIN;
|
|
opt.scheck_path=""; // disable scheck
|
|
_tree_rabin=new LTL2DSTAR_Tree_Rabin(_ltl,
|
|
opt,
|
|
_sched);
|
|
addChild(_tree_rabin);
|
|
}
|
|
|
|
/** Calculate */
|
|
virtual void calculate(int level, unsigned int limit) {
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << "Calculate ("<< level <<"): " << typeid(*this).name() << std::endl;
|
|
}
|
|
|
|
try {
|
|
children[0]->calculate(level, limit);
|
|
} catch (LimitReachedException& e) {
|
|
_automaton.reset();
|
|
return;
|
|
}
|
|
|
|
_automaton=children[0]->_automaton;
|
|
_comment=std::string("Streett{")+
|
|
children[0]->_comment+"}";
|
|
|
|
if (_automaton.get()!=0) {
|
|
_automaton->considerAsStreett();
|
|
}
|
|
|
|
hook_after_calculate();
|
|
}
|
|
|
|
void setStutterInformation(StutterSensitivenessInformation::ptr stutter_information) {
|
|
_stutter_information=stutter_information;
|
|
_tree_rabin->setStutterInformation(stutter_information);
|
|
}
|
|
|
|
private:
|
|
LTL2DSTAR_Tree_Rabin* _tree_rabin;
|
|
StutterSensitivenessInformation::ptr _stutter_information;
|
|
};
|
|
|
|
|
|
/**
|
|
* Use Scheck to generate a DBA (transformed into a DRA) for a (co-)safe LTL formula
|
|
*/
|
|
class LTL2DSTAR_Tree_Scheck : public LTL2DSTAR_Tree {
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param ltl The LTL formula
|
|
* @param options the LTL2DSTAR options
|
|
* @param sched a reference back to the scheduler
|
|
*/
|
|
|
|
LTL2DSTAR_Tree_Scheck(LTLFormula_ptr ltl,
|
|
LTL2DSTAR_Options options,
|
|
LTL2DSTAR_Scheduler& sched) :
|
|
LTL2DSTAR_Tree(ltl, options, sched) {
|
|
generateTree();
|
|
}
|
|
|
|
/** Check if the formula is syntactically (co-)safe */
|
|
static bool worksWith(LTLFormula& ltl, bool verbose=false) {
|
|
if (ltl.isSafe()) {
|
|
if (verbose) {
|
|
std::cerr << "Formula is safe" << std::endl;
|
|
}
|
|
return true;
|
|
} else if (ltl.isCoSafe()) {
|
|
if (verbose) {
|
|
std::cerr << "Formula is cosafe" << std::endl;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Generate tree */
|
|
virtual void generateTree() {
|
|
}
|
|
|
|
/** Calculate */
|
|
virtual void calculate(int level, unsigned int limit) {
|
|
if (_options.verbose_scheduler) {
|
|
std::cerr << "Calculate ("<< level <<"): " << typeid(*this).name() << std::endl;
|
|
}
|
|
|
|
LTLSafetyAutomata lsa;
|
|
_automaton=lsa.ltl2dra<DRA_t>(*_ltl, _options.scheck_path);
|
|
|
|
if (_automaton.get()==0) {return;}
|
|
_comment=std::string("Scheck");
|
|
|
|
if (_options.optimizeAcceptance) {
|
|
_automaton->optimizeAcceptanceCondition();
|
|
}
|
|
|
|
/* not really necessary with scheck
|
|
if (_options.bisim) {
|
|
DRAOptimizations<DRA_t> dra_optimizer;
|
|
_automaton=dra_optimizer.optimizeBisimulation(*_automaton,
|
|
false,
|
|
_options.detailed_states,
|
|
false);
|
|
} */
|
|
|
|
hook_after_calculate();
|
|
}
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Calculate the new limit using factor alpha (returns 0 if no limit) */
|
|
unsigned int LTL2DSTAR_Scheduler::calcLimit(unsigned int limit) {
|
|
if (limit==0) {return limit;}
|
|
if (flagOptLimits()) {
|
|
double new_limit=(limit*_alpha)+1.0;
|
|
if (new_limit > (std::numeric_limits<unsigned int>::max)()) {
|
|
limit = 0;
|
|
} else {
|
|
limit=(unsigned int)new_limit;
|
|
}
|
|
}
|
|
|
|
return limit;
|
|
}
|
|
|
|
/** Constructor
|
|
* @param ltl2dra the wrapper for LTL->NBA and NBA->DRA
|
|
* @param opt_limits use limiting?
|
|
* @param alpha the limiting factor
|
|
*/
|
|
LTL2DSTAR_Scheduler::LTL2DSTAR_Scheduler(LTL2DRA& ltl2dra,
|
|
bool opt_limits,
|
|
double alpha) :
|
|
_ltl2dra(ltl2dra), _opt_limits(opt_limits), _alpha(alpha),
|
|
_stat_NBA(false)
|
|
{}
|
|
|
|
|
|
/**
|
|
* Generate a DRA/DSA for the LTL formula
|
|
*/
|
|
DRA_ptr LTL2DSTAR_Scheduler::calculate(LTLFormula& ltl, LTL2DSTAR_Options ltl_opt) {
|
|
LTLFormula_ptr ltl_p(ltl.toPNF());
|
|
|
|
if (ltl_opt.verbose_scheduler) {
|
|
std::cerr << ltl_p->toStringInfix() << std::endl;
|
|
}
|
|
|
|
LTL2DSTAR_Scheduler_Trees::LTL2DSTAR_Tree_Start root(ltl_p, ltl_opt, *this);
|
|
|
|
if (ltl_opt.verbose_scheduler) {
|
|
root.printTree(std::cerr);
|
|
}
|
|
|
|
root.calculate();
|
|
|
|
DRA_ptr result=root._automaton;
|
|
if (result.get()!=0) {
|
|
result->setComment(root._comment+getTimingInformation());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string LTL2DSTAR_Scheduler::getTimingInformation() {
|
|
if (StutterSensitivenessInformation::hasTimekeeping()) {
|
|
unsigned long ms=StutterSensitivenessInformation::getTimeKeeper().getElapsedMilliseconds();
|
|
return " TIME(stuttercheck)=:"+
|
|
boost::lexical_cast<std::string>(ms)+
|
|
":";
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/** Get the LTL2DRA wrapper class */
|
|
LTL2DRA& LTL2DSTAR_Scheduler::getLTL2DRA() {
|
|
return _ltl2dra;
|
|
}
|