diff --git a/src/storm/generator/CompressedState.cpp b/src/storm/generator/CompressedState.cpp index 8fddc848e..041a0fac1 100644 --- a/src/storm/generator/CompressedState.cpp +++ b/src/storm/generator/CompressedState.cpp @@ -126,8 +126,34 @@ namespace storm { } } + template + storm::json unpackStateIntoJson(CompressedState const& state, VariableInformation const& variableInformation, bool onlyObservable) { + storm::json result; + for (auto const& locationVariable : variableInformation.locationVariables) { + if (onlyObservable && !locationVariable.observable) { + continue; + } + if (locationVariable.bitWidth != 0) { + result[locationVariable.variable.getName()] = state.getAsInt(locationVariable.bitOffset, locationVariable.bitWidth); + } else { + result[locationVariable.variable.getName()] = 0; + } + } + for (auto const& booleanVariable : variableInformation.booleanVariables) { + if (onlyObservable && !booleanVariable.observable) { + continue; + } + result[booleanVariable.getName()] = state.get(booleanVariable.bitOffset); + } + for (auto const& integerVariable : variableInformation.integerVariables) { + if (onlyObservable && !integerVariable.observable) { + continue; + } + result[integerVariable.getName()] = state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound; + } + return result; + } - template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager); CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit) { @@ -164,7 +190,11 @@ namespace storm { return result; } + template storm::json unpackStateIntoJson(CompressedState const& state, VariableInformation const& variableInformation, bool onlyObservable); + template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); #ifdef STORM_HAVE_CARL + template storm::json unpackStateIntoJson(CompressedState const& state, VariableInformation const& variableInformation, bool onlyObservable); + template storm::json unpackStateIntoJson(CompressedState const& state, VariableInformation const& variableInformation, bool onlyObservable); template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); #endif diff --git a/src/storm/generator/CompressedState.h b/src/storm/generator/CompressedState.h index 7a6446ecb..801e00fe9 100644 --- a/src/storm/generator/CompressedState.h +++ b/src/storm/generator/CompressedState.h @@ -2,6 +2,7 @@ #define STORM_GENERATOR_COMPRESSEDSTATE_H_ #include "storm/storage/BitVector.h" +#include "storm/adapters/JsonAdapter.h" #include #include @@ -41,6 +42,17 @@ namespace storm { */ storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager); + /** + * + * @tparam ValueType (The ValueType does not matter for the string representation.) + * @param state The state to export + * @param variableInformation Variable information to extract from the state + * @param onlyObservable Should we only export the observable information + * @return + */ + template + storm::json unpackStateIntoJson(CompressedState const& state, VariableInformation const& variableInformation, bool onlyObservable); + /*! * Appends the values of the given variables in the given state to the corresponding result vectors. * locationValues are inserted before integerValues (relevant if both, locationValues and integerValues actually refer to the same vector) diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index b68380935..e958f86b8 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -257,12 +257,25 @@ namespace storm { } } } - + template std::string NextStateGenerator::stateToString(CompressedState const& state) const { return toString(state, variableInformation); } - + + template + storm::json NextStateGenerator::currentStateToJson(bool onlyObservable) const { + storm::json result = unpackStateIntoJson(*state, variableInformation, onlyObservable); + extendStateInformation(result,onlyObservable); + return result; + } + + template + void NextStateGenerator::extendStateInformation(storm::json&, bool) const { + // Intentionally left empty. + } + + template std::shared_ptr NextStateGenerator::generateChoiceOrigins(std::vector& dataForChoiceOrigins) const { STORM_LOG_ERROR_COND(!options.isBuildChoiceOriginsSet(), "Generating choice origins is not supported for the considered model format."); diff --git a/src/storm/generator/NextStateGenerator.h b/src/storm/generator/NextStateGenerator.h index 126d0fa5a..5ef4a639a 100644 --- a/src/storm/generator/NextStateGenerator.h +++ b/src/storm/generator/NextStateGenerator.h @@ -72,6 +72,8 @@ namespace storm { std::string stateToString(CompressedState const& state) const; + storm::json currentStateToJson(bool onlyObservable = false) const; + uint32_t observabilityClass(CompressedState const& state) const; virtual storm::models::sparse::StateLabeling label(storm::storage::sparse::StateStorage const& stateStorage, std::vector const& initialStateIndices = {}, std::vector const& deadlockStateIndices = {}) = 0; @@ -106,6 +108,8 @@ namespace storm { virtual storm::storage::BitVector evaluateObservationLabels(CompressedState const& state) const =0; + virtual void extendStateInformation(storm::json& stateInfo, bool onlyObservable = false) const; + virtual storm::storage::sparse::StateValuationsBuilder initializeObservationValuationsBuilder() const; void postprocess(StateBehavior& result); diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index 6bec68bed..e9df107c5 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -727,15 +727,26 @@ namespace storm { template storm::storage::BitVector PrismNextStateGenerator::evaluateObservationLabels(CompressedState const& state) const { // TODO consider to avoid reloading by computing these bitvectors in an earlier build stage - unpackStateIntoEvaluator(state, this->variableInformation, *this->evaluator); - storm::storage::BitVector result(program.getNumberOfObservationLabels() * 64); + + if (program.getNumberOfObservationLabels() == 0) { + return result; + } + unpackStateIntoEvaluator(state, this->variableInformation, *this->evaluator); for (uint64_t i = 0; i < program.getNumberOfObservationLabels(); ++i) { result.setFromInt(64*i,64,this->evaluator->asInt(program.getObservationLabels()[i].getStatePredicateExpression())); } return result; } + template + void PrismNextStateGenerator::extendStateInformation(storm::json& result, bool onlyObservable) const { + + for (uint64_t i = 0; i < program.getNumberOfObservationLabels(); ++i) { + result[program.getObservationLabels()[i].getName()] = this->evaluator->asInt(program.getObservationLabels()[i].getStatePredicateExpression()); + } + } + template std::size_t PrismNextStateGenerator::getNumberOfRewardModels() const { diff --git a/src/storm/generator/PrismNextStateGenerator.h b/src/storm/generator/PrismNextStateGenerator.h index e302fd02e..5f06bffa5 100644 --- a/src/storm/generator/PrismNextStateGenerator.h +++ b/src/storm/generator/PrismNextStateGenerator.h @@ -101,6 +101,10 @@ namespace storm { */ void addLabeledChoices(std::vector>& choices, CompressedState const& state, StateToIdCallback stateToIdCallback, CommandFilter const& commandFilter = CommandFilter::All); + /* + * Extend the Json struct with additional information about the state. + */ + virtual void extendStateInformation(storm::json& stateInfo, bool onlyObservable = false) const override; /*! * Evaluate observation labels diff --git a/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.h b/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.h index c6694ca5b..0d3571dc5 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.h +++ b/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.h @@ -46,7 +46,6 @@ namespace storm { virtual std::vector getOverApproximationOfInitialStateResults() const override; private: - struct EpochCheckingData { std::vector bMinMax; @@ -73,8 +72,6 @@ namespace storm { boost::optional> underApproxResult; boost::optional> overApproxResult; - - }; } diff --git a/src/storm/simulator/PrismProgramSimulator.cpp b/src/storm/simulator/PrismProgramSimulator.cpp index 6d9428b6a..07911ef43 100644 --- a/src/storm/simulator/PrismProgramSimulator.cpp +++ b/src/storm/simulator/PrismProgramSimulator.cpp @@ -38,7 +38,8 @@ namespace storm { bool DiscreteTimePrismProgramSimulator::explore() { // Load the current state into the next state generator. stateGenerator->load(currentState); - // TODO: This low-level code currently expands all actions, while this may not be necessary. + // TODO: This low-level code currently expands all actions, while this is not necessary. + // However, using the next state generator ensures compatibliity with the model generator. behavior = stateGenerator->expand(stateToIdCallback); if (behavior.getStateRewards().size() > 0) { STORM_LOG_ASSERT(behavior.getStateRewards().size() == lastActionRewards.size(), "Reward vectors should have same length."); @@ -47,7 +48,27 @@ namespace storm { } template - std::vector> const& DiscreteTimePrismProgramSimulator::getChoices() { + bool DiscreteTimePrismProgramSimulator::isSinkState() const { + if(behavior.empty()) { + return true; + } + std::set successorIds; + for (Choice const& choice : behavior.getChoices()) { + for (auto it = choice.begin(); it != choice.end(); ++it) { + successorIds.insert(it->first); + if (successorIds.size() > 1) { + return false; + } + } + } + if (idToState.at(*(successorIds.begin())) == currentState) { + return true; + } + return false; + } + + template + std::vector> const& DiscreteTimePrismProgramSimulator::getChoices() const { return behavior.getChoices(); } @@ -71,6 +92,16 @@ namespace storm { return stateGenerator->stateToString(currentState); } + template + storm::json DiscreteTimePrismProgramSimulator::getStateAsJson() const { + return stateGenerator->currentStateToJson(false); + } + + template + storm::json DiscreteTimePrismProgramSimulator::getObservationAsJson() const { + return stateGenerator->currentStateToJson(true); + } + template bool DiscreteTimePrismProgramSimulator::resetToInitial() { auto indices = stateGenerator->getInitialStates(stateToIdCallback); diff --git a/src/storm/simulator/PrismProgramSimulator.h b/src/storm/simulator/PrismProgramSimulator.h index 116388b05..034d2791d 100644 --- a/src/storm/simulator/PrismProgramSimulator.h +++ b/src/storm/simulator/PrismProgramSimulator.h @@ -5,7 +5,6 @@ #include "storm/generator/PrismNextStateGenerator.h" #include "storm/utility/random.h" - namespace storm { namespace simulator { @@ -41,7 +40,10 @@ namespace storm { * * @return A list of choices that encode the possibilities in the current state. */ - std::vector> const& getChoices(); + std::vector> const& getChoices() const; + + bool isSinkState() const; + /** * Make a step and randomly select the successor. The action is given as an argument, the index reflects the index of the getChoices vector that can be accessed. * @@ -57,6 +59,10 @@ namespace storm { generator::CompressedState const& getCurrentState() const; expressions::SimpleValuation getCurrentStateAsValuation() const; + storm::json getStateAsJson() const; + + storm::json getObservationAsJson() const; + std::string getCurrentStateString() const; /** * Reset to the (unique) initial state. @@ -78,7 +84,7 @@ namespace storm { generator::CompressedState currentState; /// Generator for the next states std::shared_ptr> stateGenerator; - bool explored = false; + /// Obtained behavior of a state generator::StateBehavior behavior; /// Helper for last action reward construction std::vector zeroRewards; diff --git a/src/storm/storage/expressions/ExpressionStringFormat.h b/src/storm/storage/expressions/ExpressionStringFormat.h new file mode 100644 index 000000000..fc4d7ed8a --- /dev/null +++ b/src/storm/storage/expressions/ExpressionStringFormat.h @@ -0,0 +1,9 @@ +#pragma once + +namespace storm { + namespace expressions { + struct ExpressionStringFormat { + bool alternativeIff = false; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/prism/OverlappingGuardAnalyser.cpp b/src/storm/storage/prism/OverlappingGuardAnalyser.cpp new file mode 100644 index 000000000..2925bf3bc --- /dev/null +++ b/src/storm/storage/prism/OverlappingGuardAnalyser.cpp @@ -0,0 +1,58 @@ +#include "storm/storage/prism/OverlappingGuardAnalyser.h" +#include "storm/storage/prism/Program.h" +#include "storm/solver/SmtSolver.h" + + +namespace storm { + namespace prism { + OverlappingGuardAnalyser::OverlappingGuardAnalyser(Program const& program, std::shared_ptr& smtSolverFactory) : + program(program), smtSolver(smtSolverFactory->create(program.getManager())), initializedWithStateConstraints(false) { + // Intentionally left empty. + } + + + bool OverlappingGuardAnalyser::hasModuleWithInnerActionOverlap() { + if(!initializedWithStateConstraints) { + for(auto const& integerVariable : program.getGlobalIntegerVariables()) { + smtSolver->add(integerVariable.getExpressionVariable().getExpression() >= integerVariable.getLowerBoundExpression()); + smtSolver->add(integerVariable.getExpressionVariable().getExpression() <= integerVariable.getUpperBoundExpression()); + } + for (auto const& module : program.getModules()) { + for(auto const& integerVariable : module.getIntegerVariables()) { + smtSolver->add(integerVariable.getExpressionVariable().getExpression() >= integerVariable.getLowerBoundExpression()); + smtSolver->add(integerVariable.getExpressionVariable().getExpression() <= integerVariable.getUpperBoundExpression()); + } + } + } + + for(auto const& module : program.getModules()) { + for (auto const& actionIndex : module.getSynchronizingActionIndices()) { + auto const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex); + if (commandIndices.size() == 1) { + continue; + } else { + for (uint64_t commandIndexA : commandIndices) { + for (uint64_t commandIndexB : commandIndices) { + if (commandIndexA == commandIndexB) { + continue; + } + smtSolver->push(); + smtSolver->add(module.getCommand(commandIndexA).getGuardExpression()); + smtSolver->add(module.getCommand(commandIndexB).getGuardExpression()); + auto smtCheckResult = smtSolver->check(); + smtSolver->pop(); + if (smtCheckResult == storm::solver::SmtSolver::CheckResult::Sat) { + return true; + } + } + } + } + + + } + } + return false; + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/prism/OverlappingGuardAnalyser.h b/src/storm/storage/prism/OverlappingGuardAnalyser.h new file mode 100644 index 000000000..361b6d3af --- /dev/null +++ b/src/storm/storage/prism/OverlappingGuardAnalyser.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +namespace storm { + namespace utility { + namespace solver { + class SmtSolverFactory; + } + } + + namespace solver { + class SmtSolver; + } + + namespace prism { + class Program; + class Module; + + class OverlappingGuardAnalyser { + public: + OverlappingGuardAnalyser(Program const& program, std::shared_ptr& smtSolverFactory); + bool hasModuleWithInnerActionOverlap(); + + private: + Program const& program; + std::unique_ptr smtSolver; + bool initializedWithStateConstraints; + }; + } +} + diff --git a/src/storm/utility/random.h b/src/storm/utility/random.h index 7e6e015be..638ec72fd 100644 --- a/src/storm/utility/random.h +++ b/src/storm/utility/random.h @@ -1,3 +1,5 @@ +#pragma once + #include #include "storm/adapters/RationalNumberAdapter.h"