#include "storm/generator/TransientVariableInformation.h" #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Automaton.h" #include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" #include namespace storm { namespace generator { template <> TransientVariableData::TransientVariableData(storm::expressions::Variable const& variable, boost::optional const& lowerBound, boost::optional const& upperBound, storm::RationalFunction const& defaultValue, bool global) : variable(variable), lowerBound(lowerBound), upperBound(upperBound), defaultValue(defaultValue) { // There is no '<=' for rational functions. Therefore, do not check the bounds for this ValueType } template TransientVariableData::TransientVariableData(storm::expressions::Variable const& variable, boost::optional const& lowerBound, boost::optional const& upperBound, VariableType const& defaultValue, bool global) : variable(variable), lowerBound(lowerBound), upperBound(upperBound), defaultValue(defaultValue) { STORM_LOG_THROW(!lowerBound.is_initialized() || lowerBound.get() <= defaultValue, storm::exceptions::OutOfRangeException, "The default value for transient variable " << variable.getName() << " is smaller than its lower bound."); STORM_LOG_THROW(!upperBound.is_initialized() || defaultValue <= upperBound.get(), storm::exceptions::OutOfRangeException, "The default value for transient variable " << variable.getName() << " is higher than its upper bound."); } template TransientVariableData::TransientVariableData(storm::expressions::Variable const& variable, VariableType const& defaultValue, bool global) : variable(variable), defaultValue(defaultValue) { // Intentionally left empty. } template TransientVariableInformation::TransientVariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata) { createVariablesForVariableSet(model.getGlobalVariables(), true); for (auto const& automatonRef : parallelAutomata) { createVariablesForAutomaton(automatonRef.get()); } sortVariables(); } template void TransientVariableInformation::registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData) { arrayVariableToElementInformations.clear(); // Find for each replaced array variable the corresponding references in this variable information for (auto const& arrayVariable : arrayEliminatorData.eliminatedArrayVariables) { if (arrayVariable->isTransient()) { STORM_LOG_ASSERT(arrayEliminatorData.replacements.count(arrayVariable->getExpressionVariable()) > 0, "No replacement for array variable."); auto const& replacements = arrayEliminatorData.replacements.find(arrayVariable->getExpressionVariable())->second; std::vector varInfoIndices; for (auto const& replacedVar : replacements) { if (replacedVar->getExpressionVariable().hasIntegerType()) { uint64_t index = 0; for (auto const& intInfo : integerVariableInformation) { if (intInfo.variable == replacedVar->getExpressionVariable()) { varInfoIndices.push_back(index); break; } ++index; } STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); } else if (replacedVar->getExpressionVariable().hasBooleanType()) { uint64_t index = 0; for (auto const& boolInfo : booleanVariableInformation) { if (boolInfo.variable == replacedVar->getExpressionVariable()) { varInfoIndices.push_back(index); break; } ++index; } STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); } else if (replacedVar->getExpressionVariable().hasRationalType()) { uint64_t index = 0; for (auto const& rationalInfo : rationalVariableInformation) { if (rationalInfo.variable == replacedVar->getExpressionVariable()) { varInfoIndices.push_back(index); break; } ++index; } STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); } else { STORM_LOG_ASSERT(false, "Unhandled type of base variable."); } } this->arrayVariableToElementInformations.emplace(arrayVariable->getExpressionVariable(), std::move(varInfoIndices)); } } } template TransientVariableData const& TransientVariableInformation::getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { std::vector const& indices = arrayVariableToElementInformations.at(arrayVariable); STORM_LOG_THROW(arrayIndex < indices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << indices.size() << "."); return booleanVariableInformation[indices[arrayIndex]]; } template TransientVariableData const& TransientVariableInformation::getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { std::vector const& indices = arrayVariableToElementInformations.at(arrayVariable); STORM_LOG_THROW(arrayIndex < indices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << indices.size() << "."); return integerVariableInformation[indices[arrayIndex]]; } template TransientVariableData const& TransientVariableInformation::getRationalArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { std::vector const& indices = arrayVariableToElementInformations.at(arrayVariable); STORM_LOG_THROW(arrayIndex < indices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << indices.size() << "."); return rationalVariableInformation[indices[arrayIndex]]; } template void TransientVariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton) { createVariablesForVariableSet(automaton.getVariables(), false); } template void TransientVariableInformation::createVariablesForVariableSet(storm::jani::VariableSet const& variableSet, bool global) { for (auto const& variable : variableSet.getBooleanVariables()) { if (variable.isTransient()) { booleanVariableInformation.emplace_back(variable.getExpressionVariable(), variable.getInitExpression().evaluateAsBool(), global); } } for (auto const& variable : variableSet.getBoundedIntegerVariables()) { if (variable.isTransient()) { boost::optional lowerBound; boost::optional upperBound; if (variable.hasLowerBound()) { lowerBound = variable.getLowerBound().evaluateAsInt(); } if (variable.hasUpperBound()) { upperBound = variable.getUpperBound().evaluateAsInt(); } integerVariableInformation.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, variable.getInitExpression().evaluateAsInt(), global); } } for (auto const& variable : variableSet.getUnboundedIntegerVariables()) { if (variable.isTransient()) { integerVariableInformation.emplace_back(variable.getExpressionVariable(), variable.getInitExpression().evaluateAsInt(), global); } } for (auto const& variable : variableSet.getRealVariables()) { if (variable.isTransient()) { rationalVariableInformation.emplace_back(variable.getExpressionVariable(), storm::utility::convertNumber(variable.getInitExpression().evaluateAsRational()), global); } } } template void TransientVariableInformation::sortVariables() { // Sort the variables so we can make some assumptions when iterating over them (in the next-state generators). std::sort(booleanVariableInformation.begin(), booleanVariableInformation.end(), [] (TransientVariableData const& a, TransientVariableData const& b) { return a.variable < b.variable; } ); std::sort(integerVariableInformation.begin(), integerVariableInformation.end(), [] (TransientVariableData const& a, TransientVariableData const& b) { return a.variable < b.variable; } ); std::sort(rationalVariableInformation.begin(), rationalVariableInformation.end(), [] (TransientVariableData const& a, TransientVariableData const& b) { return a.variable < b.variable; } ); } template void TransientVariableInformation::setDefaultValuesInEvaluator(storm::expressions::ExpressionEvaluator& evaluator) const { for (auto const& variableData : booleanVariableInformation) { evaluator.setBooleanValue(variableData.variable, variableData.defaultValue); } for (auto const& variableData : integerVariableInformation) { evaluator.setIntegerValue(variableData.variable, variableData.defaultValue); } for (auto const& variableData : rationalVariableInformation) { evaluator.setRationalValue(variableData.variable, variableData.defaultValue); } } template class TransientVariableInformation; template class TransientVariableInformation; template class TransientVariableInformation; } }