Browse Source
(DA) Automata classes: DeterministicAutomaton, APSet, HOAConsumer, AcceptanceCondition
(DA) Automata classes: DeterministicAutomaton, APSet, HOAConsumer, AcceptanceCondition
Adapted from ltl2dstar.tempestpy_adaptions
Joachim Klein
4 years ago
committed by
Stefan Pranger
9 changed files with 863 additions and 0 deletions
-
65src/storm/automata/APSet.cpp
-
33src/storm/automata/APSet.h
-
100src/storm/automata/AcceptanceCondition.cpp
-
36src/storm/automata/AcceptanceCondition.h
-
103src/storm/automata/DeterministicAutomaton.cpp
-
46src/storm/automata/DeterministicAutomaton.h
-
237src/storm/automata/HOAConsumerDA.h
-
217src/storm/automata/HOAConsumerDAHeader.h
-
26src/storm/automata/HOAHeader.h
@ -0,0 +1,65 @@ |
|||
|
|||
#include "storm/automata/APSet.h"
|
|||
|
|||
#include <string>
|
|||
#include <exception>
|
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
|
|||
APSet::APSet() { |
|||
// intentionally left blank
|
|||
} |
|||
|
|||
unsigned int APSet::size() const { |
|||
return index_to_ap.size(); |
|||
} |
|||
|
|||
std::size_t APSet::alphabetSize() const { |
|||
return 1L << size(); |
|||
} |
|||
|
|||
void APSet::add(const std::string& ap) { |
|||
if (size() >= MAX_APS) |
|||
throw std::runtime_error("Set of atomic proposition size is limited to " + std::to_string(MAX_APS)); |
|||
|
|||
unsigned int index = size(); |
|||
bool fresh = ap_to_index.insert(std::make_pair(ap, index)).second; |
|||
if (!fresh) |
|||
throw std::runtime_error("Duplicate atomic proposition '" + ap + "' in APSet"); |
|||
index_to_ap.push_back(ap); |
|||
} |
|||
|
|||
unsigned int APSet::getIndex(const std::string& ap) const { |
|||
// throws out_of_range if ap is not in the set
|
|||
return ap_to_index.at(ap); |
|||
} |
|||
|
|||
const std::string& APSet::getAP(unsigned int index) const { |
|||
// throws out_of_range if index is out of range
|
|||
return index_to_ap.at(index); |
|||
} |
|||
|
|||
const std::vector<std::string>& APSet::getAPs() const { |
|||
return index_to_ap; |
|||
} |
|||
|
|||
|
|||
bool APSet::contains(const std::string& ap) const { |
|||
return ap_to_index.find(ap) != ap_to_index.end(); |
|||
} |
|||
|
|||
APSet::alphabet_element APSet::elementAllFalse() const { |
|||
return 0; |
|||
} |
|||
|
|||
APSet::alphabet_element APSet::elementAddAP(alphabet_element element, unsigned int ap) const { |
|||
if (ap >= size()) { |
|||
throw std::runtime_error("AP out of range"); |
|||
} |
|||
|
|||
return element | (1ul << ap); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,33 @@ |
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <map> |
|||
#include <string> |
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
class APSet { |
|||
public: |
|||
// TODO: uint32 |
|||
typedef std::size_t alphabet_element; |
|||
|
|||
APSet(); |
|||
|
|||
unsigned int size() const; |
|||
std::size_t alphabetSize() const; |
|||
void add(const std::string& ap); |
|||
unsigned int getIndex(const std::string& ap) const; |
|||
bool contains(const std::string& ap) const; |
|||
const std::string& getAP(unsigned int index) const; |
|||
const std::vector<std::string>& getAPs() const; |
|||
|
|||
alphabet_element elementAllFalse() const; |
|||
alphabet_element elementAddAP(alphabet_element element, unsigned int ap) const; |
|||
|
|||
const unsigned int MAX_APS = 32; |
|||
private: |
|||
std::map<std::string, unsigned int> ap_to_index; |
|||
std::vector<std::string> index_to_ap; |
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,100 @@ |
|||
#include "AcceptanceCondition.h"
|
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
|
|||
AcceptanceCondition::AcceptanceCondition(std::size_t numberOfStates, unsigned int numberOfAcceptanceSets, acceptance_expr::ptr acceptance) |
|||
: numberOfStates(numberOfStates), numberOfAcceptanceSets(numberOfAcceptanceSets), acceptance(acceptance) { |
|||
|
|||
// initialize acceptance sets
|
|||
for (unsigned int i = 0; i < numberOfAcceptanceSets; i++) { |
|||
acceptanceSets.push_back(storm::storage::BitVector(numberOfStates)); |
|||
} |
|||
} |
|||
|
|||
unsigned int AcceptanceCondition::getNumberOfAcceptanceSets() const { |
|||
return numberOfAcceptanceSets; |
|||
} |
|||
|
|||
|
|||
storm::storage::BitVector& AcceptanceCondition::getAcceptanceSet(unsigned int index) { |
|||
return acceptanceSets.at(index); |
|||
} |
|||
|
|||
const storm::storage::BitVector& AcceptanceCondition::getAcceptanceSet(unsigned int index) const { |
|||
return acceptanceSets.at(index); |
|||
} |
|||
|
|||
AcceptanceCondition::acceptance_expr::ptr AcceptanceCondition::getAcceptanceExpression() const { |
|||
return acceptance; |
|||
} |
|||
|
|||
|
|||
bool AcceptanceCondition::isAccepting(const storm::storage::StateBlock& scc) const { |
|||
return isAccepting(scc, acceptance); |
|||
} |
|||
|
|||
bool AcceptanceCondition::isAccepting(const storm::storage::StateBlock& scc, acceptance_expr::ptr expr) const { |
|||
switch (expr->getType()) { |
|||
case acceptance_expr::EXP_AND: |
|||
return isAccepting(scc, expr->getLeft()) && isAccepting(scc, expr->getRight()); |
|||
case acceptance_expr::EXP_OR: |
|||
return isAccepting(scc, expr->getLeft()) && isAccepting(scc, expr->getRight()); |
|||
case acceptance_expr::EXP_NOT: |
|||
return !isAccepting(scc, expr->getLeft()); |
|||
case acceptance_expr::EXP_TRUE: |
|||
return true; |
|||
case acceptance_expr::EXP_FALSE: |
|||
return false; |
|||
case acceptance_expr::EXP_ATOM: { |
|||
const cpphoafparser::AtomAcceptance& atom = expr->getAtom(); |
|||
const storm::storage::BitVector& acceptanceSet = acceptanceSets.at(atom.getAcceptanceSet()); |
|||
bool negated = atom.isNegated(); |
|||
bool rv; |
|||
switch (atom.getType()) { |
|||
case cpphoafparser::AtomAcceptance::TEMPORAL_INF: |
|||
rv = false; |
|||
for (auto& state : scc) { |
|||
if (acceptanceSet.get(state)) { |
|||
rv = true; |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
case cpphoafparser::AtomAcceptance::TEMPORAL_FIN: |
|||
rv = true; |
|||
for (auto& state : scc) { |
|||
if (acceptanceSet.get(state)) { |
|||
rv = false; |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
|
|||
return (negated ? !rv : rv); |
|||
} |
|||
} |
|||
|
|||
throw std::runtime_error("Missing case statement"); |
|||
} |
|||
|
|||
AcceptanceCondition::ptr AcceptanceCondition::lift(std::size_t productNumberOfStates, std::function<std::size_t (std::size_t)> mapping) const { |
|||
AcceptanceCondition::ptr lifted(new AcceptanceCondition(productNumberOfStates, numberOfAcceptanceSets, acceptance)); |
|||
for (unsigned int i = 0; i < numberOfAcceptanceSets; i++) { |
|||
const storm::storage::BitVector& set = getAcceptanceSet(i); |
|||
storm::storage::BitVector& liftedSet = lifted->getAcceptanceSet(i); |
|||
|
|||
for (std::size_t prodState = 0; prodState < productNumberOfStates; prodState++) { |
|||
if (set.get(mapping(prodState))) { |
|||
liftedSet.set(prodState); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return lifted; |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
#pragma once |
|||
|
|||
#include <functional> |
|||
#include <vector> |
|||
#include <memory> |
|||
#include "storm/storage/BitVector.h" |
|||
#include "storm/storage/StateBlock.h" |
|||
#include "cpphoafparser/consumer/hoa_consumer.hh" |
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
class AcceptanceCondition { |
|||
public: |
|||
typedef std::shared_ptr<AcceptanceCondition> ptr; |
|||
typedef cpphoafparser::HOAConsumer::acceptance_expr acceptance_expr; |
|||
|
|||
AcceptanceCondition(std::size_t numberOfStates, unsigned int numberOfAcceptanceSets, acceptance_expr::ptr acceptance); |
|||
bool isAccepting(const storm::storage::StateBlock& scc) const ; |
|||
|
|||
unsigned int getNumberOfAcceptanceSets() const; |
|||
storm::storage::BitVector& getAcceptanceSet(unsigned int index); |
|||
const storm::storage::BitVector& getAcceptanceSet(unsigned int index) const; |
|||
|
|||
acceptance_expr::ptr getAcceptanceExpression() const; |
|||
|
|||
AcceptanceCondition::ptr lift(std::size_t productNumberOfStates, std::function<std::size_t (std::size_t)> mapping) const; |
|||
private: |
|||
bool isAccepting(const storm::storage::StateBlock& scc, acceptance_expr::ptr expr) const; |
|||
|
|||
std::size_t numberOfStates; |
|||
unsigned int numberOfAcceptanceSets; |
|||
acceptance_expr::ptr acceptance; |
|||
std::vector<storm::storage::BitVector> acceptanceSets; |
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,103 @@ |
|||
#include "storm/automata/DeterministicAutomaton.h"
|
|||
#include "storm/automata/AcceptanceCondition.h"
|
|||
#include "storm/automata/HOAConsumerDA.h"
|
|||
#include "cpphoafparser/parser/hoa_parser.hh"
|
|||
#include "cpphoafparser/parser/hoa_parser_helper.hh"
|
|||
#include "cpphoafparser/consumer/hoa_intermediate_check_validity.hh"
|
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
DeterministicAutomaton::DeterministicAutomaton(APSet apSet, std::size_t numberOfStates, std::size_t initialState, AcceptanceCondition::ptr acceptance) |
|||
: apSet(apSet), numberOfStates(numberOfStates), initialState(initialState), acceptance(acceptance) { |
|||
// TODO: this could overflow, add check?
|
|||
edgesPerState = apSet.alphabetSize(); |
|||
numberOfEdges = numberOfStates * edgesPerState; |
|||
successors.resize(numberOfEdges); |
|||
} |
|||
|
|||
std::size_t DeterministicAutomaton::getInitialState() const { |
|||
return initialState; |
|||
} |
|||
|
|||
const APSet& DeterministicAutomaton::getAPSet() const { |
|||
return apSet; |
|||
} |
|||
|
|||
std::size_t DeterministicAutomaton::getSuccessor(std::size_t from, APSet::alphabet_element label) const { |
|||
std::size_t index = from * edgesPerState + label; |
|||
return successors.at(index); |
|||
} |
|||
|
|||
void DeterministicAutomaton::setSuccessor(std::size_t from, APSet::alphabet_element label, std::size_t successor) { |
|||
std::size_t index = from * edgesPerState + label; |
|||
successors.at(index) = successor; |
|||
} |
|||
|
|||
std::size_t DeterministicAutomaton::getNumberOfStates() const { |
|||
return numberOfStates; |
|||
} |
|||
|
|||
std::size_t DeterministicAutomaton::getNumberOfEdgesPerState() const { |
|||
return edgesPerState; |
|||
} |
|||
|
|||
AcceptanceCondition::ptr DeterministicAutomaton::getAcceptance() const { |
|||
return acceptance; |
|||
} |
|||
|
|||
|
|||
void DeterministicAutomaton::printHOA(std::ostream& out) const { |
|||
out << "HOA: v1\n"; |
|||
|
|||
out << "States: " << numberOfStates << "\n"; |
|||
|
|||
out << "Start: " << initialState << "\n"; |
|||
|
|||
out << "AP: " << apSet.size(); |
|||
for (unsigned int i = 0; i < apSet.size(); i++) { |
|||
out << " " << cpphoafparser::HOAParserHelper::quote(apSet.getAP(i)); |
|||
} |
|||
out << "\n"; |
|||
|
|||
out << "Acceptance: " << acceptance->getNumberOfAcceptanceSets() << " " << *acceptance->getAcceptanceExpression() << "\n"; |
|||
|
|||
out << "--BODY--" << "\n"; |
|||
|
|||
for (std::size_t s = 0; s < getNumberOfStates(); s++) { |
|||
out << "State: " << s; |
|||
out << " {"; |
|||
bool first = true; |
|||
for (unsigned int i = 0; i < acceptance->getNumberOfAcceptanceSets(); i++) { |
|||
if (acceptance->getAcceptanceSet(i).get(s)) { |
|||
if (!first) |
|||
out << " "; |
|||
first = false; |
|||
out << i; |
|||
} |
|||
} |
|||
out << "}\n"; |
|||
for (std::size_t label = 0; label < getNumberOfEdgesPerState(); label++) { |
|||
out << getSuccessor(s, label) << "\n"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
DeterministicAutomaton::ptr DeterministicAutomaton::parse(std::istream& in) { |
|||
HOAConsumerDA::ptr consumer(new HOAConsumerDA()); |
|||
cpphoafparser::HOAIntermediateCheckValidity::ptr validator(new cpphoafparser::HOAIntermediateCheckValidity(consumer)); |
|||
cpphoafparser::HOAParser::parse(in, validator); |
|||
|
|||
return consumer->getDA(); |
|||
} |
|||
|
|||
DeterministicAutomaton::ptr DeterministicAutomaton::parseFromFile(const std::string& filename) { |
|||
std::ifstream in(filename); |
|||
return parse(in); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
|
@ -0,0 +1,46 @@ |
|||
#pragma once |
|||
|
|||
#include <iostream> |
|||
#include <memory> |
|||
#include "storm/automata/APSet.h" |
|||
|
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
// fwd |
|||
class AcceptanceCondition; |
|||
|
|||
class DeterministicAutomaton { |
|||
public: |
|||
typedef std::shared_ptr<DeterministicAutomaton> ptr; |
|||
|
|||
DeterministicAutomaton(APSet apSet, std::size_t numberOfStates, std::size_t initialState, std::shared_ptr<AcceptanceCondition> acceptance); |
|||
|
|||
const APSet& getAPSet() const; |
|||
|
|||
std::size_t getInitialState() const; |
|||
|
|||
std::size_t getSuccessor(std::size_t from, APSet::alphabet_element label) const; |
|||
void setSuccessor(std::size_t from, APSet::alphabet_element label, std::size_t successor); |
|||
|
|||
std::size_t getNumberOfStates() const; |
|||
std::size_t getNumberOfEdgesPerState() const; |
|||
|
|||
std::shared_ptr<AcceptanceCondition> getAcceptance() const; |
|||
|
|||
void printHOA(std::ostream& out) const; |
|||
|
|||
static DeterministicAutomaton::ptr parse(std::istream& in); |
|||
static DeterministicAutomaton::ptr parseFromFile(const std::string& filename); |
|||
|
|||
private: |
|||
APSet apSet; |
|||
std::size_t numberOfStates; |
|||
std::size_t initialState; |
|||
std::size_t numberOfEdges; |
|||
std::size_t edgesPerState; |
|||
std::shared_ptr<AcceptanceCondition> acceptance; |
|||
std::vector<std::size_t> successors; |
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,237 @@ |
|||
#pragma once |
|||
|
|||
#include "storm/automata/APSet.h" |
|||
#include "storm/automata/DeterministicAutomaton.h" |
|||
#include "storm/automata/HOAConsumerDAHeader.h" |
|||
#include "storm/exceptions/OutOfRangeException.h" |
|||
#include "storm/exceptions/InvalidOperationException.h" |
|||
#include "storm/storage/BitVector.h" |
|||
#include "storm/storage/SparseMatrix.h" |
|||
#include "storm/storage/expressions/ExpressionManager.h" |
|||
#include "storm/solver/SmtSolver.h" |
|||
#include "storm/utility/solver.h" |
|||
|
|||
#include "cpphoafparser/consumer/hoa_consumer.hh" |
|||
#include "cpphoafparser/util/implicit_edge_helper.hh" |
|||
|
|||
#include <boost/optional.hpp> |
|||
#include <exception> |
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
|
|||
class HOAConsumerDA : public HOAConsumerDAHeader { |
|||
private: |
|||
AcceptanceCondition::ptr acceptance; |
|||
|
|||
DeterministicAutomaton::ptr da; |
|||
cpphoafparser::ImplicitEdgeHelper *helper = nullptr; |
|||
|
|||
std::shared_ptr<storm::expressions::ExpressionManager> expressionManager; |
|||
std::vector<storm::expressions::Variable> apVariables; |
|||
std::unique_ptr<storm::solver::SmtSolver> solver; |
|||
|
|||
storm::storage::BitVector seenEdges; |
|||
|
|||
public: |
|||
typedef std::shared_ptr<HOAConsumerDA> ptr; |
|||
|
|||
HOAConsumerDA() : seenEdges(0) { |
|||
expressionManager.reset(new storm::expressions::ExpressionManager()); |
|||
storm::utility::solver::SmtSolverFactory factory; |
|||
solver = factory.create(*expressionManager); |
|||
} |
|||
|
|||
~HOAConsumerDA() { |
|||
delete helper; |
|||
} |
|||
|
|||
DeterministicAutomaton::ptr getDA() { |
|||
return da; |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify that the BODY of the automaton has started [mandatory, once]. |
|||
*/ |
|||
virtual void notifyBodyStart() { |
|||
if (!header.numberOfStates) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Missing number-of-states header"); |
|||
} |
|||
|
|||
acceptance = header.getAcceptanceCondition(); |
|||
da.reset(new DeterministicAutomaton(header.apSet, *header.numberOfStates, *header.startState, acceptance)); |
|||
|
|||
helper = new cpphoafparser::ImplicitEdgeHelper(header.apSet.size()); |
|||
|
|||
seenEdges.resize(*header.numberOfStates * helper->getEdgesPerState()); |
|||
|
|||
for (const std::string& ap : header.apSet.getAPs()) { |
|||
apVariables.push_back(expressionManager->declareBooleanVariable(ap)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each "State: ..." item [multiple]. |
|||
* @param id the identifier for this state |
|||
* @param info an optional string providing additional information about the state (empty pointer if not provided) |
|||
* @param labelExpr an optional boolean expression over labels (state-labeled) (empty pointer if not provided) |
|||
* @param accSignature an optional list of acceptance set indizes (state-labeled acceptance) (empty pointer if not provided) |
|||
*/ |
|||
virtual void addState(unsigned int id, std::shared_ptr<std::string> info, label_expr::ptr labelExpr, std::shared_ptr<int_list> accSignature) { |
|||
if (accSignature) { |
|||
for (unsigned int accSet : *accSignature) { |
|||
acceptance->getAcceptanceSet(accSet).set(id); |
|||
} |
|||
} |
|||
|
|||
if (labelExpr) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: State-labeled automata not supported"); |
|||
} |
|||
|
|||
helper->startOfState(id); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each implicit edge definition [multiple], i.e., |
|||
* where the edge label is deduced from the index of the edge. |
|||
* |
|||
* If the edges are provided in implicit form, after every `addState()` there should be 2^|AP| calls to |
|||
* `addEdgeImplicit`. The corresponding boolean expression over labels / BitSet |
|||
* can be obtained by calling BooleanExpression.fromImplicit(i-1) for the i-th call of this function per state. |
|||
* |
|||
* @param stateId the index of the 'from' state |
|||
* @param conjSuccessors a list of successor state indizes, interpreted as a conjunction |
|||
* @param accSignature an optional list of acceptance set indizes (transition-labeled acceptance) (empty pointer if not provided) |
|||
*/ |
|||
virtual void addEdgeImplicit(unsigned int stateId, const int_list& conjSuccessors, std::shared_ptr<int_list> accSignature) { |
|||
std::size_t edgeIndex = helper->nextImplicitEdge(); |
|||
|
|||
if (conjSuccessors.size() != 1) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Does not support alternation (conjunction of successor states)"); |
|||
} |
|||
|
|||
if (accSignature) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Does not support transition-based acceptance"); |
|||
} |
|||
|
|||
da->setSuccessor(stateId, edgeIndex, conjSuccessors.at(0)); |
|||
markEdgeAsSeen(stateId, edgeIndex); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each explicit edge definition [optional, multiple], i.e., |
|||
* where the label is either specified for the edge or as a state-label. |
|||
* <br/> |
|||
* @param stateId the index of the 'from' state |
|||
* @param labelExpr a boolean expression over labels (empty pointer if none provided, only in case of state-labeled states) |
|||
* @param conjSuccessors a list of successors state indizes, interpreted as a conjunction |
|||
* @param accSignature an optional list of acceptance set indizes (transition-labeled acceptance) (empty pointer if none provided) |
|||
*/ |
|||
virtual void addEdgeWithLabel(unsigned int stateId, label_expr::ptr labelExpr, const int_list& conjSuccessors, std::shared_ptr<int_list> accSignature) { |
|||
if (conjSuccessors.size() != 1) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Does not support alternation (conjunction of successor states)"); |
|||
} |
|||
|
|||
if (accSignature) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Does not support transition-based acceptance"); |
|||
} |
|||
|
|||
std::size_t successor = conjSuccessors.at(0); |
|||
|
|||
solver->reset(); |
|||
solver->add(labelToStormExpression(labelExpr)); |
|||
|
|||
solver->allSat(apVariables, |
|||
[this, stateId, successor] (storm::expressions::SimpleValuation& valuation) { |
|||
// construct edge index from valuation |
|||
APSet::alphabet_element edgeIndex = header.apSet.elementAllFalse(); |
|||
for (std::size_t i = 0; i < apVariables.size(); i++) { |
|||
if (valuation.getBooleanValue(apVariables[i])) { |
|||
edgeIndex = header.apSet.elementAddAP(edgeIndex, i); |
|||
} |
|||
} |
|||
|
|||
// require: edge already exists -> same successor |
|||
STORM_LOG_THROW(!alreadyHaveEdge(stateId, edgeIndex) || da->getSuccessor(stateId, edgeIndex) == successor, |
|||
storm::exceptions::InvalidOperationException, "HOA automaton: multiple definitions of successor for state " << stateId << " and edge " << edgeIndex); |
|||
|
|||
// std::cout << stateId << " -(" << edgeIndex << ")-> " << successor << std::endl; |
|||
da->setSuccessor(stateId, edgeIndex, successor); |
|||
markEdgeAsSeen(stateId, edgeIndex); |
|||
|
|||
// continue with next valuation |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify the consumer that the definition for state `stateId` |
|||
* has ended [multiple]. |
|||
*/ |
|||
virtual void notifyEndOfState(unsigned int stateId) { |
|||
helper->endOfState(); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify the consumer that the automata definition has ended [mandatory, once]. |
|||
*/ |
|||
virtual void notifyEnd() { |
|||
// require that we have seen all edges, i.e., that the automaton is complete |
|||
STORM_LOG_THROW(seenEdges.full(), |
|||
storm::exceptions::InvalidOperationException, "HOA automaton has mismatch in number of edges, not complete?"); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify the consumer that an "ABORT" message has been encountered |
|||
* (at any time, indicating error, the automaton should be discarded). |
|||
*/ |
|||
virtual void notifyAbort() { |
|||
throw std::runtime_error("Parsing deterministic automaton: Automaton is incomplete (abort)"); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Is called whenever a condition is encountered that merits a (non-fatal) warning. |
|||
* The consumer is free to handle this situation as it wishes. |
|||
*/ |
|||
virtual void notifyWarning(const std::string& warning) { |
|||
// IGNORE |
|||
(void)warning; |
|||
} |
|||
|
|||
private: |
|||
storm::expressions::Expression labelToStormExpression(label_expr::ptr labelExpr) { |
|||
switch (labelExpr->getType()) { |
|||
case label_expr::EXP_AND: |
|||
return labelToStormExpression(labelExpr->getLeft()) && labelToStormExpression(labelExpr->getRight()); |
|||
case label_expr::EXP_OR: |
|||
return labelToStormExpression(labelExpr->getLeft()) || labelToStormExpression(labelExpr->getRight()); |
|||
case label_expr::EXP_NOT: |
|||
return !labelToStormExpression(labelExpr->getLeft()); |
|||
case label_expr::EXP_TRUE: |
|||
return expressionManager->boolean(true); |
|||
case label_expr::EXP_FALSE: |
|||
return expressionManager->boolean(false); |
|||
case label_expr::EXP_ATOM: { |
|||
unsigned int apIndex = labelExpr->getAtom().getAPIndex(); |
|||
STORM_LOG_THROW(apIndex < apVariables.size(), |
|||
storm::exceptions::OutOfRangeException, "HOA automaton refers to non-existing atomic proposition"); |
|||
return apVariables.at(apIndex).getExpression(); |
|||
} |
|||
} |
|||
throw std::runtime_error("Unknown label expression operator"); |
|||
} |
|||
|
|||
bool alreadyHaveEdge(std::size_t stateId, std::size_t edgeIndex) { |
|||
return seenEdges.get(stateId * helper->getEdgesPerState() + edgeIndex); |
|||
} |
|||
|
|||
void markEdgeAsSeen(std::size_t stateId, std::size_t edgeIndex) { |
|||
seenEdges.set(stateId * helper->getEdgesPerState() + edgeIndex); |
|||
} |
|||
|
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
@ -0,0 +1,217 @@ |
|||
#pragma once |
|||
|
|||
#include "storm/automata/APSet.h" |
|||
#include "storm/automata/DeterministicAutomaton.h" |
|||
#include "storm/automata/HOAHeader.h" |
|||
#include "storm/storage/BitVector.h" |
|||
#include "storm/storage/SparseMatrix.h" |
|||
#include "cpphoafparser/consumer/hoa_consumer.hh" |
|||
#include "cpphoafparser/util/implicit_edge_helper.hh" |
|||
|
|||
#include <boost/optional.hpp> |
|||
#include <exception> |
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
|
|||
class HOAConsumerDAHeader : public cpphoafparser::HOAConsumer { |
|||
protected: |
|||
HOAHeader header; |
|||
|
|||
public: |
|||
typedef std::shared_ptr<HOAConsumerDAHeader> ptr; |
|||
|
|||
struct header_parsing_done : public std::exception {}; |
|||
|
|||
HOAHeader& getHeader() { |
|||
return header; |
|||
} |
|||
|
|||
virtual bool parserResolvesAliases() { |
|||
return true; |
|||
} |
|||
|
|||
/** Called by the parser for the "HOA: version" item [mandatory, once]. */ |
|||
virtual void notifyHeaderStart(const std::string& version) { |
|||
// TODO: Check version |
|||
} |
|||
|
|||
/** Called by the parser for the "States: int(numberOfStates)" item [optional, once]. */ |
|||
virtual void setNumberOfStates(unsigned int numberOfStates) { |
|||
header.numberOfStates = numberOfStates; |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each "Start: state-conj" item [optional, multiple]. |
|||
* @param stateConjunction a list of state indizes, interpreted as a conjunction |
|||
**/ |
|||
virtual void addStartStates(const int_list& stateConjunction) { |
|||
if (header.startState) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Nondeterministic choice of start states not supported"); |
|||
} |
|||
if (stateConjunction.size() != 1) { |
|||
throw std::runtime_error("Parsing deterministic HOA automaton: Conjunctive choice of start states not supported"); |
|||
} |
|||
header.startState = stateConjunction.at(0); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for the "AP: ap-def" item [optional, once]. |
|||
* @param aps the list of atomic propositions |
|||
*/ |
|||
virtual void setAPs(const std::vector<std::string>& aps) { |
|||
for (const std::string& ap : aps) { |
|||
header.apSet.add(ap); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for the "Acceptance: acceptance-def" item [mandatory, once]. |
|||
* @param numberOfSets the number of acceptance sets used to tag state / transition acceptance |
|||
* @param accExpr a boolean expression over acceptance atoms |
|||
**/ |
|||
virtual void setAcceptanceCondition(unsigned int numberOfSets, acceptance_expr::ptr accExpr) { |
|||
header.numberOfAcceptanceSets = numberOfSets; |
|||
header.acceptance_expression = accExpr; |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each "acc-name: ..." item [optional, multiple]. |
|||
* @param name the provided name |
|||
* @param extraInfo the additional information for this item |
|||
* */ |
|||
virtual void provideAcceptanceName(const std::string& name, const std::vector<cpphoafparser::IntOrString>& extraInfo) { |
|||
header.accName = name; |
|||
header.accNameExtraInfo = extraInfo; |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each "Alias: alias-def" item [optional, multiple]. |
|||
* Will be called no matter the return value of `parserResolvesAliases()`. |
|||
* |
|||
* @param name the alias name (without @) |
|||
* @param labelExpr a boolean expression over labels |
|||
**/ |
|||
virtual void addAlias(const std::string& name, label_expr::ptr labelExpr) { |
|||
// IGNORE |
|||
(void)name; |
|||
(void)labelExpr; |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for the "name: ..." item [optional, once]. |
|||
**/ |
|||
virtual void setName(const std::string& name) { |
|||
// IGNORE |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for the "tool: ..." item [optional, once]. |
|||
* @param name the tool name |
|||
* @param version the tool version (option, empty pointer if not provided) |
|||
**/ |
|||
virtual void setTool(const std::string& name, std::shared_ptr<std::string> version) { |
|||
// IGNORE |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for the "properties: ..." item [optional, multiple]. |
|||
* @param properties a list of properties |
|||
*/ |
|||
virtual void addProperties(const std::vector<std::string>& properties) { |
|||
// TODO: check supported |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each unknown header item [optional, multiple]. |
|||
* @param name the name of the header (without ':') |
|||
* @param content a list of extra information provided by the header |
|||
*/ |
|||
virtual void addMiscHeader(const std::string& name, const std::vector<cpphoafparser::IntOrString>& content) { |
|||
// TODO: Check semantic headers |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify that the BODY of the automaton has started [mandatory, once]. |
|||
*/ |
|||
virtual void notifyBodyStart() { |
|||
throw header_parsing_done(); |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each "State: ..." item [multiple]. |
|||
* @param id the identifier for this state |
|||
* @param info an optional string providing additional information about the state (empty pointer if not provided) |
|||
* @param labelExpr an optional boolean expression over labels (state-labeled) (empty pointer if not provided) |
|||
* @param accSignature an optional list of acceptance set indizes (state-labeled acceptance) (empty pointer if not provided) |
|||
*/ |
|||
virtual void addState(unsigned int id, std::shared_ptr<std::string> info, label_expr::ptr labelExpr, std::shared_ptr<int_list> accSignature) { |
|||
// IGNORE |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each implicit edge definition [multiple], i.e., |
|||
* where the edge label is deduced from the index of the edge. |
|||
* |
|||
* If the edges are provided in implicit form, after every `addState()` there should be 2^|AP| calls to |
|||
* `addEdgeImplicit`. The corresponding boolean expression over labels / BitSet |
|||
* can be obtained by calling BooleanExpression.fromImplicit(i-1) for the i-th call of this function per state. |
|||
* |
|||
* @param stateId the index of the 'from' state |
|||
* @param conjSuccessors a list of successor state indizes, interpreted as a conjunction |
|||
* @param accSignature an optional list of acceptance set indizes (transition-labeled acceptance) (empty pointer if not provided) |
|||
*/ |
|||
virtual void addEdgeImplicit(unsigned int stateId, const int_list& conjSuccessors, std::shared_ptr<int_list> accSignature) { |
|||
// IGNORE |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser for each explicit edge definition [optional, multiple], i.e., |
|||
* where the label is either specified for the edge or as a state-label. |
|||
* <br/> |
|||
* @param stateId the index of the 'from' state |
|||
* @param labelExpr a boolean expression over labels (empty pointer if none provided, only in case of state-labeled states) |
|||
* @param conjSuccessors a list of successors state indizes, interpreted as a conjunction |
|||
* @param accSignature an optional list of acceptance set indizes (transition-labeled acceptance) (empty pointer if none provided) |
|||
*/ |
|||
virtual void addEdgeWithLabel(unsigned int stateId, label_expr::ptr labelExpr, const int_list& conjSuccessors, std::shared_ptr<int_list> accSignature) { |
|||
// IGNORE |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify the consumer that the definition for state `stateId` |
|||
* has ended [multiple]. |
|||
*/ |
|||
virtual void notifyEndOfState(unsigned int stateId) { |
|||
// IGNORE |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify the consumer that the automata definition has ended [mandatory, once]. |
|||
*/ |
|||
virtual void notifyEnd() { |
|||
} |
|||
|
|||
/** |
|||
* Called by the parser to notify the consumer that an "ABORT" message has been encountered |
|||
* (at any time, indicating error, the automaton should be discarded). |
|||
*/ |
|||
virtual void notifyAbort() { |
|||
throw std::runtime_error("Parsing deterministic automaton: Automaton is incomplete (abort)"); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Is called whenever a condition is encountered that merits a (non-fatal) warning. |
|||
* The consumer is free to handle this situation as it wishes. |
|||
*/ |
|||
virtual void notifyWarning(const std::string& warning) { |
|||
// IGNORE |
|||
(void)warning; |
|||
} |
|||
|
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
@ -0,0 +1,26 @@ |
|||
#pragma once |
|||
|
|||
#include "storm/automata/APSet.h" |
|||
#include "cpphoafparser/consumer/hoa_consumer.hh" |
|||
#include <boost/optional.hpp> |
|||
|
|||
namespace storm { |
|||
namespace automata { |
|||
class HOAHeader { |
|||
public: |
|||
boost::optional<unsigned int> startState; |
|||
boost::optional<unsigned int> numberOfStates; |
|||
APSet apSet; |
|||
|
|||
boost::optional<unsigned int> numberOfAcceptanceSets; |
|||
cpphoafparser::HOAConsumer::acceptance_expr::ptr acceptance_expression; |
|||
boost::optional<std::string> accName; |
|||
boost::optional<std::vector<cpphoafparser::IntOrString>> accNameExtraInfo; |
|||
|
|||
AcceptanceCondition::ptr getAcceptanceCondition() { |
|||
return AcceptanceCondition::ptr(new AcceptanceCondition(*numberOfStates, *numberOfAcceptanceSets, acceptance_expression)); |
|||
} |
|||
|
|||
}; |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue