#include "storm/storage/jani/VariableSet.h" #include "storm/storage/expressions/Expressions.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/InvalidTypeException.h" namespace storm { namespace jani { VariableSet::VariableSet() { // Intentionally left empty. } detail::Variables VariableSet::getBooleanVariables() { return detail::Variables(booleanVariables.begin(), booleanVariables.end()); } detail::ConstVariables VariableSet::getBooleanVariables() const { return detail::ConstVariables(booleanVariables.begin(), booleanVariables.end()); } detail::Variables VariableSet::getBoundedIntegerVariables() { return detail::Variables(boundedIntegerVariables.begin(), boundedIntegerVariables.end()); } detail::ConstVariables VariableSet::getBoundedIntegerVariables() const { return detail::ConstVariables(boundedIntegerVariables.begin(), boundedIntegerVariables.end()); } detail::Variables VariableSet::getUnboundedIntegerVariables() { return detail::Variables(unboundedIntegerVariables.begin(), unboundedIntegerVariables.end()); } detail::ConstVariables VariableSet::getUnboundedIntegerVariables() const { return detail::ConstVariables(unboundedIntegerVariables.begin(), unboundedIntegerVariables.end()); } detail::Variables VariableSet::getRealVariables() { return detail::Variables(realVariables.begin(), realVariables.end()); } detail::ConstVariables VariableSet::getRealVariables() const { return detail::ConstVariables(realVariables.begin(), realVariables.end()); } detail::Variables VariableSet::getArrayVariables() { return detail::Variables(arrayVariables.begin(), arrayVariables.end()); } detail::ConstVariables VariableSet::getArrayVariables() const { return detail::ConstVariables(arrayVariables.begin(), arrayVariables.end()); } detail::Variables VariableSet::getClockVariables() { return detail::Variables(clockVariables.begin(), clockVariables.end()); } detail::ConstVariables VariableSet::getClockVariables() const { return detail::ConstVariables(clockVariables.begin(), clockVariables.end()); } Variable const& VariableSet::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { return addVariable(variable.asBooleanVariable()); } else if (variable.isBoundedIntegerVariable()) { return addVariable(variable.asBoundedIntegerVariable()); } else if (variable.isUnboundedIntegerVariable()) { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); } else if (variable.isArrayVariable()) { return addVariable(variable.asArrayVariable()); } else if (variable.isClockVariable()) { return addVariable(variable.asClockVariable()); } STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Cannot add variable of unknown type."); } BooleanVariable const& VariableSet::addVariable(BooleanVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr newVariable = std::make_shared(variable); variables.push_back(newVariable); booleanVariables.push_back(newVariable); if (variable.isTransient()) { transientVariables.push_back(newVariable); } nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); variableToVariable.emplace(variable.getExpressionVariable(), newVariable); return *newVariable; } BoundedIntegerVariable const& VariableSet::addVariable(BoundedIntegerVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr newVariable = std::make_shared(variable); variables.push_back(newVariable); boundedIntegerVariables.push_back(newVariable); if (variable.isTransient()) { transientVariables.push_back(newVariable); } nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); variableToVariable.emplace(variable.getExpressionVariable(), newVariable); return *newVariable; } UnboundedIntegerVariable const& VariableSet::addVariable(UnboundedIntegerVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr newVariable = std::make_shared(variable); variables.push_back(newVariable); unboundedIntegerVariables.push_back(newVariable); if (variable.isTransient()) { transientVariables.push_back(newVariable); } nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); variableToVariable.emplace(variable.getExpressionVariable(), newVariable); return *newVariable; } RealVariable const& VariableSet::addVariable(RealVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr newVariable = std::make_shared(variable); variables.push_back(newVariable); realVariables.push_back(newVariable); if (variable.isTransient()) { transientVariables.push_back(newVariable); } nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); variableToVariable.emplace(variable.getExpressionVariable(), newVariable); return *newVariable; } ArrayVariable const& VariableSet::addVariable(ArrayVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr newVariable = std::make_shared(variable); variables.push_back(newVariable); arrayVariables.push_back(newVariable); if (variable.isTransient()) { transientVariables.push_back(newVariable); } nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); variableToVariable.emplace(variable.getExpressionVariable(), newVariable); return *newVariable; } ClockVariable const& VariableSet::addVariable(ClockVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr newVariable = std::make_shared(variable); variables.push_back(newVariable); clockVariables.push_back(newVariable); if (variable.isTransient()) { transientVariables.push_back(newVariable); } nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); variableToVariable.emplace(variable.getExpressionVariable(), newVariable); return *newVariable; } std::vector> VariableSet::dropAllArrayVariables() { if (!arrayVariables.empty()) { for (auto const& arrVar : arrayVariables) { nameToVariable.erase(arrVar->getName()); variableToVariable.erase(arrVar->getExpressionVariable()); } std::vector> newVariables; for (auto const& v : variables) { if (!v->isArrayVariable()) { newVariables.push_back(v); } } variables = std::move(newVariables); newVariables.clear(); for (auto const& v : transientVariables) { if (!v->isArrayVariable()) { newVariables.push_back(v); } } transientVariables = std::move(newVariables); } std::vector> result = std::move(arrayVariables); arrayVariables.clear(); return result; } bool VariableSet::hasVariable(std::string const& name) const { return nameToVariable.find(name) != nameToVariable.end(); } bool VariableSet::hasVariable(Variable const& var) const { return hasVariable(var.getName()); } Variable const& VariableSet::getVariable(std::string const& name) const { auto it = nameToVariable.find(name); STORM_LOG_THROW(it != nameToVariable.end(), storm::exceptions::InvalidArgumentException, "Unable to retrieve unknown variable '" << name << "'."); return getVariable(it->second); } template void eraseFromVariableVector(std::vector>& varVec, storm::expressions::Variable const& variable) { for (auto vIt = varVec.begin(); vIt != varVec.end(); ++vIt) { if ((*vIt)->getExpressionVariable() == variable) { varVec.erase(vIt); break; } } } std::shared_ptr VariableSet::eraseVariable(storm::expressions::Variable const& variable) { auto vToVIt = variableToVariable.find(variable); STORM_LOG_THROW(vToVIt != variableToVariable.end(), storm::exceptions::InvalidArgumentException, "Unable to erase unknown variable '" << variable.getName() << "'."); std::shared_ptr janiVar = std::move(vToVIt->second); variableToVariable.erase(vToVIt); nameToVariable.erase(janiVar->getName()); eraseFromVariableVector(variables, variable); if (janiVar->isBooleanVariable()) { eraseFromVariableVector(booleanVariables, variable); } if (janiVar->isBooleanVariable()) { eraseFromVariableVector(booleanVariables, variable); } if (janiVar->isBoundedIntegerVariable()) { eraseFromVariableVector(boundedIntegerVariables, variable); } if (janiVar->isUnboundedIntegerVariable()) { eraseFromVariableVector(unboundedIntegerVariables, variable); } if (janiVar->isRealVariable()) { eraseFromVariableVector(realVariables, variable); } if (janiVar->isArrayVariable()) { eraseFromVariableVector(arrayVariables, variable); } if (janiVar->isClockVariable()) { eraseFromVariableVector(clockVariables, variable); } if (janiVar->isTransient()) { eraseFromVariableVector(transientVariables, variable); } return janiVar; } typename detail::Variables::iterator VariableSet::begin() { return detail::Variables::make_iterator(variables.begin()); } typename detail::ConstVariables::iterator VariableSet::begin() const { return detail::ConstVariables::make_iterator(variables.begin()); } typename detail::Variables::iterator VariableSet::end() { return detail::Variables::make_iterator(variables.end()); } detail::ConstVariables::iterator VariableSet::end() const { return detail::ConstVariables::make_iterator(variables.end()); } Variable const& VariableSet::getVariable(storm::expressions::Variable const& variable) const { auto it = variableToVariable.find(variable); STORM_LOG_THROW(it != variableToVariable.end(), storm::exceptions::InvalidArgumentException, "Unable to retrieve unknown variable '" << variable.getName() << "'."); return *it->second; } bool VariableSet::hasVariable(storm::expressions::Variable const& variable) const { return variableToVariable.find(variable) != variableToVariable.end(); } bool VariableSet::hasTransientVariable() const { for (auto const& variable : variables) { if (variable->isTransient()) { return true; } } return false; } bool VariableSet::containsBooleanVariable() const { return !booleanVariables.empty(); } bool VariableSet::containsBoundedIntegerVariable() const { return !boundedIntegerVariables.empty(); } bool VariableSet::containsUnboundedIntegerVariables() const { return !unboundedIntegerVariables.empty(); } bool VariableSet::containsRealVariables() const { return !realVariables.empty(); } bool VariableSet::containsArrayVariables() const { return !arrayVariables.empty(); } bool VariableSet::containsClockVariables() const { return !clockVariables.empty(); } bool VariableSet::containsNonTransientRealVariables() const { for (auto const& variable : realVariables) { if (!variable->isTransient()) { return true; } } return false; } bool VariableSet::containsNonTransientUnboundedIntegerVariables() const { for (auto const& variable : unboundedIntegerVariables) { if (!variable->isTransient()) { return true; } } return false; } bool VariableSet::empty() const { return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables() || containsRealVariables() || containsArrayVariables() || containsClockVariables()); } uint64_t VariableSet::getNumberOfVariables() const { return variables.size(); } uint64_t VariableSet::getNumberOfNontransientVariables() const { return getNumberOfVariables() - getNumberOfTransientVariables(); } uint_fast64_t VariableSet::getNumberOfTransientVariables() const { uint_fast64_t result = 0; for (auto const& variable : variables) { if (variable->isTransient()) { ++result; } } return result; } uint_fast64_t VariableSet::getNumberOfRealTransientVariables() const { uint_fast64_t result = 0; for (auto const& variable : variables) { if (variable->isTransient() && variable->isRealVariable()) { ++result; } } return result; } uint_fast64_t VariableSet::getNumberOfUnboundedIntegerTransientVariables() const { uint_fast64_t result = 0; for (auto const& variable : variables) { if (variable->isTransient() && variable->isUnboundedIntegerVariable()) { ++result; } } return result; } uint_fast64_t VariableSet::getNumberOfNumericalTransientVariables() const { uint_fast64_t result = 0; for (auto const& variable : transientVariables) { if (variable->isRealVariable() || variable->isUnboundedIntegerVariable() || variable->isBoundedIntegerVariable()) { ++result; } } return result; } typename detail::ConstVariables VariableSet::getTransientVariables() const { return detail::ConstVariables(transientVariables.begin(), transientVariables.end()); } bool VariableSet::containsVariablesInBoundExpressionsOrInitialValues(std::set const& variables) const { for (auto const& booleanVariable : this->getBooleanVariables()) { if (booleanVariable.hasInitExpression()) { if (booleanVariable.getInitExpression().containsVariable(variables)) { return true; } } } for (auto const& integerVariable : this->getBoundedIntegerVariables()) { if (integerVariable.hasInitExpression()) { if (integerVariable.getInitExpression().containsVariable(variables)) { return true; } } if (integerVariable.getLowerBound().containsVariable(variables)) { return true; } if (integerVariable.getUpperBound().containsVariable(variables)) { return true; } } for (auto const& arrayVariable : this->getArrayVariables()) { if (arrayVariable.hasInitExpression()) { if (arrayVariable.getInitExpression().containsVariable(variables)) { return true; } } if (arrayVariable.hasLowerElementTypeBound()) { if (arrayVariable.getLowerElementTypeBound().containsVariable(variables)) { return true; } } if (arrayVariable.hasUpperElementTypeBound()) { if (arrayVariable.getUpperElementTypeBound().containsVariable(variables)) { return true; } } } for (auto const& clockVariable : this->getClockVariables()) { if (clockVariable.hasInitExpression()) { if (clockVariable.getInitExpression().containsVariable(variables)) { return true; } } } return false; } std::map> VariableSet::getNameToVariableMap() const { std::map> result; for (auto const& variable : variables) { result.emplace(variable->getName(), *variable); } return result; } void VariableSet::substitute(std::map const& substitution) { for (auto& variable : variables) { variable->substitute(substitution); } } void VariableSet::substituteExpressionVariables(std::map const& substitution) { for (auto& variable : variables) { auto varIt = substitution.find(variable->getExpressionVariable()); if (varIt != substitution.end()) { STORM_LOG_ASSERT(varIt->second.isVariable(), "Expected that variables are only substituted by other variables. However, we substitute " << varIt->first.getName() << " by " << varIt->second << "."); variable->setExpressionVariable(varIt->second.getBaseExpression().asVariableExpression().getVariable()); } } } } }