Browse Source
Merge branch 'jani_support' into rewards_in_jani
Merge branch 'jani_support' into rewards_in_jani
Former-commit-id:main671bbe40a5
[formerlye9070da8a6
] Former-commit-id:e7ec1284ea
86 changed files with 2622 additions and 752 deletions
-
8src/builder/DdJaniModelBuilder.cpp
-
116src/builder/JaniProgramGraphBuilder.cpp
-
135src/builder/JaniProgramGraphBuilder.h
-
77src/builder/ProgramGraphBuilder.cpp
-
152src/builder/ProgramGraphBuilder.h
-
6src/cli/cli.cpp
-
6src/generator/JaniNextStateGenerator.cpp
-
178src/parser/JaniParser.cpp
-
2src/parser/JaniParser.h
-
42src/parser/PgclParser.cpp
-
4src/parser/PgclParser.h
-
2src/settings/SettingsManager.cpp
-
42src/settings/modules/JaniExportSettings.cpp
-
38src/settings/modules/JaniExportSettings.h
-
30src/settings/modules/PGCLSettings.cpp
-
32src/settings/modules/PGCLSettings.h
-
2src/solver/SmtlibSmtSolver.cpp
-
2src/solver/SmtlibSmtSolver.h
-
2src/storage/IntegerInterval.cpp
-
56src/storage/IntegerInterval.h
-
15src/storage/expressions/Expression.cpp
-
8src/storage/expressions/Expression.h
-
4src/storage/expressions/ExpressionManager.cpp
-
3src/storage/expressions/ExpressionManager.h
-
1src/storage/jani/Action.cpp
-
1src/storage/jani/Action.h
-
15src/storage/jani/Automaton.cpp
-
10src/storage/jani/Automaton.h
-
4src/storage/jani/AutomatonComposition.cpp
-
2src/storage/jani/AutomatonComposition.h
-
2src/storage/jani/Composition.h
-
18src/storage/jani/CompositionInformationVisitor.cpp
-
10src/storage/jani/Edge.cpp
-
5src/storage/jani/Edge.h
-
10src/storage/jani/EdgeDestination.cpp
-
5src/storage/jani/EdgeDestination.h
-
405src/storage/jani/JSONExporter.cpp
-
51src/storage/jani/JSONExporter.h
-
58src/storage/jani/Model.cpp
-
37src/storage/jani/Model.h
-
44src/storage/jani/ModelType.cpp
-
1src/storage/jani/ModelType.h
-
17src/storage/jani/OrderedAssignments.cpp
-
11src/storage/jani/OrderedAssignments.h
-
20src/storage/pgcl/AbstractStatementVisitor.h
-
23src/storage/pgcl/AssignmentStatement.cpp
-
24src/storage/pgcl/AssignmentStatement.h
-
92src/storage/pgcl/Block.cpp
-
121src/storage/pgcl/Block.h
-
9src/storage/pgcl/BooleanExpression.cpp
-
17src/storage/pgcl/BooleanExpression.h
-
14src/storage/pgcl/BranchStatement.cpp
-
23src/storage/pgcl/BranchStatement.h
-
13src/storage/pgcl/CompoundStatement.h
-
29src/storage/pgcl/IfStatement.cpp
-
31src/storage/pgcl/IfStatement.h
-
16src/storage/pgcl/LoopStatement.cpp
-
11src/storage/pgcl/LoopStatement.h
-
11src/storage/pgcl/NondeterministicBranch.cpp
-
4src/storage/pgcl/NondeterministicBranch.h
-
12src/storage/pgcl/ObserveStatement.cpp
-
18src/storage/pgcl/ObserveStatement.h
-
104src/storage/pgcl/PgclProgram.cpp
-
120src/storage/pgcl/PgclProgram.h
-
11src/storage/pgcl/ProbabilisticBranch.cpp
-
17src/storage/pgcl/ProbabilisticBranch.h
-
33src/storage/pgcl/Statement.cpp
-
42src/storage/pgcl/Statement.h
-
20src/storage/pgcl/StatementPrinterVisitor.cpp
-
21src/storage/pgcl/StatementPrinterVisitor.h
-
6src/storage/pgcl/UniformExpression.cpp
-
11src/storage/pgcl/UniformExpression.h
-
19src/storage/ppg/ProgramAction.cpp
-
163src/storage/ppg/ProgramAction.h
-
19src/storage/ppg/ProgramEdge.cpp
-
51src/storage/ppg/ProgramEdge.h
-
14src/storage/ppg/ProgramEdgeGroup.cpp
-
78src/storage/ppg/ProgramEdgeGroup.h
-
48src/storage/ppg/ProgramGraph.cpp
-
236src/storage/ppg/ProgramGraph.h
-
21src/storage/ppg/ProgramLocation.cpp
-
80src/storage/ppg/ProgramLocation.h
-
16src/storage/ppg/defines.h
-
9src/storage/prism/CompositionToJaniVisitor.cpp
-
74src/storm-pgcl.cpp
-
4src/utility/storm.cpp
@ -0,0 +1,116 @@ |
|||
#include "JaniProgramGraphBuilder.h"
|
|||
#include "src/storage/jani/EdgeDestination.h"
|
|||
|
|||
namespace storm { |
|||
namespace builder { |
|||
unsigned JaniProgramGraphBuilder::janiVersion = 1; |
|||
|
|||
storm::jani::OrderedAssignments buildOrderedAssignments(storm::jani::Automaton& automaton, storm::ppg::DeterministicProgramAction const& act) { |
|||
std::vector<storm::jani::Assignment> vec; |
|||
uint64_t level = 0; |
|||
for(auto const& group : act) { |
|||
for(auto const& assignment : group) { |
|||
vec.emplace_back(automaton.getVariables().getVariable(act.getProgramGraph().getVariableName(assignment.first)) , assignment.second, level); |
|||
} |
|||
++level; |
|||
} |
|||
return storm::jani::OrderedAssignments(vec); |
|||
} |
|||
|
|||
std::vector<storm::jani::EdgeDestination> JaniProgramGraphBuilder::buildProbabilisticDestinations(storm::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge ) { |
|||
storm::ppg::ProbabilisticProgramAction const& act = static_cast<storm::ppg::ProbabilisticProgramAction const&>(edge.getAction()); |
|||
std::vector<storm::jani::EdgeDestination> vec; |
|||
for(auto const& assign : act ) { |
|||
storm::jani::Assignment assignment(automaton.getVariables().getVariable(act.getVariableName()), expManager->integer(assign.value) ,0); |
|||
vec.emplace_back(janiLocId.at(edge.getTargetId()), assign.probability, assignment); |
|||
} |
|||
return vec; |
|||
} |
|||
|
|||
std::vector<storm::jani::EdgeDestination> JaniProgramGraphBuilder::buildDestinations(storm::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge ) { |
|||
if (edge.getAction().isProbabilistic()) { |
|||
return buildProbabilisticDestinations(automaton, edge); |
|||
} else { |
|||
storm::jani::OrderedAssignments oa = buildOrderedAssignments(automaton, static_cast<storm::ppg::DeterministicProgramAction const&>(edge.getAction())); |
|||
storm::jani::EdgeDestination dest(janiLocId.at(edge.getTargetId()), expManager->rational(1.0), oa); |
|||
return {dest}; |
|||
} |
|||
} |
|||
|
|||
storm::expressions::Expression simplifyExpression(storm::expressions::Expression const& in) { |
|||
// TODO use bound restrictions etc.
|
|||
return in.simplify(); |
|||
} |
|||
|
|||
std::pair<std::vector<storm::jani::Edge>, storm::expressions::Expression> JaniProgramGraphBuilder::addVariableChecks(storm::ppg::ProgramEdge const& edge) { |
|||
std::vector<storm::jani::Edge> edges; |
|||
storm::expressions::Expression newGuard; |
|||
newGuard = expManager->boolean(true); |
|||
if (edge.getAction().isProbabilistic()) { |
|||
|
|||
} else { |
|||
storm::ppg::DeterministicProgramAction const& act = static_cast<storm::ppg::DeterministicProgramAction const&>(edge.getAction()); |
|||
STORM_LOG_THROW(act.nrLevels() <= 1, storm::exceptions::NotSupportedException, "Multi-level assignments with user variable bounds not supported"); |
|||
for(auto const& group : act) { |
|||
for(auto const& assignment : group) { |
|||
if (isUserRestricted(assignment.first)) { |
|||
assert(variableRestrictions.count(assignment.first) == 1); |
|||
storm::storage::IntegerInterval const& bound = variableRestrictions.at(assignment.first); |
|||
if (!assignment.second.containsVariables()) { |
|||
// Constant assignments can be checked statically.
|
|||
// TODO we might still want to allow assignments which go out of bounds.
|
|||
STORM_LOG_THROW(bound.contains(assignment.second.evaluateAsInt()), storm::exceptions::NotSupportedException, "User provided bounds must contain all constant expressions"); |
|||
} else { |
|||
// TODO currently only fully bounded restrictions are supported;
|
|||
assert(variableRestrictions.at(assignment.first).hasLeftBound() && variableRestrictions.at(assignment.first).hasRightBound()); |
|||
storm::expressions::Expression newCondition = simplifyExpression(edge.getCondition() && (assignment.second > bound.getRightBound().get() || assignment.second < bound.getLeftBound().get())); |
|||
storm::jani::EdgeDestination dest(varOutOfBoundsLocations.at(assignment.first), expManager->rational(1.0), storm::jani::OrderedAssignments()); |
|||
storm::jani::Edge e(janiLocId.at(edge.getSourceId()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, newCondition, {dest}); |
|||
edges.push_back(e); |
|||
newGuard = newGuard && assignment.second <= bound.getRightBound().get() && assignment.second >= bound.getLeftBound().get(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return {edges, newGuard}; |
|||
} |
|||
|
|||
|
|||
void JaniProgramGraphBuilder::addEdges(storm::jani::Automaton& automaton) { |
|||
for(auto it = programGraph.locationBegin(); it != programGraph.locationEnd(); ++it) { |
|||
ppg::ProgramLocation const& loc = it->second; |
|||
if (loc.nrOutgoingEdgeGroups() == 0) { |
|||
// TODO deadlock!
|
|||
} else if (loc.nrOutgoingEdgeGroups() == 1) { |
|||
for(auto const& edge : **(loc.begin())) { |
|||
std::pair<std::vector<storm::jani::Edge>, storm::expressions::Expression> checks = addVariableChecks(*edge); |
|||
for(auto const& check : checks.first) { |
|||
automaton.addEdge(check); |
|||
} |
|||
storm::jani::Edge e(janiLocId.at(loc.id()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, simplifyExpression(edge->getCondition() && checks.second), buildDestinations(automaton, *edge)); |
|||
automaton.addEdge(e); |
|||
} |
|||
} else { |
|||
// We have probabilistic branching
|
|||
if(loc.hasNonDeterminism()) |
|||
{ |
|||
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Combi of nondeterminism and probabilistic choices within a loc not supported yet"); |
|||
} else { |
|||
std::vector<storm::jani::EdgeDestination> destinations; |
|||
for(auto const& eg : loc) { |
|||
// TODO add assignments
|
|||
assert(eg->nrEdges() < 2); // Otherwise, non-determinism occurs.
|
|||
assert(eg->nrEdges() > 0); // Empty edge groups should not occur in input.
|
|||
uint64_t target = janiLocId.at((*eg->begin())->getTargetId()); |
|||
destinations.emplace_back(target, eg->getProbability()); |
|||
} |
|||
storm::jani::Edge e(janiLocId.at(it->second.id()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, expManager->boolean(true), destinations); |
|||
automaton.addEdge(e); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,135 @@ |
|||
#include <string> |
|||
|
|||
#include "src/storage/ppg/ProgramGraph.h" |
|||
#include "src/storage/jani/Model.h" |
|||
#include "src/storage/jani/Location.h" |
|||
#include "src/storage/jani/EdgeDestination.h" |
|||
#include "src/storage/IntegerInterval.h" |
|||
#include "src/exceptions/NotSupportedException.h" |
|||
|
|||
#include "src/utility/macros.h" |
|||
|
|||
namespace storm { |
|||
namespace builder { |
|||
|
|||
enum class JaniProgramGraphVariableDomainMethod { |
|||
Unrestricted, IntervalPropagation |
|||
}; |
|||
|
|||
struct JaniProgramGraphBuilderSetting { |
|||
JaniProgramGraphVariableDomainMethod variableDomainMethod = JaniProgramGraphVariableDomainMethod::Unrestricted; |
|||
}; |
|||
|
|||
class JaniProgramGraphBuilder { |
|||
public: |
|||
static unsigned janiVersion; |
|||
|
|||
JaniProgramGraphBuilder(storm::ppg::ProgramGraph const& pg) : programGraph(pg) { |
|||
|
|||
} |
|||
|
|||
//void addVariableRestriction(storm::expressions::Variable const& var, storm::IntegerInterval const& interval ) { |
|||
|
|||
//} |
|||
|
|||
|
|||
void restrictAllVariables(int64_t from, int64_t to) { |
|||
for (auto const& v : programGraph.getVariables()) { |
|||
variableRestrictions.emplace(v.first, storm::storage::IntegerInterval(from, to)); |
|||
} |
|||
} |
|||
|
|||
storm::jani::Model* build(std::string const& name = "program_graph") { |
|||
expManager = programGraph.getExpressionManager(); |
|||
storm::jani::Model* model = new storm::jani::Model(name, storm::jani::ModelType::MDP, janiVersion, expManager); |
|||
storm::jani::Automaton mainAutomaton("main"); |
|||
addProcedureVariables(mainAutomaton); |
|||
janiLocId = addProcedureLocations(mainAutomaton); |
|||
addVariableOoBLocations(mainAutomaton); |
|||
addEdges(mainAutomaton); |
|||
model->addAutomaton(mainAutomaton); |
|||
model->setStandardSystemComposition(); |
|||
return model; |
|||
} |
|||
|
|||
private: |
|||
std::string janiLocationName(storm::ppg::ProgramLocationIdentifier i) { |
|||
return "l" + std::to_string(i); |
|||
} |
|||
|
|||
std::string janiVariableOutOfBoundsLocationName(storm::ppg::ProgramVariableIdentifier i) { |
|||
return "oob-" + programGraph.getVariableName(i); |
|||
} |
|||
|
|||
|
|||
void addEdges(storm::jani::Automaton& automaton); |
|||
std::vector<storm::jani::EdgeDestination> buildDestinations(storm::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge ); |
|||
/** |
|||
* Helper for probabilistic assignments |
|||
*/ |
|||
std::vector<storm::jani::EdgeDestination> buildProbabilisticDestinations(storm::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge ); |
|||
|
|||
std::pair<std::vector<storm::jani::Edge>, storm::expressions::Expression> addVariableChecks(storm::ppg::ProgramEdge const& edge); |
|||
|
|||
bool isUserRestricted(storm::ppg::ProgramVariableIdentifier i) { |
|||
return variableRestrictions.count(i) == 1; |
|||
} |
|||
|
|||
void addProcedureVariables(storm::jani::Automaton& automaton) { |
|||
for (auto const& v : programGraph.getVariables()) { |
|||
if(variableRestrictions.count(v.first) == 1) { |
|||
storm::storage::IntegerInterval const& bounds = variableRestrictions.at(v.first); |
|||
if (bounds.hasLeftBound()) { |
|||
if (bounds.hasRightBound()) { |
|||
storm::jani::BoundedIntegerVariable janiVar(v.second.getName(), v.second, expManager->integer(0), false, expManager->integer(bounds.getLeftBound().get()), expManager->integer(bounds.getRightBound().get())); |
|||
automaton.addVariable(janiVar); |
|||
} else { |
|||
// Not yet supported. |
|||
assert(false); |
|||
} |
|||
} else { |
|||
// Not yet supported. |
|||
assert(false); |
|||
} |
|||
} else { |
|||
storm::jani::UnboundedIntegerVariable janiVar(v.second.getName(), v.second, expManager->integer(0), false); |
|||
automaton.addVariable(janiVar); |
|||
} |
|||
} |
|||
} |
|||
|
|||
std::map<storm::ppg::ProgramLocationIdentifier, uint64_t> addProcedureLocations(storm::jani::Automaton& automaton) { |
|||
std::map<storm::ppg::ProgramLocationIdentifier, uint64_t> result; |
|||
for (auto it = programGraph.locationBegin(); it != programGraph.locationEnd(); ++it) { |
|||
storm::jani::Location janiLoc(janiLocationName(it->second.id())); |
|||
result[it->second.id()] = automaton.addLocation(janiLoc); |
|||
if (it->second.isInitial()) { |
|||
automaton.addInitialLocation(result[it->second.id()]); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
void addVariableOoBLocations(storm::jani::Automaton& automaton) { |
|||
for(auto const& restr : variableRestrictions) { |
|||
storm::jani::Location janiLoc(janiVariableOutOfBoundsLocationName(restr.first)); |
|||
uint64_t locId = automaton.addLocation(janiLoc); |
|||
varOutOfBoundsLocations[restr.first] = locId; |
|||
|
|||
} |
|||
} |
|||
|
|||
/// Restrictions on variables |
|||
std::map<uint64_t, storm::storage::IntegerInterval> variableRestrictions; |
|||
/// Locations for variables that would have gone ot o |
|||
std::map<uint64_t, uint64_t> varOutOfBoundsLocations; |
|||
std::map<storm::ppg::ProgramLocationIdentifier, uint64_t> janiLocId; |
|||
/// The expression manager |
|||
std::shared_ptr<storm::expressions::ExpressionManager> expManager; |
|||
/// The program graph to be translated |
|||
storm::ppg::ProgramGraph const& programGraph; |
|||
|
|||
|
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,77 @@ |
|||
#include "ProgramGraphBuilder.h"
|
|||
#include "src/storage/pgcl/AssignmentStatement.h"
|
|||
#include "src/storage/pgcl/ObserveStatement.h"
|
|||
#include "src/storage/pgcl/LoopStatement.h"
|
|||
#include "src/storage/pgcl/IfStatement.h"
|
|||
#include "src/storage/pgcl/NondeterministicBranch.h"
|
|||
#include "src/storage/pgcl/ProbabilisticBranch.h"
|
|||
|
|||
|
|||
namespace storm { |
|||
namespace builder { |
|||
void ProgramGraphBuilderVisitor::visit(storm::pgcl::AssignmentStatement const& s) { |
|||
if(s.isDeterministic()) { |
|||
builder.currentLoc()->addProgramEdgeToAllGroups(builder.addAction(s.getVariable(), boost::get<storm::expressions::Expression>(s.getExpression())), builder.nextLocId()); |
|||
} else { |
|||
builder.currentLoc()->addProgramEdgeToAllGroups(builder.addAction(s.getVariable(), boost::get<storm::pgcl::UniformExpression>(s.getExpression())), builder.nextLocId()); |
|||
|
|||
} |
|||
} |
|||
void ProgramGraphBuilderVisitor::visit(storm::pgcl::ObserveStatement const& s) { |
|||
builder.currentLoc()->addProgramEdgeToAllGroups(builder.noAction(), s.getCondition().getBooleanExpression(), builder.nextLocId()); |
|||
} |
|||
void ProgramGraphBuilderVisitor::visit(storm::pgcl::IfStatement const& s) { |
|||
storm::expressions::Expression elseCondition; |
|||
storm::ppg::ProgramLocation* beforeStatementLocation = builder.currentLoc(); |
|||
builder.storeNextLocation(builder.nextLoc()); |
|||
storm::ppg::ProgramLocation* ifbodyStart = builder.newLocation(); |
|||
builder.buildBlock(*s.getIfBody()); |
|||
storm::ppg::ProgramLocation* elsebodyStart; |
|||
if(s.hasElse()) { |
|||
builder.storeNextLocation(builder.nextLoc()); |
|||
elsebodyStart = builder.newLocation(); |
|||
builder.buildBlock(*s.getElseBody()); |
|||
} |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), s.getCondition().getBooleanExpression(), ifbodyStart->id()); |
|||
elseCondition = !s.getCondition().getBooleanExpression(); |
|||
if(s.hasElse()) { |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), elseCondition, elsebodyStart->id()); |
|||
} else { |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), elseCondition, builder.nextLocId()); |
|||
} |
|||
|
|||
} |
|||
void ProgramGraphBuilderVisitor::visit(storm::pgcl::LoopStatement const& s) { |
|||
storm::ppg::ProgramLocation* beforeStatementLocation = builder.currentLoc(); |
|||
builder.storeNextLocation(beforeStatementLocation); |
|||
storm::ppg::ProgramLocation* bodyStart = builder.newLocation(); |
|||
builder.buildBlock(*s.getBody()); |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), s.getCondition().getBooleanExpression(), bodyStart->id()); |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), !s.getCondition().getBooleanExpression(), builder.nextLocId()); |
|||
} |
|||
|
|||
void ProgramGraphBuilderVisitor::visit(storm::pgcl::NondeterministicBranch const& s) { |
|||
storm::ppg::ProgramLocation* beforeStatementLocation = builder.currentLoc(); |
|||
builder.storeNextLocation(builder.nextLoc()); |
|||
storm::ppg::ProgramLocation* bodyStart = builder.newLocation(); |
|||
builder.buildBlock(*s.getLeftBranch()); |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), builder.nextLocId()); |
|||
builder.storeNextLocation(builder.nextLoc()); |
|||
bodyStart = builder.newLocation(); |
|||
beforeStatementLocation->addProgramEdgeToAllGroups(builder.noAction(), builder.nextLocId()); |
|||
builder.buildBlock(*s.getRightBranch()); |
|||
|
|||
} |
|||
void ProgramGraphBuilderVisitor::visit(storm::pgcl::ProbabilisticBranch const& s) { |
|||
storm::ppg::ProgramLocation* beforeStatementLocation = builder.currentLoc(); |
|||
builder.storeNextLocation(builder.nextLoc()); |
|||
storm::ppg::ProgramLocation* bodyStart = builder.newLocation(); |
|||
beforeStatementLocation->addProgramEdgeGroup(s.getProbability())->addEdge(builder.nextLocId(), builder.noAction()); |
|||
builder.buildBlock(*s.getLeftBranch()); |
|||
builder.storeNextLocation(builder.nextLoc()); |
|||
bodyStart = builder.newLocation(); |
|||
beforeStatementLocation->addProgramEdgeGroup(1 - s.getProbability())->addEdge(builder.nextLocId(), builder.noAction()); |
|||
builder.buildBlock(*s.getRightBranch()); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,152 @@ |
|||
#pragma once |
|||
|
|||
#include "src/storage/pgcl/PgclProgram.h" |
|||
#include "src/storage/ppg/ProgramGraph.h" |
|||
#include "src/storage/pgcl/AbstractStatementVisitor.h" |
|||
#include "src/storage/pgcl/UniformExpression.h" |
|||
|
|||
namespace storm { |
|||
namespace builder { |
|||
class ProgramGraphBuilder; |
|||
|
|||
|
|||
class ProgramGraphBuilderVisitor: public storm::pgcl::AbstractStatementVisitor{ |
|||
public: |
|||
ProgramGraphBuilderVisitor(ProgramGraphBuilder& builder) : builder(builder) { |
|||
|
|||
} |
|||
|
|||
virtual void visit(storm::pgcl::AssignmentStatement const&); |
|||
virtual void visit(storm::pgcl::ObserveStatement const&); |
|||
virtual void visit(storm::pgcl::IfStatement const&); |
|||
virtual void visit(storm::pgcl::LoopStatement const&); |
|||
virtual void visit(storm::pgcl::NondeterministicBranch const&); |
|||
virtual void visit(storm::pgcl::ProbabilisticBranch const&); |
|||
|
|||
private: |
|||
ProgramGraphBuilder& builder; |
|||
}; |
|||
|
|||
|
|||
class ProgramGraphBuilder { |
|||
|
|||
|
|||
public: |
|||
static storm::ppg::ProgramGraph* build(storm::pgcl::PgclProgram const& program) { |
|||
ProgramGraphBuilder builder(program); |
|||
builder.run(); |
|||
return builder.finalize(); |
|||
} |
|||
|
|||
~ProgramGraphBuilder() { |
|||
if (graph != nullptr) { |
|||
delete graph; |
|||
} |
|||
} |
|||
|
|||
storm::ppg::ProgramLocation* currentLoc() const { |
|||
return currentStack.back(); |
|||
} |
|||
|
|||
storm::ppg::ProgramLocation* newLocation() { |
|||
currentStack.push_back(graph->addLocation()); |
|||
return currentLoc(); |
|||
} |
|||
|
|||
void storeNextLocation(storm::ppg::ProgramLocation* loc) { |
|||
nextStack.push_back(loc); |
|||
} |
|||
|
|||
storm::ppg::ProgramLocation* nextLoc() const { |
|||
return nextStack.back(); |
|||
} |
|||
|
|||
storm::ppg::ProgramLocationIdentifier nextLocId() const { |
|||
return nextLoc()->id(); |
|||
} |
|||
|
|||
storm::ppg::ProgramActionIdentifier addAction(storm::expressions::Variable const& var, storm::expressions::Expression const& expr) const { |
|||
storm::ppg::DeterministicProgramAction* action = graph->addDeterministicAction(); |
|||
action->addAssignment(graph->getVariableId(var.getName()), expr); |
|||
return action->id(); |
|||
} |
|||
|
|||
storm::ppg::ProgramActionIdentifier addAction(storm::expressions::Variable const& var, storm::pgcl::UniformExpression const& expr) const { |
|||
storm::ppg::ProbabilisticProgramAction* action = graph->addUniformProbabilisticAction(graph->getVariableId(var.getName()), expr.getBegin(), expr.getEnd()); |
|||
return action->id(); |
|||
|
|||
} |
|||
|
|||
storm::ppg::ProgramActionIdentifier noAction() const { |
|||
return noActionId; |
|||
} |
|||
|
|||
std::shared_ptr<storm::expressions::ExpressionManager> const& getExpressionManager() const { |
|||
return program.getExpressionManager(); |
|||
} |
|||
|
|||
|
|||
|
|||
void buildBlock(storm::pgcl::PgclBlock const& block) { |
|||
ProgramGraphBuilderVisitor visitor(*this); |
|||
for (auto const& statement : block) { |
|||
if (!statement->isLast()) { |
|||
nextStack.push_back(graph->addLocation(false)); |
|||
} |
|||
assert(!currentStack.empty()); |
|||
assert(!nextStack.empty()); |
|||
statement->accept(visitor); |
|||
assert(!currentStack.empty()); |
|||
assert(!nextStack.empty()); |
|||
currentStack.back() = nextStack.back(); |
|||
nextStack.pop_back(); |
|||
} |
|||
} |
|||
|
|||
|
|||
private: |
|||
ProgramGraphBuilder(storm::pgcl::PgclProgram const& program) |
|||
: program(program) |
|||
{ |
|||
graph = new storm::ppg::ProgramGraph(program.getExpressionManager(), program.getVariables()); |
|||
noActionId = graph->getNoActionId(); |
|||
|
|||
} |
|||
|
|||
void run() { |
|||
currentStack.push_back(graph->addLocation(true)); |
|||
// Terminal state. |
|||
nextStack.push_back(graph->addLocation(false)); |
|||
// Observe Violated State. |
|||
if (program.hasObserve()) { |
|||
observeFailedState = graph->addLocation(); |
|||
} |
|||
buildBlock(program); |
|||
} |
|||
|
|||
|
|||
storm::ppg::ProgramGraph* finalize() { |
|||
storm::ppg::ProgramGraph* tmp = graph; |
|||
graph = nullptr; |
|||
return tmp; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
std::vector<storm::ppg::ProgramLocation*> currentStack; |
|||
std::vector<storm::ppg::ProgramLocation*> nextStack; |
|||
|
|||
storm::ppg::ProgramActionIdentifier noActionId; |
|||
|
|||
storm::ppg::ProgramLocation* observeFailedState = nullptr; |
|||
|
|||
storm::pgcl::PgclProgram const& program; |
|||
storm::ppg::ProgramGraph* graph; |
|||
|
|||
|
|||
|
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,42 @@ |
|||
#include "JaniExportSettings.h"
|
|||
|
|||
#include "src/settings/SettingsManager.h"
|
|||
#include "src/settings/SettingMemento.h"
|
|||
#include "src/settings/Option.h"
|
|||
#include "src/settings/OptionBuilder.h"
|
|||
#include "src/settings/ArgumentBuilder.h"
|
|||
#include "src/settings/Argument.h"
|
|||
|
|||
#include "src/exceptions/InvalidSettingsException.h"
|
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
namespace modules { |
|||
const std::string JaniExportSettings::moduleName = "exportJani"; |
|||
|
|||
const std::string JaniExportSettings::janiFileOptionName = "jani-output"; |
|||
const std::string JaniExportSettings::janiFileOptionShortName = "output"; |
|||
|
|||
|
|||
JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { |
|||
this->addOption(storm::settings::OptionBuilder(moduleName, janiFileOptionName, false, "Destination for the jani model.").setShortName(janiFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); |
|||
} |
|||
|
|||
bool JaniExportSettings::isJaniFileSet() const { |
|||
return this->getOption(janiFileOptionName).getHasOptionBeenSet(); |
|||
} |
|||
|
|||
std::string JaniExportSettings::getJaniFilename() const { |
|||
return this->getOption(janiFileOptionName).getArgumentByName("filename").getValueAsString(); |
|||
} |
|||
|
|||
void JaniExportSettings::finalize() { |
|||
|
|||
} |
|||
|
|||
bool JaniExportSettings::check() const { |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
#pragma once |
|||
|
|||
#include "storm-config.h" |
|||
#include "src/settings/modules/ModuleSettings.h" |
|||
|
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
namespace modules { |
|||
class JaniExportSettings : public ModuleSettings { |
|||
public: |
|||
/*! |
|||
* Creates a new JaniExport setting |
|||
*/ |
|||
JaniExportSettings(); |
|||
|
|||
/** |
|||
* Retrievew whether the pgcl file option was set |
|||
*/ |
|||
bool isJaniFileSet() const; |
|||
|
|||
/** |
|||
* Retrieves the pgcl file name |
|||
*/ |
|||
std::string getJaniFilename() const; |
|||
|
|||
bool check() const override; |
|||
void finalize() override; |
|||
|
|||
static const std::string moduleName; |
|||
|
|||
private: |
|||
static const std::string janiFileOptionName; |
|||
static const std::string janiFileOptionShortName; |
|||
}; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,2 @@ |
|||
#include "IntegerInterval.h"
|
|||
|
@ -0,0 +1,56 @@ |
|||
#pragma once |
|||
|
|||
#include <boost/optional.hpp> |
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
class IntegerInterval { |
|||
|
|||
public: |
|||
explicit IntegerInterval(int64_t v) : leftBound(v), rightBound(v) { |
|||
|
|||
} |
|||
|
|||
IntegerInterval(int64_t lb, int64_t rb) : leftBound(lb), rightBound(rb) { |
|||
|
|||
} |
|||
|
|||
bool hasLeftBound() const { |
|||
return leftBound != boost::none; |
|||
} |
|||
|
|||
bool hasRightBound() const { |
|||
return rightBound != boost::none; |
|||
} |
|||
|
|||
bool contains(int64_t val) const { |
|||
if (hasLeftBound()) { |
|||
if (val < leftBound.get()) { |
|||
return false; |
|||
} |
|||
} |
|||
if (hasRightBound()) { |
|||
if (val > rightBound.get()) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
boost::optional<int64_t> getLeftBound() const { |
|||
return leftBound; |
|||
} |
|||
|
|||
boost::optional<int64_t> getRightBound() const { |
|||
return rightBound; |
|||
} |
|||
|
|||
private: |
|||
boost::optional<int64_t> leftBound; |
|||
boost::optional<int64_t> rightBound; |
|||
|
|||
}; |
|||
|
|||
std::ostream& operator<<(std::ostream& os, IntegerInterval const& i); |
|||
} |
|||
} |
@ -0,0 +1,405 @@ |
|||
#include "JSONExporter.h"
|
|||
|
|||
#include <iostream>
|
|||
#include <fstream>
|
|||
#include <vector>
|
|||
|
|||
#include "src/utility/macros.h"
|
|||
#include "src/exceptions/FileIoException.h"
|
|||
|
|||
#include "src/exceptions/InvalidJaniException.h"
|
|||
|
|||
#include "src/storage/expressions/RationalLiteralExpression.h"
|
|||
#include "src/storage/expressions/IntegerLiteralExpression.h"
|
|||
#include "src/storage/expressions/BooleanLiteralExpression.h"
|
|||
#include "src/storage/expressions/UnaryBooleanFunctionExpression.h"
|
|||
#include "src/storage/expressions/UnaryNumericalFunctionExpression.h"
|
|||
#include "src/storage/expressions/BinaryBooleanFunctionExpression.h"
|
|||
#include "src/storage/expressions/BinaryNumericalFunctionExpression.h"
|
|||
#include "src/storage/expressions/IfThenElseExpression.h"
|
|||
#include "src/storage/expressions/BinaryRelationExpression.h"
|
|||
#include "src/storage/expressions/VariableExpression.h"
|
|||
|
|||
#include "src/storage/jani/AutomatonComposition.h"
|
|||
#include "src/storage/jani/ParallelComposition.h"
|
|||
|
|||
namespace storm { |
|||
namespace jani { |
|||
|
|||
|
|||
class CompositionJsonExporter : public CompositionVisitor { |
|||
public: |
|||
CompositionJsonExporter(bool allowRecursion) : allowRecursion(allowRecursion){ |
|||
|
|||
} |
|||
|
|||
static modernjson::json translate(storm::jani::Composition const& comp, bool allowRecursion = true) { |
|||
CompositionJsonExporter visitor(allowRecursion); |
|||
return boost::any_cast<modernjson::json>(comp.accept(visitor, boost::none)); |
|||
} |
|||
|
|||
virtual boost::any visit(AutomatonComposition const& composition, boost::any const& data) { |
|||
modernjson::json compDecl; |
|||
modernjson::json autDecl; |
|||
autDecl["automaton"] = composition.getAutomatonName(); |
|||
std::vector<modernjson::json> elements; |
|||
elements.push_back(autDecl); |
|||
compDecl["elements"] = elements; |
|||
return compDecl; |
|||
} |
|||
|
|||
virtual boost::any visit(ParallelComposition const& composition, boost::any const& data) { |
|||
modernjson::json compDecl; |
|||
|
|||
std::vector<modernjson::json> elems; |
|||
for (auto const& subcomp : composition.getSubcompositions()) { |
|||
modernjson::json elemDecl; |
|||
if (subcomp->isAutomaton()) { |
|||
modernjson::json autDecl; |
|||
autDecl["automaton"] = std::static_pointer_cast<AutomatonComposition>(subcomp)->getAutomatonName(); |
|||
std::vector<modernjson::json> elements; |
|||
elements.push_back(autDecl); |
|||
elemDecl["elements"] = elements; |
|||
} else { |
|||
STORM_LOG_THROW(allowRecursion, storm::exceptions::InvalidJaniException, "Nesting composition " << *subcomp << " is not supported by JANI."); |
|||
elemDecl = boost::any_cast<modernjson::json>(subcomp->accept(*this, boost::none)); |
|||
} |
|||
elems.push_back(elemDecl); |
|||
} |
|||
compDecl["elements"] = elems; |
|||
std::vector<modernjson::json> synElems; |
|||
for (auto const& syncs : composition.getSynchronizationVectors()) { |
|||
modernjson::json syncDecl; |
|||
syncDecl["synchronise"] = syncs.getInput(); |
|||
syncDecl["result"] = syncs.getOutput(); |
|||
synElems.push_back(syncDecl); |
|||
} |
|||
if (!synElems.empty()) { |
|||
compDecl["syncs"] = synElems; |
|||
} |
|||
|
|||
return compDecl; |
|||
} |
|||
|
|||
private: |
|||
bool allowRecursion; |
|||
}; |
|||
|
|||
|
|||
std::string operatorTypeToJaniString(storm::expressions::OperatorType optype) { |
|||
|
|||
using OpType = storm::expressions::OperatorType; |
|||
switch(optype) { |
|||
case OpType::And: |
|||
return "∧"; |
|||
case OpType::Or: |
|||
return "∨"; |
|||
case OpType::Xor: |
|||
return "≠"; |
|||
case OpType::Implies: |
|||
return "⇒"; |
|||
case OpType::Iff: |
|||
return "="; |
|||
case OpType::Plus: |
|||
return "+"; |
|||
case OpType::Minus: |
|||
return "-"; |
|||
case OpType::Times: |
|||
return "*"; |
|||
case OpType::Divide: |
|||
return "/"; |
|||
case OpType::Min: |
|||
return "min"; |
|||
case OpType::Max: |
|||
return "max"; |
|||
case OpType::Power: |
|||
return "pow"; |
|||
case OpType::Equal: |
|||
return "="; |
|||
case OpType::NotEqual: |
|||
return "≠"; |
|||
case OpType::Less: |
|||
return "<"; |
|||
case OpType::LessOrEqual: |
|||
return "≤"; |
|||
case OpType::Greater: |
|||
return ">"; |
|||
case OpType::GreaterOrEqual: |
|||
return "≥"; |
|||
case OpType::Not: |
|||
return "¬"; |
|||
case OpType::Floor: |
|||
return "floor"; |
|||
case OpType::Ceil: |
|||
return "ceil"; |
|||
case OpType::Ite: |
|||
return "ite"; |
|||
default: |
|||
STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Operator not supported by Jani"); |
|||
} |
|||
} |
|||
|
|||
modernjson::json ExpressionToJson::translate(storm::expressions::Expression const& expr) { |
|||
ExpressionToJson visitor; |
|||
return boost::any_cast<modernjson::json>(expr.accept(visitor, boost::none)); |
|||
} |
|||
|
|||
|
|||
boost::any ExpressionToJson::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) { |
|||
modernjson::json opDecl; |
|||
opDecl["op"] = "ite"; |
|||
opDecl["if"] = boost::any_cast<modernjson::json>(expression.getCondition()->accept(*this, boost::none)); |
|||
opDecl["then"] = boost::any_cast<modernjson::json>(expression.getThenExpression()->accept(*this, boost::none)); |
|||
opDecl["else"] = boost::any_cast<modernjson::json>(expression.getElseExpression()->accept(*this, boost::none)); |
|||
return opDecl; |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) { |
|||
modernjson::json opDecl; |
|||
opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); |
|||
opDecl["left"] = boost::any_cast<modernjson::json>(expression.getOperand(0)->accept(*this, boost::none)); |
|||
opDecl["right"] = boost::any_cast<modernjson::json>(expression.getOperand(1)->accept(*this, boost::none)); |
|||
return opDecl; |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) { |
|||
modernjson::json opDecl; |
|||
opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); |
|||
opDecl["left"] = boost::any_cast<modernjson::json>(expression.getOperand(0)->accept(*this, boost::none)); |
|||
opDecl["right"] = boost::any_cast<modernjson::json>(expression.getOperand(1)->accept(*this, boost::none)); |
|||
return opDecl; |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) { |
|||
modernjson::json opDecl; |
|||
opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); |
|||
opDecl["left"] = boost::any_cast<modernjson::json>(expression.getOperand(0)->accept(*this, boost::none)); |
|||
opDecl["right"] = boost::any_cast<modernjson::json>(expression.getOperand(1)->accept(*this, boost::none)); |
|||
return opDecl; |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::VariableExpression const& expression, boost::any const& data) { |
|||
return modernjson::json(expression.getVariableName()); |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) { |
|||
modernjson::json opDecl; |
|||
opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); |
|||
opDecl["exp"] = boost::any_cast<modernjson::json>(expression.getOperand()->accept(*this, boost::none)); |
|||
return opDecl; |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) { |
|||
modernjson::json opDecl; |
|||
opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); |
|||
opDecl["exp"] = boost::any_cast<modernjson::json>(expression.getOperand()->accept(*this, boost::none)); |
|||
return opDecl; |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) { |
|||
return modernjson::json(expression.getValue()); |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) { |
|||
return modernjson::json(expression.getValue()); |
|||
} |
|||
boost::any ExpressionToJson::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) { |
|||
return modernjson::json(expression.getValueAsDouble()); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
void JsonExporter::toFile(storm::jani::Model const& janiModel, std::string const& filepath, bool checkValid) { |
|||
std::ofstream ofs; |
|||
ofs.open (filepath, std::ofstream::out ); |
|||
if(ofs.is_open()) { |
|||
toStream(janiModel, ofs, checkValid); |
|||
} else { |
|||
STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Cannot open " << filepath); |
|||
} |
|||
} |
|||
|
|||
void JsonExporter::toStream(storm::jani::Model const& janiModel, std::ostream& os, bool checkValid) { |
|||
if(checkValid) { |
|||
janiModel.checkValid(); |
|||
} |
|||
JsonExporter exporter; |
|||
exporter.convertModel(janiModel); |
|||
os << exporter.finalize().dump(4) << std::endl; |
|||
} |
|||
|
|||
modernjson::json buildActionArray(std::vector<storm::jani::Action> const& actions) { |
|||
std::vector<modernjson::json> actionReprs; |
|||
uint64_t actIndex = 0; |
|||
for(auto const& act : actions) { |
|||
if(actIndex == storm::jani::Model::SILENT_ACTION_INDEX) { |
|||
actIndex++; |
|||
continue; |
|||
} |
|||
actIndex++; |
|||
modernjson::json actEntry; |
|||
actEntry["name"] = act.getName(); |
|||
actionReprs.push_back(actEntry); |
|||
} |
|||
|
|||
return modernjson::json(actionReprs); |
|||
|
|||
} |
|||
|
|||
|
|||
modernjson::json buildExpression(storm::expressions::Expression const& exp) { |
|||
return ExpressionToJson::translate(exp); |
|||
} |
|||
|
|||
|
|||
modernjson::json buildConstantsArray(std::vector<storm::jani::Constant> const& constants) { |
|||
std::vector<modernjson::json> constantDeclarations; |
|||
for(auto const& constant : constants) { |
|||
modernjson::json constantEntry; |
|||
constantEntry["name"] = constant.getName(); |
|||
modernjson::json typeDesc; |
|||
if(constant.isBooleanConstant()) { |
|||
typeDesc = "bool"; |
|||
} else if(constant.isRealConstant()) { |
|||
typeDesc = "real"; |
|||
} else { |
|||
assert(constant.isIntegerConstant()); |
|||
typeDesc = "int"; |
|||
} |
|||
constantEntry["type"] = typeDesc; |
|||
if(constant.isDefined()) { |
|||
constantEntry["value"] = buildExpression(constant.getExpression()); |
|||
} |
|||
constantDeclarations.push_back(constantEntry); |
|||
} |
|||
return modernjson::json(constantDeclarations); |
|||
} |
|||
|
|||
modernjson::json buildVariablesArray(storm::jani::VariableSet const& varSet) { |
|||
std::vector<modernjson::json> variableDeclarations; |
|||
for(auto const& variable : varSet) { |
|||
modernjson::json varEntry; |
|||
varEntry["name"] = variable.getName(); |
|||
varEntry["transient"] = variable.isTransient(); |
|||
modernjson::json typeDesc; |
|||
if(variable.isBooleanVariable()) { |
|||
typeDesc = "bool"; |
|||
} else if(variable.isRealVariable()) { |
|||
typeDesc = "real"; |
|||
} else if(variable.isUnboundedIntegerVariable()) { |
|||
typeDesc = "int"; |
|||
} else { |
|||
assert(variable.isBoundedIntegerVariable()); |
|||
typeDesc["kind"] = "bounded"; |
|||
typeDesc["base"] = "int"; |
|||
typeDesc["lower-bound"] = buildExpression(variable.asBoundedIntegerVariable().getLowerBound()); |
|||
typeDesc["upper-bound"] = buildExpression(variable.asBoundedIntegerVariable().getUpperBound()); |
|||
} |
|||
|
|||
varEntry["type"] = typeDesc; |
|||
if(variable.hasInitExpression()) { |
|||
varEntry["initial-value"] = buildExpression(variable.getInitExpression()); |
|||
} |
|||
variableDeclarations.push_back(varEntry); |
|||
} |
|||
return modernjson::json(variableDeclarations); |
|||
|
|||
} |
|||
|
|||
modernjson::json buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments) { |
|||
std::vector<modernjson::json> assignmentDeclarations; |
|||
bool addIndex = orderedAssignments.hasMultipleLevels(); |
|||
for(auto const& assignment : orderedAssignments) { |
|||
modernjson::json assignmentEntry; |
|||
assignmentEntry["ref"] = assignment.getVariable().getName(); |
|||
assignmentEntry["value"] = buildExpression(assignment.getAssignedExpression()); |
|||
if(addIndex) { |
|||
assignmentEntry["index"] = assignment.getLevel(); |
|||
} |
|||
assignmentDeclarations.push_back(assignmentEntry); |
|||
} |
|||
return modernjson::json(assignmentDeclarations); |
|||
} |
|||
|
|||
modernjson::json buildLocationsArray(std::vector<storm::jani::Location> const& locations) { |
|||
std::vector<modernjson::json> locationDeclarations; |
|||
for(auto const& location : locations) { |
|||
modernjson::json locEntry; |
|||
locEntry["name"] = location.getName(); |
|||
// TODO support invariants?
|
|||
locEntry["transient-values"] = buildAssignmentArray(location.getAssignments()); |
|||
locationDeclarations.push_back(locEntry); |
|||
} |
|||
return modernjson::json(locationDeclarations); |
|||
} |
|||
|
|||
modernjson::json buildInitialLocations(storm::jani::Automaton const& automaton) { |
|||
std::vector<std::string> names; |
|||
for(auto const& initLocIndex : automaton.getInitialLocationIndices()) { |
|||
names.push_back(automaton.getLocation(initLocIndex).getName()); |
|||
} |
|||
return modernjson::json(names); |
|||
} |
|||
|
|||
modernjson::json buildDestinations(std::vector<EdgeDestination> const& destinations, std::map<uint64_t, std::string> const& locationNames) { |
|||
std::vector<modernjson::json> destDeclarations; |
|||
for(auto const& destination : destinations) { |
|||
modernjson::json destEntry; |
|||
destEntry["location"] = locationNames.at(destination.getLocationIndex()); |
|||
destEntry["probability"]["exp"] = buildExpression(destination.getProbability()); |
|||
destEntry["assignments"] = buildAssignmentArray(destination.getOrderedAssignments()); |
|||
destDeclarations.push_back(destEntry); |
|||
} |
|||
return modernjson::json(destDeclarations); |
|||
} |
|||
|
|||
modernjson::json buildEdges(std::vector<Edge> const& edges , std::map<uint64_t, std::string> const& actionNames, std::map<uint64_t, std::string> const& locationNames) { |
|||
std::vector<modernjson::json> edgeDeclarations; |
|||
for(auto const& edge : edges) { |
|||
modernjson::json edgeEntry; |
|||
edgeEntry["location"] = locationNames.at(edge.getSourceLocationIndex()); |
|||
if(!edge.hasSilentAction()) { |
|||
edgeEntry["action"] = actionNames.at(edge.getActionIndex()); |
|||
} |
|||
if(edge.hasRate()) { |
|||
edgeEntry["rate"]["exp"] = buildExpression(edge.getRate()); |
|||
} |
|||
edgeEntry["guard"]["exp"] = buildExpression(edge.getGuard()); |
|||
edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames); |
|||
|
|||
edgeDeclarations.push_back(edgeEntry); |
|||
} |
|||
return modernjson::json(edgeDeclarations); |
|||
} |
|||
|
|||
modernjson::json buildAutomataArray(std::vector<storm::jani::Automaton> const& automata, std::map<uint64_t, std::string> const& actionNames) { |
|||
std::vector<modernjson::json> automataDeclarations; |
|||
for(auto const& automaton : automata) { |
|||
modernjson::json autoEntry; |
|||
autoEntry["name"] = automaton.getName(); |
|||
autoEntry["variables"] = buildVariablesArray(automaton.getVariables()); |
|||
if(automaton.hasRestrictedInitialStates()) { |
|||
autoEntry["restrict-initial"]["exp"] = buildExpression(automaton.getInitialStatesRestriction()); |
|||
} |
|||
autoEntry["locations"] = buildLocationsArray(automaton.getLocations()); |
|||
autoEntry["initial-locations"] = buildInitialLocations(automaton); |
|||
autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap()); |
|||
automataDeclarations.push_back(autoEntry); |
|||
} |
|||
return modernjson::json(automataDeclarations); |
|||
} |
|||
|
|||
|
|||
void JsonExporter::convertModel(storm::jani::Model const& janiModel) { |
|||
jsonStruct["jani-version"] = janiModel.getJaniVersion(); |
|||
jsonStruct["name"] = janiModel.getName(); |
|||
jsonStruct["type"] = to_string(janiModel.getModelType()); |
|||
jsonStruct["actions"] = buildActionArray(janiModel.getActions()); |
|||
jsonStruct["constants"] = buildConstantsArray(janiModel.getConstants()); |
|||
jsonStruct["variables"] = buildVariablesArray(janiModel.getGlobalVariables()); |
|||
jsonStruct["restrict-initial"]["exp"] = buildExpression(janiModel.getInitialStatesRestriction()); |
|||
jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap()); |
|||
jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition()); |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
} |
@ -0,0 +1,51 @@ |
|||
#pragma once |
|||
|
|||
|
|||
#include "src/storage/expressions/ExpressionVisitor.h" |
|||
#include "Model.h" |
|||
// JSON parser |
|||
#include "json.hpp" |
|||
namespace modernjson = nlohmann; |
|||
|
|||
namespace storm { |
|||
namespace jani { |
|||
|
|||
class ExpressionToJson : public storm::expressions::ExpressionVisitor { |
|||
|
|||
public: |
|||
static modernjson::json translate(storm::expressions::Expression const& expr); |
|||
|
|||
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data); |
|||
virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data); |
|||
|
|||
}; |
|||
|
|||
class JsonExporter { |
|||
JsonExporter() = default; |
|||
|
|||
public: |
|||
static void toFile(storm::jani::Model const& janiModel, std::string const& filepath, bool checkValid = true); |
|||
static void toStream(storm::jani::Model const& janiModel, std::ostream& ostream, bool checkValid = false); |
|||
|
|||
private: |
|||
void convertModel(storm::jani::Model const& model); |
|||
void appendVariableDeclaration(storm::jani::Variable const& variable); |
|||
|
|||
modernjson::json finalize() { |
|||
return jsonStruct; |
|||
} |
|||
|
|||
modernjson::json jsonStruct; |
|||
|
|||
|
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
#include "Block.h"
|
|||
#include "StatementPrinterVisitor.h"
|
|||
#include <typeinfo>
|
|||
|
|||
namespace storm { |
|||
namespace pgcl { |
|||
|
|||
|
|||
PgclBlock::PgclBlock(vector const &statements, std::shared_ptr<storm::expressions::ExpressionManager> expressions, bool hasLoop, bool hasNondet, bool hasObserve) |
|||
: sequenceOfStatements(statements), |
|||
expressions(expressions), |
|||
loop(hasLoop), |
|||
nondet(hasNondet), |
|||
observe(hasObserve) |
|||
{ |
|||
|
|||
} |
|||
|
|||
iterator PgclBlock::begin() { |
|||
return this->sequenceOfStatements.begin(); |
|||
} |
|||
|
|||
const_iterator PgclBlock::begin() const { |
|||
return this->sequenceOfStatements.begin(); |
|||
} |
|||
|
|||
iterator PgclBlock::end() { |
|||
return this->sequenceOfStatements.end(); |
|||
} |
|||
|
|||
const_iterator PgclBlock::end() const { |
|||
return this->sequenceOfStatements.end(); |
|||
} |
|||
|
|||
bool PgclBlock::empty() { |
|||
return this->sequenceOfStatements.empty(); |
|||
} |
|||
|
|||
element PgclBlock::front() { |
|||
return this->sequenceOfStatements.front(); |
|||
} |
|||
|
|||
element PgclBlock::back() { |
|||
return this->sequenceOfStatements.back(); |
|||
} |
|||
|
|||
unsigned long PgclBlock::size() { |
|||
return this->sequenceOfStatements.size(); |
|||
} |
|||
|
|||
element PgclBlock::at(size_type n) { |
|||
return this->sequenceOfStatements.at(n); |
|||
} |
|||
|
|||
iterator PgclBlock::insert(iterator position, const element& statement) { |
|||
return this->sequenceOfStatements.insert(position, statement); |
|||
} |
|||
|
|||
void PgclBlock::clear() { |
|||
this->sequenceOfStatements.clear(); |
|||
} |
|||
|
|||
std::shared_ptr<storm::expressions::ExpressionManager> const& PgclBlock::getExpressionManager() const { |
|||
return this->expressions; |
|||
} |
|||
|
|||
std::vector<storm::expressions::Variable> PgclBlock::getParameters() { |
|||
return this->parameters; |
|||
} |
|||
|
|||
bool PgclBlock::hasParameters() const { |
|||
return !(this->parameters.empty()); |
|||
} |
|||
|
|||
bool PgclBlock::hasObserve() const { |
|||
return this->observe; |
|||
} |
|||
|
|||
bool PgclBlock::hasNondet() const { |
|||
return this->nondet; |
|||
} |
|||
|
|||
bool PgclBlock::hasLoop() const { |
|||
return this->loop; |
|||
} |
|||
|
|||
iterator PgclBlock::find(element &statement) { |
|||
return std::find(this->sequenceOfStatements.begin(), this->sequenceOfStatements.end(), statement); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,121 @@ |
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include "src/storage/pgcl/Statement.h" |
|||
#include "src/storage/pgcl/StatementPrinterVisitor.h" |
|||
#include "src/storage/expressions/ExpressionManager.h" |
|||
|
|||
namespace storm { |
|||
namespace pgcl { |
|||
|
|||
typedef std::shared_ptr<storm::pgcl::Statement> element; |
|||
typedef std::vector<element> vector; |
|||
typedef std::vector<element>::iterator iterator; |
|||
typedef std::vector<element>::const_iterator const_iterator; |
|||
typedef std::vector<element>::size_type size_type; |
|||
|
|||
/** |
|||
* This class represents a complete and functional PGCL program. It |
|||
* contains an expression manager which keeps track of the current |
|||
* identifiers and variable valuations. Other than that, it basically |
|||
* wraps a std::vector of program statements and is intended to be used |
|||
* as such. |
|||
*/ |
|||
class PgclBlock { |
|||
public: |
|||
PgclBlock() = default; |
|||
/** |
|||
* Does the same as the beforementioned constructor, but sets the |
|||
* location to statement vector to the empty vector. This |
|||
* constructor should be used for sub-programs, for which the |
|||
* location to statement relation doesn't make much sense. |
|||
* @param statements The sequence of statements representing the |
|||
* program. |
|||
* @param expressions The manager responsible for the expressions |
|||
* and variables of the program. |
|||
* @param hasLoop Whether the program contains a loop |
|||
* @param hasNondet Whether the program contains a nondeterministic |
|||
* statement. |
|||
* @param hasParam Whether the program is parameterized. |
|||
*/ |
|||
PgclBlock(vector const& statements, std::shared_ptr<storm::expressions::ExpressionManager> expressions, bool hasLoop, bool hasNondet, bool hasObserve); |
|||
PgclBlock(const PgclBlock & orig) = default; |
|||
PgclBlock & operator=(PgclBlock const& other) = default; |
|||
iterator begin(); |
|||
const_iterator begin() const; |
|||
iterator end(); |
|||
const_iterator end() const; |
|||
element front(); |
|||
element back(); |
|||
unsigned long size(); |
|||
element at(size_type n); |
|||
iterator insert(iterator position, const element& statement); |
|||
iterator find(element& statement); |
|||
void clear(); |
|||
bool empty(); |
|||
|
|||
/** |
|||
* Returns the list of parameters of the PGCL program. |
|||
*/ |
|||
std::vector<storm::expressions::Variable> getParameters(); |
|||
/** |
|||
* Returns the expression manager of the PGCL program, which is |
|||
* responsible for managing all expressions and variables of the |
|||
* the program and all its subprograms. |
|||
* @return The expression manager of the program. |
|||
*/ |
|||
std::shared_ptr<storm::expressions::ExpressionManager> const& getExpressionManager() const; |
|||
|
|||
/** |
|||
* Returns true if the program contains a loop statement. |
|||
* @return True if the program has a loop. |
|||
*/ |
|||
bool hasLoop() const; |
|||
/** |
|||
* Returns true if the program contains a nondeterministic |
|||
* statement. |
|||
* @return True if the program has a nondeterministic statement. |
|||
*/ |
|||
bool hasNondet() const; |
|||
/** |
|||
* Returns true if the program contains an observe statement. |
|||
* @return True if the program has an observe statement. |
|||
*/ |
|||
bool hasObserve() const; |
|||
/** |
|||
* Returns true if the program is parameterized. |
|||
* @return True if the program has at least one parameter. |
|||
*/ |
|||
bool hasParameters() const; |
|||
|
|||
protected: |
|||
/** |
|||
* We are basically wrapping a std::vector which represents the |
|||
* ordered single statements of the program. |
|||
*/ |
|||
vector sequenceOfStatements; |
|||
/** |
|||
* Stores the parameters a.k.a. free variables of the PGCL program. |
|||
*/ |
|||
std::vector<storm::expressions::Variable> parameters; |
|||
/** |
|||
* Handles the expressions and variables for the whole program. |
|||
* The expressions of every subprogram are also handled by this |
|||
* manager. We are using a shared pointer since all subprograms |
|||
* are referring to that expression manager, too. |
|||
*/ |
|||
std::shared_ptr<storm::expressions::ExpressionManager> expressions; |
|||
/** |
|||
* Boolean variables to save some properties of the PGCL program. |
|||
* They are later on used by the model builder to possibly |
|||
* construct simpler models (e.g. if no loops, params and nondets |
|||
* are used, a DTMC suffices). |
|||
* The values are set to true if the PGCL parser hits a loop resp. |
|||
* nondet resp. observe resp. parameter statement. |
|||
*/ |
|||
bool loop = false; |
|||
bool nondet = false; |
|||
bool observe = false; |
|||
}; |
|||
} |
|||
} |
@ -1,25 +1,15 @@ |
|||
/*
|
|||
* File: BranchStatement.cpp |
|||
* Author: Lukas Westhofen |
|||
* |
|||
* Created on 11. April 2015, 17:42 |
|||
*/ |
|||
|
|||
#include "src/storage/pgcl/BranchStatement.h"
|
|||
#include "src/storage/pgcl/AbstractStatementVisitor.h"
|
|||
|
|||
namespace storm { |
|||
namespace pgcl { |
|||
std::shared_ptr<storm::pgcl::PgclProgram> BranchStatement::getLeftBranch() { |
|||
std::shared_ptr<storm::pgcl::PgclBlock> const& BranchStatement::getLeftBranch() const { |
|||
return this->leftBranch; |
|||
} |
|||
|
|||
std::shared_ptr<storm::pgcl::PgclProgram> BranchStatement::getRightBranch() { |
|||
std::shared_ptr<storm::pgcl::PgclBlock> const& BranchStatement::getRightBranch() const { |
|||
return this->rightBranch; |
|||
} |
|||
|
|||
std::size_t BranchStatement::getNumberOfOutgoingTransitions() { |
|||
return 2; |
|||
} |
|||
} |
|||
} |
@ -1,34 +1,24 @@ |
|||
/*
|
|||
* File: LoopStatement.cpp |
|||
* Author: Lukas Westhofen |
|||
* |
|||
* Created on 11. April 2015, 17:42 |
|||
*/ |
|||
|
|||
#include "src/storage/pgcl/LoopStatement.h"
|
|||
#include "src/storage/pgcl/AbstractStatementVisitor.h"
|
|||
|
|||
namespace storm { |
|||
namespace pgcl { |
|||
LoopStatement::LoopStatement(storm::pgcl::BooleanExpression const& condition, std::shared_ptr<storm::pgcl::PgclProgram> const& body) : |
|||
LoopStatement::LoopStatement(storm::pgcl::BooleanExpression const& condition, std::shared_ptr<storm::pgcl::PgclBlock> const& body) : |
|||
body(body), condition(condition) { |
|||
} |
|||
|
|||
std::shared_ptr<storm::pgcl::PgclProgram> LoopStatement::getBody() { |
|||
std::shared_ptr<storm::pgcl::PgclBlock> const& LoopStatement::getBody() const { |
|||
return this->body; |
|||
} |
|||
|
|||
storm::pgcl::BooleanExpression& LoopStatement::getCondition() { |
|||
storm::pgcl::BooleanExpression const& LoopStatement::getCondition() const{ |
|||
return this->condition; |
|||
} |
|||
|
|||
void LoopStatement::accept(storm::pgcl::AbstractStatementVisitor& visitor) { |
|||
visitor.visit(*this); |
|||
} |
|||
|
|||
std::size_t LoopStatement::getNumberOfOutgoingTransitions() { |
|||
return 1; |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,19 @@ |
|||
#include "ProgramAction.h"
|
|||
#include "ProgramGraph.h"
|
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
|
|||
ProbabilisticProgramAction::ProbabilisticProgramAction(ProgramGraph* graph, ProgramActionIdentifier actId, ProgramVariableIdentifier var, int64_t from, int64_t to) : ProgramAction(graph, actId), var(var) { |
|||
assert(from <= to); |
|||
storm::expressions::Expression prob = graph->getExpressionManager()->integer(1) / graph->getExpressionManager()->integer(to - from + 1); |
|||
for(int64_t i = from; i <= to; ++i) { |
|||
values.emplace_back(i, prob); |
|||
} |
|||
} |
|||
|
|||
std::string const& ProbabilisticProgramAction::getVariableName() const { |
|||
return getProgramGraph().getVariableName(var); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,163 @@ |
|||
#pragma once |
|||
#include "defines.h" |
|||
#include "src/storage/expressions/Expression.h" |
|||
#include "src/storage/expressions/Variable.h" |
|||
#include "src/storage/expressions/ExpressionManager.h" |
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
|
|||
class ProgramAction { |
|||
public: |
|||
ProgramAction(ProgramGraph* graph, ProgramActionIdentifier id) : graph(graph), actId(id) { |
|||
|
|||
} |
|||
|
|||
ProgramActionIdentifier id() const { |
|||
return actId; |
|||
} |
|||
|
|||
ProgramGraph const& getProgramGraph() const { |
|||
return *graph; |
|||
} |
|||
|
|||
virtual bool isProbabilistic() const = 0; |
|||
private: |
|||
ProgramGraph* graph; |
|||
ProgramActionIdentifier actId; |
|||
}; |
|||
|
|||
|
|||
struct ValueProbabilityPair { |
|||
ValueProbabilityPair(int64_t value, storm::expressions::Expression const& probability) : value(value), probability(probability) { |
|||
// Intentionally left empty. |
|||
} |
|||
|
|||
int64_t value; |
|||
storm::expressions::Expression probability; |
|||
}; |
|||
|
|||
class ProbabilisticProgramAction : public ProgramAction { |
|||
public: |
|||
// TODO in the long run, we probably need own iterators for this. |
|||
using iterator = std::vector<ValueProbabilityPair>::iterator; |
|||
using const_iterator = std::vector<ValueProbabilityPair>::const_iterator; |
|||
|
|||
|
|||
|
|||
/** |
|||
* Constructs a uniform assignment operation to a variable; |
|||
* Action assigns a variable according to a uniform distribution [from, to] |
|||
*/ |
|||
ProbabilisticProgramAction(ProgramGraph* graph, ProgramActionIdentifier actId, ProgramVariableIdentifier var, int64_t from, int64_t to); |
|||
|
|||
bool isProbabilistic() const override{ |
|||
return true; |
|||
} |
|||
|
|||
std::string const& getVariableName() const; |
|||
|
|||
iterator begin() { |
|||
return values.begin(); |
|||
} |
|||
|
|||
iterator end() { |
|||
return values.end(); |
|||
} |
|||
|
|||
const_iterator begin() const { |
|||
return values.begin(); |
|||
} |
|||
|
|||
const_iterator end() const { |
|||
return values.end(); |
|||
} |
|||
|
|||
private: |
|||
// TODO not the smartest representation (but at least it is internal!) |
|||
std::vector<ValueProbabilityPair> values; |
|||
ProgramVariableIdentifier var; |
|||
|
|||
}; |
|||
|
|||
|
|||
struct AssignmentGroup { |
|||
using iterator = std::unordered_map<uint64_t, storm::expressions::Expression>::iterator; |
|||
using const_iterator = std::unordered_map<uint64_t, storm::expressions::Expression>::const_iterator; |
|||
|
|||
storm::expressions::Expression& operator[](uint64_t varIndex) { |
|||
return map[varIndex]; |
|||
} |
|||
|
|||
bool hasVariable(uint64_t varIndex) const { |
|||
return map.count(varIndex) > 0; |
|||
} |
|||
|
|||
iterator begin() { |
|||
return map.begin(); |
|||
} |
|||
|
|||
iterator end() { |
|||
return map.end(); |
|||
} |
|||
|
|||
const_iterator begin() const { |
|||
return map.begin(); |
|||
} |
|||
|
|||
const_iterator end() const { |
|||
return map.end(); |
|||
} |
|||
|
|||
private: |
|||
std::unordered_map<ProgramVariableIdentifier, storm::expressions::Expression> map; |
|||
}; |
|||
|
|||
class DeterministicProgramAction : public ProgramAction { |
|||
|
|||
public: |
|||
using iterator = std::vector<AssignmentGroup>::iterator; |
|||
using const_iterator = std::vector<AssignmentGroup>::const_iterator; |
|||
|
|||
DeterministicProgramAction(ProgramGraph* graph, ProgramActionIdentifier actId) : ProgramAction(graph, actId) { |
|||
|
|||
} |
|||
|
|||
void addAssignment(ProgramVariableIdentifier varIndex, storm::expressions::Expression const& expr, uint64_t level=0) { |
|||
if(assignments.size() <= level) { |
|||
assignments.resize(level+1); |
|||
} |
|||
assert(!assignments[level].hasVariable(varIndex)); |
|||
assignments[level][varIndex] = expr; |
|||
} |
|||
|
|||
size_t nrLevels() const { |
|||
return assignments.size(); |
|||
} |
|||
|
|||
iterator begin() { |
|||
return assignments.begin(); |
|||
} |
|||
|
|||
iterator end() { |
|||
return assignments.end(); |
|||
} |
|||
|
|||
const_iterator begin() const { |
|||
return assignments.begin(); |
|||
} |
|||
|
|||
const_iterator end() const { |
|||
return assignments.end(); |
|||
} |
|||
|
|||
bool isProbabilistic() const override{ |
|||
return false; |
|||
} |
|||
|
|||
protected: |
|||
std::vector<AssignmentGroup> assignments; |
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
#include "ProgramEdge.h"
|
|||
#include "ProgramGraph.h"
|
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
|
|||
ProgramLocationIdentifier ProgramEdge::getSourceId() const { |
|||
return group->getSourceId(); |
|||
} |
|||
|
|||
ProgramAction const& ProgramEdge::getAction() const { |
|||
return group->getGraph().getAction(action); |
|||
} |
|||
|
|||
bool ProgramEdge::hasNoAction() const { |
|||
return action == group->getGraph().getNoActionId(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,51 @@ |
|||
#pragma once |
|||
#include "defines.h" |
|||
|
|||
#include "src/storage/expressions/Expression.h" |
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
class ProgramAction; |
|||
|
|||
class ProgramEdge { |
|||
public: |
|||
ProgramEdge(ProgramEdgeGroup* group, ProgramEdgeIdentifier id, ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier targetId) |
|||
: group(group), edgeId(id), target(targetId), action(action), condition(condition) |
|||
{ |
|||
// Intentionally left empty. |
|||
} |
|||
|
|||
ProgramLocationIdentifier getSourceId() const; |
|||
ProgramLocationIdentifier getTargetId() const { |
|||
return target; |
|||
} |
|||
|
|||
storm::expressions::Expression const& getCondition() const { |
|||
return condition; |
|||
} |
|||
|
|||
bool hasNoAction() const; |
|||
ProgramAction const& getAction() const; |
|||
ProgramActionIdentifier getActionId() const { |
|||
return action; |
|||
} |
|||
|
|||
virtual ~ProgramEdge() { |
|||
// Intentionally left empty. |
|||
} |
|||
|
|||
private: |
|||
/// Pointer to the group; not owned |
|||
ProgramEdgeGroup* group; |
|||
/// Edge identifier |
|||
ProgramEdgeIdentifier edgeId; |
|||
/// Target location identifier |
|||
ProgramLocationIdentifier target; |
|||
/// Action identifier |
|||
ProgramActionIdentifier action; |
|||
/// Condition |
|||
storm::expressions::Expression condition; |
|||
|
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
#include "ProgramEdgeGroup.h"
|
|||
#include "ProgramGraph.h"
|
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
ProgramEdge* ProgramEdgeGroup::addEdge(ProgramActionIdentifier action, ProgramLocationIdentifier target) { |
|||
return graph->addProgramEdge(*this, action, target); |
|||
} |
|||
ProgramEdge* ProgramEdgeGroup::addEdge(ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier target) { |
|||
return graph->addProgramEdge(*this, action, condition, target); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,78 @@ |
|||
#pragma once |
|||
|
|||
#include "defines.h" |
|||
#include "ProgramEdge.h" |
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
|
|||
class ProgramEdgeGroup { |
|||
public: |
|||
using const_iterator = std::vector<ProgramEdge*>::const_iterator; |
|||
|
|||
ProgramEdgeGroup(ProgramGraph* graph, ProgramEdgeGroupIdentifier id, ProgramLocationIdentifier sourceId, storm::expressions::Expression const& probability) |
|||
: graph(graph), groupId(id), sourceId(sourceId), probability(probability) |
|||
{ |
|||
// Intentionally left empty. |
|||
} |
|||
|
|||
virtual ~ProgramEdgeGroup() { |
|||
for( auto const& e : edges) { |
|||
delete e; |
|||
} |
|||
} |
|||
|
|||
ProgramEdge* addEdge(ProgramActionIdentifier action, ProgramLocationIdentifier target); |
|||
ProgramEdge* addEdge(ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier target); |
|||
|
|||
/** |
|||
* Constructs an outgoing edge in this edge group. |
|||
*/ |
|||
ProgramEdge* emplaceEdge(ProgramEdgeIdentifier id, ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier target) { |
|||
edges.emplace_back(new ProgramEdge(this, id, action, condition, target)); |
|||
return edges.back(); |
|||
} |
|||
|
|||
const_iterator begin() const { |
|||
return edges.begin(); |
|||
} |
|||
|
|||
const_iterator end() const { |
|||
return edges.end(); |
|||
} |
|||
|
|||
size_t nrEdges() const { |
|||
return edges.size(); |
|||
} |
|||
|
|||
storm::expressions::Expression const& getProbability() const { |
|||
return probability; |
|||
} |
|||
|
|||
ProgramGraph const& getGraph() const { |
|||
return *graph; |
|||
} |
|||
|
|||
ProgramLocationIdentifier getSourceId() const { |
|||
return sourceId; |
|||
} |
|||
|
|||
ProgramEdgeGroupIdentifier getId() const { |
|||
return groupId; |
|||
} |
|||
|
|||
private: |
|||
/// Pointer to the graph; not owned. |
|||
ProgramGraph* graph; |
|||
/// Own id (persistent over copy) |
|||
ProgramEdgeGroupIdentifier groupId; |
|||
/// Id of source location |
|||
ProgramLocationIdentifier sourceId; |
|||
/// Probability for this group |
|||
storm::expressions::Expression probability; |
|||
/// Outgoing edges |
|||
std::vector<ProgramEdge*> edges; |
|||
|
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,48 @@ |
|||
|
|||
#include "ProgramGraph.h"
|
|||
|
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
void ProgramGraph::printDot(std::ostream& os) const { |
|||
os << "digraph ppg {" << std::endl; |
|||
|
|||
for (auto const& loc : locations) { |
|||
os << "\tl" << loc.first << "[label=" << loc.first << "];"<< std::endl; |
|||
} |
|||
os << std::endl; |
|||
for (auto const& loc : locations) { |
|||
if (loc.second.nrOutgoingEdgeGroups() > 1) { |
|||
for (auto const& edgegroup : loc.second) { |
|||
os << "\teg" << edgegroup->getId() << "[shape=circle];"<< std::endl; |
|||
} |
|||
} |
|||
} |
|||
os << std::endl; |
|||
for (auto const& loc : locations) { |
|||
for (auto const& edgegroup : loc.second) { |
|||
|
|||
if (loc.second.nrOutgoingEdgeGroups() > 1) { |
|||
os << "\tl" << loc.first << " -> eg" << edgegroup->getId() << ";" << std::endl; |
|||
for (auto const& edge : *edgegroup) { |
|||
os << "\teg" << edgegroup->getId() << " -> l" << edge->getTargetId(); |
|||
if (!edge->hasNoAction()) { |
|||
os << " [label=\"" << edge->getActionId() << "\"]"; |
|||
} |
|||
os << ";" << std::endl; |
|||
} |
|||
} else { |
|||
for (auto const& edge : *edgegroup) { |
|||
os << "\tl" << loc.first << " -> l" << edge->getTargetId(); |
|||
if (!edge->hasNoAction()) { |
|||
os << " [label=\"" << edge->getActionId() << "\"]"; |
|||
} |
|||
os << ";" << std::endl; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
os << "}" << std::endl; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,236 @@ |
|||
#pragma once |
|||
|
|||
#include "defines.h" |
|||
#include "src/storage/expressions/Expression.h" |
|||
#include "src/storage/expressions/Variable.h" |
|||
#include "src/storage/expressions/ExpressionManager.h" |
|||
|
|||
#include "ProgramLocation.h" |
|||
#include "ProgramEdge.h" |
|||
#include "ProgramEdgeGroup.h" |
|||
#include "ProgramAction.h" |
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
/** |
|||
* Program graph as based on Principles of Model Checking, Def 2.13 |
|||
* Action effects are part of the action. |
|||
*/ |
|||
class ProgramGraph { |
|||
public: |
|||
using EdgeGroupIterator = ProgramLocation::EdgeGroupIterator; |
|||
using ConstLocationIterator = std::unordered_map<ProgramLocationIdentifier, ProgramLocation>::const_iterator; |
|||
|
|||
ProgramGraph(std::shared_ptr<storm::expressions::ExpressionManager> const& expManager, std::vector<storm::expressions::Variable> const& variables) : expManager(expManager), variables() { |
|||
for(auto const& v : variables) { |
|||
this->variables.emplace(v.getIndex(), v); |
|||
} |
|||
// No Action: |
|||
deterministicActions.emplace(noActionId, DeterministicProgramAction(this, noActionId)); |
|||
} |
|||
|
|||
ProgramGraph(ProgramGraph const&) = delete; |
|||
|
|||
virtual ~ProgramGraph() { |
|||
} |
|||
|
|||
DeterministicProgramAction* addDeterministicAction() { |
|||
ProgramActionIdentifier newId = freeActionIndex(); |
|||
assert(!hasAction(newId)); |
|||
return &(deterministicActions.emplace(newId, DeterministicProgramAction(this, newId)).first->second); |
|||
} |
|||
|
|||
ProbabilisticProgramAction* addUniformProbabilisticAction(ProgramVariableIdentifier var, int64_t from, int64_t to) { |
|||
ProgramActionIdentifier newId = freeActionIndex(); |
|||
assert(!hasAction(newId)); |
|||
return &(probabilisticActions.emplace(newId, ProbabilisticProgramAction(this, newId, var, from, to)).first->second); |
|||
} |
|||
|
|||
ProgramLocation* addLocation(bool isInitial = false) { |
|||
ProgramLocationIdentifier newId = freeLocationIndex(); |
|||
assert(!hasLocation(newId)); |
|||
return &(locations.emplace(newId, ProgramLocation(this, newId, isInitial)).first->second); |
|||
} |
|||
|
|||
|
|||
ProgramEdgeGroup* addProgramEdgeGroup(ProgramLocation& source, storm::expressions::Expression const& probability) { |
|||
ProgramEdgeGroupIdentifier newId = freeEdgeGroupIndex(); |
|||
return source.emplaceEdgeGroup(newId, probability); |
|||
} |
|||
|
|||
ProgramEdgeGroup* addProgramEdgeGroup(ProgramLocationIdentifier sourceId, storm::expressions::Expression const& probability) { |
|||
assert(hasLocation(sourceId)); |
|||
return addProgramEdgeGroup(getLocation(sourceId), probability); |
|||
} |
|||
|
|||
ProgramEdge* addProgramEdge(ProgramEdgeGroup& group, ProgramActionIdentifier action, ProgramLocationIdentifier targetId) { |
|||
return addProgramEdge(group, action, expManager->boolean(true), targetId); |
|||
} |
|||
|
|||
ProgramEdge* addProgramEdge(ProgramEdgeGroup& group, ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier targetId) { |
|||
ProgramEdgeIdentifier newId = freeEdgeIndex(); |
|||
return group.emplaceEdge(newId, action, condition, targetId); |
|||
} |
|||
|
|||
std::vector<ProgramEdge*> addProgramEdgeToAllGroups(ProgramLocation& source, ProgramActionIdentifier action, ProgramLocationIdentifier targetId) { |
|||
return addProgramEdgeToAllGroups(source, action, expManager->boolean(true), targetId); |
|||
} |
|||
|
|||
std::vector<ProgramEdge*> addProgramEdgeToAllGroups(ProgramLocation& source, ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier targetId) { |
|||
assert(hasLocation(targetId)); |
|||
assert(hasAction(action)); |
|||
|
|||
if(source.nrOutgoingEdgeGroups() == 0) { |
|||
addProgramEdgeGroup(source, expManager->rational(1)); |
|||
} |
|||
|
|||
std::vector<ProgramEdge*> res; |
|||
for(EdgeGroupIterator eg = source.getOutgoingEdgeGroupBegin(); eg != source.getOutgoingEdgeGroupEnd(); ++eg) { |
|||
ProgramEdgeIdentifier newId = freeEdgeIndex(); |
|||
res.push_back((*eg)->emplaceEdge(newId, action, condition, targetId)); |
|||
|
|||
} |
|||
|
|||
return res; |
|||
|
|||
} |
|||
|
|||
|
|||
ProgramActionIdentifier getNoActionId() const { |
|||
return noActionId; |
|||
} |
|||
|
|||
std::vector<ProgramEdge*> addProgramEdgeToAllGroups(ProgramLocationIdentifier sourceId, ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier targetId) { |
|||
assert(hasLocation(sourceId)); |
|||
return addProgramEdgeToAllGroups(getLocation(sourceId), action, condition, targetId); |
|||
} |
|||
|
|||
|
|||
ProgramVariableIdentifier getVariableId(std::string const& varName) const { |
|||
// TODO consider holding a map for this. |
|||
for(auto const& v : variables) { |
|||
if(v.second.getName() == varName) { |
|||
return v.first; |
|||
} |
|||
} |
|||
assert(false); |
|||
} |
|||
|
|||
std::string const& getVariableName(ProgramVariableIdentifier id) const { |
|||
return variables.at(id).getName(); |
|||
} |
|||
|
|||
bool hasVariable(std::string const& varName) const { |
|||
for(auto const& v : variables) { |
|||
if(v.second.getName() == varName) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool hasLocation(ProgramLocationIdentifier id) const { |
|||
return locations.count(id) == 1; |
|||
} |
|||
|
|||
bool hasAction(ProgramActionIdentifier id) const { |
|||
return deterministicActions.count(id) == 1 || probabilisticActions.count(id); |
|||
} |
|||
|
|||
ProgramAction const& getAction(ProgramActionIdentifier id) const { |
|||
assert(hasAction(id)); |
|||
if(isDeterministicAction(id)) { |
|||
return deterministicActions.at(id); |
|||
} else { |
|||
return probabilisticActions.at(id); |
|||
} |
|||
} |
|||
|
|||
bool isDeterministicAction(ProgramActionIdentifier id) const { |
|||
assert(hasAction(id)); |
|||
return probabilisticActions.count(id) == 0; |
|||
} |
|||
|
|||
size_t nrLocations() const { |
|||
return locations.size(); |
|||
} |
|||
|
|||
size_t nrVariables() const { |
|||
return variables.size(); |
|||
} |
|||
|
|||
size_t nrActions() const { |
|||
return variables.size(); |
|||
} |
|||
|
|||
|
|||
ConstLocationIterator locationBegin() const { |
|||
return locations.begin(); |
|||
} |
|||
|
|||
ConstLocationIterator locationEnd() const { |
|||
return locations.end(); |
|||
} |
|||
|
|||
std::unordered_map<ProgramVariableIdentifier, storm::expressions::Variable> const& getVariables() const { |
|||
return variables; |
|||
} |
|||
|
|||
std::shared_ptr<storm::expressions::ExpressionManager> const& getExpressionManager() const { |
|||
return expManager; |
|||
} |
|||
|
|||
void checkValid() { |
|||
|
|||
} |
|||
|
|||
void printInfo(std::ostream& os) const { |
|||
os << "Number of variables: " << nrVariables() << std::endl; |
|||
os << "Number of locations: " << nrLocations() << std::endl; |
|||
os << "Number of actions: " << nrActions() << std::endl; |
|||
} |
|||
|
|||
void printDot(std::ostream& os) const; |
|||
protected: |
|||
|
|||
ProgramLocation& getLocation(ProgramLocationIdentifier id) { |
|||
return locations.at(id); |
|||
} |
|||
|
|||
/** |
|||
* Gets a free location index (based on whatever scheme we are using). |
|||
*/ |
|||
ProgramLocationIdentifier freeLocationIndex() { |
|||
return newLocationId++; |
|||
} |
|||
|
|||
ProgramActionIdentifier freeActionIndex() { |
|||
return newActionId++; |
|||
} |
|||
|
|||
ProgramEdgeIdentifier freeEdgeIndex() { |
|||
return newEdgeId++; |
|||
} |
|||
|
|||
ProgramEdgeGroupIdentifier freeEdgeGroupIndex() { |
|||
return newEdgeGroupId++; |
|||
} |
|||
|
|||
std::unordered_map<ProgramActionIdentifier, DeterministicProgramAction> deterministicActions; |
|||
std::unordered_map<ProgramActionIdentifier, ProbabilisticProgramAction> probabilisticActions; |
|||
std::unordered_map<ProgramLocationIdentifier, ProgramLocation> locations; |
|||
storm::expressions::Expression initialValueRestriction; |
|||
std::unordered_map<ProgramVariableIdentifier, storm::expressions::Variable> variables; |
|||
|
|||
std::shared_ptr<storm::expressions::ExpressionManager> expManager; |
|||
private: |
|||
// Helper for IDs, may be changed later. |
|||
ProgramEdgeGroupIdentifier newEdgeGroupId = 0; |
|||
ProgramLocationIdentifier newLocationId = 0; |
|||
ProgramEdgeIdentifier newEdgeId = 0; |
|||
ProgramActionIdentifier newActionId = 1; |
|||
ProgramActionIdentifier noActionId = 0; |
|||
|
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
|
|||
#include "ProgramLocation.h"
|
|||
#include "ProgramGraph.h"
|
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
|
|||
std::vector<ProgramEdge*> ProgramLocation::addProgramEdgeToAllGroups(ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier targetId) { |
|||
return graph->addProgramEdgeToAllGroups(*this, action, condition, targetId); |
|||
} |
|||
|
|||
std::vector<ProgramEdge*> ProgramLocation::addProgramEdgeToAllGroups(ProgramActionIdentifier action, ProgramLocationIdentifier targetId) { |
|||
return graph->addProgramEdgeToAllGroups(*this, action, targetId); |
|||
} |
|||
|
|||
ProgramEdgeGroup* ProgramLocation::addProgramEdgeGroup(storm::expressions::Expression const& probability) { |
|||
return graph->addProgramEdgeGroup(*this, probability); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,80 @@ |
|||
#pragma once |
|||
|
|||
#include "defines.h" |
|||
#include "ProgramEdgeGroup.h" |
|||
|
|||
namespace storm { |
|||
namespace ppg { |
|||
class ProgramLocation { |
|||
public: |
|||
using EdgeGroupIterator = std::vector<ProgramEdgeGroup*>::iterator; |
|||
using const_iterator = std::vector<ProgramEdgeGroup*>::const_iterator; |
|||
|
|||
ProgramLocation(ProgramGraph* graph, ProgramLocationIdentifier id, bool initial) : graph(graph), locId(id), init(initial){ |
|||
// Intentionally left empty |
|||
} |
|||
|
|||
virtual ~ProgramLocation() { |
|||
for( auto const& e : edgeGroups) { |
|||
delete e; |
|||
} |
|||
} |
|||
|
|||
|
|||
std::vector<ProgramEdge*> addProgramEdgeToAllGroups(ProgramActionIdentifier action, storm::expressions::Expression const& condition, ProgramLocationIdentifier targetId); |
|||
std::vector<ProgramEdge*> addProgramEdgeToAllGroups(ProgramActionIdentifier action, ProgramLocationIdentifier targetId); |
|||
ProgramEdgeGroup* addProgramEdgeGroup(storm::expressions::Expression const& probability); |
|||
|
|||
|
|||
ProgramEdgeGroup* emplaceEdgeGroup(ProgramEdgeGroupIdentifier id, storm::expressions::Expression const& probability) { |
|||
edgeGroups.emplace_back(new ProgramEdgeGroup(graph, id, locId, probability)); |
|||
return edgeGroups.back(); |
|||
} |
|||
|
|||
bool isInitial() const { |
|||
return init; |
|||
} |
|||
|
|||
size_t nrOutgoingEdgeGroups() const { |
|||
return edgeGroups.size(); |
|||
} |
|||
|
|||
bool hasNonDeterminism() const { |
|||
for(auto const& eg : edgeGroups) { |
|||
if(eg->nrEdges() > 1) return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
const_iterator begin() const { |
|||
return edgeGroups.begin(); |
|||
} |
|||
|
|||
const_iterator end() const { |
|||
return edgeGroups.end(); |
|||
} |
|||
|
|||
// Todo rename? |
|||
EdgeGroupIterator getOutgoingEdgeGroupBegin() { |
|||
return edgeGroups.begin(); |
|||
} |
|||
|
|||
// Todo rename? |
|||
EdgeGroupIterator getOutgoingEdgeGroupEnd() { |
|||
return edgeGroups.end(); |
|||
} |
|||
|
|||
ProgramLocationIdentifier id() const { |
|||
return locId; |
|||
} |
|||
|
|||
private: |
|||
ProgramGraph* graph; |
|||
ProgramLocationIdentifier locId; |
|||
bool init; |
|||
std::vector<ProgramEdgeGroup*> edgeGroups; |
|||
|
|||
|
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
#pragma once |
|||
#include <cassert> |
|||
#include <vector> |
|||
namespace storm { |
|||
namespace ppg { |
|||
class ProgramGraph; |
|||
class ProgramEdgeGroup; |
|||
class ProgramLocation; |
|||
using ProgramLocationIdentifier = uint64_t; |
|||
using ProgramActionIdentifier = uint64_t; |
|||
using ProgramEdgeGroupIdentifier = uint64_t; |
|||
using ProgramEdgeIdentifier = uint64_t; |
|||
using ProgramVariableIdentifier = uint64_t; |
|||
|
|||
} |
|||
} |
Reference in new issue
xxxxxxxxxx