diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index b927b6203..80ba611aa 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -494,7 +494,7 @@ namespace storm { storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(state)); for (auto element : transitionMatrix.getRow(nondeterministicChoiceIndices[state])) { - constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn())); + constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn())) * storm::expressions::Expression::createDoubleLiteral(element.getValue()); } constraint = constraint + storm::expressions::Expression::createDoubleLiteral(storm::utility::constantOne<ValueType>() / exitRates[state]) * storm::expressions::Expression::createDoubleVariable("k"); @@ -512,7 +512,7 @@ namespace storm { storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(state)); for (auto element : transitionMatrix.getRow(choice)) { - constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn())); + constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn())) * storm::expressions::Expression::createDoubleLiteral(element.getValue()); } storm::expressions::Expression rightHandSide = storm::expressions::Expression::createDoubleLiteral(storm::utility::constantZero<ValueType>()); diff --git a/src/settings/SettingsManager.cpp b/src/settings/SettingsManager.cpp index d8b9284d9..26fb6070d 100644 --- a/src/settings/SettingsManager.cpp +++ b/src/settings/SettingsManager.cpp @@ -110,14 +110,42 @@ namespace storm { if (optionActive) { setOptionsArguments(activeOptionName, activeOptionIsShortName ? this->shortNameToOptions : this->longNameToOptions, argumentCache); } + + // Include the options from a possibly specified configuration file, but don't overwrite existing settings. + if (storm::settings::generalSettings().isConfigSet()) { + this->setFromConfigurationFile(storm::settings::generalSettings().getConfigFilename()); + } + + // Finally, check whether all modules are okay with the current settings. + this->checkAllModules(); } void SettingsManager::setFromConfigurationFile(std::string const& configFilename) { - STORM_LOG_ASSERT(false, "Not yet implemented."); + std::map<std::string, std::vector<std::string>> configurationFileSettings = parseConfigFile(configFilename); + + for (auto const& optionArgumentsPair : configurationFileSettings) { + auto options = this->longNameToOptions.find(optionArgumentsPair.first); + + // We don't need to check whether this option exists or not, because this is already checked when + // parsing the configuration file. + + // Now go through all the matching options and set them according to the values. + for (auto option : options->second) { + if (option->getHasOptionBeenSet()) { + // If the option was already set from the command line, we issue a warning and ignore the + // settings from the configuration file. + STORM_LOG_WARN("The option '" << option->getLongName() << "' of module '" << option->getModuleName() << "' has been set in the configuration file '" << configFilename << "', but was overwritten on the command line." << std::endl); + } else { + // If, however, the option has not been set yet, we try to assign values ot its arguments + // based on the argument strings. + setOptionArguments(optionArgumentsPair.first, option, optionArgumentsPair.second); + } + } + } } void SettingsManager::printHelp(std::string const& hint) const { - std::cout << "usage: storm [options]" << std::endl << std::endl; + STORM_PRINT("usage: storm [options]" << std::endl << std::endl); if (hint == "all") { // Find longest option name. @@ -166,7 +194,7 @@ namespace storm { // Print the matching modules. uint_fast64_t maxLength = std::max(maxLengthModules, maxLengthOptions); if (matchingModuleNames.size() > 0) { - std::cout << "Matching modules for hint '" << hint << "':" << std::endl; + STORM_PRINT("Matching modules for hint '" << hint << "':" << std::endl) for (auto const& matchingModuleName : matchingModuleNames) { printHelpForModule(matchingModuleName, maxLength); } @@ -174,14 +202,14 @@ namespace storm { // Print the matching options. if (matchingOptions.size() > 0) { - std::cout << "Matching options for hint '" << hint << "':" << std::endl; + STORM_PRINT("Matching options for hint '" << hint << "':" << std::endl); for (auto const& option : matchingOptions) { - std::cout << std::setw(maxLength) << std::left << *option << std::endl; + STORM_PRINT(std::setw(maxLength) << std::left << *option << std::endl); } } if (matchingModuleNames.empty() && matchingOptions.empty()) { - std::cout << "Hint '" << hint << "' did not match any modules or options." << std::endl; + STORM_PRINT("Hint '" << hint << "' did not match any modules or options." << std::endl); } } } @@ -189,20 +217,16 @@ namespace storm { void SettingsManager::printHelpForModule(std::string const& moduleName, uint_fast64_t maxLength) const { auto moduleIterator = moduleOptions.find(moduleName); STORM_LOG_THROW(moduleIterator != moduleOptions.end(), storm::exceptions::IllegalFunctionCallException, "Cannot print help for unknown module '" << moduleName << "'."); - std::cout << "##### Module '" << moduleName << "' "; - for (uint_fast64_t i = 0; i < std::min(maxLength, maxLength - moduleName.length() - 16); ++i) { - std::cout << "#"; - } - std::cout << std::endl; + STORM_PRINT("##### Module '" << moduleName << "' " << std::string(std::min(maxLength, maxLength - moduleName.length() - 16), '#') << std::endl); // Save the flags for std::cout so we can manipulate them and be sure they will be restored as soon as this // stream goes out of scope. boost::io::ios_flags_saver out(std::cout); for (auto const& option : moduleIterator->second) { - std::cout << std::setw(maxLength) << std::left << *option << std::endl; + STORM_PRINT(std::setw(maxLength) << std::left << *option << std::endl); } - std::cout << std::endl; + STORM_PRINT(std::endl); } uint_fast64_t SettingsManager::getPrintLengthOfLongestOption() const { @@ -290,27 +314,32 @@ namespace storm { return true; } + void SettingsManager::setOptionArguments(std::string const& optionName, std::shared_ptr<Option> option, std::vector<std::string> const& argumentCache) { + STORM_LOG_THROW(argumentCache.size() <= option->getArgumentCount(), storm::exceptions::OptionParserException, "Too many arguments for option '" << optionName << "'."); + + // Now set the provided argument values one by one. + for (uint_fast64_t i = 0; i < argumentCache.size(); ++i) { + ArgumentBase& argument = option->getArgument(i); + bool conversionOk = argument.setFromStringValue(argumentCache[i]); + STORM_LOG_THROW(conversionOk, storm::exceptions::OptionParserException, "Conversion of value of argument '" << argument.getName() << "' to its type failed."); + } + + // In case there are optional arguments that were not set, we set them to their default value. + for (uint_fast64_t i = argumentCache.size(); i < option->getArgumentCount(); ++i) { + ArgumentBase& argument = option->getArgument(i); + argument.setFromDefaultValue(); + } + + option->setHasOptionBeenSet(); + } + void SettingsManager::setOptionsArguments(std::string const& optionName, std::unordered_map<std::string, std::vector<std::shared_ptr<Option>>> const& optionMap, std::vector<std::string> const& argumentCache) { auto optionIterator = optionMap.find(optionName); STORM_LOG_THROW(optionIterator != optionMap.end(), storm::exceptions::OptionParserException, "Unknown option '" << optionName << "'."); // Iterate over all options and set the arguments. for (auto& option : optionIterator->second) { - option->setHasOptionBeenSet(); - STORM_LOG_THROW(argumentCache.size() <= option->getArgumentCount(), storm::exceptions::OptionParserException, "Too many arguments for option '" << optionName << "'."); - - // Now set the provided argument values one by one. - for (uint_fast64_t i = 0; i < argumentCache.size(); ++i) { - ArgumentBase& argument = option->getArgument(i); - bool conversionOk = argument.setFromStringValue(argumentCache[i]); - STORM_LOG_THROW(conversionOk, storm::exceptions::OptionParserException, "Conversion of value of argument '" << argument.getName() << "' to its type failed."); - } - - // In case there are optional arguments that were not set, we set them to their default value. - for (uint_fast64_t i = argumentCache.size(); i < option->getArgumentCount(); ++i) { - ArgumentBase& argument = option->getArgument(i); - argument.setFromDefaultValue(); - } + setOptionArguments(optionName, option, argumentCache); } } @@ -325,6 +354,105 @@ namespace storm { } } + void SettingsManager::checkAllModules() const { + for (auto const& nameModulePair : this->modules) { + nameModulePair.second->check(); + } + } + + std::map<std::string, std::vector<std::string>> SettingsManager::parseConfigFile(std::string const& filename) const { + std::map<std::string, std::vector<std::string>> result; + + std::ifstream input(filename); + STORM_LOG_THROW(input.good(), storm::exceptions::OptionParserException, "Could not read from config file '" << filename << "'."); + + bool globalScope = true; + std::string activeModule = ""; + uint_fast64_t lineNumber = 1; + for (std::string line; getline(input, line); ++lineNumber) { + // If the first character of the line is a "[", we expect the settings of a new module to start and + // the line to be of the shape [<module>]. + if (line.at(0) == '[') { + STORM_LOG_THROW(line.at(0) == '[' && line.find("]") == line.length() - 1 && line.find("[", 1) == line.npos, storm::exceptions::OptionParserException, "Illegal module name header in configuration file '" << filename << " in line " << std::to_string(lineNumber) << ". Expected [<module>] where <module> is a placeholder for a known module."); + + // Extract the module name and check whether it's a legal one. + std::string moduleName = line.substr(1, line.length() - 2); + STORM_LOG_THROW(moduleName != "" && (moduleName == "global" || (this->modules.find(moduleName) != this->modules.end())), storm::exceptions::OptionParserException, "Module header in configuration file '" << filename << " in line " << std::to_string(lineNumber) << " refers to unknown module '" << moduleName << "."); + + // If the module name is "global", we unset the currently active module and treat all options to follow as unprefixed. + if (moduleName == "global") { + globalScope = true; + } else { + activeModule = moduleName; + globalScope = false; + } + } else { + // In this case, we expect the line to be of the shape o or o=a b c, where o is an option and a, b + // and c are the values that are supposed to be assigned to the arguments of the option. + std::size_t assignmentSignIndex = line.find("="); + bool containsAssignment = false; + if (assignmentSignIndex != line.npos) { + containsAssignment = true; + } + + std::string optionName; + if (containsAssignment) { + optionName = line.substr(0, assignmentSignIndex); + } else { + optionName = line; + } + + if (globalScope) { + STORM_LOG_THROW(this->longNameToOptions.find(optionName) != this->longNameToOptions.end(), storm::exceptions::OptionParserException, "Option assignment in configuration file '" << filename << " in line " << lineNumber << " refers to unknown option '" << optionName << "'."); + } else { + STORM_LOG_THROW(this->longNameToOptions.find(activeModule + ":" + optionName) != this->longNameToOptions.end(), storm::exceptions::OptionParserException, "Option assignment in configuration file '" << filename << " in line " << lineNumber << " refers to unknown option '" << activeModule << ":" << optionName << "'."); + } + + std::string fullOptionName = (!globalScope ? activeModule + ":" : "") + optionName; + STORM_LOG_WARN_COND(result.find(fullOptionName) == result.end(), "Option '" << fullOptionName << "' is set in line " << lineNumber << " of configuration file " << filename << ", but has been set before."); + + // If the current line is an assignment, split the right-hand side of the assignment into parts + // enclosed by quotation marks. + if (containsAssignment) { + std::string assignedValues = line.substr(assignmentSignIndex + 1); + std::vector<std::string> argumentCache; + + // As horrible as it may look, this regular expression matches either a quoted string (possibly + // containing escaped quotes) or a simple word (without whitespaces and quotes). + std::regex argumentRegex("\"(([^\\\\\"]|((\\\\\\\\)*\\\\\")|\\\\[^\"])*)\"|(([^ \\\\\"]|((\\\\\\\\)*\\\\\")|\\\\[^\"])+)"); + boost::algorithm::trim_left(assignedValues); + + while (!assignedValues.empty()) { + std::smatch match; + bool hasMatch = std::regex_search(assignedValues, match, argumentRegex); + + // If the input could not be matched, we have a parsing error. + STORM_LOG_THROW(hasMatch, storm::exceptions::OptionParserException, "Parsing error in configuration file '" << filename << "' in line " << lineNumber << ". Unexpected input '" << assignedValues << "'."); + + // Extract the matched argument and cut off the quotation marks if necessary. + std::string matchedArgument = std::string(match[0].first, match[0].second); + if (matchedArgument.at(0) == '"') { + matchedArgument = matchedArgument.substr(1, matchedArgument.length() - 2); + } + argumentCache.push_back(matchedArgument); + + assignedValues = assignedValues.substr(match.length()); + boost::algorithm::trim_left(assignedValues); + } + + + // After successfully parsing the argument values, we store them in the result map. + result.emplace(fullOptionName, argumentCache); + } else { + // In this case, we can just insert the option to indicate it should be set (without arguments). + result.emplace(fullOptionName, std::vector<std::string>()); + } + } + } + + return result; + } + SettingsManager const& manager() { return SettingsManager::manager(); } diff --git a/src/settings/SettingsManager.h b/src/settings/SettingsManager.h index 94d309813..41383f336 100644 --- a/src/settings/SettingsManager.h +++ b/src/settings/SettingsManager.h @@ -8,6 +8,7 @@ #include <utility> #include <functional> #include <unordered_map> +#include <map> #include <vector> #include <memory> @@ -156,6 +157,15 @@ namespace storm { */ void addOption(std::shared_ptr<Option> const& option); + /*! + * Sets the arguments of the given option from the provided strings. + * + * @param optionName The name of the option. This is only used for error output. + * @param option The option for which to set the arguments. + * @param argumentCache The arguments of the option as string values. + */ + static void setOptionArguments(std::string const& optionName, std::shared_ptr<Option> option, std::vector<std::string> const& argumentCache); + /*! * Sets the arguments of the options matching the given name from the provided strings. * @@ -179,6 +189,11 @@ namespace storm { */ static void addOptionToMap(std::string const& name, std::shared_ptr<Option> const& option, std::unordered_map<std::string, std::vector<std::shared_ptr<Option>>>& optionMap); + /*! + * Checks all modules for consistency by calling their respective check method. + */ + void checkAllModules() const; + /*! * Retrieves the (print) length of the longest option of all modules. * @@ -193,6 +208,14 @@ namespace storm { * @return The length of the longest option name. */ uint_fast64_t getPrintLengthOfLongestOption(std::string const& moduleName) const; + + /*! + * Parses the given file and stores the settings in the returned map. + * + * @param filename The name of the file that is to be scanned for settings. + * @return A mapping of option names to the argument values (represented as strings). + */ + std::map<std::string, std::vector<std::string>> parseConfigFile(std::string const& filename) const; }; /*! diff --git a/src/settings/modules/CounterexampleGeneratorSettings.cpp b/src/settings/modules/CounterexampleGeneratorSettings.cpp index e2e29834d..6191b1643 100644 --- a/src/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/settings/modules/CounterexampleGeneratorSettings.cpp @@ -1,6 +1,7 @@ #include "src/settings/modules/CounterexampleGeneratorSettings.h" #include "src/settings/SettingsManager.h" +#include "src/exceptions/InvalidSettingsException.h" namespace storm { namespace settings { @@ -19,7 +20,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, schedulerCutsOptionName, true, "Sets whether to add the scheduler cuts for MILP-based minimal command counterexample generation.").build()); } - bool CounterexampleGeneratorSettings::isMinimalCommandGenerationSet() const { + bool CounterexampleGeneratorSettings::isMinimalCommandSetGenerationSet() const { return this->getOption(minimalCommandSetOptionName).getHasOptionBeenSet(); } @@ -40,6 +41,18 @@ namespace storm { return this->getOption(schedulerCutsOptionName).getHasOptionBeenSet(); } + bool CounterexampleGeneratorSettings::check() const { + // Ensure that the model was given either symbolically or explicitly. + STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::generalSettings().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified symbolically."); + + if (isMinimalCommandSetGenerationSet()) { + STORM_LOG_WARN_COND(isUseMaxSatBasedMinimalCommandSetGenerationSet() || !isEncodeReachabilitySet(), "Encoding reachability is only available for the MaxSat-based minimal command set generation, so selecting it has no effect."); + STORM_LOG_WARN_COND(isUseMilpBasedMinimalCommandSetGenerationSet() || !isUseSchedulerCutsSet(), "Using scheduler cuts is only available for the MaxSat-based minimal command set generation, so selecting it has no effect."); + } + + return true; + } + } // namespace modules } // namespace settings } // namespace storm \ No newline at end of file diff --git a/src/settings/modules/CounterexampleGeneratorSettings.h b/src/settings/modules/CounterexampleGeneratorSettings.h index 680224b5a..049747183 100644 --- a/src/settings/modules/CounterexampleGeneratorSettings.h +++ b/src/settings/modules/CounterexampleGeneratorSettings.h @@ -24,7 +24,7 @@ namespace storm { * * @return True iff a minimal command set counterexample is to be generated. */ - bool isMinimalCommandGenerationSet() const; + bool isMinimalCommandSetGenerationSet() const; /*! * Retrieves whether the MILP-based technique is to be used to generate a minimal command set @@ -58,6 +58,8 @@ namespace storm { */ bool isUseSchedulerCutsSet() const; + bool check() const override; + // The name of the module. static const std::string moduleName; diff --git a/src/settings/modules/GeneralSettings.cpp b/src/settings/modules/GeneralSettings.cpp index 45d3b58a6..585bcfdfb 100644 --- a/src/settings/modules/GeneralSettings.cpp +++ b/src/settings/modules/GeneralSettings.cpp @@ -2,6 +2,7 @@ #include "src/settings/SettingsManager.h" #include "src/settings/SettingMemento.h" +#include "src/exceptions/InvalidSettingsException.h" namespace storm { namespace settings { @@ -266,6 +267,17 @@ namespace storm { return this->getOption(statisticsOptionName).getHasOptionBeenSet(); } + bool GeneralSettings::check() const { + // Ensure that the model was given either symbolically or explicitly. + STORM_LOG_THROW(!isSymbolicSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format, but not both."); + + // Make sure that one "source" for properties is given. + uint_fast64_t propertySources = 0 + (isPctlPropertySet() ? 1 : 0) + (isPctlFileSet() ? 1 : 0) + (isCslPropertySet() ? + 1 : 0) + (isCslFileSet() ? 1 : 0) + (isLtlPropertySet() ? 1 : 0) + (isLtlFileSet() ? 1 : 0); + STORM_LOG_THROW(propertySources <= 1, storm::exceptions::InvalidSettingsException, "Please specify exactly one source of properties."); + + return true; + } + } // namespace modules } // namespace settings } // namespace storm \ No newline at end of file diff --git a/src/settings/modules/GeneralSettings.h b/src/settings/modules/GeneralSettings.h index 10e4aa77d..75f48d8f1 100644 --- a/src/settings/modules/GeneralSettings.h +++ b/src/settings/modules/GeneralSettings.h @@ -313,6 +313,8 @@ namespace storm { * @return True iff statistics are to be shown for counterexample generation. */ bool isShowStatisticsSet() const; + + bool check() const override; // The name of the module. static const std::string moduleName; diff --git a/src/settings/modules/GlpkSettings.cpp b/src/settings/modules/GlpkSettings.cpp index c45eb93a5..030a69006 100644 --- a/src/settings/modules/GlpkSettings.cpp +++ b/src/settings/modules/GlpkSettings.cpp @@ -19,10 +19,22 @@ namespace storm { return this->getOption(outputOptionName).getHasOptionBeenSet(); } + bool GlpkSettings::isIntegerToleranceSet() const { + return this->getOption(integerToleranceOption).getHasOptionBeenSet(); + } + double GlpkSettings::getIntegerTolerance() const { return this->getOption(integerToleranceOption).getArgumentByName("value").getValueAsDouble(); } + bool GlpkSettings::check() const { + if (isOutputSet() || isIntegerToleranceSet()) { + STORM_LOG_WARN_COND(storm::settings::generalSettings().getLpSolver() == storm::settings::modules::GeneralSettings::LpSolver::glpk, "glpk is not selected as the used LP solver, so setting options for glpk has no effect."); + } + + return true; + } + } // namespace modules } // namespace settings } // namespace storm \ No newline at end of file diff --git a/src/settings/modules/GlpkSettings.h b/src/settings/modules/GlpkSettings.h index c23b2add0..b58e91746 100644 --- a/src/settings/modules/GlpkSettings.h +++ b/src/settings/modules/GlpkSettings.h @@ -26,6 +26,13 @@ namespace storm { */ bool isOutputSet() const; + /*! + * Retrieves whether the integer tolerance has been set. + * + * @return True iff the integer tolerance has been set. + */ + bool isIntegerToleranceSet() const; + /*! * Retrieves the integer tolerance to be used. * @@ -33,6 +40,8 @@ namespace storm { */ double getIntegerTolerance() const; + bool check() const override; + // The name of the module. static const std::string moduleName; diff --git a/src/settings/modules/GmmxxEquationSolverSettings.cpp b/src/settings/modules/GmmxxEquationSolverSettings.cpp index c9c8b1840..4b9f27f9e 100644 --- a/src/settings/modules/GmmxxEquationSolverSettings.cpp +++ b/src/settings/modules/GmmxxEquationSolverSettings.cpp @@ -32,6 +32,10 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, absoluteOptionName, false, "Sets whether the relative or the absolute error is considered for detecting convergence.").build()); } + bool GmmxxEquationSolverSettings::isLinearEquationSystemTechniqueSet() const { + return this->getOption(techniqueOptionName).getHasOptionBeenSet(); + } + GmmxxEquationSolverSettings::LinearEquationTechnique GmmxxEquationSolverSettings::getLinearEquationSystemTechnique() const { std::string linearEquationSystemTechniqueAsString = this->getOption(techniqueOptionName).getArgumentByName("name").getValueAsString(); if (linearEquationSystemTechniqueAsString == "bicgstab") { @@ -46,6 +50,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown solution technique '" << linearEquationSystemTechniqueAsString << "' selected."); } + bool GmmxxEquationSolverSettings::isPreconditioningTechniqueSet() const { + return this->getOption(preconditionOptionName).getHasOptionBeenSet(); + } + GmmxxEquationSolverSettings::PreconditioningTechnique GmmxxEquationSolverSettings::getPreconditioningTechnique() const { std::string preconditioningTechniqueAsString = this->getOption(preconditionOptionName).getArgumentByName("name").getValueAsString(); if (preconditioningTechniqueAsString == "ilu") { @@ -58,22 +66,46 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown preconditioning technique '" << preconditioningTechniqueAsString << "' selected."); } + bool GmmxxEquationSolverSettings::isRestartIterationCountSet() const { + return this->getOption(restartOptionName).getHasOptionBeenSet(); + } + uint_fast64_t GmmxxEquationSolverSettings::getRestartIterationCount() const { return this->getOption(restartOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); } + bool GmmxxEquationSolverSettings::isMaximalIterationCountSet() const { + return this->getOption(maximalIterationsOptionName).getHasOptionBeenSet(); + } + uint_fast64_t GmmxxEquationSolverSettings::getMaximalIterationCount() const { return this->getOption(maximalIterationsOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); } + bool GmmxxEquationSolverSettings::isPrecisionSet() const { + return this->getOption(precisionOptionName).getHasOptionBeenSet(); + } + double GmmxxEquationSolverSettings::getPrecision() const { return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); } + bool GmmxxEquationSolverSettings::isConvergenceCriterionSet() const { + return this->getOption(absoluteOptionName).getHasOptionBeenSet(); + } + GmmxxEquationSolverSettings::ConvergenceCriterion GmmxxEquationSolverSettings::getConvergenceCriterion() const { return this->getOption(absoluteOptionName).getHasOptionBeenSet() ? GmmxxEquationSolverSettings::ConvergenceCriterion::Absolute : GmmxxEquationSolverSettings::ConvergenceCriterion::Relative; } + bool GmmxxEquationSolverSettings::check() const { + bool optionsSet = isLinearEquationSystemTechniqueSet() || isPreconditioningTechniqueSet() || isRestartIterationCountSet() | isMaximalIterationCountSet() || isPrecisionSet() || isConvergenceCriterionSet(); + + STORM_LOG_WARN_COND(storm::settings::generalSettings().getEquationSolver() == storm::settings::modules::GeneralSettings::EquationSolver::Gmmxx || !optionsSet, "gmm++ is not selected as the equation solver, so setting options for gmm++ has no effect."); + + return true; + } + } // namespace modules } // namespace settings } // namespace storm \ No newline at end of file diff --git a/src/settings/modules/GmmxxEquationSolverSettings.h b/src/settings/modules/GmmxxEquationSolverSettings.h index 7504f7456..07bc90174 100644 --- a/src/settings/modules/GmmxxEquationSolverSettings.h +++ b/src/settings/modules/GmmxxEquationSolverSettings.h @@ -28,6 +28,13 @@ namespace storm { */ GmmxxEquationSolverSettings(storm::settings::SettingsManager& settingsManager); + /*! + * Retrieves whether the linear equation system technique has been set. + * + * @return True iff the linear equation system technique has been set. + */ + bool isLinearEquationSystemTechniqueSet() const; + /*! * Retrieves the technique that is to be used for solving systems of linear equations. * @@ -35,6 +42,13 @@ namespace storm { */ LinearEquationTechnique getLinearEquationSystemTechnique() const; + /*! + * Retrieves whether the preconditioning technique has been set. + * + * @return True iff the preconditioning technique has been set. + */ + bool isPreconditioningTechniqueSet() const; + /*! * Retrieves the technique that is to be used for preconditioning solving systems of linear equations. * @@ -42,6 +56,13 @@ namespace storm { */ PreconditioningTechnique getPreconditioningTechnique() const; + /*! + * Retrieves whether the restart iteration count has been set. + * + * @return True iff the restart iteration count has been set. + */ + bool isRestartIterationCountSet() const; + /*! * Retrieves the number of iterations after which restarted techniques are to be restarted. * @@ -49,6 +70,13 @@ namespace storm { */ uint_fast64_t getRestartIterationCount() const; + /*! + * Retrieves whether the maximal iteration count has been set. + * + * @return True iff the maximal iteration count has been set. + */ + bool isMaximalIterationCountSet() const; + /*! * Retrieves the maximal number of iterations to perform until giving up on converging. * @@ -56,6 +84,13 @@ namespace storm { */ uint_fast64_t getMaximalIterationCount() const; + /*! + * Retrieves whether the precision has been set. + * + * @return True iff the precision has been set. + */ + bool isPrecisionSet() const; + /*! * Retrieves the precision that is used for detecting convergence. * @@ -63,6 +98,13 @@ namespace storm { */ double getPrecision() const; + /*! + * Retrieves whether the convergence criterion has been set. + * + * @return True iff the convergence criterion has been set. + */ + bool isConvergenceCriterionSet() const; + /*! * Retrieves the selected convergence criterion. * @@ -70,6 +112,8 @@ namespace storm { */ ConvergenceCriterion getConvergenceCriterion() const; + bool check() const override; + // The name of the module. static const std::string moduleName; diff --git a/src/settings/modules/GurobiSettings.cpp b/src/settings/modules/GurobiSettings.cpp index 1038fce26..86751cc1d 100644 --- a/src/settings/modules/GurobiSettings.cpp +++ b/src/settings/modules/GurobiSettings.cpp @@ -19,10 +19,18 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, integerToleranceOption, true, "Sets Gurobi's precision for integer variables.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); } + bool GurobiSettings::isIntegerToleranceSet() const { + return this->getOption(integerToleranceOption).getHasOptionBeenSet(); + } + double GurobiSettings::getIntegerTolerance() const { return this->getOption(integerToleranceOption).getArgumentByName("value").getValueAsDouble(); } + bool GurobiSettings::isNumberOfThreadsSet() const { + return this->getOption(threadsOption).getHasOptionBeenSet(); + } + uint_fast64_t GurobiSettings::getNumberOfThreads() const { return this->getOption(threadsOption).getArgumentByName("count").getValueAsUnsignedInteger(); } @@ -31,6 +39,14 @@ namespace storm { return this->getOption(outputOption).getHasOptionBeenSet(); } + bool GurobiSettings::check() const { + if (isOutputSet() || isIntegerToleranceSet() || isNumberOfThreadsSet()) { + STORM_LOG_WARN_COND(storm::settings::generalSettings().getLpSolver() == storm::settings::modules::GeneralSettings::LpSolver::Gurobi, "Gurobi is not selected as the used LP solver, so setting options for Gurobi has no effect."); + } + + return true; + } + } // namespace modules } // namespace settings } // namespace storm \ No newline at end of file diff --git a/src/settings/modules/GurobiSettings.h b/src/settings/modules/GurobiSettings.h index d0e92127b..ce7fcd78f 100644 --- a/src/settings/modules/GurobiSettings.h +++ b/src/settings/modules/GurobiSettings.h @@ -19,6 +19,13 @@ namespace storm { */ GurobiSettings(storm::settings::SettingsManager& settingsManager); + /*! + * Retrieves whether the integer tolerance has been set. + * + * @return True iff the integer tolerance has been set. + */ + bool isIntegerToleranceSet() const; + /*! * Retrieves the integer tolerance to be used. * @@ -26,6 +33,13 @@ namespace storm { */ double getIntegerTolerance() const; + /*! + * Retrieves whether the number of threads has been set. + * + * @return True iff the number of threads has been set. + */ + bool isNumberOfThreadsSet() const; + /*! * Retrieves the maximal number of threads Gurobi is allowed to use. * @@ -40,6 +54,8 @@ namespace storm { */ bool isOutputSet() const; + bool check() const override; + // The name of the module. static const std::string moduleName; diff --git a/src/settings/modules/NativeEquationSolverSettings.cpp b/src/settings/modules/NativeEquationSolverSettings.cpp index b03feece6..76af99b3e 100644 --- a/src/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/settings/modules/NativeEquationSolverSettings.cpp @@ -24,6 +24,10 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, absoluteOptionName, false, "Sets whether the relative or the absolute error is considered for detecting convergence.").build()); } + bool NativeEquationSolverSettings::isLinearEquationSystemTechniqueSet() const { + return this->getOption(techniqueOptionName).getHasOptionBeenSet(); + } + NativeEquationSolverSettings::LinearEquationTechnique NativeEquationSolverSettings::getLinearEquationSystemTechnique() const { std::string linearEquationSystemTechniqueAsString = this->getOption(techniqueOptionName).getArgumentByName("name").getValueAsString(); if (linearEquationSystemTechniqueAsString == "jacobi") { @@ -32,18 +36,38 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown solution technique '" << linearEquationSystemTechniqueAsString << "' selected."); } + bool NativeEquationSolverSettings::isMaximalIterationCountSet() const { + return this->getOption(maximalIterationsOptionName).getHasOptionBeenSet(); + } + uint_fast64_t NativeEquationSolverSettings::getMaximalIterationCount() const { return this->getOption(maximalIterationsOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); } + bool NativeEquationSolverSettings::isPrecisionSet() const { + return this->getOption(precisionOptionName).getHasOptionBeenSet(); + } + double NativeEquationSolverSettings::getPrecision() const { return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); } + bool NativeEquationSolverSettings::isConvergenceCriterionSet() const { + return this->getOption(absoluteOptionName).getHasOptionBeenSet(); + } + NativeEquationSolverSettings::ConvergenceCriterion NativeEquationSolverSettings::getConvergenceCriterion() const { return this->getOption(absoluteOptionName).getHasOptionBeenSet() ? NativeEquationSolverSettings::ConvergenceCriterion::Absolute : NativeEquationSolverSettings::ConvergenceCriterion::Relative; } + bool NativeEquationSolverSettings::check() const { + bool optionSet = isLinearEquationSystemTechniqueSet() || isMaximalIterationCountSet() || isPrecisionSet() || isConvergenceCriterionSet(); + + STORM_LOG_WARN_COND(storm::settings::generalSettings().getEquationSolver() == storm::settings::modules::GeneralSettings::EquationSolver::Native || !optionSet, "Native is not selected as the equation solver, so setting options for native has no effect."); + + return true; + } + } // namespace modules } // namespace settings } // namespace storm \ No newline at end of file diff --git a/src/settings/modules/NativeEquationSolverSettings.h b/src/settings/modules/NativeEquationSolverSettings.h index 826d40941..9d6e43ecd 100644 --- a/src/settings/modules/NativeEquationSolverSettings.h +++ b/src/settings/modules/NativeEquationSolverSettings.h @@ -25,6 +25,13 @@ namespace storm { */ NativeEquationSolverSettings(storm::settings::SettingsManager& settingsManager); + /*! + * Retrieves whether the linear equation system technique has been set. + * + * @return True iff the linear equation system technique has been set. + */ + bool isLinearEquationSystemTechniqueSet() const; + /*! * Retrieves the technique that is to be used for solving systems of linear equations. * @@ -32,6 +39,13 @@ namespace storm { */ LinearEquationTechnique getLinearEquationSystemTechnique() const; + /*! + * Retrieves whether the maximal iteration count has been set. + * + * @return True iff the maximal iteration count has been set. + */ + bool isMaximalIterationCountSet() const; + /*! * Retrieves the maximal number of iterations to perform until giving up on converging. * @@ -39,6 +53,13 @@ namespace storm { */ uint_fast64_t getMaximalIterationCount() const; + /*! + * Retrieves whether the precision has been set. + * + * @return True iff the precision has been set. + */ + bool isPrecisionSet() const; + /*! * Retrieves the precision that is used for detecting convergence. * @@ -46,6 +67,13 @@ namespace storm { */ double getPrecision() const; + /*! + * Retrieves whether the convergence criterion has been set. + * + * @return True iff the convergence criterion has been set. + */ + bool isConvergenceCriterionSet() const; + /*! * Retrieves the selected convergence criterion. * @@ -53,6 +81,8 @@ namespace storm { */ ConvergenceCriterion getConvergenceCriterion() const; + bool check() const override; + // The name of the module. static const std::string moduleName; diff --git a/src/utility/cli.h b/src/utility/cli.h index 162d2a393..2be0bd112 100644 --- a/src/utility/cli.h +++ b/src/utility/cli.h @@ -200,9 +200,8 @@ namespace storm { try { manager.setFromCommandLine(argc, argv); } catch (storm::exceptions::OptionParserException& e) { - std::cout << "Could not recover from settings error: " << e.what() << "." << std::endl; - std::cout << std::endl; manager.printHelp(); + throw e; return false; } @@ -260,7 +259,7 @@ namespace storm { } void generateCounterexample(std::shared_ptr<storm::models::AbstractModel<double>> model, std::shared_ptr<storm::properties::prctl::AbstractPrctlFormula<double>> const& formula) { - if (storm::settings::counterexampleGeneratorSettings().isMinimalCommandGenerationSet()) { + if (storm::settings::counterexampleGeneratorSettings().isMinimalCommandSetGenerationSet()) { STORM_LOG_THROW(model->getType() == storm::models::MDP, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); STORM_LOG_THROW(storm::settings::generalSettings().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "Minimal command set generation is only available for symbolic models."); diff --git a/src/utility/macros.h b/src/utility/macros.h index 511fdcc12..a8d75d3c8 100644 --- a/src/utility/macros.h +++ b/src/utility/macros.h @@ -44,14 +44,49 @@ extern log4cplus::Logger logger; LOG4CPLUS_WARN(logger, message); \ } while (false) +#define STORM_LOG_WARN_COND(cond, message) \ +{ \ + if (!(cond)) { \ + LOG4CPLUS_WARN(logger, message); \ + } \ +} while (false) + #define STORM_LOG_INFO(message) \ { \ LOG4CPLUS_INFO(logger, message); \ } while (false) +#define STORM_LOG_INFO_COND(cond, message) \ +{ \ + if (!(cond)) { \ + LOG4CPLUS_INFO(logger, message); \ + } \ +} while (false) + #define STORM_LOG_ERROR(message) \ { \ LOG4CPLUS_ERROR(logger, message); \ } while (false) +#define STORM_LOG_ERROR_COND(cond, message) \ +{ \ + if (!(cond)) { \ + LOG4CPLUS_ERROR(logger, message); \ + } \ +} while (false) + +/*! + * Define the macros that print information and optionally also log it. + */ +#define STORM_PRINT(message) \ +{ \ + std::cout << message; \ +} + +#define STORM_PRINT_AND_LOG(message) \ +{ \ + STORM_LOG_INFO(message); \ + STORM_PRINT(message); \ +} + #endif /* STORM_UTILITY_MACROS_H_ */ \ No newline at end of file