You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
13 KiB
187 lines
13 KiB
#include "JaniProgramGraphBuilder.h"
|
|
|
|
#include "storm/storage/jani/EdgeDestination.h"
|
|
#include "storm/exceptions/NotSupportedException.h"
|
|
|
|
namespace storm {
|
|
namespace builder {
|
|
unsigned JaniProgramGraphBuilder::janiVersion = 1;
|
|
|
|
void JaniProgramGraphBuilder::addProcedureVariables(storm::jani::Model& model, storm::jani::Automaton& automaton) {
|
|
for (auto const& v : programGraph.getVariables()) {
|
|
if (isConstant(v.first)) {
|
|
storm::jani::Constant constant(v.second.getName(), v.second, programGraph.getInitialValue(v.first));
|
|
model.addConstant(constant);
|
|
} else if (v.second.hasBooleanType()) {
|
|
storm::jani::BooleanVariable* janiVar = new storm::jani::BooleanVariable(v.second.getName(), v.second, programGraph.getInitialValue(v.first), false);
|
|
automaton.addVariable(*janiVar);
|
|
variables.emplace(v.first, janiVar);
|
|
} else if (isRestrictedVariable(v.first) && !isRewardVariable(v.first)) {
|
|
storm::storage::IntegerInterval const& bounds = variableBounds(v.first);
|
|
if (bounds.hasLeftBound()) {
|
|
if (bounds.hasRightBound()) {
|
|
storm::jani::BoundedIntegerVariable* janiVar = new storm::jani::BoundedIntegerVariable (v.second.getName(), v.second, programGraph.getInitialValue(v.first), false, expManager->integer(bounds.getLeftBound().get()), expManager->integer(bounds.getRightBound().get()));
|
|
variables.emplace(v.first, janiVar);
|
|
automaton.addVariable(*janiVar);
|
|
} else {
|
|
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unbounded right bound is not supported yet");
|
|
}
|
|
} else {
|
|
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unbounded left bound is not supported yet");
|
|
}
|
|
} else {
|
|
storm::jani::UnboundedIntegerVariable* janiVar = new storm::jani::UnboundedIntegerVariable(v.second.getName(), v.second, programGraph.getInitialValue(v.first), isRewardVariable(v.first));
|
|
if(isRewardVariable(v.first)) {
|
|
model.addVariable(*janiVar);
|
|
} else {
|
|
automaton.addVariable(*janiVar);
|
|
}
|
|
variables.emplace(v.first, janiVar);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
storm::jani::OrderedAssignments JaniProgramGraphBuilder::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) {
|
|
if(isRewardVariable(assignment.first)) {
|
|
std::unordered_map<storm::expressions::Variable, storm::expressions::Expression> eval;
|
|
eval.emplace((variables.at(assignment.first))->getExpressionVariable(), expManager->integer(0));
|
|
vec.emplace_back(storm::jani::LValue(*(variables.at(assignment.first))), assignment.second.substitute(eval).simplify(), level);
|
|
} else {
|
|
vec.emplace_back(storm::jani::LValue(*(variables.at(assignment.first))), assignment.second, level);
|
|
}
|
|
}
|
|
++level;
|
|
}
|
|
return storm::jani::OrderedAssignments(vec);
|
|
}
|
|
|
|
std::vector<std::pair<uint64_t, storm::expressions::Expression>> JaniProgramGraphBuilder::buildProbabilisticDestinations(storm::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge, storm::jani::TemplateEdge& templateEdge) {
|
|
storm::ppg::ProbabilisticProgramAction const& act = static_cast<storm::ppg::ProbabilisticProgramAction const&>(edge.getAction());
|
|
std::vector<std::pair<uint64_t, storm::expressions::Expression>> vec;
|
|
for(auto const& assign : act) {
|
|
storm::jani::Assignment assignment(storm::jani::LValue(automaton.getVariables().getVariable(act.getVariableName())), expManager->integer(assign.value), 0);
|
|
templateEdge.addDestination(storm::jani::TemplateEdgeDestination(storm::jani::OrderedAssignments(assignment)));
|
|
vec.emplace_back(janiLocId.at(edge.getTargetId()), assign.probability);
|
|
}
|
|
return vec;
|
|
}
|
|
|
|
std::vector<std::pair<uint64_t, storm::expressions::Expression>> JaniProgramGraphBuilder::buildDestinations(storm::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge, storm::jani::TemplateEdge& templateEdge) {
|
|
if (edge.getAction().isProbabilistic()) {
|
|
return buildProbabilisticDestinations(automaton, edge, templateEdge);
|
|
} else {
|
|
storm::jani::OrderedAssignments oa = buildOrderedAssignments(automaton, static_cast<storm::ppg::DeterministicProgramAction const&>(edge.getAction()));
|
|
templateEdge.addDestination(storm::jani::TemplateEdgeDestination(oa));
|
|
return {std::make_pair(janiLocId.at(edge.getTargetId()), expManager->rational(1.0))};
|
|
}
|
|
}
|
|
|
|
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::jani::Automaton& automaton, storm::ppg::ProgramEdge const& edge) {
|
|
std::vector<storm::jani::Edge> edges;
|
|
storm::expressions::Expression newGuard;
|
|
newGuard = expManager->boolean(true);
|
|
if (edge.getAction().isProbabilistic()) {
|
|
// No check necessary currently, but at least we should statically check that the bounds are okay.
|
|
storm::ppg::ProbabilisticProgramAction const& act = static_cast<storm::ppg::ProbabilisticProgramAction const&>(edge.getAction());
|
|
if (isUserRestrictedVariable(act.getVariableIdentifier())) {
|
|
storm::storage::IntegerInterval const& bound = userVariableRestrictions.at(act.getVariableIdentifier());
|
|
storm::storage::IntegerInterval supportInterval = act.getSupportInterval();
|
|
STORM_LOG_THROW(bound.contains(supportInterval), storm::exceptions::NotSupportedException, "User provided bounds must contain all constant expressions");
|
|
}
|
|
} 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 (isUserRestrictedVariable(assignment.first)) {
|
|
assert(userVariableRestrictions.count(assignment.first) == 1);
|
|
storm::storage::IntegerInterval const& bound = userVariableRestrictions.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(userVariableRestrictions.at(assignment.first).hasLeftBound() && userVariableRestrictions.at(assignment.first).hasRightBound());
|
|
storm::expressions::Expression newCondition = simplifyExpression(edge.getCondition() && (assignment.second > bound.getRightBound().get() || assignment.second < bound.getLeftBound().get()));
|
|
|
|
std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(newCondition);
|
|
automaton.registerTemplateEdge(templateEdge);
|
|
templateEdge->addDestination(storm::jani::TemplateEdgeDestination());
|
|
storm::jani::Edge e(janiLocId.at(edge.getSourceId()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, templateEdge, {varOutOfBoundsLocations.at(assignment.first)}, {expManager->rational(1.0)});
|
|
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) {
|
|
std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(expManager->boolean(true));
|
|
automaton.registerTemplateEdge(templateEdge);
|
|
templateEdge->addDestination(storm::jani::TemplateEdgeDestination());
|
|
storm::jani::Edge e(janiLocId.at(loc.id()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, templateEdge, {janiLocId.at(loc.id())}, {expManager->rational(1.0)});
|
|
automaton.addEdge(e);
|
|
} else if (loc.nrOutgoingEdgeGroups() == 1) {
|
|
for(auto const& edge : **(loc.begin())) {
|
|
std::pair<std::vector<storm::jani::Edge>, storm::expressions::Expression> checks = addVariableChecks(automaton, *edge);
|
|
for(auto const& check : checks.first) {
|
|
automaton.addEdge(check);
|
|
}
|
|
std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(simplifyExpression(edge->getCondition() && checks.second));
|
|
automaton.registerTemplateEdge(templateEdge);
|
|
|
|
std::vector<std::pair<uint64_t, storm::expressions::Expression>> destinationLocationsAndProbabilities = buildDestinations(automaton, *edge, *templateEdge);
|
|
|
|
storm::jani::Edge e(janiLocId.at(loc.id()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, templateEdge, destinationLocationsAndProbabilities);
|
|
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::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(expManager->boolean(true));
|
|
automaton.registerTemplateEdge(templateEdge);
|
|
|
|
|
|
std::vector<storm::expressions::Expression> destinationProbabilities;
|
|
std::vector<uint64_t> destinationLocations;
|
|
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.
|
|
destinationLocations.push_back(janiLocId.at((*eg->begin())->getTargetId()));
|
|
destinationProbabilities.push_back(eg->getProbability());
|
|
templateEdge->addDestination(storm::jani::TemplateEdgeDestination());
|
|
}
|
|
|
|
storm::jani::Edge e(janiLocId.at(it->second.id()), storm::jani::Model::SILENT_ACTION_INDEX, boost::none, templateEdge, destinationLocations, destinationProbabilities);
|
|
automaton.addEdge(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|