diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index de4c0fde1..ee67568ba 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-cli-utilities PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-cli-utilities) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers) +target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers storm-conv) # Install storm headers to include directory. foreach(HEADER ${STORM_CLI_UTIL_HEADERS}) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 524d772be..14cd9aa3f 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -4,6 +4,7 @@ #include "storm-counterexamples/api/counterexamples.h" #include "storm-parsers/api/storm-parsers.h" +#include "storm-conv/api/storm-conv.h" #include "storm/utility/resources.h" #include "storm/utility/file.h" @@ -154,6 +155,15 @@ namespace storm { } } + if (output.model && output.model.get().isJaniModel()) { + storm::converter::JaniConversionOptions options; + options.allowFunctions = false; + options.allowArrays = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse && !buildSettings.isJitSet(); + options.standardCompliant = false; + options.flatten = false; + output.preprocessedProperties = output.properties; + storm::api::transformJani(output.model.get().asJaniModel(), output.preprocessedProperties.get(), options); + } return output; } diff --git a/src/storm/builder/BuilderOptions.cpp b/src/storm/builder/BuilderOptions.cpp index 271a4e873..069f44b68 100644 --- a/src/storm/builder/BuilderOptions.cpp +++ b/src/storm/builder/BuilderOptions.cpp @@ -129,7 +129,7 @@ namespace storm { return labelNames; } - std::vector const& BuilderOptions::getExpressionLabels() const { + std::vector> const& BuilderOptions::getExpressionLabels() const { return expressionLabels; } @@ -211,7 +211,9 @@ namespace storm { } BuilderOptions& BuilderOptions::addLabel(storm::expressions::Expression const& expression) { - expressionLabels.emplace_back(expression); + std::stringstream stream; + stream << expression; + expressionLabels.emplace_back(stream.str(), expression); return *this; } @@ -261,5 +263,19 @@ namespace storm { return *this; } + BuilderOptions& BuilderOptions::substituteExpressions(std::function const& substitutionFunction) { + for (auto& e : expressionLabels) { + e.second = substitutionFunction(e.second); + } + + for (auto& t : terminalStates) { + if (t.first.isExpression()) { + t.first = LabelOrExpression(substitutionFunction(t.first.getExpression())); + } + } + return *this; + } + + } } diff --git a/src/storm/builder/BuilderOptions.h b/src/storm/builder/BuilderOptions.h index eba9ff1da..813f31b67 100644 --- a/src/storm/builder/BuilderOptions.h +++ b/src/storm/builder/BuilderOptions.h @@ -96,7 +96,7 @@ namespace storm { * Which expression labels are built * @return */ - std::vector const& getExpressionLabels() const; + std::vector> const& getExpressionLabels() const; std::vector> const& getTerminalStates() const; bool hasTerminalStates() const; void clearTerminalStates(); @@ -179,7 +179,11 @@ namespace storm { */ BuilderOptions& setAddOverlappingGuardsLabel(bool newValue = true); - + /** + * Substitutes all expressions occurring in these options. + */ + BuilderOptions& substituteExpressions(std::function const& substitutionFunction); + private: /// A flag that indicates whether all reward models are to be built. In this case, the reward model names are /// to be ignored. @@ -195,7 +199,7 @@ namespace storm { std::set labelNames; /// The expression that are to be used for creating the state labeling. - std::vector expressionLabels; + std::vector> expressionLabels; /// If one of these labels/expressions evaluates to the given bool, the builder can abort the exploration. std::vector> terminalStates; diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index 4260c7c7f..47cd321db 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -1986,6 +1986,9 @@ namespace storm { } STORM_LOG_THROW(!model.usesAssignmentLevels(), storm::exceptions::WrongFormatException, "The symbolic JANI model builder currently does not support assignment levels."); + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The dd jani model builder does not support the following model feature(s): " << features.toString() << "."); storm::jani::Model preparedModel = model; diff --git a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp index 9a7042d81..d34a6c9f1 100644 --- a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp +++ b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp @@ -107,10 +107,6 @@ namespace storm { transientVariables.insert(variable.getExpressionVariable()); } - if (this->model.containsArrayVariables()) { - this->model.eliminateArrays(); - } - // Construct vector of the automata to be put in parallel. storm::jani::Composition const& topLevelComposition = this->model.getSystemComposition(); if (topLevelComposition.isAutomatonComposition()) { @@ -151,6 +147,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The input model contains undefined constants that influence the graph structure of the underlying model, which is not allowed."); } #endif + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidArgumentException, "The jit model builder does not support the following model feature(s): " << features.toString() << "."); + //STORM_LOG_THROW(!model.reusesActionsInComposition(), storm::exceptions::InvalidArgumentException, "The jit JANI model builder currently does not support reusing actions in parallel composition"); // Comment this in to print the JANI model for debugging purposes. @@ -1562,11 +1562,12 @@ namespace storm { } std::set expressionLabelStrings; - for (auto const& expression : this->options.getExpressionLabels()) { + for (auto const& expressionLabel : this->options.getExpressionLabels()) { cpptempl::data_map label; - std::string expressionLabelString = expression.toString(); + std::string const& expressionLabelString = expressionLabel.first; + auto const& expression = expressionLabel.second; if(expressionLabelStrings.count(expressionLabelString) == 0) { - label["name"] = expression.toString(); + label["name"] = expressionLabelString; label["predicate"] = expressionTranslator.translate(shiftVariablesWrtLowerBound(expression), storm::expressions::ToCppTranslationOptions(variablePrefixes, variableToName, storm::expressions::ToCppTranslationMode::CastDouble)); labels.push_back(label); expressionLabelStrings.insert(expressionLabelString); diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 7801db91d..8575f3a7d 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -3,7 +3,6 @@ #include "storm/models/sparse/StateLabeling.h" #include "storm/storage/expressions/SimpleValuation.h" - #include "storm/solver/SmtSolver.h" #include "storm/storage/jani/Edge.h" @@ -15,6 +14,7 @@ #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/CompositionInformationVisitor.h" #include "storm/storage/jani/traverser/AssignmentLevelFinder.h" +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" #include "storm/storage/sparse/JaniChoiceOrigins.h" @@ -42,10 +42,15 @@ namespace storm { STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables."); STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels."); + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); // Eliminate arrays if necessary. - if (this->model.containsArrayVariables()) { + if (features.hasArrays()) { arrayEliminatorData = this->model.eliminateArrays(true); + this->options.substituteExpressions([this](storm::expressions::Expression const& exp) {return arrayEliminatorData.transformExpression(exp);}); + features.remove(storm::jani::ModelFeature::Arrays); } + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator does not support the following model feature(s): " << features.toString() << "."); // Lift the transient edge destinations of the first assignment level. uint64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); @@ -809,7 +814,6 @@ namespace storm { for (auto const& element : transientVariableToExpressionMap) { transientVariableExpressions.push_back(std::make_pair(element.first.getName(), element.second)); } - return NextStateGenerator::label(stateStorage, initialStateIndices, deadlockStateIndices, transientVariableExpressions); } diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index 3b3186b68..6e1d91bc4 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -67,11 +67,7 @@ namespace storm { template storm::models::sparse::StateLabeling NextStateGenerator::label(storm::storage::sparse::StateStorage const& stateStorage, std::vector const& initialStateIndices, std::vector const& deadlockStateIndices, std::vector> labelsAndExpressions) { - for (auto const& expression : this->options.getExpressionLabels()) { - std::stringstream stream; - stream << expression; - labelsAndExpressions.push_back(std::make_pair(stream.str(), expression)); - } + labelsAndExpressions.insert(labelsAndExpressions.end(), this->options.getExpressionLabels().begin(), this->options.getExpressionLabels().end()); // Make the labels unique. std::sort(labelsAndExpressions.begin(), labelsAndExpressions.end(), [] (std::pair const& a, std::pair const& b) { return a.first < b.first; } ); diff --git a/src/storm/logic/ExpressionSubstitutionVisitor.cpp b/src/storm/logic/ExpressionSubstitutionVisitor.cpp new file mode 100644 index 000000000..267fcf42c --- /dev/null +++ b/src/storm/logic/ExpressionSubstitutionVisitor.cpp @@ -0,0 +1,99 @@ +#include "storm/logic/ExpressionSubstitutionVisitor.h" + +#include "storm/logic/Formulas.h" + +namespace storm { + namespace logic { + + std::shared_ptr ExpressionSubstitutionVisitor::substitute(Formula const& f, std::function const& substitutionFunction) const { + boost::any result = f.accept(*this, &substitutionFunction); + return boost::any_cast>(result); + } + + OperatorInformation substituteOperatorInformation(OperatorInformation const& operatorInformation, std::function const& substitutionFunction) { + boost::optional bound; + if(operatorInformation.bound) { + bound = Bound(operatorInformation.bound->comparisonType, substitutionFunction(operatorInformation.bound->threshold)); + } + return OperatorInformation(operatorInformation.optimalityType, bound); + } + + boost::any ExpressionSubstitutionVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::vector> lowerBounds, upperBounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + if (f.hasLowerBound(i)) { + lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), substitutionFunction(f.getLowerBound(i)))); + } else { + lowerBounds.emplace_back(); + } + if (f.hasUpperBound(i)) { + upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), substitutionFunction(f.getUpperBound(i)))); + } else { + upperBounds.emplace_back(); + } + timeBoundReferences.push_back(f.getTimeBoundReference(i)); + } + if (f.hasMultiDimensionalSubformulas()) { + std::vector> leftSubformulas, rightSubformulas; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + leftSubformulas.push_back(boost::any_cast>(f.getLeftSubformula(i).accept(*this, data))); + rightSubformulas.push_back(boost::any_cast>(f.getRightSubformula(i).accept(*this, data))); + } + return std::static_pointer_cast(std::make_shared(leftSubformulas, rightSubformulas, lowerBounds, upperBounds, timeBoundReferences)); + } else { + std::shared_ptr left = boost::any_cast>(f.getLeftSubformula().accept(*this, data)); + std::shared_ptr right = boost::any_cast>(f.getRightSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(left, right, lowerBounds, upperBounds, timeBoundReferences)); + } + } + + boost::any ExpressionSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::vector bounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + bounds.emplace_back(TimeBound(f.isBoundStrict(i), substitutionFunction(f.getBound(i)))); + timeBoundReferences.push_back(f.getTimeBoundReference(i)); + } + return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences)); + } + + boost::any ExpressionSubstitutionVisitor::visit(InstantaneousRewardFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(substitutionFunction(f.getBound()), f.getTimeBoundType())); + } + + boost::any ExpressionSubstitutionVisitor::visit(AtomicExpressionFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(substitutionFunction(f.getExpression()))); + } + + + } +} diff --git a/src/storm/logic/ExpressionSubstitutionVisitor.h b/src/storm/logic/ExpressionSubstitutionVisitor.h new file mode 100644 index 000000000..e594f9b79 --- /dev/null +++ b/src/storm/logic/ExpressionSubstitutionVisitor.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "storm/logic/CloneVisitor.h" + +#include "storm/storage/expressions/Expression.h" + +namespace storm { + + namespace logic { + + class ExpressionSubstitutionVisitor : public CloneVisitor { + public: + ExpressionSubstitutionVisitor() = default; + + std::shared_ptr substitute(Formula const& f, std::function const& substitutionFunction) const; + + virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(ProbabilityOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; + virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(AtomicExpressionFormula const& f, boost::any const& data) const override; + + }; + + } +} + diff --git a/src/storm/logic/Formula.cpp b/src/storm/logic/Formula.cpp index 3f871908e..aa27d8dbf 100644 --- a/src/storm/logic/Formula.cpp +++ b/src/storm/logic/Formula.cpp @@ -3,7 +3,8 @@ #include "storm/logic/FragmentChecker.h" #include "storm/logic/FormulaInformationVisitor.h" -#include "storm/logic/VariableSubstitutionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" +#include "storm/logic/ExpressionSubstitutionVisitor.h" #include "storm/logic/LabelSubstitutionVisitor.h" #include "storm/logic/ToExpressionVisitor.h" @@ -438,8 +439,13 @@ namespace storm { } std::shared_ptr Formula::substitute(std::map const& substitution) const { - VariableSubstitutionVisitor visitor(substitution); - return visitor.substitute(*this); + storm::expressions::JaniExpressionSubstitutionVisitor> v(substitution); + return substitute([&v](storm::expressions::Expression const& exp) {return v.substitute(exp);}); + } + + std::shared_ptr Formula::substitute(std::function const& expressionSubstitution) const { + ExpressionSubstitutionVisitor visitor; + return visitor.substitute(*this, expressionSubstitution); } std::shared_ptr Formula::substitute(std::map const& labelSubstitution) const { diff --git a/src/storm/logic/Formula.h b/src/storm/logic/Formula.h index a76dd0ef7..44826ff9e 100644 --- a/src/storm/logic/Formula.h +++ b/src/storm/logic/Formula.h @@ -198,6 +198,7 @@ namespace storm { std::shared_ptr asSharedPointer() const; std::shared_ptr substitute(std::map const& substitution) const; + std::shared_ptr substitute(std::function const& expressionSubstitution) const; std::shared_ptr substitute(std::map const& labelSubstitution) const; std::shared_ptr substitute(std::map const& labelSubstitution) const; diff --git a/src/storm/storage/jani/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp index d3d7d47fb..e733c295e 100644 --- a/src/storm/storage/jani/ArrayEliminator.cpp +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -578,15 +578,20 @@ namespace storm { return eliminator.eliminate(arrayExpression); } + void ArrayEliminatorData::transformProperty(storm::jani::Property& property) const { + property = property.substitute([this](storm::expressions::Expression const& exp) {return transformExpression(exp);}); + } + ArrayEliminatorData ArrayEliminator::eliminate(Model& model, bool keepNonTrivialArrayAccess) { auto sizes = detail::MaxArraySizeDeterminer().getMaxSizes(model); ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess, sizes).replace(model); - + if (!keepNonTrivialArrayAccess) { + model.getModelFeatures().remove(ModelFeature::Arrays); + } model.finalize(); STORM_LOG_ASSERT(!containsArrayExpression(model), "the model still contains array expressions."); return result; } - } } diff --git a/src/storm/storage/jani/ArrayEliminator.h b/src/storm/storage/jani/ArrayEliminator.h index 860aa37ea..70d2fe897 100644 --- a/src/storm/storage/jani/ArrayEliminator.h +++ b/src/storm/storage/jani/ArrayEliminator.h @@ -4,6 +4,7 @@ #include #include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/Property.h" namespace storm { namespace jani { @@ -14,6 +15,8 @@ namespace storm { // Transforms the given expression (which might contain array expressions) to an equivalent expression without array variables. storm::expressions::Expression transformExpression(storm::expressions::Expression const& arrayExpression) const; + // Transforms the given property (which might contain array expressions) to an equivalent property without array variables. + void transformProperty(storm::jani::Property& property) const; }; class ArrayEliminator { diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index c59eb5a34..a02a919eb 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -16,7 +16,7 @@ #include "storm/storage/jani/CompositionInformationVisitor.h" #include "storm/storage/jani/Compositions.h" #include "storm/storage/jani/JSONExporter.h" -#include "storm/storage/jani/traverser/ArrayEliminator.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -69,6 +69,7 @@ namespace storm { if (this != &other) { this->name = other.name; this->modelType = other.modelType; + this->modelFeatures = other.modelFeatures; this->version = other.version; this->expressionManager = other.expressionManager; this->actions = other.actions; diff --git a/src/storm/storage/jani/ModelFeatures.cpp b/src/storm/storage/jani/ModelFeatures.cpp index 755ac99d8..ada96c565 100644 --- a/src/storm/storage/jani/ModelFeatures.cpp +++ b/src/storm/storage/jani/ModelFeatures.cpp @@ -44,6 +44,10 @@ namespace storm { return features.count(ModelFeature::StateExitRewards) > 0; } + bool ModelFeatures::empty() const { + return features.empty(); + } + void ModelFeatures::add(ModelFeature const& modelFeature) { features.insert(modelFeature); } diff --git a/src/storm/storage/jani/ModelFeatures.h b/src/storm/storage/jani/ModelFeatures.h index f2604af96..363ee236c 100644 --- a/src/storm/storage/jani/ModelFeatures.h +++ b/src/storm/storage/jani/ModelFeatures.h @@ -19,6 +19,9 @@ namespace storm { bool hasDerivedOperators() const; bool hasStateExitRewards() const; + // Returns true, if no model feature is enabled. + bool empty() const; + void add(ModelFeature const& modelFeature); void remove(ModelFeature const& modelFeature); diff --git a/src/storm/storage/jani/Property.cpp b/src/storm/storage/jani/Property.cpp index 73c6d0dec..2da62b33e 100644 --- a/src/storm/storage/jani/Property.cpp +++ b/src/storm/storage/jani/Property.cpp @@ -30,6 +30,10 @@ namespace storm { return Property(name, filterExpression.substitute(substitution), comment); } + Property Property::substitute(std::function const& substitutionFunction) const { + return Property(name, filterExpression.substitute(substitutionFunction), comment); + } + Property Property::substituteLabels(std::map const& substitution) const { return Property(name, filterExpression.substituteLabels(substitution), comment); } diff --git a/src/storm/storage/jani/Property.h b/src/storm/storage/jani/Property.h index 74aceab5c..140afa3e7 100644 --- a/src/storm/storage/jani/Property.h +++ b/src/storm/storage/jani/Property.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "storm/modelchecker/results/FilterType.h" #include "storm/logic/Formulas.h" #include "storm/logic/FragmentSpecification.h" @@ -54,10 +56,14 @@ namespace storm { return FilterExpression(formula->substitute(substitution), ft, statesFormula->substitute(substitution)); } + FilterExpression substitute(std::function const& substitutionFunction) const { + return FilterExpression(formula->substitute(substitutionFunction), ft, statesFormula->substitute(substitutionFunction)); + } + FilterExpression substituteLabels(std::map const& labelSubstitution) const { return FilterExpression(formula->substitute(labelSubstitution), ft, statesFormula->substitute(labelSubstitution)); } - + private: // For now, we assume that the states are always the initial states. std::shared_ptr formula; @@ -103,6 +109,7 @@ namespace storm { std::string const& getComment() const; Property substitute(std::map const& substitution) const; + Property substitute(std::function const& substitutionFunction) const; Property substituteLabels(std::map const& labelSubstitution) const; FilterExpression const& getFilter() const;