#include "ParameterRegion.h" #include "storm/utility/region.h" #include "storm/utility/macros.h" #include "storm/parser/MappedFile.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/RegionSettings.h" #include "storm/exceptions/InvalidSettingsException.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/utility/constants.h" #include "storm/utility/file.h" namespace storm { namespace storage { template ParameterRegion::ParameterRegion(Valuation const& lowerBoundaries, Valuation const& upperBoundaries) : lowerBoundaries(lowerBoundaries), upperBoundaries(upperBoundaries) { init(); } template ParameterRegion::ParameterRegion(Valuation&& lowerBoundaries, Valuation&& upperBoundaries) : lowerBoundaries(lowerBoundaries), upperBoundaries(upperBoundaries) { init(); } template void ParameterRegion::init() { //check whether both mappings map the same variables, check that lower boundary <= upper boundary, and pre-compute the set of variables for (auto const& variableWithLowerBoundary : this->lowerBoundaries) { auto variableWithUpperBoundary = this->upperBoundaries.find(variableWithLowerBoundary.first); STORM_LOG_THROW((variableWithUpperBoundary != upperBoundaries.end()), storm::exceptions::InvalidArgumentException, "Could not create region. No upper boundary specified for Variable " << variableWithLowerBoundary.first); STORM_LOG_THROW((variableWithLowerBoundary.second<=variableWithUpperBoundary->second), storm::exceptions::InvalidArgumentException, "Could not create region. The lower boundary for " << variableWithLowerBoundary.first << " is larger then the upper boundary"); this->variables.insert(variableWithLowerBoundary.first); } for (auto const& variableWithBoundary : this->upperBoundaries) { STORM_LOG_THROW((this->variables.find(variableWithBoundary.first) != this->variables.end()), storm::exceptions::InvalidArgumentException, "Could not create region. No lower boundary specified for Variable " << variableWithBoundary.first); } } template std::set::VariableType> const& ParameterRegion::getVariables() const { return this->variables; } template typename ParameterRegion::CoefficientType const& ParameterRegion::getLowerBoundary(VariableType const& variable) const { auto const& result = lowerBoundaries.find(variable); STORM_LOG_THROW(result != lowerBoundaries.end(), storm::exceptions::InvalidArgumentException, "Tried to find a lower boundary for variable " << variable << " which is not specified by this region"); return (*result).second; } template typename ParameterRegion::CoefficientType const& ParameterRegion::getUpperBoundary(VariableType const& variable) const { auto const& result = upperBoundaries.find(variable); STORM_LOG_THROW(result != upperBoundaries.end(), storm::exceptions::InvalidArgumentException, "Tried to find an upper boundary for variable " << variable << " which is not specified by this region"); return (*result).second; } template typename ParameterRegion::Valuation const& ParameterRegion::getUpperBoundaries() const { return upperBoundaries; } template typename ParameterRegion::Valuation const& ParameterRegion::getLowerBoundaries() const { return lowerBoundaries; } template std::vector::Valuation> ParameterRegion::getVerticesOfRegion(std::set const& consideredVariables) const { std::size_t const numOfVariables = consideredVariables.size(); std::size_t const numOfVertices = std::pow(2, numOfVariables); std::vector resultingVector(numOfVertices); for (uint_fast64_t vertexId = 0; vertexId < numOfVertices; ++vertexId) { //interprete vertexId as a bit sequence //the consideredVariables.size() least significant bits of vertex will always represent the next vertex //(00...0 = lower boundaries for all variables, 11...1 = upper boundaries for all variables) uint_fast64_t variableIndex = 0; for (auto const& variable : consideredVariables) { if ((vertexId >> variableIndex) % 2 == 0) { resultingVector[vertexId].insert(std::pair(variable, getLowerBoundary(variable))); } else { resultingVector[vertexId].insert(std::pair(variable, getUpperBoundary(variable))); } ++variableIndex; } } return resultingVector; } template typename ParameterRegion::Valuation ParameterRegion::getSomePoint() const { return this->getLowerBoundaries(); } template typename ParameterRegion::Valuation ParameterRegion::getCenterPoint() const { Valuation result; for (auto const& variable : this->variables) { result.insert(typename Valuation::value_type(variable, (this->getLowerBoundary(variable) + this->getUpperBoundary(variable))/2)); } return result; } template typename ParameterRegion::CoefficientType ParameterRegion::area() const { CoefficientType result = storm::utility::one(); for( auto const& variable : this->variables){ result *= (this->getUpperBoundary(variable) - this->getLowerBoundary(variable)); } return result; } template void ParameterRegion::split(Valuation const& splittingPoint, std::vector >& regionVector) const{ //Check if splittingPoint is valid. STORM_LOG_THROW(splittingPoint.size() == this->variables.size(), storm::exceptions::InvalidArgumentException, "Tried to split a region w.r.t. a point, but the point considers a different number of variables."); for(auto const& variable : this->variables){ auto splittingPointEntry=splittingPoint.find(variable); STORM_LOG_THROW(splittingPointEntry != splittingPoint.end(), storm::exceptions::InvalidArgumentException, "Tried to split a region but a variable of this region is not defined by the splitting point."); STORM_LOG_THROW(this->getLowerBoundary(variable) <=splittingPointEntry->second, storm::exceptions::InvalidArgumentException, "Tried to split a region but the splitting point is not contained in the region."); STORM_LOG_THROW(this->getUpperBoundary(variable) >=splittingPointEntry->second, storm::exceptions::InvalidArgumentException, "Tried to split a region but the splitting point is not contained in the region."); } //Now compute the subregions. std::vector vertices(this->getVerticesOfRegion(this->variables)); for(auto const& vertex : vertices){ //The resulting subregion is the smallest region containing vertex and splittingPoint. Valuation subLower, subUpper; for(auto variableBound : this->lowerBoundaries){ VariableType variable = variableBound.first; auto vertexEntry=vertex.find(variable); auto splittingPointEntry=splittingPoint.find(variable); subLower.insert(typename Valuation::value_type(variable, std::min(vertexEntry->second, splittingPointEntry->second))); subUpper.insert(typename Valuation::value_type(variable, std::max(vertexEntry->second, splittingPointEntry->second))); } ParameterRegion subRegion(std::move(subLower), std::move(subUpper)); if(!storm::utility::isZero(subRegion.area())){ regionVector.push_back(std::move(subRegion)); } } } template std::string ParameterRegion::toString(bool boundariesAsDouble) const { std::stringstream regionstringstream; if(boundariesAsDouble) { for (auto var : this->getVariables()) { regionstringstream << storm::utility::convertNumber(this->getLowerBoundary(var)); regionstringstream << "<="; regionstringstream << var; regionstringstream << "<="; regionstringstream << storm::utility::convertNumber(this->getUpperBoundary(var)); regionstringstream << ","; } } else { for (auto var : this->getVariables()) { regionstringstream << this->getLowerBoundary(var); regionstringstream << "<="; regionstringstream << var; regionstringstream << "<="; regionstringstream << this->getUpperBoundary(var); regionstringstream << ","; } } std::string regionstring = regionstringstream.str(); //the last comma should actually be a semicolon regionstring = regionstring.substr(0, regionstring.length() - 1) + ";"; return regionstring; } template void ParameterRegion::parseParameterBoundaries(Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString){ std::string::size_type positionOfFirstRelation = parameterBoundariesString.find("<="); STORM_LOG_THROW(positionOfFirstRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a '<=' after the first number"); std::string::size_type positionOfSecondRelation = parameterBoundariesString.find("<=", positionOfFirstRelation+2); STORM_LOG_THROW(positionOfSecondRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a '<=' after the parameter"); std::string parameter=parameterBoundariesString.substr(positionOfFirstRelation+2,positionOfSecondRelation-(positionOfFirstRelation+2)); //removes all whitespaces from the parameter string: parameter.erase(std::remove_if(parameter.begin(), parameter.end(), ::isspace), parameter.end()); STORM_LOG_THROW(parameter.length()>0, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a parameter"); VariableType var = storm::utility::region::getVariableFromString(parameter); CoefficientType lb = storm::utility::convertNumber(parameterBoundariesString.substr(0,positionOfFirstRelation)); CoefficientType ub = storm::utility::convertNumber(parameterBoundariesString.substr(positionOfSecondRelation+2)); lowerBoundaries.emplace(std::make_pair(var, lb)); upperBoundaries.emplace(std::make_pair(var, ub)); } template ParameterRegion ParameterRegion::parseRegion( std::string const& regionString){ Valuation lowerBoundaries; Valuation upperBoundaries; std::vector parameterBoundaries; boost::split(parameterBoundaries, regionString, boost::is_any_of(",")); for(auto const& parameterBoundary : parameterBoundaries){ if(!std::all_of(parameterBoundary.begin(),parameterBoundary.end(), ::isspace)){ //skip this string if it only consists of space parseParameterBoundaries(lowerBoundaries, upperBoundaries, parameterBoundary); } } return ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); } template std::vector> ParameterRegion::parseMultipleRegions(std::string const& regionsString) { std::vector result; std::vector regionsStrVec; boost::split(regionsStrVec, regionsString, boost::is_any_of(";")); for(auto const& regionStr : regionsStrVec){ if(!std::all_of(regionStr.begin(),regionStr.end(), ::isspace)){ //skip this string if it only consists of space result.emplace_back(parseRegion(regionStr)); } } return result; } template std::vector> ParameterRegion::getRegionsFromSettings(){ STORM_LOG_THROW(storm::settings::getModule().isRegionsSet() ||storm::settings::getModule().isRegionFileSet(), storm::exceptions::InvalidSettingsException, "Tried to obtain regions from the settings but no regions are specified."); STORM_LOG_THROW(!(storm::settings::getModule().isRegionsSet() && storm::settings::getModule().isRegionFileSet()), storm::exceptions::InvalidSettingsException, "Regions are specified via file AND cmd line. Only one option is allowed."); std::string regionsString; if(storm::settings::getModule().isRegionsSet()){ regionsString = storm::settings::getModule().getRegionsFromCmdLine(); } else{ //if we reach this point we can assume that the region is given as a file. STORM_LOG_THROW(storm::utility::fileExistsAndIsReadable(storm::settings::getModule().getRegionFilePath()), storm::exceptions::InvalidSettingsException, "The path to the file in which the regions are specified is not valid."); storm::parser::MappedFile mf(storm::settings::getModule().getRegionFilePath().c_str()); regionsString = std::string(mf.getData(),mf.getDataSize()); } return parseMultipleRegions(regionsString); } #ifdef STORM_HAVE_CARL template class ParameterRegion; #endif } }