You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

341 lines
16 KiB

#include "storm-conv/api/storm-conv.h"
#include "storm/settings/SettingsManager.h"
#include "storm-conv/settings/ConvSettings.h"
#include "storm-conv/settings/modules/ConversionGeneralSettings.h"
#include "storm-conv/settings/modules/ConversionInputSettings.h"
#include "storm-conv/settings/modules/ConversionOutputSettings.h"
#include "storm/api/storm.h"
#include "storm-parsers/api/storm-parsers.h"
#include "storm/utility/initialize.h"
#include "storm/utility/macros.h"
#include "storm/utility/Stopwatch.h"
#include "storm/storage/SymbolicModelDescription.h"
#include "storm/storage/jani/Model.h"
#include "storm/storage/jani/Property.h"
#include "storm-cli-utilities/cli.h"
#include "storm/exceptions/OptionParserException.h"
namespace storm {
namespace conv {
void setUrgentOptions() {
// Set the correct log level
if (storm::settings::getModule<storm::settings::modules::ConversionOutputSettings>().isStdOutOutputEnabled()) {
storm::utility::setLogLevel(l3pp::LogLevel::OFF);
} else {
auto const& general = storm::settings::getModule<storm::settings::modules::ConversionGeneralSettings>();
if (general.isVerboseSet()) {
storm::utility::setLogLevel(l3pp::LogLevel::INFO);
}
if (general.isDebugOutputSet()) {
storm::utility::setLogLevel(l3pp::LogLevel::DEBUG);
}
if (general.isTraceOutputSet()) {
storm::utility::setLogLevel(l3pp::LogLevel::TRACE);
}
}
}
storm::utility::Stopwatch startStopwatch(std::string const& message) {
STORM_PRINT_AND_LOG(message);
return storm::utility::Stopwatch(true);
}
void stopStopwatch(storm::utility::Stopwatch& stopWatch) {
stopWatch.stop();
STORM_PRINT_AND_LOG(" done. (" << stopWatch << " seconds)." << std::endl);
}
void processPrismInputJaniOutput(storm::prism::Program const& prismProg, std::vector<storm::jani::Property> const& properties) {
auto const& output = storm::settings::getModule<storm::settings::modules::ConversionOutputSettings>();
auto const& input = storm::settings::getModule<storm::settings::modules::ConversionInputSettings>();
auto const& jani = storm::settings::getModule<storm::settings::modules::JaniExportSettings>();
auto conversionTime = startStopwatch("Converting PRISM Program to JANI model ... " );
storm::converter::PrismToJaniConverterOptions options;
options.allVariablesGlobal = jani.isGlobalVarsSet();
options.suffix = "";
options.janiOptions = storm::converter::JaniConversionOptions(jani);
options.janiOptions.substituteConstants = true;
// Get the name of the output file
std::string outputFilename = "";
if (output.isJaniOutputFilenameSet()) {
outputFilename = output.getJaniOutputFilename();
} else if (input.isPrismInputSet() && !output.isStdOutOutputEnabled()) {
outputFilename = input.getPrismInputFilename();
// Remove extension if present
auto dotPos = outputFilename.rfind('.');
if (dotPos != std::string::npos) {
outputFilename.erase(dotPos);
}
std::string suffix = "";
if (input.isConstantsSet()) {
suffix = input.getConstantDefinitionString();
std::replace(suffix.begin(), suffix.end(), ',', '_');
std::replace(suffix.begin(), suffix.end(), '=', '-');
}
suffix = suffix + ".jani";
outputFilename += suffix;
}
// Find a good model name
auto startOfFilename = outputFilename.rfind("/");
if (startOfFilename == std::string::npos) {
startOfFilename = 0;
} else {
++startOfFilename;
}
auto endOfFilename = outputFilename.rfind(".");
if (endOfFilename == std::string::npos) {
endOfFilename = outputFilename.size();
}
options.janiOptions.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename);
auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options);
stopStopwatch(conversionTime);
auto exportingTime = startStopwatch("Exporting JANI model ... ");
if (outputFilename != "") {
storm::api::exportJaniToFile(janiModelProperties.first, janiModelProperties.second, outputFilename, jani.isCompactJsonSet());
STORM_PRINT_AND_LOG("Stored to file '" << outputFilename << "'");
}
if (output.isStdOutOutputEnabled()) {
storm::api::printJaniToStream(janiModelProperties.first, janiModelProperties.second, std::cout, jani.isCompactJsonSet());
}
stopStopwatch(exportingTime);
}
void processPrismInput() {
auto parsingTime = startStopwatch("Parsing PRISM input ... " );
auto const& input = storm::settings::getModule<storm::settings::modules::ConversionInputSettings>();
// Parse the prism program
storm::storage::SymbolicModelDescription prismProg = storm::api::parseProgram(input.getPrismInputFilename(), input.isPrismCompatibilityEnabled(), false);
// Parse properties (if available)
std::vector<storm::jani::Property> properties;
if (input.isPropertyInputSet()) {
boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter());
properties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), prismProg, propertyFilter);
}
// Set constant definitions in program
std::string constantDefinitionString = input.getConstantDefinitionString();
auto constantDefinitions = prismProg.parseConstantDefinitions(constantDefinitionString);
prismProg = storm::storage::SymbolicModelDescription(prismProg.asPrismProgram().defineUndefinedConstants(constantDefinitions));
// Substitution of constants can only be done after conversion in order to preserve formula definitions in which
// constants appear that are renamed in some modules...
stopStopwatch(parsingTime);
// Branch on the type of output
auto const& output = storm::settings::getModule<storm::settings::modules::ConversionOutputSettings>();
if (output.isJaniOutputSet()) {
processPrismInputJaniOutput(prismProg.asPrismProgram(), properties);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible.");
}
}
void processJaniInputJaniOutput(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& properties) {
auto conversionTime = startStopwatch("Performing transformations on JANI model ... " );
auto const& output = storm::settings::getModule<storm::settings::modules::ConversionOutputSettings>();
auto const& input = storm::settings::getModule<storm::settings::modules::ConversionInputSettings>();
auto const& jani = storm::settings::getModule<storm::settings::modules::JaniExportSettings>();
storm::converter::JaniConversionOptions options(jani);
// Get the name of the output file
std::string outputFilename = "";
if (output.isJaniOutputFilenameSet()) {
outputFilename = output.getJaniOutputFilename();
} else if (input.isJaniInputSet() && !output.isStdOutOutputEnabled()) {
outputFilename = input.getJaniInputFilename();
// Remove extension if present
auto dotPos = outputFilename.rfind('.');
if (dotPos != std::string::npos) {
outputFilename.erase(dotPos);
}
outputFilename += "_converted.jani";
}
// Get a good model name from the output filename
auto startOfFilename = outputFilename.rfind("/");
if (startOfFilename == std::string::npos) {
startOfFilename = 0;
} else {
++startOfFilename;
}
auto endOfFilename = outputFilename.rfind(".");
if (endOfFilename == std::string::npos) {
endOfFilename = outputFilename.size();
}
options.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename);
auto transformedJaniModel = janiModel;
auto transformedProperties = properties;
storm::api::transformJani(transformedJaniModel, transformedProperties, options);
stopStopwatch(conversionTime);
auto exportingTime = startStopwatch("Exporting JANI model ... ");
if (outputFilename != "") {
storm::api::exportJaniToFile(transformedJaniModel, transformedProperties, outputFilename, jani.isCompactJsonSet());
STORM_PRINT_AND_LOG("Stored to file '" << outputFilename << "'");
}
if (output.isStdOutOutputEnabled()) {
storm::api::printJaniToStream(transformedJaniModel, transformedProperties, std::cout, jani.isCompactJsonSet());
}
stopStopwatch(exportingTime);
}
void processJaniInput() {
auto parsingTime = startStopwatch("Parsing JANI input ... " );
auto const& input = storm::settings::getModule<storm::settings::modules::ConversionInputSettings>();
// Parse the jani model and selected properties
boost::optional<std::vector<std::string>> janiPropertyFilter;
if (input.isJaniPropertiesSet()) {
if (input.areJaniPropertiesSelected()) {
janiPropertyFilter = input.getSelectedJaniProperties();
} else {
janiPropertyFilter = boost::none;
}
} else {
if (input.isPropertyInputSet()) {
janiPropertyFilter = std::vector<std::string>();
} else {
// If no properties are selected, take the ones from the jani file.
janiPropertyFilter = boost::none;
}
}
auto janiModelProperties = storm::api::parseJaniModel(input.getJaniInputFilename(), storm::jani::getAllKnownModelFeatures(), janiPropertyFilter);
// Parse additional properties given from command line
std::vector<storm::jani::Property> properties = std::move(janiModelProperties.second);
if (input.isPropertyInputSet()) {
boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter());
auto additionalProperties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), janiModelProperties.first, propertyFilter);
properties.insert(properties.end(), additionalProperties.begin(), additionalProperties.end());
}
storm::storage::SymbolicModelDescription symbDescr(janiModelProperties.first);
// Substitute constant definitions in model and properties.
std::string constantDefinitionString = input.getConstantDefinitionString();
auto constantDefinitions = symbDescr.parseConstantDefinitions(constantDefinitionString);
auto janiModel = janiModelProperties.first.defineUndefinedConstants(constantDefinitions).substituteConstants();
if (!properties.empty()) {
properties = storm::api::substituteConstantsInProperties(properties, constantDefinitions);
}
stopStopwatch(parsingTime);
// Branch on the type of output
auto const& output = storm::settings::getModule<storm::settings::modules::ConversionOutputSettings>();
if (output.isJaniOutputSet()) {
processJaniInputJaniOutput(janiModel, properties);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible.");
}
}
void processOptions() {
// Start by setting some urgent options (log levels, etc.)
setUrgentOptions();
// Branch on the type of input
auto const& input = storm::settings::getModule<storm::settings::modules::ConversionInputSettings>();
STORM_LOG_THROW(!(input.isPrismInputSet() && input.isJaniInputSet()), storm::exceptions::InvalidSettingsException, "Multiple input options were set.");
if (input.isPrismInputSet()) {
processPrismInput();
} else if (input.isJaniInputSet()) {
processJaniInput();
}
}
}
}
bool parseOptions(const int argc, const char* argv[]) {
try {
storm::settings::mutableManager().setFromCommandLine(argc, argv);
} catch (storm::exceptions::OptionParserException& e) {
storm::settings::manager().printHelp();
throw e;
return false;
}
auto const& general = storm::settings::getModule<storm::settings::modules::ConversionGeneralSettings>();
// Set options from config file (if given)
if (general.isConfigSet()) {
storm::settings::mutableManager().setFromConfigurationFile(general.getConfigFilename());
}
bool result = true;
if (general.isHelpSet()) {
storm::settings::manager().printHelp(general.getHelpModuleName());
result = false;
}
if (general.isVersionSet()) {
storm::cli::printVersion("storm-conv");
result = false;;
}
return result;
}
/*!
* Main entry point of the executable storm-conv.
*/
int main(const int argc, const char** argv) {
try {
storm::utility::setUp();
// Print header info only if output to sdtout is disabled
bool outputToStdOut = false;
for (int i = 1; i < argc; ++i) {
if (std::string(argv[i]) == "--" + storm::settings::modules::ConversionOutputSettings::stdoutOptionName) {
outputToStdOut = true;
}
}
if (outputToStdOut) {
storm::utility::setLogLevel(l3pp::LogLevel::OFF);
} else {
storm::cli::printHeader("Storm-conv", argc, argv);
}
storm::settings::initializeConvSettings("Storm-conv", "storm-conv");
if (!parseOptions(argc, argv)) {
return -1;
}
storm::conv::processOptions();
storm::utility::cleanUp();
return 0;
} catch (storm::exceptions::BaseException const& exception) {
STORM_LOG_ERROR("An exception caused Storm-conv to terminate. The message of the exception is: " << exception.what());
return 1;
} catch (std::exception const& exception) {
STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-conv to terminate. The message of this exception is: " << exception.what());
return 2;
}
}