diff --git a/src/storm-parsers/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp
index c95c42af2..624dda819 100644
--- a/src/storm-parsers/parser/PrismParser.cpp
+++ b/src/storm-parsers/parser/PrismParser.cpp
@@ -23,7 +23,7 @@ namespace storm {
             std::ifstream inputFileStream;
             storm::utility::openFile(filename, inputFileStream);
             storm::prism::Program result;
-            
+
             // Now try to parse the contents of the file.
             try {
                 std::string fileContent((std::istreambuf_iterator<char>(inputFileStream)), (std::istreambuf_iterator<char>()));
@@ -37,15 +37,15 @@ namespace storm {
                 storm::utility::closeFile(inputFileStream);
                 throw e;
             }
-            
+
             // Close the stream in case everything went smoothly and return result.
             storm::utility::closeFile(inputFileStream);
             return result;
         }
-        
+
         storm::prism::Program PrismParser::parseFromString(std::string const& input, std::string const& filename, bool prismCompatibility) {
             bool hasByteOrderMark = input.size() >= 3 && input[0] == '\xEF' && input[1] == '\xBB' && input[2] == '\xBF';
-            
+
             PositionIteratorType first(hasByteOrderMark ? input.begin() + 3 : input.begin());
             PositionIteratorType iter = first;
             PositionIteratorType last(input.end());
@@ -53,7 +53,7 @@ namespace storm {
 
             // Create empty result;
             storm::prism::Program result;
-            
+
             // Create grammar.
             storm::parser::PrismParser grammar(filename, first, prismCompatibility);
             try {
@@ -62,7 +62,7 @@ namespace storm {
                 bool succeeded = qi::phrase_parse(iter, last, grammar, space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result);
                 STORM_LOG_THROW(succeeded,  storm::exceptions::WrongFormatException, "Parsing failed in first pass.");
                 STORM_LOG_DEBUG("First pass of parsing PRISM input finished.");
-                
+
                 // Start second run.
                 first = PositionIteratorType(input.begin());
                 iter = first;
@@ -73,98 +73,98 @@ namespace storm {
             } catch (qi::expectation_failure<PositionIteratorType> const& e) {
                 // If the parser expected content different than the one provided, display information about the location of the error.
                 std::size_t lineNumber = boost::spirit::get_line(e.first);
-                
+
                 // Now propagate exception.
                 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << lineNumber << " of file " << filename << ".");
             }
-            
+
             STORM_LOG_TRACE("Parsed PRISM input: " << result);
-            
+
             return result;
         }
-        
+
         PrismParser::PrismParser(std::string const& filename, Iterator first, bool prismCompatibility) : PrismParser::base_type(start), secondRun(false), prismCompatibility(prismCompatibility), filename(filename), annotate(first), manager(new storm::expressions::ExpressionManager()), expressionParser(new ExpressionParser(*manager, keywords_, false, false)) {
-            
+
             ExpressionParser& expression_ = *expressionParser;
             boolExpression = (expression_[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isOfBoolType, phoenix::ref(*this), qi::_val)];
             boolExpression.name("boolean expression");
-            
+
             intExpression = (expression_[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isOfIntType, phoenix::ref(*this), qi::_val)];
             intExpression.name("integer expression");
-            
+
             numericalExpression = (expression_[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isOfNumericalType, phoenix::ref(*this), qi::_val)];
             numericalExpression.name("numerical expression");
-            
+
             // Parse simple identifier.
             identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))]]][qi::_pass = phoenix::bind(&PrismParser::isValidIdentifier, phoenix::ref(*this), qi::_1)];
             identifier.name("identifier");
-            
+
             // Fail if the identifier has been used before
             freshIdentifier = (identifier[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isFreshIdentifier, phoenix::ref(*this), qi::_1)];
             freshIdentifier.name("fresh identifier");
-            
+
             modelTypeDefinition %= modelType_;
             modelTypeDefinition.name("model type");
-            
+
             // Defined constants. Will be checked before undefined constants.
             // ">>" before literal '=' because we can still parse an undefined constant afterwards.
             definedBooleanConstantDefinition = (((qi::lit("const") >> qi::lit("bool")) > freshIdentifier)
                     >> (qi::lit("=") > boolExpression > qi::lit(";"))
                     )[qi::_val = phoenix::bind(&PrismParser::createDefinedBooleanConstant, phoenix::ref(*this), qi::_1, qi::_2)];
             definedBooleanConstantDefinition.name("defined boolean constant declaration");
-            
+
             definedIntegerConstantDefinition = (((qi::lit("const") >> -qi::lit("int")) >> freshIdentifier)
                     >> (qi::lit("=") > intExpression > qi::lit(";"))
                     )[qi::_val = phoenix::bind(&PrismParser::createDefinedIntegerConstant, phoenix::ref(*this), qi::_1, qi::_2)]; // '>>' before freshIdentifier because of the optional 'int'.  Otherwise, undefined constant 'const bool b;' would not parse.
             definedIntegerConstantDefinition.name("defined integer constant declaration");
-            
+
             definedDoubleConstantDefinition = (((qi::lit("const") >> qi::lit("double")) > freshIdentifier)
                     >> (qi::lit("=") > numericalExpression > qi::lit(";"))
                     )[qi::_val = phoenix::bind(&PrismParser::createDefinedDoubleConstant, phoenix::ref(*this), qi::_1, qi::_2)];
             definedDoubleConstantDefinition.name("defined double constant declaration");
-            
+
             definedConstantDefinition %= (definedBooleanConstantDefinition | definedDoubleConstantDefinition | definedIntegerConstantDefinition);
             definedConstantDefinition.name("defined constant definition");
-            
+
             // Undefined constants. At this point we already checked for a defined constant, therefore a ";" is required after the identifier;
             undefinedBooleanConstantDefinition = (((qi::lit("const") >> qi::lit("bool")) > freshIdentifier) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createUndefinedBooleanConstant, phoenix::ref(*this), qi::_1)];
             undefinedBooleanConstantDefinition.name("undefined boolean constant declaration");
-            
+
             undefinedIntegerConstantDefinition = (((qi::lit("const") >> -qi::lit("int")) > freshIdentifier) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createUndefinedIntegerConstant, phoenix::ref(*this), qi::_1)];
             undefinedIntegerConstantDefinition.name("undefined integer constant declaration");
-            
+
             undefinedDoubleConstantDefinition = (((qi::lit("const") >> qi::lit("double")) > freshIdentifier) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createUndefinedDoubleConstant, phoenix::ref(*this), qi::_1)];
             undefinedDoubleConstantDefinition.name("undefined double constant definition");
-            
+
             undefinedConstantDefinition = (undefinedBooleanConstantDefinition | undefinedDoubleConstantDefinition | undefinedIntegerConstantDefinition); // Due to the 'const N;' syntax, it is important to have integer constants last
 
             undefinedConstantDefinition.name("undefined constant definition");
-            
+
             // formula definitions. This will be changed for the second run.
             formulaDefinitionRhs = (qi::lit("=") > qi::as_string[(+(qi::char_ - (qi::lit(";") | qi::lit("endmodule"))))][qi::_val = qi::_1] > qi::lit(";"));
             formulaDefinitionRhs.name("formula defining expression");
-            
+
             formulaDefinition = (qi::lit("formula") > freshIdentifier > formulaDefinitionRhs )[qi::_val = phoenix::bind(&PrismParser::createFormulaFirstRun, phoenix::ref(*this), qi::_1, qi::_2)];
             formulaDefinition.name("formula definition");
-            
+
             booleanVariableDefinition = (((freshIdentifier > qi::lit(":")) >> qi::lit("bool")) > -((qi::lit("init") > boolExpression[qi::_a = qi::_1]) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_a)];
             booleanVariableDefinition.name("boolean variable definition");
-            
+
             integerVariableDefinition = (((freshIdentifier > qi::lit(":")) >> qi::lit("[")) > intExpression > qi::lit("..") > intExpression > qi::lit("]") > -(qi::lit("init") > intExpression[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)];
             integerVariableDefinition.name("integer variable definition");
-            
+
             clockVariableDefinition = (((freshIdentifier > qi::lit(":")) >> qi::lit("clock")) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createClockVariable, phoenix::ref(*this), qi::_1)];
             clockVariableDefinition.name("clock variable definition");
-            
+
             variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)] | clockVariableDefinition[phoenix::push_back(qi::_r3, qi::_1)]);
             variableDefinition.name("variable declaration");
-            
+
             globalVariableDefinition = (qi::lit("global") > (booleanVariableDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::globalBooleanVariables, qi::_r1), qi::_1)] | integerVariableDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::globalIntegerVariables, qi::_r1), qi::_1)]));
             globalVariableDefinition.name("global variable declaration list");
-                        
+
             stateRewardDefinition = (boolExpression > qi::lit(":") > numericalExpression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createStateReward, phoenix::ref(*this), qi::_1, qi::_2)];
             stateRewardDefinition.name("state reward definition");
-            
+
             stateActionRewardDefinition = (qi::lit("[") > -identifier > qi::lit("]") > boolExpression > qi::lit(":") > numericalExpression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createStateActionReward, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_r1)];
             stateActionRewardDefinition.name("state action reward definition");
 
@@ -181,28 +181,28 @@ namespace storm {
                                          )
                                      > qi::lit("endrewards"))[qi::_val = phoenix::bind(&PrismParser::createRewardModel, phoenix::ref(*this), qi::_a, qi::_b, qi::_c, qi::_d)];
             rewardModelDefinition.name("reward model definition");
-            
+
             initialStatesConstruct = (qi::lit("init") > boolExpression > qi::lit("endinit"))[qi::_pass = phoenix::bind(&PrismParser::addInitialStatesConstruct, phoenix::ref(*this), qi::_1, qi::_r1)];
             initialStatesConstruct.name("initial construct");
 
             observablesConstruct = (qi::lit("observables") > (identifier % qi::lit(",") )> qi::lit("endobservables"))[phoenix::bind(&PrismParser::createObservablesList, phoenix::ref(*this), qi::_1)];
             observablesConstruct.name("observables construct");
-            
+
             invariantConstruct = (qi::lit("invariant") > boolExpression > qi::lit("endinvariant"))[qi::_val = qi::_1];
             invariantConstruct.name("invariant construct");
 
             knownModuleName = (identifier[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isKnownModuleName, phoenix::ref(*this), qi::_1)];
             knownModuleName.name("existing module name");
-            
+
             freshModuleName = (identifier[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isFreshModuleName, phoenix::ref(*this), qi::_1)];
             freshModuleName.name("fresh module name");
 
             systemCompositionConstruct = (qi::lit("system") > parallelComposition > qi::lit("endsystem"))[phoenix::bind(&PrismParser::addSystemCompositionConstruct, phoenix::ref(*this), qi::_1, qi::_r1)];
             systemCompositionConstruct.name("system composition construct");
-            
+
             actionNameList %= identifier[phoenix::insert(qi::_val, qi::_1)] >> *("," >> identifier[phoenix::insert(qi::_val, qi::_1)]);
             actionNameList.name("action list");
-            
+
             parallelComposition = hidingOrRenamingComposition[qi::_val = qi::_1] >> *((interleavingParallelComposition > hidingOrRenamingComposition)[qi::_val = phoenix::bind(&PrismParser::createInterleavingParallelComposition, phoenix::ref(*this), qi::_val, qi::_1)] |
                                                                                       (synchronizingParallelComposition > hidingOrRenamingComposition)[qi::_val = phoenix::bind(&PrismParser::createSynchronizingParallelComposition, phoenix::ref(*this), qi::_val, qi::_1)] |
                                                                                       (restrictedParallelComposition > hidingOrRenamingComposition)[qi::_val = phoenix::bind(&PrismParser::createRestrictedParallelComposition, phoenix::ref(*this), qi::_val, qi::_1, qi::_2)]
@@ -211,31 +211,31 @@ namespace storm {
 
             synchronizingParallelComposition = qi::lit("||");
             synchronizingParallelComposition.name("synchronizing parallel composition");
-            
+
             interleavingParallelComposition = qi::lit("|||");
             interleavingParallelComposition.name("interleaving parallel composition");
 
             restrictedParallelComposition = qi::lit("|[") > actionNameList > qi::lit("]|");
             restrictedParallelComposition.name("restricted parallel composition");
-            
+
             hidingOrRenamingComposition = hidingComposition | renamingComposition | atomicComposition;
             hidingOrRenamingComposition.name("hiding/renaming composition");
-            
+
             hidingComposition = (atomicComposition >> (qi::lit("/") > (qi::lit("{") > actionNameList > qi::lit("}"))))[qi::_val = phoenix::bind(&PrismParser::createHidingComposition, phoenix::ref(*this), qi::_1, qi::_2)];
             hidingComposition.name("hiding composition");
-            
+
             actionRenamingList = +(identifier >> (qi::lit("<-") >> identifier))[phoenix::insert(qi::_val, phoenix::construct<std::pair<std::string, std::string>>(qi::_1, qi::_2))];
             actionRenamingList.name("action renaming list");
-            
+
             renamingComposition = (atomicComposition >> (qi::lit("{") > (actionRenamingList > qi::lit("}"))))[qi::_val = phoenix::bind(&PrismParser::createRenamingComposition, phoenix::ref(*this), qi::_1, qi::_2)];
             renamingComposition.name("renaming composition");
-            
+
             atomicComposition = (qi::lit("(") > parallelComposition > qi::lit(")")) | moduleComposition;
             atomicComposition.name("atomic composition");
-            
+
             moduleComposition = identifier[qi::_val = phoenix::bind(&PrismParser::createModuleComposition, phoenix::ref(*this), qi::_1)];
             moduleComposition.name("module composition");
-            
+
             freshLabelName = (identifier[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isFreshLabelName, phoenix::ref(*this), qi::_1)];
             freshLabelName.name("fresh label name");
 
@@ -247,20 +247,20 @@ namespace storm {
 
             observableDefinition = (qi::lit("observable") > -qi::lit("\"") > freshObservationLabelName > -qi::lit("\"") > qi::lit("=") > (intExpression | boolExpression) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createObservationLabel, phoenix::ref(*this), qi::_1, qi::_2)];
             observableDefinition.name("observable definition");
-            
+
             assignmentDefinition = ((qi::lit("(") >> identifier >> qi::lit("'")) > qi::lit("=") > expression_ > qi::lit(")"))[qi::_val = phoenix::bind(&PrismParser::createAssignment, phoenix::ref(*this), qi::_1, qi::_2)];
             assignmentDefinition.name("assignment");
-            
+
             assignmentDefinitionList = (assignmentDefinition % "&")[qi::_val = qi::_1] | (qi::lit("true"))[qi::_val = phoenix::construct<std::vector<storm::prism::Assignment>>()];
             assignmentDefinitionList.name("assignment list");
-            
+
             updateDefinition = (assignmentDefinitionList[qi::_val = phoenix::bind(&PrismParser::createUpdate, phoenix::ref(*this), manager->rational(1), qi::_1, qi::_r1)]
                     | ((numericalExpression > qi::lit(":") > assignmentDefinitionList)[qi::_val = phoenix::bind(&PrismParser::createUpdate, phoenix::ref(*this), qi::_1, qi::_2, qi::_r1)]));
             updateDefinition.name("update");
-            
+
             updateListDefinition %= +updateDefinition(qi::_r1) % "+";
             updateListDefinition.name("update list");
-            
+
             // This is a dummy command-definition (it ignores the actual contents of the command) that is overwritten when the parser is moved to the second run.
             commandDefinition = (((qi::lit("[") > -identifier > qi::lit("]"))
                                   |
@@ -272,20 +272,37 @@ namespace storm {
             // We first check for a module renaming, i.e., for this rule we certainly have to see a module definition
             moduleDefinition = ((qi::lit("module") > freshModuleName > *(variableDefinition(qi::_a, qi::_b, qi::_c))) > -invariantConstruct > (*commandDefinition(qi::_r1)) > qi::lit("endmodule"))[qi::_val = phoenix::bind(&PrismParser::createModule, phoenix::ref(*this), qi::_1, qi::_a, qi::_b, qi::_c, qi::_2, qi::_3, qi::_r1)];
             moduleDefinition.name("module definition");
-            
+
+            freshPlayerName = (identifier[qi::_val = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isFreshPlayerName, phoenix::ref(*this), qi::_1)];
+            freshPlayerName.name("fresh player name");
+
+            commandName = (qi::lit("[") >> identifier >> qi::lit("]"))[qi::_val = qi::_1];
+            commandName.name("command name");
+
+            moduleName = identifier[qi::_val = qi::_1];
+            moduleName.name("module name");
+
+            playerDefinition = (qi::lit("player") > freshPlayerName[qi::_a = qi::_1]
+                    > +(   (commandName[phoenix::push_back(qi::_c, qi::_1)]
+                        |   moduleName[phoenix::push_back(qi::_b, qi::_1)]) % ','
+                        )
+                    > qi::lit("endplayer"))[qi::_val = phoenix::bind(&PrismParser::createPlayer, phoenix::ref(*this), qi::_a, qi::_b, qi::_c)];
+            playerDefinition.name("player definition");
+
             moduleRenaming = (qi::lit("[") > ((identifier > qi::lit("=") > identifier)[phoenix::insert(qi::_a, phoenix::construct<std::pair<std::string,std::string>>(qi::_1, qi::_2))] % ",") > qi::lit("]"))[qi::_val = phoenix::bind(&PrismParser::createModuleRenaming, phoenix::ref(*this), qi::_a)];
             moduleRenaming.name("Module renaming list");
-            
+
             renamedModule = (((qi::lit("module") > freshModuleName) >> qi::lit("="))
                               > knownModuleName[qi::_a = qi::_1]
                               > (moduleRenaming[qi::_b = qi::_1])[qi::_pass = phoenix::bind(&PrismParser::isValidModuleRenaming, phoenix::ref(*this), qi::_a, qi::_b, qi::_r1)]
                               > qi::lit("endmodule"))[qi::_val = phoenix::bind(&PrismParser::createRenamedModule, phoenix::ref(*this), qi::_1, qi::_a, qi::_b, qi::_r1)];
             renamedModule.name("module definition via renaming");
-            
+
             start = (qi::eps[phoenix::bind(&PrismParser::removeInitialConstruct, phoenix::ref(*this), phoenix::ref(globalProgramInformation))]
                      > modelTypeDefinition[phoenix::bind(&PrismParser::setModelType, phoenix::ref(*this), phoenix::ref(globalProgramInformation), qi::_1)]
                      > -observablesConstruct
                      >  *( definedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, phoenix::ref(globalProgramInformation)), qi::_1)]
+                         | playerDefinition(phoenix::ref(globalProgramInformation))[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::players, phoenix::ref(globalProgramInformation)), qi::_1)]
                          | undefinedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, phoenix::ref(globalProgramInformation)), qi::_1)]
                          | formulaDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::formulas, phoenix::ref(globalProgramInformation)), qi::_1)]
                          | globalVariableDefinition(phoenix::ref(globalProgramInformation))
@@ -298,7 +315,7 @@ namespace storm {
                      )
                      > -(systemCompositionConstruct(phoenix::ref(globalProgramInformation))) > qi::eoi)[qi::_val = phoenix::bind(&PrismParser::createProgram, phoenix::ref(*this), phoenix::ref(globalProgramInformation))];
             start.name("probabilistic program");
-            
+
             // Enable location tracking for important entities.
             auto setLocationInfoFunction = this->annotate(qi::_val, qi::_1, qi::_3);
             qi::on_success(undefinedBooleanConstantDefinition, setLocationInfoFunction);
@@ -320,16 +337,16 @@ namespace storm {
             qi::on_success(commandDefinition, setLocationInfoFunction);
             qi::on_success(updateDefinition, setLocationInfoFunction);
             qi::on_success(assignmentDefinition, setLocationInfoFunction);
-            
+
             // Enable error reporting.
             qi::on_error<qi::fail>(start, handler(qi::_1, qi::_2, qi::_3, qi::_4));
         }
-        
+
         void PrismParser::moveToSecondRun() {
             // In the second run, we actually need to parse the commands instead of just skipping them,
             // so we adapt the rule for parsing commands.
             STORM_LOG_THROW(observables.empty(), storm::exceptions::WrongFormatException, "Some variables marked as observable, but never declared, e.g. " <<  *observables.begin());
-            
+
             commandDefinition = (((qi::lit("[") > -identifier > qi::lit("]"))
                                  |
                                   (qi::lit("<") > -identifier > qi::lit(">")[qi::_a = true]))
@@ -350,10 +367,10 @@ namespace storm {
             // * in the first run, the type of the formula (int, bool, clock) is not known
             // * in the second run, formulas might be used before they are declared
             createFormulaIdentifiers(this->globalProgramInformation.formulas);
-            
+
             this->globalProgramInformation.moveToSecondRun();
         }
-        
+
         void PrismParser::createFormulaIdentifiers(std::vector<storm::prism::Formula> const& formulas) {
             STORM_LOG_THROW(formulas.size() == this->formulaExpressions.size(), storm::exceptions::UnexpectedException, "Unexpected number of formulas and formula expressions");
             this->formulaOrder.clear();
@@ -397,22 +414,22 @@ namespace storm {
                 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Unable to parse expression for formula '" << formulas[unprocessed.getNextSetIndex(0)].getName() << "'.");
             }
         }
-        
+
         void PrismParser::allowDoubleLiterals(bool flag) {
             this->expressionParser->setAcceptDoubleLiterals(flag);
         }
-        
+
         std::string const& PrismParser::getFilename() const {
             return this->filename;
         }
-        
+
         bool PrismParser::isValidIdentifier(std::string const& identifier) {
             if (this->keywords_.find(identifier) != nullptr) {
                 return false;
             }
             return true;
         }
-        
+
         bool PrismParser::isKnownModuleName(std::string const& moduleName) {
             if (!this->secondRun && this->globalProgramInformation.moduleToIndexMap.count(moduleName) == 0) {
                 STORM_LOG_ERROR("Parsing error in " << this->getFilename() << ": Unknown module '" << moduleName << "'.");
@@ -420,7 +437,7 @@ namespace storm {
             }
             return true;
         }
-        
+
         bool PrismParser::isFreshModuleName(std::string const& moduleName) {
             if (!this->secondRun && this->globalProgramInformation.moduleToIndexMap.count(moduleName) != 0) {
                 STORM_LOG_ERROR("Parsing error in " << this->getFilename() << ": Duplicate module name '" << moduleName << "'.");
@@ -428,7 +445,7 @@ namespace storm {
             }
             return true;
         }
-        
+
         bool PrismParser::isFreshIdentifier(std::string const& identifier) {
             if (!this->secondRun && this->manager->hasVariable(identifier)) {
                 STORM_LOG_ERROR("Parsing error in " << this->getFilename() << ": Duplicate identifier '" << identifier << "'.");
@@ -436,7 +453,7 @@ namespace storm {
             }
             return true;
         }
-        
+
         bool PrismParser::isFreshLabelName(std::string const& labelName) {
             if (!this->secondRun) {
                 for (auto const& existingLabel : this->globalProgramInformation.labels) {
@@ -460,7 +477,7 @@ namespace storm {
             }
             return true;
         }
-        
+
         bool PrismParser::isFreshRewardModelName(std::string const& rewardModelName) {
             if (!this->secondRun) {
                 for (auto const& existingRewardModel : this->globalProgramInformation.rewardModels) {
@@ -472,19 +489,23 @@ namespace storm {
             }
             return true;
         }
-        
+
+        bool PrismParser::isFreshPlayerName(std::string const& playerName) {
+            return true;
+        }
+
         bool PrismParser::isOfBoolType(storm::expressions::Expression const& expression) {
             return !this->secondRun || expression.hasBooleanType();
         }
-        
+
         bool PrismParser::isOfIntType(storm::expressions::Expression const& expression) {
             return !this->secondRun || expression.hasIntegerType();
         }
-        
+
         bool PrismParser::isOfNumericalType(storm::expressions::Expression const& expression) {
             return !this->secondRun || expression.hasNumericalType();
         }
-        
+
         bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation) {
             STORM_LOG_THROW(!globalProgramInformation.hasInitialConstruct, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ": Program must not define two initial constructs.");
             if (globalProgramInformation.hasInitialConstruct) {
@@ -494,12 +515,12 @@ namespace storm {
             globalProgramInformation.initialConstruct = storm::prism::InitialConstruct(initialStatesExpression, this->getFilename(), get_line(qi::_3));
             return true;
         }
-        
+
         bool PrismParser::addSystemCompositionConstruct(std::shared_ptr<storm::prism::Composition> const& composition, GlobalProgramInformation& globalProgramInformation) {
             globalProgramInformation.systemCompositionConstruct = storm::prism::SystemCompositionConstruct(composition, this->getFilename(), get_line(qi::_3));
             return true;
         }
-        
+
         void PrismParser::setModelType(GlobalProgramInformation& globalProgramInformation, storm::prism::Program::ModelType const& modelType) {
             STORM_LOG_THROW(globalProgramInformation.modelType == storm::prism::Program::ModelType::UNDEFINED, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ": Program must not set model type multiple times.");
             globalProgramInformation.modelType = modelType;
@@ -508,27 +529,27 @@ namespace storm {
         std::shared_ptr<storm::prism::Composition> PrismParser::createModuleComposition(std::string const& moduleName) const {
             return std::make_shared<storm::prism::ModuleComposition>(moduleName);
         }
-        
+
         std::shared_ptr<storm::prism::Composition> PrismParser::createRenamingComposition(std::shared_ptr<storm::prism::Composition> const& subcomposition, std::map<std::string, std::string> const& renaming) const {
             return std::make_shared<storm::prism::RenamingComposition>(subcomposition, renaming);
         }
-        
+
         std::shared_ptr<storm::prism::Composition> PrismParser::createHidingComposition(std::shared_ptr<storm::prism::Composition> const& subcomposition, std::set<std::string> const& actionsToHide) const {
             return std::make_shared<storm::prism::HidingComposition>(subcomposition, actionsToHide);
         }
-        
+
         std::shared_ptr<storm::prism::Composition> PrismParser::createSynchronizingParallelComposition(std::shared_ptr<storm::prism::Composition> const& left, std::shared_ptr<storm::prism::Composition> const& right) const {
             return std::make_shared<storm::prism::SynchronizingParallelComposition>(left, right);
         }
-        
+
         std::shared_ptr<storm::prism::Composition> PrismParser::createInterleavingParallelComposition(std::shared_ptr<storm::prism::Composition> const& left, std::shared_ptr<storm::prism::Composition> const& right) const {
             return std::make_shared<storm::prism::InterleavingParallelComposition>(left, right);
         }
-        
+
         std::shared_ptr<storm::prism::Composition> PrismParser::createRestrictedParallelComposition(std::shared_ptr<storm::prism::Composition> const& left, std::set<std::string> const& synchronizingActions, std::shared_ptr<storm::prism::Composition> const& right) const {
             return std::make_shared<storm::prism::RestrictedParallelComposition>(left, synchronizingActions, right);
         }
-        
+
         storm::prism::Constant PrismParser::createUndefinedBooleanConstant(std::string const& newConstant) const {
             if (!this->secondRun) {
                 try {
@@ -540,7 +561,7 @@ namespace storm {
             }
             return storm::prism::Constant(manager->getVariable(newConstant), this->getFilename());
         }
-        
+
         storm::prism::Constant PrismParser::createUndefinedIntegerConstant(std::string const& newConstant) const {
             if (!this->secondRun) {
                 try {
@@ -552,7 +573,7 @@ namespace storm {
             }
             return storm::prism::Constant(manager->getVariable(newConstant), this->getFilename());
         }
-        
+
         storm::prism::Constant PrismParser::createUndefinedDoubleConstant(std::string const& newConstant) const {
             if (!this->secondRun) {
                 try {
@@ -564,7 +585,7 @@ namespace storm {
             }
             return storm::prism::Constant(manager->getVariable(newConstant), this->getFilename());
         }
-        
+
         storm::prism::Constant PrismParser::createDefinedBooleanConstant(std::string const& newConstant, storm::expressions::Expression expression) const {
             if (!this->secondRun) {
                 try {
@@ -576,7 +597,7 @@ namespace storm {
             }
             return storm::prism::Constant(manager->getVariable(newConstant), expression, this->getFilename());
         }
-        
+
         storm::prism::Constant PrismParser::createDefinedIntegerConstant(std::string const& newConstant, storm::expressions::Expression expression) const {
             if (!this->secondRun) {
                 try {
@@ -588,7 +609,7 @@ namespace storm {
             }
             return storm::prism::Constant(manager->getVariable(newConstant), expression, this->getFilename());
         }
-        
+
         storm::prism::Constant PrismParser::createDefinedDoubleConstant(std::string const& newConstant, storm::expressions::Expression expression) const {
             if (!this->secondRun) {
                 try {
@@ -600,7 +621,7 @@ namespace storm {
             }
             return storm::prism::Constant(manager->getVariable(newConstant), expression, this->getFilename());
         }
-        
+
         storm::prism::Formula PrismParser::createFormulaFirstRun(std::string const& formulaName, std::string const& expression) {
             // Only store the expression as a string. It will be parsed between first and second run
             // This is necessary because the resulting type of the formula is only known after the first run.
@@ -608,14 +629,14 @@ namespace storm {
             formulaExpressions.push_back(expression);
             return storm::prism::Formula(formulaName, this->getFilename());
         }
-        
+
         storm::prism::Formula PrismParser::createFormulaSecondRun(std::string const& formulaName, storm::expressions::Expression const& expression) {
             // This is necessary because the resulting type of the formula is only known after the first run.
             STORM_LOG_ASSERT(this->secondRun, "This constructor should have only been called during the second run.");
             storm::expressions::Expression lhsExpression = *this->identifiers_.find(formulaName);
             return storm::prism::Formula(lhsExpression.getBaseExpression().asVariableExpression().getVariable(), expression, this->getFilename());
         }
-        
+
         storm::prism::Label PrismParser::createLabel(std::string const& labelName, storm::expressions::Expression expression) const {
             return storm::prism::Label(labelName, expression, this->getFilename());
         }
@@ -623,11 +644,11 @@ namespace storm {
         storm::prism::ObservationLabel PrismParser::createObservationLabel(std::string const& labelName, storm::expressions::Expression expression) const {
             return storm::prism::ObservationLabel(labelName, expression, this->getFilename());
         }
-        
+
         storm::prism::RewardModel PrismParser::createRewardModel(std::string const& rewardModelName, std::vector<storm::prism::StateReward> const& stateRewards, std::vector<storm::prism::StateActionReward> const& stateActionRewards, std::vector<storm::prism::TransitionReward> const& transitionRewards) const {
             return storm::prism::RewardModel(rewardModelName, stateRewards, stateActionRewards, transitionRewards, this->getFilename());
         }
-        
+
         storm::prism::StateReward PrismParser::createStateReward(storm::expressions::Expression statePredicateExpression, storm::expressions::Expression rewardValueExpression) const {
             if (this->secondRun) {
                 return storm::prism::StateReward(statePredicateExpression, rewardValueExpression, this->getFilename());
@@ -635,11 +656,11 @@ namespace storm {
                 return storm::prism::StateReward();
             }
         }
-        
+
         storm::prism::StateActionReward PrismParser::createStateActionReward(boost::optional<std::string> const& actionName, storm::expressions::Expression statePredicateExpression, storm::expressions::Expression rewardValueExpression, GlobalProgramInformation& globalProgramInformation) const {
             if (this->secondRun) {
                 std::string realActionName = actionName ? actionName.get() : "";
-                
+
                 auto const& nameIndexPair = globalProgramInformation.actionIndices.find(realActionName);
                 STORM_LOG_THROW(nameIndexPair != globalProgramInformation.actionIndices.end(), storm::exceptions::WrongFormatException, "Action reward refers to illegal action '" << realActionName << "'.");
                 return storm::prism::StateActionReward(nameIndexPair->second, realActionName, statePredicateExpression, rewardValueExpression, this->getFilename());
@@ -647,11 +668,11 @@ namespace storm {
                 return storm::prism::StateActionReward();
             }
         }
-        
+
         storm::prism::TransitionReward PrismParser::createTransitionReward(boost::optional<std::string> const& actionName, storm::expressions::Expression sourceStatePredicateExpression, storm::expressions::Expression targetStatePredicateExpression, storm::expressions::Expression rewardValueExpression, GlobalProgramInformation& globalProgramInformation) const {
             if (this->secondRun) {
                 std::string realActionName = actionName ? actionName.get() : "";
-    
+
                 auto const& nameIndexPair = globalProgramInformation.actionIndices.find(realActionName);
                 STORM_LOG_THROW(nameIndexPair != globalProgramInformation.actionIndices.end(), storm::exceptions::WrongFormatException, "Transition reward refers to illegal action '" << realActionName << "'.");
                 return storm::prism::TransitionReward(nameIndexPair->second, realActionName, sourceStatePredicateExpression, targetStatePredicateExpression, rewardValueExpression, this->getFilename());
@@ -659,22 +680,22 @@ namespace storm {
                 return storm::prism::TransitionReward();
             }
         }
-        
+
         storm::prism::Assignment PrismParser::createAssignment(std::string const& variableName, storm::expressions::Expression assignedExpression) const {
             return storm::prism::Assignment(manager->getVariable(variableName), assignedExpression, this->getFilename());
         }
-        
+
         storm::prism::Update PrismParser::createUpdate(storm::expressions::Expression likelihoodExpression, std::vector<storm::prism::Assignment> const& assignments, GlobalProgramInformation& globalProgramInformation) const {
             ++globalProgramInformation.currentUpdateIndex;
             return storm::prism::Update(globalProgramInformation.currentUpdateIndex - 1, likelihoodExpression, assignments, this->getFilename());
         }
-        
+
         storm::prism::Command PrismParser::createCommand(bool markovian, boost::optional<std::string> const& actionName, storm::expressions::Expression guardExpression, std::vector<storm::prism::Update> const& updates, GlobalProgramInformation& globalProgramInformation) const {
             ++globalProgramInformation.currentCommandIndex;
             std::string realActionName = actionName ? actionName.get() : "";
 
             uint_fast64_t actionIndex = 0;
-            
+
             // If the action name was not yet seen, record it.
             auto nameIndexPair = globalProgramInformation.actionIndices.find(realActionName);
             if (nameIndexPair == globalProgramInformation.actionIndices.end()) {
@@ -686,7 +707,7 @@ namespace storm {
             }
             return storm::prism::Command(globalProgramInformation.currentCommandIndex - 1, markovian, actionIndex, realActionName, guardExpression, updates, this->getFilename());
         }
-        
+
         storm::prism::Command PrismParser::createDummyCommand(boost::optional<std::string> const& actionName, GlobalProgramInformation& globalProgramInformation) const {
             STORM_LOG_ASSERT(!this->secondRun, "Dummy procedure must not be called in second run.");
             std::string realActionName = actionName ? actionName.get() : "";
@@ -697,10 +718,10 @@ namespace storm {
                 std::size_t nextIndex = globalProgramInformation.actionIndices.size();
                 globalProgramInformation.actionIndices.emplace(realActionName, nextIndex);
             }
-            
+
             return storm::prism::Command();
         }
-        
+
         storm::prism::BooleanVariable PrismParser::createBooleanVariable(std::string const& variableName, storm::expressions::Expression initialValueExpression) const {
             if (!this->secondRun) {
                 try {
@@ -716,7 +737,7 @@ namespace storm {
             }
             return storm::prism::BooleanVariable(manager->getVariable(variableName), initialValueExpression, observable, this->getFilename());
         }
-        
+
         storm::prism::IntegerVariable PrismParser::createIntegerVariable(std::string const& variableName, storm::expressions::Expression lowerBoundExpression, storm::expressions::Expression upperBoundExpression, storm::expressions::Expression initialValueExpression) const {
             if (!this->secondRun) {
                 try {
@@ -733,7 +754,7 @@ namespace storm {
 
             return storm::prism::IntegerVariable(manager->getVariable(variableName), lowerBoundExpression, upperBoundExpression, initialValueExpression, observable, this->getFilename());
         }
-        
+
         storm::prism::ClockVariable PrismParser::createClockVariable(std::string const& variableName) const {
             if (!this->secondRun) {
                 try {
@@ -755,12 +776,53 @@ namespace storm {
             this->observables.insert(observables.begin(), observables.end());
             // We need this list to be filled in both runs.
         }
-        
+
         storm::prism::Module PrismParser::createModule(std::string const& moduleName, std::vector<storm::prism::BooleanVariable> const& booleanVariables, std::vector<storm::prism::IntegerVariable> const& integerVariables, std::vector<storm::prism::ClockVariable> const& clockVariables, boost::optional<storm::expressions::Expression> const& invariant, std::vector<storm::prism::Command> const& commands, GlobalProgramInformation& globalProgramInformation) const {
-            globalProgramInformation.moduleToIndexMap[moduleName] = globalProgramInformation.modules.size();
+            if (!this->secondRun) {
+                globalProgramInformation.moduleToIndexMap[moduleName] = globalProgramInformation.modules.size();
+            } else {
+                STORM_LOG_THROW(globalProgramInformation.moduleToIndexMap[moduleName] == globalProgramInformation.modules.size(), storm::exceptions::WrongFormatException, "Internal error while parsing: the index for module " << moduleName << " does not match the on in the first run.");
+            }
             return storm::prism::Module(moduleName, booleanVariables, integerVariables, clockVariables, invariant.is_initialized()? invariant.get() : storm::expressions::Expression(), commands, this->getFilename());
         }
-        
+
+        storm::prism::Player PrismParser::createPlayer(std::string const& playerName, std::vector<std::string> const& moduleNames, std::vector<std::string> const & actionNames) {
+            if (this->secondRun) {
+                std::map<std::string, uint_fast64_t> controlledModuleIndices;
+                std::map<std::string, uint_fast64_t> controlledActionIndices;
+                for(std::string moduleName : moduleNames) {
+                    auto const& moduleIndexPair = globalProgramInformation.moduleToIndexMap.find(moduleName);
+                    if (moduleIndexPair != globalProgramInformation.moduleToIndexMap.end()) {
+                        controlledModuleIndices.insert(std::pair<std::string, uint_fast64_t>(moduleIndexPair->first, moduleIndexPair->second));
+                        if (std::find(globalProgramInformation.playerControlledModules.begin(), globalProgramInformation.playerControlledModules.end(), moduleName) != globalProgramInformation.playerControlledModules.end()) {
+                            STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": Module '" << moduleName << "' already controlled by another player.");
+                        } else {
+                            globalProgramInformation.playerControlledModules.push_back(moduleName);
+                        }
+                    } else {
+                        STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": No module named '" << moduleName << "' present.");
+                    }
+                }
+                for(std::string actionName : actionNames) {
+                    auto const& actionIndexPair = globalProgramInformation.actionIndices.find(actionName);
+                    if (actionIndexPair != globalProgramInformation.actionIndices.end()) {
+                        controlledActionIndices.insert(std::pair<std::string, uint_fast64_t>(actionIndexPair->first, actionIndexPair->second));
+                        if (std::find(globalProgramInformation.playerControlledCommands.begin(), globalProgramInformation.playerControlledCommands.end(), actionName) != globalProgramInformation.playerControlledCommands.end()) {
+                            STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": Command '" << actionName << "' already controlled by another player.");
+                        } else {
+                            globalProgramInformation.playerControlledCommands.push_back(actionName);
+                        }
+                    } else {
+                        STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": No action named '" << actionName << "' present.");
+                    }
+                }
+                STORM_LOG_DEBUG("PLAYER created:" << playerName);
+                return storm::prism::Player(playerName, controlledModuleIndices, controlledActionIndices);
+            } else {
+                return storm::prism::Player();
+            }
+        }
+
         bool PrismParser::isValidModuleRenaming(std::string const& oldModuleName, storm::prism::ModuleRenaming const& moduleRenaming, GlobalProgramInformation const& globalProgramInformation) const {
             if (!this->secondRun) {
                 auto const& renaming = moduleRenaming.getRenaming();
@@ -795,18 +857,18 @@ namespace storm {
             }
             return true;
         }
-        
+
         storm::prism::ModuleRenaming PrismParser::createModuleRenaming(std::map<std::string,std::string> const& renaming) const {
             return storm::prism::ModuleRenaming(renaming);
         }
-        
+
         storm::prism::Module PrismParser::createRenamedModule(std::string const& newModuleName, std::string const& oldModuleName, storm::prism::ModuleRenaming const& moduleRenaming, GlobalProgramInformation& globalProgramInformation) const {
             // Check whether the module to rename actually exists.
             auto const& moduleIndexPair = globalProgramInformation.moduleToIndexMap.find(oldModuleName);
             STORM_LOG_THROW(moduleIndexPair != globalProgramInformation.moduleToIndexMap.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ": No module named '" << oldModuleName << "' to rename.");
             storm::prism::Module const& moduleToRename = globalProgramInformation.modules[moduleIndexPair->second];
             auto const& renaming = moduleRenaming.getRenaming();
-            
+
             if (!this->secondRun) {
                 // Register all (renamed) variables for later use.
                 // We already checked before, whether the renaiming is valid.
@@ -837,7 +899,7 @@ namespace storm {
                         this->observables.erase(renamingPair->second);
                     }
                 }
-                
+
                 for (auto const& command : moduleToRename.getCommands()) {
                     std::string newActionName = command.getActionName();
                     auto const& renamingPair = renaming.find(command.getActionName());
@@ -852,13 +914,13 @@ namespace storm {
                         globalProgramInformation.actionIndices.emplace(newActionName, nextIndex);
                     }
                 }
-                
+
                 // Return a dummy module in the first pass.
                 return storm::prism::Module();
             } else {
                 // Add a mapping from the new module name to its (future) index.
                 globalProgramInformation.moduleToIndexMap[newModuleName] = globalProgramInformation.modules.size();
-                
+
                 // Create a mapping from identifiers to the expressions they need to be replaced with.
                 std::map<storm::expressions::Variable, storm::expressions::Expression> expressionRenaming;
                 for (auto const& namePair : renaming) {
@@ -868,7 +930,7 @@ namespace storm {
                         expressionRenaming.emplace(manager->getVariable(namePair.first), *substitutedExpression);
                     }
                 }
-                
+
                 // Rename the boolean variables.
                 std::vector<storm::prism::BooleanVariable> booleanVariables;
                 for (auto const& variable : moduleToRename.getBooleanVariables()) {
@@ -880,7 +942,7 @@ namespace storm {
                     }
                     booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), observable, this->getFilename(), moduleRenaming.getLineNumber()));
                 }
-                
+
                 // Rename the integer variables.
                 std::vector<storm::prism::IntegerVariable> integerVariables;
                 for (auto const& variable : moduleToRename.getIntegerVariables()) {
@@ -904,13 +966,13 @@ namespace storm {
                     }
                     clockVariables.push_back(storm::prism::ClockVariable(manager->getVariable(renamingPair->second), observable, this->getFilename(), moduleRenaming.getLineNumber()));
                 }
-                
+
                 // Rename invariant (if present)
                 storm::expressions::Expression invariant;
                 if (moduleToRename.hasInvariant()) {
                     invariant = moduleToRename.getInvariant().substitute(expressionRenaming);
                 }
-                
+
                 // Rename commands.
                 std::vector<storm::prism::Command> commands;
                 for (auto const& command : moduleToRename.getCommands()) {
@@ -928,13 +990,13 @@ namespace storm {
                         updates.emplace_back(globalProgramInformation.currentUpdateIndex, update.getLikelihoodExpression().substitute(expressionRenaming), assignments, this->getFilename(), moduleRenaming.getLineNumber());
                         ++globalProgramInformation.currentUpdateIndex;
                     }
-                    
+
                     std::string newActionName = command.getActionName();
                     auto const& renamingPair = renaming.find(command.getActionName());
                     if (renamingPair != renaming.end()) {
                         newActionName = renamingPair->second;
                     }
-                    
+
                     uint_fast64_t actionIndex = 0;
                     auto nameIndexPair = globalProgramInformation.actionIndices.find(newActionName);
                     if (nameIndexPair == globalProgramInformation.actionIndices.end()) {
@@ -944,22 +1006,22 @@ namespace storm {
                     } else {
                         actionIndex = nameIndexPair->second;
                     }
-                    
+
                     commands.emplace_back(globalProgramInformation.currentCommandIndex, command.isMarkovian(), actionIndex, newActionName, command.getGuardExpression().substitute(expressionRenaming), updates, this->getFilename(), moduleRenaming.getLineNumber());
                     ++globalProgramInformation.currentCommandIndex;
                 }
-                
+
                 return storm::prism::Module(newModuleName, booleanVariables, integerVariables, clockVariables, invariant, commands, oldModuleName, renaming);
             }
         }
-        
+
         storm::prism::Program PrismParser::createProgram(GlobalProgramInformation const& globalProgramInformation) const {
             storm::prism::Program::ModelType finalModelType = globalProgramInformation.modelType;
             if (globalProgramInformation.modelType == storm::prism::Program::ModelType::UNDEFINED) {
                 STORM_LOG_WARN("Program does not specify model type. Implicitly assuming 'mdp'.");
                 finalModelType = storm::prism::Program::ModelType::MDP;
             }
-            
+
             // make sure formulas are stored in a proper order.
             std::vector<storm::prism::Formula> orderedFormulas;
             if (this->secondRun) {
@@ -969,9 +1031,9 @@ namespace storm {
                 }
             }
 
-            return storm::prism::Program(manager, finalModelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, orderedFormulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, globalProgramInformation.observationLabels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::make_optional(globalProgramInformation.initialConstruct), globalProgramInformation.systemCompositionConstruct, prismCompatibility, this->getFilename(), 1, this->secondRun);
+            return storm::prism::Program(manager, finalModelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, orderedFormulas, globalProgramInformation.players, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, globalProgramInformation.observationLabels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::make_optional(globalProgramInformation.initialConstruct), globalProgramInformation.systemCompositionConstruct, prismCompatibility, this->getFilename(), 1, this->secondRun);
         }
-        
+
         void PrismParser::removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const {
             globalProgramInformation.hasInitialConstruct = false;
         }
diff --git a/src/storm-parsers/parser/PrismParser.h b/src/storm-parsers/parser/PrismParser.h
index 2668dcb68..9153f64bd 100644
--- a/src/storm-parsers/parser/PrismParser.h
+++ b/src/storm-parsers/parser/PrismParser.h
@@ -20,7 +20,7 @@ namespace storm {
 namespace storm {
     namespace parser {
         class ExpressionParser;
-        
+
         // A class that stores information about the parsed program.
         class GlobalProgramInformation {
         public:
@@ -29,7 +29,7 @@ namespace storm {
                 // Map the empty action to index 0.
                 actionIndices.emplace("", 0);
             }
-            
+
             void moveToSecondRun() {
                 // Clear all data except the action to indices mapping.
                 modelType = storm::prism::Program::ModelType::UNDEFINED;
@@ -38,6 +38,9 @@ namespace storm {
                 globalBooleanVariables.clear();
                 globalIntegerVariables.clear();
                 moduleToIndexMap.clear();
+                players.clear();
+                playerControlledModules.clear();
+                playerControlledCommands.clear();
                 modules.clear();
                 rewardModels.clear();
                 labels.clear();
@@ -45,11 +48,11 @@ namespace storm {
                 hasInitialConstruct = false;
                 initialConstruct = storm::prism::InitialConstruct();
                 systemCompositionConstruct = boost::none;
-                
+
                 currentCommandIndex = 0;
                 currentUpdateIndex = 0;
             }
-            
+
             // Members for all essential information that needs to be collected.
             storm::prism::Program::ModelType modelType;
             std::vector<storm::prism::Constant> constants;
@@ -62,11 +65,16 @@ namespace storm {
             std::vector<storm::prism::RewardModel> rewardModels;
             std::vector<storm::prism::Label> labels;
             std::vector<storm::prism::ObservationLabel> observationLabels;
+            std::vector<storm::prism::Player> players;
+
+            std::vector<std::string> playerControlledModules;
+            std::vector<std::string> playerControlledCommands;
+
             bool hasInitialConstruct;
             storm::prism::InitialConstruct initialConstruct;
             boost::optional<storm::prism::SystemCompositionConstruct> systemCompositionConstruct;
 
-            
+
             // Counters to provide unique indexing for commands and updates.
             uint_fast64_t currentCommandIndex;
             uint_fast64_t currentUpdateIndex;
@@ -81,7 +89,7 @@ namespace storm {
              * @return The resulting PRISM program.
              */
             static storm::prism::Program parse(std::string const& filename, bool prismCompatability = false);
-            
+
             /*!
              * Parses the given input stream into the PRISM storage classes assuming it complies with the PRISM syntax.
              *
@@ -90,7 +98,7 @@ namespace storm {
              * @return The resulting PRISM program.
              */
             static storm::prism::Program parseFromString(std::string const& input, std::string const& filename, bool prismCompatability = false);
-            
+
         private:
             struct modelTypeStruct : qi::symbols<char, storm::prism::Program::ModelType> {
                 modelTypeStruct() {
@@ -101,10 +109,11 @@ namespace storm {
                     ("ctmdp", storm::prism::Program::ModelType::CTMDP)
                     ("ma", storm::prism::Program::ModelType::MA)
                     ("pomdp", storm::prism::Program::ModelType::POMDP)
-                    ("pta", storm::prism::Program::ModelType::PTA);
+                    ("pta", storm::prism::Program::ModelType::PTA)
+                    ("smg", storm::prism::Program::ModelType::SMG);
                 }
             };
-            
+
             struct keywordsStruct : qi::symbols<char, uint_fast64_t> {
                 keywordsStruct() {
                     add
@@ -131,19 +140,21 @@ namespace storm {
                     ("init", 21)
                     ("endinit", 22)
                     ("invariant", 23)
-                    ("endinvariant", 24);
+                    ("endinvariant", 24)
+                    ("smg", 25)
+                    ("endplayer", 26);
                 }
             };
-            
+
             // Functor used for annotating entities with line number information.
             class PositionAnnotation {
             public:
                 typedef void result_type;
-                
+
                 PositionAnnotation(Iterator first) : first(first) {
                     // Intentionally left empty.
                 }
-                
+
                 template<typename Entity, typename First, typename Last>
                 result_type operator()(Entity& entity, First f, Last) const {
                     entity.setLineNumber(get_line(f));
@@ -152,7 +163,7 @@ namespace storm {
                 std::string filename;
                 Iterator const first;
             };
-            
+
             /*!
              * Creates a grammar for the given filename and the iterator to the first input to parse.
              *
@@ -160,32 +171,32 @@ namespace storm {
              * @param first The iterator to the beginning of the input.
              */
             PrismParser(std::string const& filename, Iterator first, bool prismCompatibility);
-            
+
             /*!
              * Sets an internal flag that indicates the second run is now taking place.
              */
             void moveToSecondRun();
-            
+
             /*!
              * Parses the stored formula Expressions.
              */
             void createFormulaIdentifiers(std::vector<storm::prism::Formula> const& formulas);
-            
+
             // A flag that stores whether the grammar is currently doing the second run.
             bool secondRun;
 
             bool prismCompatibility;
-            
+
             /*!
              * Sets whether doubles literals are allowed in the parsed expression.
              *
              * @param flag Indicates whether to allow or forbid double literals in the parsed expression.
              */
             void allowDoubleLiterals(bool flag);
-            
+
             // The name of the file being parsed.
             std::string filename;
-            
+
             /*!
              * Retrieves the name of the file currently being parsed.
              *
@@ -194,22 +205,22 @@ namespace storm {
             std::string const& getFilename() const;
 
             mutable std::set<std::string> observables;
-            
+
             // Store the expressions of formulas. They have to be parsed after the first and before the second run
             std::vector<std::string> formulaExpressions;
             // Stores a proper order in which formulas can be evaluated. This is necessary since formulas might depend on each other.
             // E.g. for "formula x = y; formula y = z;" we have to swap the order of the two formulas.
             std::vector<uint64_t> formulaOrder;
-            
+
             // A function used for annotating the entities with their position.
             phoenix::function<PositionAnnotation> annotate;
-            
+
             // An object gathering information about the program while parsing.
             GlobalProgramInformation globalProgramInformation;
-            
+
             // The starting point of the grammar.
             qi::rule<Iterator, storm::prism::Program(), Skipper> start;
-            
+
             // Rules for model type.
             qi::rule<Iterator, storm::prism::Program::ModelType(), Skipper> modelTypeDefinition;
 
@@ -217,7 +228,7 @@ namespace storm {
             qi::rule<Iterator, storm::expressions::Expression(), Skipper> boolExpression;
             qi::rule<Iterator, storm::expressions::Expression(), Skipper> intExpression;
             qi::rule<Iterator, storm::expressions::Expression(), Skipper> numericalExpression;
-            
+
             // Rules for parsing the program header.
             qi::rule<Iterator, storm::prism::Constant(), Skipper> undefinedConstantDefinition;
             qi::rule<Iterator, storm::prism::Constant(), Skipper> undefinedBooleanConstantDefinition;
@@ -227,45 +238,51 @@ namespace storm {
             qi::rule<Iterator, storm::prism::Constant(), Skipper> definedBooleanConstantDefinition;
             qi::rule<Iterator, storm::prism::Constant(), Skipper> definedIntegerConstantDefinition;
             qi::rule<Iterator, storm::prism::Constant(), Skipper> definedDoubleConstantDefinition;
-            
+
             // Rules for global variable definitions.
             qi::rule<Iterator, qi::unused_type(GlobalProgramInformation&), Skipper> globalVariableDefinition;
             qi::rule<Iterator, qi::unused_type(GlobalProgramInformation&), Skipper> globalBooleanVariableDefinition;
             qi::rule<Iterator, qi::unused_type(GlobalProgramInformation&), Skipper> globalIntegerVariableDefinition;
-            
+
             // Rules for modules definition.
             qi::rule<Iterator, std::string(), Skipper> knownModuleName;
             qi::rule<Iterator, std::string(), Skipper> freshModuleName;
             qi::rule<Iterator, storm::prism::Module(GlobalProgramInformation&), qi::locals<std::vector<storm::prism::BooleanVariable>, std::vector<storm::prism::IntegerVariable>, std::vector<storm::prism::ClockVariable>>, Skipper> moduleDefinition;
             qi::rule<Iterator, storm::prism::ModuleRenaming, qi::locals<std::map<std::string, std::string>>, Skipper> moduleRenaming;
             qi::rule<Iterator, storm::prism::Module(GlobalProgramInformation&), qi::locals<std::string, storm::prism::ModuleRenaming>, Skipper> renamedModule;
-            
+
             // Rules for variable definitions.
             qi::rule<Iterator, qi::unused_type(std::vector<storm::prism::BooleanVariable>&, std::vector<storm::prism::IntegerVariable>&, std::vector<storm::prism::ClockVariable>&), Skipper> variableDefinition;
             qi::rule<Iterator, storm::prism::BooleanVariable(), qi::locals<storm::expressions::Expression>, Skipper> booleanVariableDefinition;
             qi::rule<Iterator, storm::prism::IntegerVariable(), qi::locals<storm::expressions::Expression>, Skipper> integerVariableDefinition;
             qi::rule<Iterator, storm::prism::ClockVariable(), qi::locals<storm::expressions::Expression>, Skipper> clockVariableDefinition;
-            
+
             // Rules for command definitions.
             qi::rule<Iterator, storm::prism::Command(GlobalProgramInformation&), qi::locals<bool>, Skipper> commandDefinition;
             qi::rule<Iterator, std::vector<storm::prism::Update>(GlobalProgramInformation&), Skipper> updateListDefinition;
             qi::rule<Iterator, storm::prism::Update(GlobalProgramInformation&), Skipper> updateDefinition;
             qi::rule<Iterator, std::vector<storm::prism::Assignment>(), Skipper> assignmentDefinitionList;
             qi::rule<Iterator, storm::prism::Assignment(), Skipper> assignmentDefinition;
-            
+
             // Rules for reward definitions.
             qi::rule<Iterator, std::string(), Skipper> freshRewardModelName;
             qi::rule<Iterator, storm::prism::RewardModel(GlobalProgramInformation&), qi::locals<std::string, std::vector<storm::prism::StateReward>, std::vector<storm::prism::StateActionReward>, std::vector<storm::prism::TransitionReward>>, Skipper> rewardModelDefinition;
             qi::rule<Iterator, storm::prism::StateReward(), Skipper> stateRewardDefinition;
             qi::rule<Iterator, storm::prism::StateActionReward(GlobalProgramInformation&), Skipper> stateActionRewardDefinition;
             qi::rule<Iterator, storm::prism::TransitionReward(GlobalProgramInformation&), qi::locals<std::string, storm::expressions::Expression, storm::expressions::Expression,storm::expressions::Expression>, Skipper> transitionRewardDefinition;
-            
+
+            // Rules for player definitions
+            qi::rule<Iterator, std::string(), Skipper> freshPlayerName;
+            qi::rule<Iterator, std::string(), qi::locals<std::string>, Skipper> commandName;
+            qi::rule<Iterator, std::string(), qi::locals<std::string>, Skipper> moduleName;
+            qi::rule<Iterator, storm::prism::Player(GlobalProgramInformation&), qi::locals<std::string, std::vector<std::string>, std::vector<std::string>>, Skipper> playerDefinition;
+
             // Rules for initial states expression.
             qi::rule<Iterator, qi::unused_type(GlobalProgramInformation&), Skipper> initialStatesConstruct;
 
             // Rules for POMDP observables (standard prism)
             qi::rule<Iterator, qi::unused_type(), Skipper> observablesConstruct;
-            
+
             // Rules for invariant constructs
             qi::rule<Iterator, storm::expressions::Expression(), Skipper> invariantConstruct;
 
@@ -294,20 +311,20 @@ namespace storm {
             // Rules for formula definitions.
             qi::rule<Iterator, std::string(), Skipper> formulaDefinitionRhs;
             qi::rule<Iterator, storm::prism::Formula(), Skipper> formulaDefinition;
-            
+
             // Rules for identifier parsing.
             qi::rule<Iterator, std::string(), Skipper> identifier;
             qi::rule<Iterator, std::string(), Skipper> freshIdentifier;
-            
+
             // Parsers that recognize special keywords and model types.
             storm::parser::PrismParser::keywordsStruct keywords_;
             storm::parser::PrismParser::modelTypeStruct modelType_;
             qi::symbols<char, storm::expressions::Expression> identifiers_;
-            
+
             // Parser and manager used for recognizing expressions.
             std::shared_ptr<storm::expressions::ExpressionManager> manager;
             std::shared_ptr<storm::parser::ExpressionParser> expressionParser;
-            
+
             // Helper methods used in the grammar.
             bool isValidIdentifier(std::string const& identifier);
             bool isFreshIdentifier(std::string const& identifier);
@@ -316,6 +333,7 @@ namespace storm {
             bool isFreshLabelName(std::string const& moduleName);
             bool isFreshObservationLabelName(std::string const& labelName);
             bool isFreshRewardModelName(std::string const& moduleName);
+            bool isFreshPlayerName(std::string const& playerName);
             bool isOfBoolType(storm::expressions::Expression const& expression);
             bool isOfIntType(storm::expressions::Expression const& expression);
             bool isOfNumericalType(storm::expressions::Expression const& expression);
@@ -323,7 +341,7 @@ namespace storm {
             bool addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation);
             bool addSystemCompositionConstruct(std::shared_ptr<storm::prism::Composition> const& composition, GlobalProgramInformation& globalProgramInformation);
             void setModelType(GlobalProgramInformation& globalProgramInformation, storm::prism::Program::ModelType const& modelType);
-            
+
             std::shared_ptr<storm::prism::Composition> createModuleComposition(std::string const& moduleName) const;
             std::shared_ptr<storm::prism::Composition> createRenamingComposition(std::shared_ptr<storm::prism::Composition> const& subcomposition, std::map<std::string, std::string> const& renaming) const;
             std::shared_ptr<storm::prism::Composition> createHidingComposition(std::shared_ptr<storm::prism::Composition> const& subcomposition, std::set<std::string> const& actionsToHide) const;
@@ -355,12 +373,13 @@ namespace storm {
             storm::prism::Module createModule(std::string const& moduleName, std::vector<storm::prism::BooleanVariable> const& booleanVariables, std::vector<storm::prism::IntegerVariable> const& integerVariables, std::vector<storm::prism::ClockVariable> const& clockVariables, boost::optional<storm::expressions::Expression> const& invariant, std::vector<storm::prism::Command> const& commands, GlobalProgramInformation& globalProgramInformation) const;
             storm::prism::ModuleRenaming createModuleRenaming(std::map<std::string,std::string> const& renaming) const;
             storm::prism::Module createRenamedModule(std::string const& newModuleName, std::string const& oldModuleName, storm::prism::ModuleRenaming const& renaming, GlobalProgramInformation& globalProgramInformation) const;
+            storm::prism::Player createPlayer(std::string const& playerName, std::vector<std::string> const& moduleNames, std::vector<std::string> const & commandNames);
             storm::prism::Program createProgram(GlobalProgramInformation const& globalProgramInformation) const;
             void createObservablesList(std::vector<std::string> const& observables);
 
 
             void removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const;
-            
+
             // An error handler function.
             phoenix::function<SpiritErrorHandler> handler;
         };
@@ -368,4 +387,3 @@ namespace storm {
 } // namespace storm
 
 #endif	/* STORM_PARSER_PRISMPARSER_H_ */
-
diff --git a/src/storm/builder/ExplicitModelBuilder.cpp b/src/storm/builder/ExplicitModelBuilder.cpp
index 8fedf075b..10e0c8927 100644
--- a/src/storm/builder/ExplicitModelBuilder.cpp
+++ b/src/storm/builder/ExplicitModelBuilder.cpp
@@ -49,26 +49,26 @@ namespace storm {
         ExplicitModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : explorationOrder(storm::settings::getModule<storm::settings::modules::BuildSettings>().getExplorationOrder()) {
             // Intentionally left empty.
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ExplicitModelBuilder(std::shared_ptr<storm::generator::NextStateGenerator<ValueType, StateType>> const& generator, Options const& options) : generator(generator), options(options), stateStorage(generator->getStateSize()) {
             // Intentionally left empty.
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ExplicitModelBuilder(storm::prism::Program const& program, storm::generator::NextStateGeneratorOptions const& generatorOptions, Options const& builderOptions) : ExplicitModelBuilder(std::make_shared<storm::generator::PrismNextStateGenerator<ValueType, StateType>>(program, generatorOptions), builderOptions) {
             // Intentionally left empty.
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ExplicitModelBuilder(storm::jani::Model const& model, storm::generator::NextStateGeneratorOptions const& generatorOptions, Options const& builderOptions) : ExplicitModelBuilder(std::make_shared<storm::generator::JaniNextStateGenerator<ValueType, StateType>>(model, generatorOptions), builderOptions) {
             // Intentionally left empty.
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitModelBuilder<ValueType, RewardModelType, StateType>::build() {
             STORM_LOG_DEBUG("Exploration order is: " << options.explorationOrder);
-            
+
             switch (generator->getModelType()) {
                 case storm::generator::ModelType::DTMC:
                     return storm::utility::builder::buildModelFromComponents(storm::models::ModelType::Dtmc, buildModelComponents());
@@ -80,22 +80,24 @@ namespace storm {
                     return storm::utility::builder::buildModelFromComponents(storm::models::ModelType::Pomdp, buildModelComponents());
                 case storm::generator::ModelType::MA:
                     return storm::utility::builder::buildModelFromComponents(storm::models::ModelType::MarkovAutomaton, buildModelComponents());
+                case storm::generator::ModelType::SMG:
+                    return storm::utility::builder::buildModelFromComponents(storm::models::ModelType::Smg, buildModelComponents());
                 default:
                     STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Error while creating model: cannot handle this model type.");
             }
-            
+
             return nullptr;
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         StateType ExplicitModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex(CompressedState const& state) {
             StateType newIndex = static_cast<StateType>(stateStorage.getNumberOfStates());
-            
+
             // Check, if the state was already registered.
             std::pair<StateType, std::size_t> actualIndexBucketPair = stateStorage.stateToId.findOrAddAndGetBucket(state, newIndex);
-            
+
             StateType actualIndex = actualIndexBucketPair.first;
-            
+
             if (actualIndex == newIndex) {
                 if (options.explorationOrder == ExplorationOrder::Dfs) {
                     statesToExplore.emplace_front(state, actualIndex);
@@ -108,7 +110,7 @@ namespace storm {
                     STORM_LOG_ASSERT(false, "Invalid exploration order.");
                 }
             }
-            
+
             return actualIndex;
         }
 
@@ -118,24 +120,30 @@ namespace storm {
         }
 
         template <typename ValueType, typename RewardModelType, typename StateType>
-        void ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional<storm::storage::BitVector>& markovianStates, boost::optional<storm::storage::sparse::StateValuationsBuilder>& stateValuationsBuilder) {
-            
+        void ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional<storm::storage::BitVector>& markovianStates, boost::optional<std::vector<uint_fast32_t>> playerActionIndices, boost::optional<storm::storage::sparse::StateValuationsBuilder>& stateValuationsBuilder) {
+
             // Create markovian states bit vector, if required.
             if (generator->getModelType() == storm::generator::ModelType::MA) {
                 // The bit vector will be resized when the correct size is known.
                 markovianStates = storm::storage::BitVector(1000);
             }
 
+            // Create the player indices vector, if required.
+            if (generator->getModelType() == storm::generator::ModelType::SMG) {
+                playerActionIndices = std::vector<uint_fast32_t>{};
+                playerActionIndices.get().reserve(1000);
+            }
+
             // Create a callback for the next-state generator to enable it to request the index of states.
             std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind(&ExplicitModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this, std::placeholders::_1);
-            
+
             // If the exploration order is something different from breadth-first, we need to keep track of the remapping
             // from state ids to row groups. For this, we actually store the reversed mapping of row groups to state-ids
             // and later reverse it.
             if (options.explorationOrder != ExplorationOrder::Bfs) {
                 stateRemapping = std::vector<uint_fast64_t>();
             }
-            
+
             // Let the generator create all initial states.
             this->stateStorage.initialStateIndices = generator->getInitialStates(stateToIdCallback);
             STORM_LOG_THROW(!this->stateStorage.initialStateIndices.empty(), storm::exceptions::WrongFormatException, "The model does not have a single initial state.");
@@ -148,30 +156,30 @@ namespace storm {
             auto timeOfLastMessage = std::chrono::high_resolution_clock::now();
             uint64_t numberOfExploredStates = 0;
             uint64_t numberOfExploredStatesSinceLastMessage = 0;
-            
+
             // Perform a search through the model.
             while (!statesToExplore.empty()) {
                 // Get the first state in the queue.
                 CompressedState currentState = statesToExplore.front().first;
                 StateType currentIndex = statesToExplore.front().second;
                 statesToExplore.pop_front();
-                
+
                 // If the exploration order differs from breadth-first, we remember that this row group was actually
                 // filled with the transitions of a different state.
                 if (options.explorationOrder != ExplorationOrder::Bfs) {
                     stateRemapping.get()[currentIndex] = currentRowGroup;
                 }
-                
+
                 if (currentIndex % 100000 == 0) {
                     STORM_LOG_TRACE("Exploring state with id " << currentIndex << ".");
                 }
-                
+
                 generator->load(currentState);
                 if (stateValuationsBuilder) {
                     generator->addStateValuation(currentIndex, stateValuationsBuilder.get());
                 }
                 storm::generator::StateBehavior<ValueType, StateType> behavior = generator->expand(stateToIdCallback);
-                
+
                 // If there is no behavior, we might have to introduce a self-loop.
                 if (behavior.empty()) {
                     if (!storm::settings::getModule<storm::settings::modules::BuildSettings>().isDontFixDeadlocksSet() || !behavior.wasExpanded()) {
@@ -179,28 +187,33 @@ namespace storm {
                         if (behavior.wasExpanded()) {
                             this->stateStorage.deadlockStateIndices.push_back(currentIndex);
                         }
-                        
+
                         if (markovianStates) {
                             markovianStates.get().grow(currentRowGroup + 1, false);
                             markovianStates.get().set(currentRowGroup);
                         }
-                        
+
                         if (!generator->isDeterministicModel()) {
                             transitionMatrixBuilder.newRowGroup(currentRow);
                         }
-                        
+
                         transitionMatrixBuilder.addNextValue(currentRow, currentIndex, storm::utility::one<ValueType>());
-                        
+
                         for (auto& rewardModelBuilder : rewardModelBuilders) {
                             if (rewardModelBuilder.hasStateRewards()) {
                                 rewardModelBuilder.addStateReward(storm::utility::zero<ValueType>());
                             }
-                            
+
                             if (rewardModelBuilder.hasStateActionRewards()) {
                                 rewardModelBuilder.addStateActionReward(storm::utility::zero<ValueType>());
                             }
                         }
-                        
+
+                        if (playerActionIndices) {
+                            // TODO change this to storm::utility::infinity<ValueType>() ?
+                            playerActionIndices.get().push_back(-1);
+                        }
+
                         ++currentRow;
                         ++currentRowGroup;
                     } else {
@@ -215,15 +228,15 @@ namespace storm {
                         }
                         ++stateRewardIt;
                     }
-                    
+
                     // If the model is nondeterministic, we need to open a row group.
                     if (!generator->isDeterministicModel()) {
                         transitionMatrixBuilder.newRowGroup(currentRow);
                     }
-                    
+
                     // Now add all choices.
                     for (auto const& choice : behavior) {
-                        
+
                         // add the generated choice information
                         if (choice.hasLabels()) {
                             for (auto const& label : choice.getLabels()) {
@@ -233,18 +246,18 @@ namespace storm {
                         if (choice.hasOriginData()) {
                             choiceInformationBuilder.addOriginData(choice.getOriginData(), currentRow);
                         }
-                        
+
                         // If we keep track of the Markovian choices, store whether the current one is Markovian.
                         if (markovianStates && choice.isMarkovian()) {
                             markovianStates.get().grow(currentRowGroup + 1, false);
                             markovianStates.get().set(currentRowGroup);
                         }
-                        
+
                         // Add the probabilistic behavior to the matrix.
                         for (auto const& stateProbabilityPair : choice) {
                             transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
                         }
-                        
+
                         // Add the rewards to the reward models.
                         auto choiceRewardIt = choice.getRewards().begin();
                         for (auto& rewardModelBuilder : rewardModelBuilders) {
@@ -255,6 +268,10 @@ namespace storm {
                         }
                         ++currentRow;
                     }
+
+                    if (playerActionIndices) {
+                        playerActionIndices.get().push_back(behavior.getChoices().at(0).getPlayerIndex());
+                    }
                     ++currentRowGroup;
                 }
 
@@ -280,24 +297,28 @@ namespace storm {
                     break;
                 }
             }
-            
+
             if (markovianStates) {
                 // Since we now know the correct size, cut the bit vector to the correct length.
                 markovianStates->resize(currentRowGroup, false);
             }
 
+            if (playerActionIndices) {
+                playerActionIndices.get().shrink_to_fit();
+            }
+
             // If the exploration order was not breadth-first, we need to fix the entries in the matrix according to
             // (reversed) mapping of row groups to indices.
             if (options.explorationOrder != ExplorationOrder::Bfs) {
                 STORM_LOG_ASSERT(stateRemapping, "Unable to fix columns without mapping.");
                 std::vector<uint_fast64_t> const& remapping = stateRemapping.get();
-                
+
                 // We need to fix the following entities:
                 // (a) the transition matrix
                 // (b) the initial states
                 // (c) the hash map storing the mapping states -> ids
                 // (d) fix remapping for state-generation labels
-                
+
                 // Fix (a).
                 transitionMatrixBuilder.replaceColumns(remapping, 0);
 
@@ -306,21 +327,21 @@ namespace storm {
                 std::transform(this->stateStorage.initialStateIndices.begin(), this->stateStorage.initialStateIndices.end(), newInitialStateIndices.begin(), [&remapping] (StateType const& state) { return remapping[state]; } );
                 std::sort(newInitialStateIndices.begin(), newInitialStateIndices.end());
                 this->stateStorage.initialStateIndices = std::move(newInitialStateIndices);
-                
+
                 // Fix (c).
                 this->stateStorage.stateToId.remap([&remapping] (StateType const& state) { return remapping[state]; } );
 
                 this->generator->remapStateIds([&remapping] (StateType const& state) { return remapping[state]; });
             }
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         storm::storage::sparse::ModelComponents<ValueType, RewardModelType> ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents() {
-            
+
             // Determine whether we have to combine different choices to one or whether this model can have more than
             // one choice per state.
             bool deterministicModel = generator->isDeterministicModel();
-            
+
             // Prepare the component builders
             storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
             std::vector<RewardModelBuilder<typename RewardModelType::ValueType>> rewardModelBuilders;
@@ -329,25 +350,26 @@ namespace storm {
             }
             ChoiceInformationBuilder choiceInformationBuilder;
             boost::optional<storm::storage::BitVector> markovianStates;
-            
+            boost::optional<std::vector<uint_fast32_t>> playerActionIndices;
+
             // If we need to build state valuations, initialize them now.
             boost::optional<storm::storage::sparse::StateValuationsBuilder> stateValuationsBuilder;
             if (generator->getOptions().isBuildStateValuationsSet()) {
                 stateValuationsBuilder = generator->initializeStateValuationsBuilder();
             }
-            
-            buildMatrices(transitionMatrixBuilder, rewardModelBuilders, choiceInformationBuilder, markovianStates, stateValuationsBuilder);
-            
+
+            buildMatrices(transitionMatrixBuilder, rewardModelBuilders, choiceInformationBuilder, markovianStates, playerActionIndices, stateValuationsBuilder);
+
             // Initialize the model components with the obtained information.
-            storm::storage::sparse::ModelComponents<ValueType, RewardModelType> modelComponents(transitionMatrixBuilder.build(0, transitionMatrixBuilder.getCurrentRowGroupCount()), buildStateLabeling(), std::unordered_map<std::string, RewardModelType>(), !generator->isDiscreteTimeModel(), std::move(markovianStates));
-            
+            storm::storage::sparse::ModelComponents<ValueType, RewardModelType> modelComponents(transitionMatrixBuilder.build(0, transitionMatrixBuilder.getCurrentRowGroupCount()), buildStateLabeling(), std::unordered_map<std::string, RewardModelType>(), !generator->isDiscreteTimeModel(), std::move(markovianStates), /* player1Matrix = */ boost::none, std::move(playerActionIndices));
+
             // Now finalize all reward models.
             for (auto& rewardModelBuilder : rewardModelBuilders) {
                 modelComponents.rewardModels.emplace(rewardModelBuilder.getName(), rewardModelBuilder.build(modelComponents.transitionMatrix.getRowCount(), modelComponents.transitionMatrix.getColumnCount(), modelComponents.transitionMatrix.getRowGroupCount()));
             }
             // Build the choice labeling
             modelComponents.choiceLabeling = choiceInformationBuilder.buildChoiceLabeling(modelComponents.transitionMatrix.getRowCount());
-            
+
             // If requested, build the state valuations and choice origins
             if (stateValuationsBuilder) {
                 modelComponents.stateValuations = stateValuationsBuilder->build(modelComponents.transitionMatrix.getRowGroupCount());
@@ -372,12 +394,12 @@ namespace storm {
             }
             return modelComponents;
         }
-        
+
         template <typename ValueType, typename RewardModelType, typename StateType>
         storm::models::sparse::StateLabeling ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling() {
             return generator->label(stateStorage, stateStorage.initialStateIndices, stateStorage.deadlockStateIndices);
         }
-        
+
         // Explicitly instantiate the class.
         template class ExplicitModelBuilder<double, storm::models::sparse::StandardRewardModel<double>, uint32_t>;
         template class ExplicitStateLookup<uint32_t>;
diff --git a/src/storm/builder/ExplicitModelBuilder.h b/src/storm/builder/ExplicitModelBuilder.h
index 132345075..af068b3fa 100644
--- a/src/storm/builder/ExplicitModelBuilder.h
+++ b/src/storm/builder/ExplicitModelBuilder.h
@@ -131,40 +131,40 @@ namespace storm {
              * @param markovianChoices is set to a bit vector storing whether a choice is Markovian (is only set if the model type requires this information).
              * @param stateValuationsBuilder if not boost::none, we insert valuations for the corresponding states
              */
-            void buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional<storm::storage::BitVector>& markovianChoices, boost::optional<storm::storage::sparse::StateValuationsBuilder>& stateValuationsBuilder);
-            
+            void buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional<storm::storage::BitVector>& markovianChoices, boost::optional<std::vector<uint_fast32_t>> playerActionIndices, boost::optional<storm::storage::sparse::StateValuationsBuilder>& stateValuationsBuilder);
+
             /*!
              * Explores the state space of the given program and returns the components of the model as a result.
              *
              * @return A structure containing the components of the resulting model.
              */
             storm::storage::sparse::ModelComponents<ValueType, RewardModelType> buildModelComponents();
-            
+
             /*!
              * Builds the state labeling for the given program.
              *
              * @return The state labeling of the given program.
              */
             storm::models::sparse::StateLabeling buildStateLabeling();
-            
+
             /// The generator to use for the building process.
             std::shared_ptr<storm::generator::NextStateGenerator<ValueType, StateType>> generator;
-            
+
             /// The options to be used for the building process.
             Options options;
 
             /// Internal information about the states that were explored.
             storm::storage::sparse::StateStorage<StateType> stateStorage;
-            
+
             /// A set of states that still need to be explored.
             std::deque<std::pair<CompressedState, StateType>> statesToExplore;
-            
+
             /// An optional mapping from state indices to the row groups in which they actually reside. This needs to be
             /// built in case the exploration order is not BFS.
             boost::optional<std::vector<uint_fast64_t>> stateRemapping;
 
         };
-        
+
     } // namespace adapters
 } // namespace storm
 
diff --git a/src/storm/generator/Choice.cpp b/src/storm/generator/Choice.cpp
index 5d69c98ab..517dffd6c 100644
--- a/src/storm/generator/Choice.cpp
+++ b/src/storm/generator/Choice.cpp
@@ -81,17 +81,32 @@ namespace storm {
                 labels = newLabels;
             }
         }
-            
+
         template<typename ValueType, typename StateType>
         bool Choice<ValueType, StateType>::hasLabels() const {
             return labels.is_initialized();
         }
-            
+
         template<typename ValueType, typename StateType>
         std::set<std::string> const& Choice<ValueType, StateType>::getLabels() const {
             return labels.get();
         }
-            
+
+        template<typename ValueType, typename StateType>
+        void Choice<ValueType, StateType>::setPlayerIndex(uint_fast32_t playerIndex) {
+            this->playerIndex = playerIndex;
+        }
+
+        template<typename ValueType, typename StateType>
+        bool Choice<ValueType, StateType>::hasPlayerIndex() const {
+            return playerIndex.is_initialized();
+        }
+
+        template<typename ValueType, typename StateType>
+        uint_fast32_t const& Choice<ValueType, StateType>::getPlayerIndex() const {
+            return playerIndex.get();
+        }
+
         template<typename ValueType, typename StateType>
         void Choice<ValueType, StateType>::addOriginData(boost::any const& data) {
             if (!this->originData || this->originData->empty()) {
diff --git a/src/storm/generator/Choice.h b/src/storm/generator/Choice.h
index 1dbc41760..80f8f7031 100644
--- a/src/storm/generator/Choice.h
+++ b/src/storm/generator/Choice.h
@@ -64,118 +64,140 @@ namespace storm {
              */
             template<typename ValueTypePrime, typename StateTypePrime>
             friend std::ostream& operator<<(std::ostream& out, Choice<ValueTypePrime, StateTypePrime> const& choice);
-            
+
             /*!
              * Adds the given label to the labels associated with this choice.
              *
              * @param label The label to associate with this choice.
              */
             void addLabel(std::string const& label);
-            
+
             /*!
              * Adds the given label set to the labels associated with this choice.
              *
              * @param labelSet The label set to associate with this choice.
              */
             void addLabels(std::set<std::string> const& labels);
-            
+
             /*!
              * Returns whether there are labels defined for this choice
              */
             bool hasLabels() const;
-            
+
             /*!
              * Retrieves the set of labels associated with this choice.
              *
              * @return The set of labels associated with this choice.
              */
             std::set<std::string> const& getLabels() const;
-            
+
+            /*!
+             * Sets the players index
+             *
+             * @param The player index associated with this choice.
+             */
+            void setPlayerIndex(uint_fast32_t playerIndex);
+
+            /*!
+             * Returns whether there is an index for the player defined for this choice.
+             */
+            bool hasPlayerIndex() const;
+
+            /*!
+             * Retrieves the players index associated with this choice
+             *
+             * @return The player index associated with this choice.
+             */
+            uint_fast32_t const& getPlayerIndex() const;
+
             /*!
              * Adds the given data that specifies the origin of this choice w.r.t. the model specification
              */
             void addOriginData(boost::any const& data);
-            
+
             /*!
              * Returns whether there is origin data defined for this choice
              */
             bool hasOriginData() const;
-            
+
             /*!
              * Returns the origin data associated with this choice.
              */
             boost::any const& getOriginData() const;
-            
+
             /*!
              * Retrieves the index of the action of this choice.
              *
              * @return The index of the action of this choice.
              */
             uint_fast64_t getActionIndex() const;
-            
+
             /*!
              * Retrieves the total mass of this choice.
              *
              * @return The total mass.
              */
             ValueType getTotalMass() const;
-            
+
             /*!
              * Adds the given probability value to the given state in the underlying distribution.
              */
             void addProbability(StateType const& state, ValueType const& value);
-            
+
             /*!
              * Adds the given value to the reward associated with this choice.
              */
             void addReward(ValueType const& value);
-            
+
             /*!
              * Adds the given choices rewards to this choice.
              */
             void addRewards(std::vector<ValueType>&& values);
-            
+
             /*!
              * Retrieves the rewards for this choice under selected reward models.
              */
             std::vector<ValueType> const& getRewards() const;
-            
+
             /*!
              * Retrieves whether the choice is Markovian.
              */
             bool isMarkovian() const;
-            
+
             /*!
              * Retrieves the size of the distribution associated with this choice.
              */
             std::size_t size() const;
-            
+
             /*!
              * If the size is already known, reserves space in the underlying distribution.
              */
             void reserve(std::size_t const& size);
-            
+
         private:
             // A flag indicating whether this choice is Markovian or not.
             bool markovian;
 
             // The action index associated with this choice.
             uint_fast64_t actionIndex;
-            
+
             // The distribution that is associated with the choice.
             storm::storage::Distribution<ValueType, StateType> distribution;
-            
+
             // The total probability mass (or rates) of this choice.
             ValueType totalMass;
-            
+
             // The reward values associated with this choice.
             std::vector<ValueType> rewards;
-            
+
             // The data that stores what part of the model specification induced this choice
             boost::optional<boost::any> originData;
-            
+
             // The labels of this choice
             boost::optional<std::set<std::string>> labels;
+
+            // The playerIndex of this choice
+            boost::optional<uint_fast32_t> playerIndex = boost::none;
         };
 
         template<typename ValueType, typename StateType>
diff --git a/src/storm/generator/NextStateGenerator.h b/src/storm/generator/NextStateGenerator.h
index 126d0fa5a..671158870 100644
--- a/src/storm/generator/NextStateGenerator.h
+++ b/src/storm/generator/NextStateGenerator.h
@@ -24,44 +24,45 @@
 namespace storm {
     namespace generator {
         typedef storm::builder::BuilderOptions NextStateGeneratorOptions;
-        
+
         enum class ModelType {
             DTMC,
             CTMC,
             MDP,
             MA,
-            POMDP
+            POMDP,
+            SMG
         };
-        
+
         template<typename ValueType, typename StateType = uint32_t>
         class NextStateGenerator {
         public:
             typedef std::function<StateType (CompressedState const&)> StateToIdCallback;
 
             NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options);
-            
+
             /*!
              * Creates a new next state generator. This version of the constructor default-constructs the variable information.
              * Hence, the subclass is responsible for suitably initializing it in its constructor.
              */
             NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, NextStateGeneratorOptions const& options);
-            
+
             virtual ~NextStateGenerator() = default;
-            
+
             uint64_t getStateSize() const;
             virtual ModelType getModelType() const = 0;
             virtual bool isDeterministicModel() const = 0;
             virtual bool isDiscreteTimeModel() const = 0;
             virtual bool isPartiallyObservable() const = 0;
             virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0;
-            
+
             /// Initializes a builder for state valuations by adding the appropriate variables.
             virtual storm::storage::sparse::StateValuationsBuilder initializeStateValuationsBuilder() const;
-            
+
             void load(CompressedState const& state);
             virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) = 0;
             bool satisfies(storm::expressions::Expression const& expression) const;
-            
+
             /// Adds the valuation for the currently loaded state to the given builder
             virtual void addStateValuation(storm::storage::sparse::state_type const& currentStateIndex, storm::storage::sparse::StateValuationsBuilder& valuationsBuilder) const;
             /// Adds the valuation for the currently loaded state
@@ -69,7 +70,7 @@ namespace storm {
 
             virtual std::size_t getNumberOfRewardModels() const = 0;
             virtual storm::builder::RewardModelInformation getRewardModelInformation(uint64_t const& index) const = 0;
-            
+
             std::string stateToString(CompressedState const& state) const;
 
             uint32_t observabilityClass(CompressedState const& state) const;
@@ -88,7 +89,7 @@ namespace storm {
              * @param remapping The remapping to apply.
              */
             void remapStateIds(std::function<StateType(StateType const&)> const& remapping);
-            
+
         protected:
             /*!
              * Creates the state labeling for the given states using the provided labels and expressions.
@@ -109,25 +110,25 @@ namespace storm {
             virtual storm::storage::sparse::StateValuationsBuilder initializeObservationValuationsBuilder() const;
 
             void postprocess(StateBehavior<ValueType, StateType>& result);
-            
+
             /// The options to be used for next-state generation.
             NextStateGeneratorOptions options;
-            
+
             /// The expression manager used for evaluating expressions.
             std::shared_ptr<storm::expressions::ExpressionManager const> expressionManager;
-            
+
             /// The expressions that define terminal states.
             std::vector<std::pair<storm::expressions::Expression, bool>> terminalStates;
-            
+
             /// Information about how the variables are packed.
             VariableInformation variableInformation;
-            
+
             /// An evaluator used to evaluate expressions.
             std::unique_ptr<storm::expressions::ExpressionEvaluator<ValueType>> evaluator;
-            
+
             /// The currently loaded state.
             CompressedState const* state;
-            
+
             /// A comparator used to compare constants.
             storm::utility::ConstantsComparator<ValueType> comparator;
 
diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp
index 6bec68bed..03b4975a6 100644
--- a/src/storm/generator/PrismNextStateGenerator.cpp
+++ b/src/storm/generator/PrismNextStateGenerator.cpp
@@ -20,24 +20,24 @@
 
 namespace storm {
     namespace generator {
-        
+
         template<typename ValueType, typename StateType>
         PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options) : PrismNextStateGenerator<ValueType, StateType>(program.substituteConstantsFormulas(), options, false) {
             // Intentionally left empty.
         }
-        
+
         template<typename ValueType, typename StateType>
         PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options, bool) : NextStateGenerator<ValueType, StateType>(program.getManager(), options), program(program), rewardModels(), hasStateActionRewards(false) {
             STORM_LOG_TRACE("Creating next-state generator for PRISM program: " << program);
             STORM_LOG_THROW(!this->program.specifiesSystemComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions.");
-                        
+
             // Only after checking validity of the program, we initialize the variable information.
             this->checkValid();
             this->variableInformation = VariableInformation(program, options.isAddOutOfBoundsStateSet());
-            
+
             // Create a proper evalator.
             this->evaluator = std::make_unique<storm::expressions::ExpressionEvaluator<ValueType>>(program.getManager());
-            
+
             if (this->options.isBuildAllRewardModelsSet()) {
                 for (auto const& rewardModel : this->program.getRewardModels()) {
                     rewardModels.push_back(rewardModel);
@@ -52,19 +52,19 @@ namespace storm {
                         STORM_LOG_THROW(this->program.getNumberOfRewardModels() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
                     }
                 }
-                
+
                 // If no reward model was yet added, but there was one that was given in the options, we try to build the
                 // standard reward model.
                 if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) {
                     rewardModels.push_back(this->program.getRewardModel(0));
                 }
             }
-            
+
             // Determine whether any reward model has state action rewards.
             for (auto const& rewardModel : rewardModels) {
                 hasStateActionRewards |= rewardModel.get().hasStateActionRewards();
             }
-            
+
             // If there are terminal states we need to handle, we now need to translate all labels to expressions.
             if (this->options.hasTerminalStates()) {
                 for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
@@ -80,6 +80,18 @@ namespace storm {
                     }
                 }
             }
+
+            if (program.getModelType() == storm::prism::Program::ModelType::SMG) {
+                for (auto const& player : program.getPlayers()) {
+                    uint_fast32_t playerIndex = program.getIndexOfPlayer(player.getName());
+                    for (auto const& moduleIndexPair : player.getModules()) {
+                        moduleIndexToPlayerIndexMap[moduleIndexPair.second] = playerIndex;
+                    }
+                    for (auto const& commandIndexPair : player.getCommands()) {
+                        commandIndexToPlayerIndexMap[commandIndexPair.second] = playerIndex;
+                    }
+                }
+            }
         }
 
         template<typename ValueType, typename StateType>
@@ -87,7 +99,7 @@ namespace storm {
             // We can handle all valid prism programs (except for PTAs)
             return program.getModelType() != storm::prism::Program::ModelType::PTA;
         }
-        
+
         template<typename ValueType, typename StateType>
         void PrismNextStateGenerator<ValueType, StateType>::checkValid() const {
             // If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message.
@@ -118,7 +130,7 @@ namespace storm {
             }
 #endif
         }
-        
+
         template<typename ValueType, typename StateType>
         ModelType PrismNextStateGenerator<ValueType, StateType>::getModelType() const {
             switch (program.getModelType()) {
@@ -127,16 +139,17 @@ namespace storm {
                 case storm::prism::Program::ModelType::MDP: return ModelType::MDP;
                 case storm::prism::Program::ModelType::MA: return ModelType::MA;
                 case storm::prism::Program::ModelType::POMDP: return ModelType::POMDP;
+                case storm::prism::Program::ModelType::SMG: return ModelType::SMG;
                 default:
                     STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Invalid model type.");
             }
         }
-        
+
         template<typename ValueType, typename StateType>
         bool PrismNextStateGenerator<ValueType, StateType>::isDeterministicModel() const {
             return program.isDeterministicModel();
         }
-        
+
         template<typename ValueType, typename StateType>
         bool PrismNextStateGenerator<ValueType, StateType>::isDiscreteTimeModel() const {
             return program.isDiscreteTimeModel();
@@ -146,7 +159,7 @@ namespace storm {
         bool PrismNextStateGenerator<ValueType, StateType>::isPartiallyObservable() const {
             return program.isPartiallyObservable();
         }
-        
+
         template<typename ValueType, typename StateType>
         std::vector<StateType> PrismNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
             std::vector<StateType> initialStateIndices;
@@ -162,9 +175,9 @@ namespace storm {
                     currentIntegerValues.emplace_back(0);
                     initialState.setFromInt(variable.bitOffset, variable.bitWidth, 0);
                 }
-                
+
                 initialStateIndices.emplace_back(stateToIdCallback(initialState));
-                
+
                 bool done = false;
                 while (!done) {
                     bool changedBooleanVariable = false;
@@ -177,7 +190,7 @@ namespace storm {
                             initialState.set(booleanVariable.bitOffset, false);
                         }
                     }
-                    
+
                     bool changedIntegerVariable = false;
                     if (changedBooleanVariable) {
                         initialStateIndices.emplace_back(stateToIdCallback(initialState));
@@ -191,37 +204,37 @@ namespace storm {
                                 currentIntegerValues[integerVariableIndex] = integerVariable.lowerBound;
                             }
                             initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, currentIntegerValues[integerVariableIndex]);
-                            
+
                             if (changedIntegerVariable) {
                                 break;
                             }
                         }
                     }
-                    
+
                     if (changedIntegerVariable) {
                         initialStateIndices.emplace_back(stateToIdCallback(initialState));
                     }
-                    
+
                     done = !changedBooleanVariable && !changedIntegerVariable;
                 }
-                
+
                 STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using brute force enumeration.");
             } else {
                 // Prepare an SMT solver to enumerate all initial states.
                 storm::utility::solver::SmtSolverFactory factory;
                 std::unique_ptr<storm::solver::SmtSolver> solver = factory.create(program.getManager());
-                
+
                 std::vector<storm::expressions::Expression> rangeExpressions = program.getAllRangeExpressions();
                 for (auto const& expression : rangeExpressions) {
                     solver->add(expression);
                 }
                 solver->add(program.getInitialStatesExpression());
-                
+
                 // Proceed ss long as the solver can still enumerate initial states.
                 while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) {
                     // Create fresh state.
                     CompressedState initialState(this->variableInformation.getTotalBitOffset(true));
-                    
+
                     // Read variable assignment from the solution of the solver. Also, create an expression we can use to
                     // prevent the variable assignment from being enumerated again.
                     storm::expressions::Expression blockingExpression;
@@ -238,29 +251,29 @@ namespace storm {
                         blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression;
                         initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(variableValue - integerVariable.lowerBound));
                     }
-                    
+
                     // Register initial state and return it.
                     StateType id = stateToIdCallback(initialState);
                     initialStateIndices.push_back(id);
-                    
+
                     // Block the current initial state to search for the next one.
                     if (!blockingExpression.isInitialized()) {
                         break;
                     }
                     solver->add(blockingExpression);
                 }
-                
+
                 STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using SMT solving.");
             }
-            
+
             return initialStateIndices;
         }
-        
+
         template<typename ValueType, typename StateType>
         StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(StateToIdCallback const& stateToIdCallback) {
             // Prepare the result, in case we return early.
             StateBehavior<ValueType, StateType> result;
-            
+
             // First, construct the state rewards, as we may return early if there are no choices later and we already
             // need the state rewards then.
             for (auto const& rewardModel : rewardModels) {
@@ -274,7 +287,7 @@ namespace storm {
                 }
                 result.addStateReward(stateRewardValue);
             }
-            
+
             // If a terminal expression was set and we must not expand this state, return now.
             if (!this->terminalStates.empty()) {
                 for (auto const& expressionBool : this->terminalStates) {
@@ -286,7 +299,7 @@ namespace storm {
 
             // Get all choices for the state.
             result.setExpanded();
-            
+
             std::vector<Choice<ValueType>> allChoices;
             if (this->getOptions().isApplyMaximalProgressAssumptionSet()) {
                 // First explore only edges without a rate
@@ -301,15 +314,15 @@ namespace storm {
                 allChoices = getUnlabeledChoices(*this->state, stateToIdCallback);
                 addLabeledChoices(allChoices, *this->state, stateToIdCallback);
             }
-            
+
             std::size_t totalNumberOfChoices = allChoices.size();
-            
+
             // If there is not a single choice, we return immediately, because the state has no behavior (other than
             // the state reward).
             if (totalNumberOfChoices == 0) {
                 return result;
             }
-            
+
             // If the model is a deterministic model, we need to fuse the choices into one.
             if (this->isDeterministicModel() && totalNumberOfChoices > 1) {
                 Choice<ValueType> globalChoice;
@@ -317,11 +330,11 @@ namespace storm {
                 if (this->options.isAddOverlappingGuardLabelSet()) {
                     this->overlappingGuardStates->push_back(stateToIdCallback(*this->state));
                 }
-                
+
                 // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
                 // this is equal to the number of choices, which is why we initialize it like this here.
                 ValueType totalExitRate = this->isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();
-                
+
                 // Iterate over all choices and combine the probabilities/rates into one choice.
                 for (auto const& choice : allChoices) {
                     for (auto const& stateProbabilityPair : choice) {
@@ -331,20 +344,20 @@ namespace storm {
                             globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second);
                         }
                     }
-                    
+
                     if (hasStateActionRewards && !this->isDiscreteTimeModel()) {
                         totalExitRate += choice.getTotalMass();
                     }
-                    
+
                     if (this->options.isBuildChoiceLabelsSet() && choice.hasLabels()) {
                         globalChoice.addLabels(choice.getLabels());
                     }
-                    
+
                     if (this->options.isBuildChoiceOriginsSet() && choice.hasOriginData()) {
                         globalChoice.addOriginData(choice.getOriginData());
                     }
                 }
-                
+
                 // Now construct the state-action reward for all selected reward models.
                 for (auto const& rewardModel : rewardModels) {
                     ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
@@ -355,41 +368,54 @@ namespace storm {
                                     stateActionRewardValue += ValueType(this->evaluator->asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass();
                                 }
                             }
-                            
+
                         }
                     }
                     if (hasStateActionRewards) {
                         globalChoice.addReward(stateActionRewardValue / totalExitRate);
                     }
                 }
-                
+
                 // Move the newly fused choice in place.
                 allChoices.clear();
                 allChoices.push_back(std::move(globalChoice));
             }
-            
+
+            if (program.getModelType() == storm::prism::Program::ModelType::SMG) {
+                uint_fast32_t statePlayerIndex = allChoices.at(0).getPlayerIndex();
+                for(auto& choice : allChoices) {
+                    if (allChoices.size() == 1) break;
+                    // getPlayerIndex().is_initialized()?
+                    if (choice.hasPlayerIndex()) {
+                        STORM_LOG_ASSERT(choice.getPlayerIndex() == statePlayerIndex, "State '" << this->stateToString(*this->state) << "' comprises choices for different players.");
+                    } else {
+                        STORM_LOG_WARN("State '" << this->stateToString(*this->state) << "' features a choice without player index.");
+                    }
+                }
+            }
+
             // Move all remaining choices in place.
             for (auto& choice : allChoices) {
                 result.addChoice(std::move(choice));
             }
 
             this->postprocess(result);
-            
+
             return result;
         }
-        
+
         template<typename ValueType, typename StateType>
         CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) {
             CompressedState newState(state);
-            
+
             // NOTE: the following process assumes that the assignments of the update are ordered in such a way that the
             // assignments to boolean variables precede the assignments to all integer variables and that within the
             // types, the assignments to variables are ordered (in ascending order) by the expression variables.
             // This is guaranteed for PRISM models, by sorting the assignments as soon as an update is created.
-            
+
             auto assignmentIt = update.getAssignments().begin();
             auto assignmentIte = update.getAssignments().end();
-            
+
             // Iterate over all boolean assignments and carry them out.
             auto boolIt = this->variableInformation.booleanVariables.begin();
             for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) {
@@ -398,7 +424,7 @@ namespace storm {
                 }
                 newState.set(boolIt->bitOffset, this->evaluator->asBool(assignmentIt->getExpression()));
             }
-            
+
             // Iterate over all integer assignments and carry them out.
             auto integerIt = this->variableInformation.integerVariables.begin();
             for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) {
@@ -417,13 +443,13 @@ namespace storm {
                 newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound);
                 STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ").");
             }
-            
+
             // Check that we processed all assignments.
             STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed.");
-            
+
             return newState;
         }
-        
+
         struct ActiveCommandData {
             ActiveCommandData(storm::prism::Module const* modulePtr, std::set<uint_fast64_t> const* commandIndicesPtr, typename std::set<uint_fast64_t>::const_iterator currentCommandIndexIt) : modulePtr(modulePtr), commandIndicesPtr(commandIndicesPtr), currentCommandIndexIt(currentCommandIndexIt) {
                 // Intentionally left empty
@@ -432,33 +458,33 @@ namespace storm {
             std::set<uint_fast64_t> const* commandIndicesPtr;
             typename std::set<uint_fast64_t>::const_iterator currentCommandIndexIt;
         };
-        
+
         template<typename ValueType, typename StateType>
         boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex, CommandFilter const& commandFilter) {
-            
+
             // First check whether there is at least one enabled command at each module
             // This avoids evaluating unnecessarily many guards.
             // If we find one module without an enabled command, we return boost::none.
             // At the same time, we store pointers to the relevant modules, the relevant command sets and the first enabled command within each set.
-            
+
             // Iterate over all modules.
             std::vector<ActiveCommandData> activeCommands;
             for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
                 storm::prism::Module const& module = program.getModule(i);
-                
+
                 // If the module has no command labeled with the given action, we can skip this module.
                 if (!module.hasActionIndex(actionIndex)) {
                     continue;
                 }
-                
+
                 std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
-                
+
                 // If the module contains the action, but there is no command in the module that is labeled with
                 // this action, we don't have any feasible command combinations.
                 if (commandIndices.empty()) {
                     return boost::none;
                 }
-                
+
                 // Look up commands by their indices and check if the guard evaluates to true in the given state.
                 bool hasOneEnabledCommand = false;
                 for (auto commandIndexIt = commandIndices.begin(), commandIndexIte = commandIndices.end(); commandIndexIt != commandIndexIte; ++commandIndexIt) {
@@ -476,23 +502,23 @@ namespace storm {
                         break;
                     }
                 }
-                
+
                 if (!hasOneEnabledCommand) {
                     return boost::none;
                 }
             }
-            
+
             // If we reach this point, there has to be at least one active command for each relevant module.
             std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> result;
 
             // Iterate over all command sets.
             for (auto const& activeCommand : activeCommands) {
                 std::vector<std::reference_wrapper<storm::prism::Command const>> commands;
-                
+
                 auto commandIndexIt = activeCommand.currentCommandIndexIt;
                 // The command at the current position is already known to be enabled
                 commands.push_back(activeCommand.modulePtr->getCommand(*commandIndexIt));
-                
+
                 // Look up commands by their indices and add them if the guard evaluates to true in the given state.
                 auto commandIndexIte = activeCommand.commandIndicesPtr->end();
                 for (++commandIndexIt; commandIndexIt != commandIndexIte; ++commandIndexIt) {
@@ -507,29 +533,29 @@ namespace storm {
                         commands.push_back(command);
                     }
                 }
-                
+
                 result.push_back(std::move(commands));
             }
-            
+
             STORM_LOG_ASSERT(!result.empty(), "Expected non-empty list.");
             return result;
         }
-        
+
         template<typename ValueType, typename StateType>
         std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback, CommandFilter const& commandFilter) {
             std::vector<Choice<ValueType>> result;
-            
+
             // Iterate over all modules.
             for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
                 storm::prism::Module const& module = program.getModule(i);
-                
+
                 // Iterate over all commands.
                 for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
                     storm::prism::Command const& command = module.getCommand(j);
-                    
+
                     // Only consider unlabeled commands.
                     if (command.isLabeled()) continue;
-                    
+
                     if (commandFilter != CommandFilter::All) {
                         STORM_LOG_ASSERT(commandFilter == CommandFilter::Markovian || commandFilter == CommandFilter::Probabilistic, "Unexpected command filter.");
                         if ((commandFilter == CommandFilter::Markovian) != command.isMarkovian()) {
@@ -541,16 +567,16 @@ namespace storm {
                     if (!this->evaluator->asBool(command.getGuardExpression())) {
                         continue;
                     }
-                    
+
                     result.push_back(Choice<ValueType>(command.getActionIndex(), command.isMarkovian()));
                     Choice<ValueType>& choice = result.back();
-                    
+
                     // Remember the choice origin only if we were asked to.
                     if (this->options.isBuildChoiceOriginsSet()) {
                         CommandSet commandIndex { command.getGlobalIndex() };
                         choice.addOriginData(boost::any(std::move(commandIndex)));
                     }
-                    
+
                     // Iterate over all updates of the current command.
                     ValueType probabilitySum = storm::utility::zero<ValueType>();
                     for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) {
@@ -561,7 +587,7 @@ namespace storm {
                             // Obtain target state index and add it to the list of known states. If it has not yet been
                             // seen, we also add it to the set of states that have yet to be explored.
                             StateType stateIndex = stateToIdCallback(applyUpdate(state, update));
-                            
+
                             // Update the choice by adding the probability/target state to it.
                             choice.addProbability(stateIndex, probability);
                             if (this->options.isExplorationChecksSet()) {
@@ -569,7 +595,7 @@ namespace storm {
                             }
                         }
                     }
-                    
+
                     // Create the state-action reward for the newly created choice.
                     for (auto const& rewardModel : rewardModels) {
                         ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
@@ -582,24 +608,30 @@ namespace storm {
                         }
                         choice.addReward(stateActionRewardValue);
                     }
-                    
+
+                    if (program.getModelType() == storm::prism::Program::ModelType::SMG) {
+                        // Can we trust the model ordering here?
+                        // I.e. is i the correct moduleIndex set in Program.cpp:805? TODO
+                        choice.setPlayerIndex(moduleIndexToPlayerIndexMap[i]);
+                    }
+
                     if (this->options.isExplorationChecksSet()) {
                         // Check that the resulting distribution is in fact a distribution.
                         STORM_LOG_THROW(!program.isDiscreteTimeModel() || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ").");
                     }
                 }
             }
-            
+
             return result;
         }
 
         template<typename ValueType, typename StateType>
         void PrismNextStateGenerator<ValueType, StateType>::generateSynchronizedDistribution(storm::storage::BitVector const& state, ValueType const& probability, uint64_t position, std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> const& iteratorList, storm::builder::jit::Distribution<StateType, ValueType>& distribution, StateToIdCallback stateToIdCallback) {
-            
+
             if (storm::utility::isZero<ValueType>(probability)) {
                 return;
             }
-            
+
             if (position >= iteratorList.size()) {
                 StateType id = stateToIdCallback(state);
                 distribution.add(id, probability);
@@ -611,7 +643,7 @@ namespace storm {
                 }
             }
         }
-            
+
         template<typename ValueType, typename StateType>
         void PrismNextStateGenerator<ValueType, StateType>::addLabeledChoices(std::vector<Choice<ValueType>>& choices, CompressedState const& state, StateToIdCallback stateToIdCallback, CommandFilter const& commandFilter) {
 
@@ -645,6 +677,10 @@ namespace storm {
                         // Now create the actual distribution.
                         Choice<ValueType>& choice = choices.back();
 
+                        if (program.getModelType() == storm::prism::Program::ModelType::SMG) {
+                            choice.setPlayerIndex(commandIndexToPlayerIndexMap[actionIndex]);
+                        }
+
                         // Remember the choice label and origins only if we were asked to.
                         if (this->options.isBuildChoiceLabelsSet()) {
                             choice.addLabel(program.getActionName(actionIndex));
@@ -702,7 +738,7 @@ namespace storm {
                 }
             }
         }
-        
+
         template<typename ValueType, typename StateType>
         storm::models::sparse::StateLabeling PrismNextStateGenerator<ValueType, StateType>::label(storm::storage::sparse::StateStorage<StateType> const& stateStorage, std::vector<StateType> const& initialStateIndices, std::vector<StateType> const& deadlockStateIndices) {
             // Gather a vector of labels and their expressions.
@@ -720,7 +756,7 @@ namespace storm {
                     }
                 }
             }
-            
+
             return NextStateGenerator<ValueType, StateType>::label(stateStorage, initialStateIndices, deadlockStateIndices, labels);
         }
 
@@ -741,22 +777,22 @@ namespace storm {
         std::size_t PrismNextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const {
             return rewardModels.size();
         }
-        
+
         template<typename ValueType, typename StateType>
         storm::builder::RewardModelInformation PrismNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const {
             storm::prism::RewardModel const& rewardModel = rewardModels[index].get();
             return storm::builder::RewardModelInformation(rewardModel.getName(), rewardModel.hasStateRewards(), rewardModel.hasStateActionRewards(), rewardModel.hasTransitionRewards());
         }
-        
+
         template<typename ValueType, typename StateType>
         std::shared_ptr<storm::storage::sparse::ChoiceOrigins> PrismNextStateGenerator<ValueType, StateType>::generateChoiceOrigins(std::vector<boost::any>& dataForChoiceOrigins) const {
             if (!this->getOptions().isBuildChoiceOriginsSet()) {
                 return nullptr;
             }
-            
+
             std::vector<uint_fast64_t> identifiers;
             identifiers.reserve(dataForChoiceOrigins.size());
-            
+
             std::map<CommandSet, uint_fast64_t> commandSetToIdentifierMap;
             // The empty commandset (i.e., the choices without origin) always has to get identifier getIdentifierForChoicesWithNoOrigin() -- which is assumed to be 0
             STORM_LOG_ASSERT(storm::storage::sparse::ChoiceOrigins::getIdentifierForChoicesWithNoOrigin() == 0, "The no origin identifier is assumed to be zero");
@@ -764,7 +800,7 @@ namespace storm {
             uint_fast64_t currentIdentifier = 1;
             for (boost::any& originData : dataForChoiceOrigins) {
                 STORM_LOG_ASSERT(originData.empty() || boost::any_cast<CommandSet>(&originData) != nullptr, "Origin data has unexpected type: " << originData.type().name() << ".");
-                
+
                 CommandSet currentCommandSet = originData.empty() ? CommandSet() : boost::any_cast<CommandSet>(std::move(originData));
                 auto insertionRes = commandSetToIdentifierMap.insert(std::make_pair(std::move(currentCommandSet), currentIdentifier));
                 identifiers.push_back(insertionRes.first->second);
@@ -772,16 +808,16 @@ namespace storm {
                     ++currentIdentifier;
                 }
             }
-            
+
             std::vector<CommandSet> identifierToCommandSetMapping(currentIdentifier);
             for (auto const& setIdPair : commandSetToIdentifierMap) {
                 identifierToCommandSetMapping[setIdPair.second] = setIdPair.first;
             }
-            
+
             return std::make_shared<storm::storage::sparse::PrismChoiceOrigins>(std::make_shared<storm::prism::Program>(program), std::move(identifiers), std::move(identifierToCommandSetMapping));
         }
 
-                
+
         template class PrismNextStateGenerator<double>;
 
 #ifdef STORM_HAVE_CARL
diff --git a/src/storm/generator/PrismNextStateGenerator.h b/src/storm/generator/PrismNextStateGenerator.h
index e302fd02e..dc9564dd8 100644
--- a/src/storm/generator/PrismNextStateGenerator.h
+++ b/src/storm/generator/PrismNextStateGenerator.h
@@ -111,17 +111,21 @@ namespace storm {
              * A recursive helper function to generate a synchronziing distribution.
              */
             void generateSynchronizedDistribution(storm::storage::BitVector const& state, ValueType const& probability, uint64_t position, std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> const& iteratorList, storm::builder::jit::Distribution<StateType, ValueType>& distribution, StateToIdCallback stateToIdCallback);
-            
+
             // The program used for the generation of next states.
             storm::prism::Program program;
-            
+
             // The reward models that need to be considered.
             std::vector<std::reference_wrapper<storm::prism::RewardModel const>> rewardModels;
-            
+
             // A flag that stores whether at least one of the selected reward models has state-action rewards.
             bool hasStateActionRewards;
+
+            // A mapping from modules/commands to the programs players
+            std::map<uint_fast32_t, uint_fast32_t> moduleIndexToPlayerIndexMap;
+            std::map<uint_fast32_t, uint_fast32_t> commandIndexToPlayerIndexMap;
         };
-        
+
     }
 }
 
diff --git a/src/storm/models/ModelType.cpp b/src/storm/models/ModelType.cpp
index d556448bb..1e89ec163 100644
--- a/src/storm/models/ModelType.cpp
+++ b/src/storm/models/ModelType.cpp
@@ -19,6 +19,8 @@ namespace storm {
                 return ModelType::S2pg;
             } else if (type == "POMDP") {
                 return ModelType::Pomdp;
+            } else if (type == "SMG") {
+                return ModelType::Smg;
             } else {
                 STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Type " << type << "not known.");
             }
@@ -44,6 +46,9 @@ namespace storm {
                 case ModelType::Pomdp:
                     os << "POMDP";
                     break;
+                case ModelType::Smg:
+                    os << "Smg";
+                    break;
                 default:
                     STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Unknown model type.");
             }
diff --git a/src/storm/models/ModelType.h b/src/storm/models/ModelType.h
index b183a598d..d9d7b0dc8 100644
--- a/src/storm/models/ModelType.h
+++ b/src/storm/models/ModelType.h
@@ -7,11 +7,11 @@ namespace storm {
     namespace models {
         // All supported model types.
         enum class ModelType {
-            Dtmc, Ctmc, Mdp, MarkovAutomaton, S2pg, Pomdp
+            Dtmc, Ctmc, Mdp, MarkovAutomaton, S2pg, Pomdp, Smg
         };
 
         ModelType getModelType(std::string const& type);
-        
+
         std::ostream& operator<<(std::ostream& os, ModelType const& type);
     }
 }
diff --git a/src/storm/models/sparse/Model.cpp b/src/storm/models/sparse/Model.cpp
index bf9d69d4c..b1e80ab8b 100644
--- a/src/storm/models/sparse/Model.cpp
+++ b/src/storm/models/sparse/Model.cpp
@@ -62,14 +62,17 @@ namespace storm {
                     STORM_LOG_THROW(stateCount == this->getTransitionMatrix().getRowGroupCount(), storm::exceptions::IllegalArgumentException, "Can not create nondeterministic model: Number of row groups (" << this->getTransitionMatrix().getRowGroupCount() << ") of transition matrix does not match state count (" << stateCount << ").");
                     STORM_LOG_THROW(stateCount == this->getTransitionMatrix().getColumnCount(), storm::exceptions::IllegalArgumentException, "Can not create nondeterministic model: Number of columns of transition matrix does not match state count.");
                     STORM_LOG_ERROR_COND(!components.player1Matrix.is_initialized(), "Player 1 matrix given for a model that is no stochastic game (will be ignored).");
-                } else {
-                    STORM_LOG_THROW(this->isOfType(ModelType::S2pg), storm::exceptions::IllegalArgumentException, "Invalid model type.");
+                } else if (this->isOfType(ModelType::S2pg)) {
                     STORM_LOG_THROW(components.player1Matrix.is_initialized(), storm::exceptions::IllegalArgumentException, "No player 1 matrix given for stochastic game.");
                     STORM_LOG_ASSERT(components.player1Matrix->isProbabilistic(), "Can not create stochastic game: There is a row in the p1 matrix with not exactly one entry.");
                     STORM_LOG_THROW(stateCount == components.player1Matrix->getRowGroupCount(), storm::exceptions::IllegalArgumentException, "Can not create stochastic game: Number of row groups of p1 matrix does not match state count.");
                     STORM_LOG_THROW(this->getTransitionMatrix().getRowGroupCount() == components.player1Matrix->getColumnCount(), storm::exceptions::IllegalArgumentException, "Can not create stochastic game: Number of row groups of p2 matrix does not match column count of p1 matrix.");
+                } else if (this->isOfType(ModelType::Smg)) {
+                    STORM_LOG_DEBUG("Smg parsed");
+                } else {
+                    STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Invalid model type.");
                 }
-                
+
                 // Branch on continuous/discrete timing
                 if (this->isOfType(ModelType::Ctmc) || this->isOfType(ModelType::MarkovAutomaton)) {
                     STORM_LOG_THROW(components.rateTransitions || components.exitRates.is_initialized(), storm::exceptions::IllegalArgumentException, "Can not create continuous time model: no rates are given.");
diff --git a/src/storm/models/sparse/Smg.cpp b/src/storm/models/sparse/Smg.cpp
new file mode 100644
index 000000000..e0419844c
--- /dev/null
+++ b/src/storm/models/sparse/Smg.cpp
@@ -0,0 +1,49 @@
+#include "storm/models/sparse/Smg.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/utility/constants.h"
+#include "storm/utility/vector.h"
+#include "storm/adapters/RationalFunctionAdapter.h"
+
+#include "storm/models/sparse/StandardRewardModel.h"
+
+namespace storm {
+    namespace models {
+        namespace sparse {
+
+            template <typename ValueType, typename RewardModelType>
+            Smg<ValueType, RewardModelType>::Smg(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::models::sparse::StateLabeling const& stateLabeling,
+                                  std::unordered_map<std::string, RewardModelType> const& rewardModels, ModelType type)
+                    : Smg<ValueType, RewardModelType>(storm::storage::sparse::ModelComponents<ValueType, RewardModelType>(transitionMatrix, stateLabeling, rewardModels), type) {
+                // Intentionally left empty
+            }
+
+            template <typename ValueType, typename RewardModelType>
+            Smg<ValueType, RewardModelType>::Smg(storm::storage::SparseMatrix<ValueType>&& transitionMatrix, storm::models::sparse::StateLabeling&& stateLabeling,
+                                  std::unordered_map<std::string, RewardModelType>&& rewardModels, ModelType type)
+                    : Smg<ValueType, RewardModelType>(storm::storage::sparse::ModelComponents<ValueType, RewardModelType>(std::move(transitionMatrix), std::move(stateLabeling), std::move(rewardModels)), type) {
+                // Intentionally left empty
+            }
+
+            template <typename ValueType, typename RewardModelType>
+            Smg<ValueType, RewardModelType>::Smg(storm::storage::sparse::ModelComponents<ValueType, RewardModelType> const& components, ModelType type)
+                    : NondeterministicModel<ValueType, RewardModelType>(type, components) {
+                assert(type == storm::models::ModelType::Smg);
+                // Intentionally left empty
+            }
+
+           template <typename ValueType, typename RewardModelType>
+            Smg<ValueType, RewardModelType>::Smg(storm::storage::sparse::ModelComponents<ValueType, RewardModelType>&& components, ModelType type)
+                    : NondeterministicModel<ValueType, RewardModelType>(type, std::move(components)) {
+               assert(type == storm::models::ModelType::Smg);
+                // Intentionally left empty
+            }
+
+            template class Smg<double>;
+            template class Smg<storm::RationalNumber>;
+
+            template class Smg<double, storm::models::sparse::StandardRewardModel<storm::Interval>>;
+            template class Smg<storm::RationalFunction>;
+        } // namespace sparse
+    } // namespace models
+} // namespace storm
diff --git a/src/storm/models/sparse/Smg.h b/src/storm/models/sparse/Smg.h
new file mode 100644
index 000000000..663817418
--- /dev/null
+++ b/src/storm/models/sparse/Smg.h
@@ -0,0 +1,57 @@
+#ifndef STORM_MODELS_SPARSE_SMG_H_
+#define STORM_MODELS_SPARSE_SMG_H_
+
+#include "storm/models/sparse/NondeterministicModel.h"
+
+namespace storm {
+    namespace models {
+        namespace sparse {
+
+            /*!
+             * This class represents a stochastic multiplayer game.
+             */
+            template<class ValueType, typename RewardModelType = StandardRewardModel<ValueType>>
+            class Smg : public NondeterministicModel<ValueType, RewardModelType> {
+            public:
+                /*!
+                 * Constructs a model from the given data.
+                 *
+                 * @param transitionMatrix The matrix representing the transitions in the model.
+                 * @param stateLabeling The labeling of the states.
+                 * @param rewardModels A mapping of reward model names to reward models.
+                 */
+                Smg(storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
+                    storm::models::sparse::StateLabeling const& stateLabeling,
+                    std::unordered_map<std::string, RewardModelType> const& rewardModels = std::unordered_map<std::string, RewardModelType>(), ModelType type = ModelType::Smg);
+
+                /*!
+                 * Constructs a model by moving the given data.
+                 *
+                 * @param transitionMatrix The matrix representing the transitions in the model.
+                 * @param stateLabeling The labeling of the states.
+                 * @param rewardModels A mapping of reward model names to reward models.
+                 */
+                Smg(storm::storage::SparseMatrix<ValueType>&& transitionMatrix,
+                    storm::models::sparse::StateLabeling&& stateLabeling,
+                    std::unordered_map<std::string, RewardModelType>&& rewardModels = std::unordered_map<std::string, RewardModelType>(), ModelType type = ModelType::Smg);
+
+                /*!
+                 * Constructs a model from the given data.
+                 *
+                 * @param components The components for this model.
+                 */
+                Smg(storm::storage::sparse::ModelComponents<ValueType, RewardModelType> const& components, ModelType type = ModelType::Smg);
+                Smg(storm::storage::sparse::ModelComponents<ValueType, RewardModelType>&& components, ModelType type = ModelType::Smg);
+
+                Smg(Smg<ValueType, RewardModelType> const& other) = default;
+                Smg& operator=(Smg<ValueType, RewardModelType> const& other) = default;
+
+                Smg(Smg<ValueType, RewardModelType>&& other) = default;
+                Smg& operator=(Smg<ValueType, RewardModelType>&& other) = default;
+            };
+
+        } // namespace sparse
+    } // namespace models
+} // namespace storm
+
+#endif /* STORM_MODELS_SPARSE_SMG_H_ */
diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp
index 3e59f4090..abf9aa340 100644
--- a/src/storm/storage/SymbolicModelDescription.cpp
+++ b/src/storm/storage/SymbolicModelDescription.cpp
@@ -15,37 +15,37 @@
 
 namespace storm {
     namespace storage {
-        
+
         SymbolicModelDescription::SymbolicModelDescription(storm::jani::Model const& model) : modelDescription(model) {
             // Intentionally left empty.
         }
-        
+
         SymbolicModelDescription::SymbolicModelDescription(storm::prism::Program const& program) : modelDescription(program) {
             // Intentionally left empty.
         }
-        
+
         SymbolicModelDescription& SymbolicModelDescription::operator=(storm::jani::Model const& model) {
             this->modelDescription = model;
             return *this;
         }
-        
+
         SymbolicModelDescription& SymbolicModelDescription::operator=(storm::prism::Program const& program) {
             this->modelDescription = program;
             return *this;
         }
-        
+
         bool SymbolicModelDescription::hasModel() const {
             return static_cast<bool>(modelDescription);
         }
-        
+
         bool SymbolicModelDescription::isJaniModel() const {
             return modelDescription.get().which() == 0;
         }
-        
+
         bool SymbolicModelDescription::isPrismProgram() const {
             return modelDescription.get().which() == 1;
         }
-        
+
         SymbolicModelDescription::ModelType SymbolicModelDescription::getModelType() const {
             if (this->isJaniModel()) {
                 storm::jani::Model const& janiModel = this->asJaniModel();
@@ -65,12 +65,13 @@ namespace storm {
                     case storm::prism::Program::ModelType::MDP: return SymbolicModelDescription::ModelType::MDP;
                     case storm::prism::Program::ModelType::POMDP: return SymbolicModelDescription::ModelType::POMDP;
                     case storm::prism::Program::ModelType::MA: return SymbolicModelDescription::ModelType::MA;
+                    case storm::prism::Program::ModelType::SMG: return SymbolicModelDescription::ModelType::SMG;
                     default:
                         STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Expected other PRISM model type.");
                 }
             }
         }
-        
+
         storm::expressions::ExpressionManager& SymbolicModelDescription::getManager() const {
             if (this->isPrismProgram()) {
                 return this->asPrismProgram().getManager();
@@ -78,15 +79,15 @@ namespace storm {
                 return this->asJaniModel().getManager();
             }
         }
-        
+
         void SymbolicModelDescription::setModel(storm::jani::Model const& model) {
             modelDescription = model;
         }
-        
+
         void SymbolicModelDescription::setModel(storm::prism::Program const& program) {
             modelDescription = program;
         }
-        
+
         storm::jani::Model const& SymbolicModelDescription::asJaniModel() const {
             STORM_LOG_THROW(isJaniModel(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type.");
             return boost::get<storm::jani::Model>(modelDescription.get());
@@ -120,7 +121,7 @@ namespace storm {
             }
             return result;
         }
-        
+
         SymbolicModelDescription SymbolicModelDescription::toJani(bool makeVariablesGlobal) const {
             if (this->isJaniModel()) {
                 return *this;
@@ -131,7 +132,7 @@ namespace storm {
                 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format.");
             }
         }
-        
+
         std::pair<SymbolicModelDescription, std::vector<storm::jani::Property>> SymbolicModelDescription::toJani(std::vector<storm::jani::Property> const& properties, bool makeVariablesGlobal) const {
             if (this->isJaniModel()) {
                 return std::make_pair(*this, std::vector<storm::jani::Property>());
@@ -143,12 +144,12 @@ namespace storm {
                 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format.");
             }
         }
-        
+
         SymbolicModelDescription SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) const {
             std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = parseConstantDefinitions(constantDefinitionString);
             return preprocess(substitution);
         }
-        
+
         SymbolicModelDescription SymbolicModelDescription::preprocess(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const {
             if (this->isJaniModel()) {
                 storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(constantDefinitions).substituteConstantsFunctions();
@@ -158,7 +159,7 @@ namespace storm {
             }
             return *this;
         }
-        
+
         std::map<storm::expressions::Variable, storm::expressions::Expression> SymbolicModelDescription::parseConstantDefinitions(std::string const& constantDefinitionString) const {
             if (this->isJaniModel()) {
                 return storm::utility::cli::parseConstantDefinitionString(this->asJaniModel().getManager(), constantDefinitionString);
@@ -166,7 +167,7 @@ namespace storm {
                 return storm::utility::cli::parseConstantDefinitionString(this->asPrismProgram().getManager(), constantDefinitionString);
             }
         }
-        
+
         void SymbolicModelDescription::requireNoUndefinedConstants() const {
             if (this->isJaniModel()) {
                 storm::utility::jani::requireNoUndefinedConstants(this->asJaniModel());
@@ -174,7 +175,7 @@ namespace storm {
                 storm::utility::prism::requireNoUndefinedConstants(this->asPrismProgram());
             }
         }
-        
+
         bool SymbolicModelDescription::hasUndefinedConstants() const {
             if (this->isPrismProgram()) {
                 return this->asPrismProgram().hasUndefinedConstants();
@@ -182,7 +183,7 @@ namespace storm {
                 return this->asJaniModel().hasUndefinedConstants();
             }
         }
-        
+
         std::vector<storm::expressions::Variable> SymbolicModelDescription::getUndefinedConstants() const {
             std::vector<storm::expressions::Variable> result;
             if (this->isPrismProgram()) {
@@ -198,7 +199,7 @@ namespace storm {
             }
             return result;
         }
-        
+
         std::ostream& operator<<(std::ostream& out, SymbolicModelDescription const& model) {
             if (model.isPrismProgram()) {
                 out << model.asPrismProgram();
diff --git a/src/storm/storage/SymbolicModelDescription.h b/src/storm/storage/SymbolicModelDescription.h
index da07e10f8..495091755 100644
--- a/src/storm/storage/SymbolicModelDescription.h
+++ b/src/storm/storage/SymbolicModelDescription.h
@@ -7,39 +7,39 @@
 
 namespace storm {
     namespace storage {
-        
+
         class SymbolicModelDescription {
         public:
             enum class ModelType {
-                DTMC, CTMC, MDP, MA, POMDP
+                DTMC, CTMC, MDP, MA, POMDP, SMG
             };
-            
+
             SymbolicModelDescription() = default;
             SymbolicModelDescription(storm::jani::Model const& model);
             SymbolicModelDescription(storm::prism::Program const& program);
 
             SymbolicModelDescription& operator=(storm::jani::Model const& model);
             SymbolicModelDescription& operator=(storm::prism::Program const& program);
-            
+
             bool hasModel() const;
             bool isJaniModel() const;
             bool isPrismProgram() const;
-            
+
             ModelType getModelType() const;
             storm::expressions::ExpressionManager& getManager() const;
 
             void setModel(storm::jani::Model const& model);
             void setModel(storm::prism::Program const& program);
-            
+
             storm::jani::Model const& asJaniModel() const;
             storm::jani::Model& asJaniModel();
             storm::prism::Program const& asPrismProgram() const;
             storm::prism::Program& asPrismProgram();
-            
+
             std::vector<std::string> getParameterNames() const;
-            
+
             SymbolicModelDescription toJani(bool makeVariablesGlobal = true) const;
-            
+
             /*!
              * Ensures that this model is a JANI model by, e.g., converting prism to jani.
              * If labels or reward models had to be converted during conversion, the renamings are applied to the given properties
@@ -49,20 +49,20 @@ namespace storm {
              * @note The returned property vector might be empty in case no renaming is necessary.
              */
             std::pair<SymbolicModelDescription, std::vector<storm::jani::Property>> toJani(std::vector<storm::jani::Property> const& properties, bool makeVariablesGlobal) const;
-            
+
             SymbolicModelDescription preprocess(std::string const& constantDefinitionString = "") const;
             SymbolicModelDescription preprocess(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const;
-            
+
             std::map<storm::expressions::Variable, storm::expressions::Expression> parseConstantDefinitions(std::string const& constantDefinitionString) const;
-            
+
             void requireNoUndefinedConstants() const;
             bool hasUndefinedConstants() const;
             std::vector<storm::expressions::Variable> getUndefinedConstants() const;
-            
+
         private:
             boost::optional<boost::variant<storm::jani::Model, storm::prism::Program>> modelDescription;
         };
-        
+
         std::ostream& operator<<(std::ostream& out, SymbolicModelDescription const& model);
 
         std::ostream& operator<<(std::ostream& out, SymbolicModelDescription::ModelType const& type);
diff --git a/src/storm/storage/prism/Player.cpp b/src/storm/storage/prism/Player.cpp
new file mode 100644
index 000000000..f2e30d3ad
--- /dev/null
+++ b/src/storm/storage/prism/Player.cpp
@@ -0,0 +1,37 @@
+#include "storm/storage/prism/Player.h"
+
+namespace storm {
+    namespace prism {
+        Player::Player(std::string const& playerName, std::map<std::string, uint_fast32_t> const& controlledModules, std::map<std::string, uint_fast32_t> const& controlledCommands, std::string const& filename, uint_fast32_t lineNumber) : LocatedInformation(filename, lineNumber), playerName(playerName), controlledModules(controlledModules), controlledCommands(controlledCommands) {
+            // Nothing to do here.
+        }
+
+        std::string const& Player::getName() const {
+            return this->playerName;
+        }
+
+        std::map<std::string, uint_fast32_t> const& Player::getModules() const {
+            return this->controlledModules;
+        }
+
+        std::map<std::string, uint_fast32_t> const& Player::getCommands() const {
+            return this->controlledCommands;
+        }
+
+        std::ostream& operator<<(std::ostream& stream, Player const& player) {
+            stream << "player";
+            if (player.getName() != "") {
+                stream << " " << player.getName();
+            }
+            stream << std::endl;
+            for (auto const& module : player.getModules()) {
+                stream << "\t" << module.first << std::endl;
+            }
+            for (auto const& command : player.getCommands()) {
+                stream << "\t[" << command.first << "]" << std::endl;
+            }
+            stream << "endplayer" << std::endl;
+            return stream;
+        }
+    } // namespace prism
+} // namespace storm
diff --git a/src/storm/storage/prism/Player.h b/src/storm/storage/prism/Player.h
new file mode 100644
index 000000000..7d9437f7f
--- /dev/null
+++ b/src/storm/storage/prism/Player.h
@@ -0,0 +1,72 @@
+#ifndef STORM_STORAGE_PRISM_PLAYER_H_
+#define STORM_STORAGE_PRISM_PLAYER_H_
+
+#include <string>
+#include <vector>
+
+#include "storm/storage/prism/Module.h"
+#include "storm/storage/prism/Command.h"
+
+// needed?
+#include "storm/storage/BoostTypes.h"
+#include "storm/utility/OsDetection.h"
+
+namespace storm {
+    namespace prism {
+        class Player : public LocatedInformation {
+        public:
+            /*!
+             * Creates a player with the given name, controlled modules and actions.
+             *
+             * @param playerName The name of the player.
+             * @param controlledModules The controlled modules.
+             * @param controlledCommands The controlled actions.
+             * @param filename The filename in which the player is defined.
+             * @param lineNumber The line number in which the player is defined.
+             */
+            Player(std::string const& playerName, std::map<std::string, uint_fast32_t> const& controlledModules, std::map<std::string, uint_fast32_t> const& controlledCommands, std::string const& filename = "", uint_fast32_t lineNumber = 0);
+
+            // Create default implementations of constructors/assignment.
+            Player() = default;
+            Player(Player const& other) = default;
+            Player& operator=(Player const& other) = default;
+            Player(Player&& other) = default;
+            Player& operator=(Player&& other) = default;
+
+            /*!
+             * Retrieves the name of the player.
+             *
+             * @return The name of the player.
+             */
+            std::string const& getName() const;
+
+            /*!
+             * Retrieves all controlled Modules of the player.
+             *
+             * @return The modules controlled by the player.
+             */
+            std::map<std::string, uint_fast32_t> const& getModules() const; // TODO
+
+            /*!
+             * Retrieves all controlled Commands of the player.
+             *
+             * @return The commands controlled by the player.
+             */
+            std::map<std::string, uint_fast32_t> const& getCommands() const;
+
+            friend std::ostream& operator<<(std::ostream& stream, Player const& player);
+        private:
+            // The name of the player.
+            std::string playerName;
+
+            // The modules associated with this player.
+            std::map<std::string, uint_fast32_t> controlledModules;
+
+            // The commands associated with this player.
+            std::map<std::string, uint_fast32_t> controlledCommands;
+        };
+
+    } // namespace prism
+} // namespace storm
+
+#endif /* STORM_STORAGE_PRISM_PLAYER_H_ */
diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp
index cdd41f7c3..3acef442e 100644
--- a/src/storm/storage/prism/Program.cpp
+++ b/src/storm/storage/prism/Program.cpp
@@ -32,14 +32,14 @@ namespace storm {
             CompositionValidityChecker(storm::prism::Program const& program) : program(program) {
                 // Intentionally left empty.
             }
-            
+
             void check(Composition const& composition) {
                 composition.accept(*this, boost::any());
                 if (appearingModules.size() != program.getNumberOfModules()) {
                     STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Not every module is used in the system composition.");
                 }
             }
-            
+
             virtual boost::any visit(ModuleComposition const& composition, boost::any const&) override {
                 bool isValid = program.hasModule(composition.getModuleName());
                 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "The module \"" << composition.getModuleName() << "\" referred to in the system composition does not exist.");
@@ -49,10 +49,10 @@ namespace storm {
                 std::set<uint_fast64_t> synchronizingActionIndices = program.getModule(composition.getModuleName()).getSynchronizingActionIndices();
                 return synchronizingActionIndices;
             }
-            
+
             virtual boost::any visit(RenamingComposition const& composition, boost::any const& data) override {
                 std::set<uint_fast64_t> subSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getSubcomposition().accept(*this, data));
-                
+
                 std::set<uint_fast64_t> newSynchronizingActionIndices = subSynchronizingActionIndices;
                 for (auto const& namePair : composition.getActionRenaming()) {
                     if (!program.hasAction(namePair.first)) {
@@ -68,14 +68,14 @@ namespace storm {
                         newSynchronizingActionIndices.insert(toIndex);
                     }
                 }
-                
-                
+
+
                 return newSynchronizingActionIndices;
             }
-            
+
             virtual boost::any visit(HidingComposition const& composition, boost::any const& data) override {
                 std::set<uint_fast64_t> subSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getSubcomposition().accept(*this, data));
-                
+
                 for (auto const& action : composition.getActionsToHide()) {
                     if (!program.hasAction(action)) {
                         STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << action << "'.");
@@ -86,34 +86,34 @@ namespace storm {
                         subSynchronizingActionIndices.erase(it);
                     }
                 }
-                
+
                 return subSynchronizingActionIndices;
             }
-            
+
             virtual boost::any visit(SynchronizingParallelComposition const& composition, boost::any const& data) override {
                 std::set<uint_fast64_t> leftSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getLeftSubcomposition().accept(*this, data));
                 std::set<uint_fast64_t> rightSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getRightSubcomposition().accept(*this, data));
-                
+
                 std::set<uint_fast64_t> synchronizingActionIndices;
                 std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(), rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin()));
-                
+
                 return synchronizingActionIndices;
             }
-            
+
             virtual boost::any visit(InterleavingParallelComposition const& composition, boost::any const& data) override {
                 std::set<uint_fast64_t> leftSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getLeftSubcomposition().accept(*this, data));
                 std::set<uint_fast64_t> rightSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getRightSubcomposition().accept(*this, data));
-                
+
                 std::set<uint_fast64_t> synchronizingActionIndices;
                 std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(), rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin()));
-                
+
                 return synchronizingActionIndices;
             }
-            
+
             virtual boost::any visit(RestrictedParallelComposition const& composition, boost::any const& data) override {
                 std::set<uint_fast64_t> leftSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getLeftSubcomposition().accept(*this, data));
                 std::set<uint_fast64_t> rightSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getRightSubcomposition().accept(*this, data));
-                
+
                 for (auto const& action : composition.getSynchronizingActions()) {
                     if (!program.hasAction(action)) {
                         STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << action << "'.");
@@ -125,32 +125,32 @@ namespace storm {
                         STORM_LOG_THROW(it != rightSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException, "Cannot synchronize on action '" << action << "', because module '" << composition.getRightSubcomposition() << " does not have this action.");
                     }
                 }
-                
+
                 std::set<uint_fast64_t> synchronizingActionIndices;
                 std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(), rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin()));
-                
+
                 return synchronizingActionIndices;
             }
-            
+
         private:
             storm::prism::Program const& program;
             std::set<std::string> appearingModules;
         };
-        
-        Program::Program(std::shared_ptr<storm::expressions::ExpressionManager> manager, ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Module> const& modules, std::map<std::string, uint_fast64_t> const& actionToIndexMap, std::vector<RewardModel> const& rewardModels, std::vector<Label> const& labels, std::vector<ObservationLabel> const& observationLabels, boost::optional<InitialConstruct> const& initialConstruct, boost::optional<SystemCompositionConstruct> const& compositionConstruct, bool prismCompatibility, std::string const& filename, uint_fast64_t lineNumber, bool finalModel)
+
+        Program::Program(std::shared_ptr<storm::expressions::ExpressionManager> manager, ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Player> const& players, std::vector<Module> const& modules, std::map<std::string, uint_fast64_t> const& actionToIndexMap, std::vector<RewardModel> const& rewardModels, std::vector<Label> const& labels, std::vector<ObservationLabel> const& observationLabels, boost::optional<InitialConstruct> const& initialConstruct, boost::optional<SystemCompositionConstruct> const& compositionConstruct, bool prismCompatibility, std::string const& filename, uint_fast64_t lineNumber, bool finalModel)
         : LocatedInformation(filename, lineNumber), manager(manager),
         modelType(modelType), constants(constants), constantToIndexMap(),
         globalBooleanVariables(globalBooleanVariables), globalBooleanVariableToIndexMap(),
         globalIntegerVariables(globalIntegerVariables), globalIntegerVariableToIndexMap(),
-        formulas(formulas), formulaToIndexMap(), modules(modules), moduleToIndexMap(),
+        formulas(formulas), formulaToIndexMap(), players(players), modules(modules), moduleToIndexMap(),
         rewardModels(rewardModels), rewardModelToIndexMap(), systemCompositionConstruct(compositionConstruct),
         labels(labels), labelToIndexMap(), observationLabels(observationLabels), actionToIndexMap(actionToIndexMap), indexToActionMap(), actions(),
         synchronizingActionIndices(), actionIndicesToModuleIndexMap(), variableToModuleIndexMap(), prismCompatibility(prismCompatibility)
         {
-            
+
             // Start by creating the necessary mappings from the given ones.
             this->createMappings();
-            
+
             // Set the initial construct if given.
             if (initialConstruct) {
                 this->initialConstruct = initialConstruct.get();
@@ -161,7 +161,7 @@ namespace storm {
                     modules.createMissingInitialValues();
                 }
             }
-            
+
             if (finalModel) {
                 // If the model is supposed to be a CTMC, but contains probabilistic commands, we transform them to Markovian
                 // commands and issue a warning.
@@ -181,15 +181,15 @@ namespace storm {
                 this->checkValidity(Program::ValidityCheckLevel::VALIDINPUT);
             }
         }
-        
+
         Program::ModelType Program::getModelType() const {
             return modelType;
         }
-        
+
         bool Program::isDiscreteTimeModel() const {
-            return modelType == ModelType::DTMC || modelType == ModelType::MDP || modelType == ModelType::POMDP;
+            return modelType == ModelType::DTMC || modelType == ModelType::MDP || modelType == ModelType::POMDP || modelType == ModelType::SMG;
         }
-        
+
         bool Program::isDeterministicModel() const {
             return modelType == ModelType::DTMC || modelType == ModelType::CTMC;
         }
@@ -206,7 +206,7 @@ namespace storm {
             }
             return res;
         }
-        
+
         bool Program::hasUndefinedConstants() const {
             for (auto const& constant : this->getConstants()) {
                 if (!constant.isDefined()) {
@@ -215,12 +215,12 @@ namespace storm {
             }
             return false;
         }
-        
+
         bool Program::undefinedConstantsAreGraphPreserving() const {
             if (!this->hasUndefinedConstants()) {
                 return true;
             }
-            
+
             // Gather the variables of all undefined constants.
             std::set<storm::expressions::Variable> undefinedConstantVariables;
             for (auto const& constant : this->getConstants()) {
@@ -228,7 +228,7 @@ namespace storm {
                     undefinedConstantVariables.insert(constant.getExpressionVariable());
                 }
             }
-                        
+
             // Start by checking the defining expressions of all defined constants. If it contains a currently undefined
             // constant, we need to mark the target constant as undefined as well.
             for (auto const& constant : this->getConstants()) {
@@ -238,7 +238,7 @@ namespace storm {
                     }
                 }
             }
-            
+
             // Now check initial value and range expressions of global variables.
             for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
                 if (booleanVariable.hasInitialValue()) {
@@ -260,7 +260,7 @@ namespace storm {
                     return false;
                 }
             }
-            
+
 
             // Proceed by checking each of the modules.
             for (auto const& module : this->getModules()) {
@@ -268,29 +268,29 @@ namespace storm {
                     return false;
                 }
             }
-            
+
             // Check the reward models.
             for (auto const& rewardModel : this->getRewardModels()) {
                 rewardModel.containsVariablesOnlyInRewardValueExpressions(undefinedConstantVariables);
             }
-            
+
             // Initial construct.
             if (this->hasInitialConstruct()) {
                 if (this->getInitialConstruct().getInitialStatesExpression().containsVariable(undefinedConstantVariables)) {
                     return false;
                 }
             }
-            
+
             // Labels.
             for (auto const& label : this->getLabels()) {
                 if (label.getStatePredicateExpression().containsVariable(undefinedConstantVariables)) {
                     return false;
                 }
             }
-            
+
             return true;
         }
-        
+
         std::vector<std::reference_wrapper<storm::prism::Constant const>> Program::getUndefinedConstants() const {
             std::vector<std::reference_wrapper<storm::prism::Constant const>> result;
             for (auto const& constant : this->getConstants()) {
@@ -300,7 +300,7 @@ namespace storm {
             }
             return result;
         }
-        
+
         std::string Program::getUndefinedConstantsAsString() const {
             std::stringstream stream;
             bool printComma = false;
@@ -315,28 +315,28 @@ namespace storm {
             stream << ".";
             return stream.str();
         }
-        
+
         bool Program::hasConstant(std::string const& constantName) const {
             return this->constantToIndexMap.find(constantName) != this->constantToIndexMap.end();
         }
-        
+
         Constant const& Program::getConstant(std::string const& constantName) const {
             auto const& constantIndexPair = this->constantToIndexMap.find(constantName);
             return this->getConstants()[constantIndexPair->second];
         }
-        
+
         std::vector<Constant> const& Program::getConstants() const {
             return this->constants;
         }
-        
+
         std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getConstantsSubstitution() const {
             return getConstantsFormulasSubstitution(true, false);
         }
-        
+
         std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getFormulasSubstitution() const {
             return getConstantsFormulasSubstitution(false, true);
         }
-        
+
         std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getConstantsFormulasSubstitution(bool getConstantsSubstitution, bool getFormulasSubstitution) const {
             std::map<storm::expressions::Variable, storm::expressions::Expression> result;
             if (getConstantsSubstitution) {
@@ -353,7 +353,7 @@ namespace storm {
             }
             return result;
         }
-        
+
         std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getSubstitutionForRenamedModule(Module const& renamedModule, std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
             auto renaming = getFinalRenamingOfModule(renamedModule);
             std::map<storm::expressions::Variable, storm::expressions::Expression> renamingAsSubstitution;
@@ -363,7 +363,7 @@ namespace storm {
                     renamingAsSubstitution.emplace(getManager().getVariable(renamingPair.first), getManager().getVariableExpression(renamingPair.second));
                 }
             }
-            
+
             std::map<storm::expressions::Variable, storm::expressions::Expression> newSubstitution;
             for (auto const& substVarExpr : substitution) {
                 newSubstitution.emplace(substVarExpr.first, storm::jani::substituteJaniExpression(substVarExpr.second, renamingAsSubstitution));
@@ -376,7 +376,7 @@ namespace storm {
             while (moduleStack.back()->isRenamedFromModule()) {
                 moduleStack.push_back(&getModule(moduleStack.back()->getBaseModule()));
             }
-            
+
             assert(!moduleStack.back()->isRenamedFromModule());
             moduleStack.pop_back();
             assert(moduleStack.empty() || moduleStack.back()->isRenamedFromModule());
@@ -399,23 +399,23 @@ namespace storm {
             return currentRenaming;
         }
 
-        
-        
+
+
         std::size_t Program::getNumberOfConstants() const {
             return this->getConstants().size();
         }
-        
+
         std::vector<BooleanVariable> const& Program::getGlobalBooleanVariables() const {
             return this->globalBooleanVariables;
         }
-        
+
         std::vector<IntegerVariable> const& Program::getGlobalIntegerVariables() const {
             return this->globalIntegerVariables;
         }
 
         std::set<storm::expressions::Variable> Program::getAllExpressionVariables() const {
             std::set<storm::expressions::Variable> result;
-            
+
             for (auto const& constant : constants) {
                 result.insert(constant.getExpressionVariable());
             }
@@ -429,28 +429,28 @@ namespace storm {
                 auto const& moduleVariables = module.getAllExpressionVariables();
                 result.insert(moduleVariables.begin(), moduleVariables.end());
             }
-            
+
             return result;
         }
-        
+
         std::vector<storm::expressions::Expression> Program::getAllRangeExpressions() const {
             std::vector<storm::expressions::Expression> result;
             for (auto const& globalIntegerVariable : this->globalIntegerVariables) {
                 result.push_back(globalIntegerVariable.getRangeExpression());
             }
-            
+
             for (auto const& module : modules) {
                 std::vector<storm::expressions::Expression> moduleRangeExpressions = module.getAllRangeExpressions();
                 result.insert(result.end(), moduleRangeExpressions.begin(), moduleRangeExpressions.end());
             }
-            
+
             return result;
         }
-        
+
         bool Program::globalBooleanVariableExists(std::string const& variableName) const {
             return this->globalBooleanVariableToIndexMap.count(variableName) > 0;
         }
-        
+
         bool Program::globalIntegerVariableExists(std::string const& variableName) const {
             return this->globalIntegerVariableToIndexMap.count(variableName) > 0;
         }
@@ -460,51 +460,63 @@ namespace storm {
             STORM_LOG_THROW(nameIndexPair != this->globalBooleanVariableToIndexMap.end(), storm::exceptions::OutOfRangeException, "Unknown boolean variable '" << variableName << "'.");
             return this->getGlobalBooleanVariables()[nameIndexPair->second];
         }
-        
+
         IntegerVariable const& Program::getGlobalIntegerVariable(std::string const& variableName) const {
             auto const& nameIndexPair = this->globalIntegerVariableToIndexMap.find(variableName);
             STORM_LOG_THROW(nameIndexPair != this->globalIntegerVariableToIndexMap.end(), storm::exceptions::OutOfRangeException, "Unknown integer variable '" << variableName << "'.");
             return this->getGlobalIntegerVariables()[nameIndexPair->second];
         }
-        
+
         std::size_t Program::getNumberOfGlobalBooleanVariables() const {
             return this->getGlobalBooleanVariables().size();
         }
-        
+
         std::size_t Program::getNumberOfGlobalIntegerVariables() const {
             return this->getGlobalIntegerVariables().size();
         }
-        
+
         std::vector<Formula> const& Program::getFormulas() const {
             return this->formulas;
         }
-        
+
+        std::vector<Player> const& Program::getPlayers() const {
+            return this->players;
+        }
+
         std::size_t Program::getNumberOfFormulas() const {
             return this->getFormulas().size();
         }
-        
+
         std::size_t Program::getNumberOfModules() const {
             return this->getModules().size();
         }
-        
+
+        std::size_t Program::getNumberOfPlayers() const {
+            return this->getPlayers().size();
+        }
+
         storm::prism::Module const& Program::getModule(uint_fast64_t index) const {
             return this->modules[index];
         }
-        
+
         bool Program::hasModule(std::string const& moduleName) const {
             return this->moduleToIndexMap.find(moduleName) != this->moduleToIndexMap.end();
         }
-        
+
         Module const& Program::getModule(std::string const& moduleName) const {
             auto const& nameIndexPair = this->moduleToIndexMap.find(moduleName);
             STORM_LOG_THROW(nameIndexPair != this->moduleToIndexMap.end(), storm::exceptions::OutOfRangeException, "Unknown module '" << moduleName << "'.");
             return this->getModules()[nameIndexPair->second];
         }
-        
+
         std::vector<storm::prism::Module> const& Program::getModules() const {
             return this->modules;
         }
-        
+
+        uint_fast32_t const& Program::getIndexOfPlayer(std::string playerName) const {
+            return this->playerToIndexMap.at(playerName);
+        }
+
         std::map<std::string, uint_fast64_t> const& Program::getActionNameToIndexMapping() const {
             return actionToIndexMap;
         }
@@ -520,15 +532,15 @@ namespace storm {
         bool Program::hasInitialConstruct() const {
             return static_cast<bool>(initialConstruct);
         }
-        
+
         storm::prism::InitialConstruct const& Program::getInitialConstruct() const {
             return this->initialConstruct.get();
         }
-        
+
         boost::optional<InitialConstruct> const& Program::getOptionalInitialConstruct() const {
             return this->initialConstruct;
         }
-        
+
         storm::expressions::Expression Program::getInitialStatesExpression() const {
             // If there is an initial construct, return its expression. If not, we construct the expression from the
             // initial values of the variables (which have to exist).
@@ -536,7 +548,7 @@ namespace storm {
                 return this->getInitialConstruct().getInitialStatesExpression();
             } else {
                 storm::expressions::Expression result;
-                
+
                 for (auto const& variable : this->getGlobalBooleanVariables()) {
                     if (result.isInitialized()) {
                         result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
@@ -567,86 +579,86 @@ namespace storm {
                         }
                     }
                 }
-                
+
                 // If there are no variables, there is no restriction on the initial states.
                 if (!result.isInitialized()) {
                     result = manager->boolean(true);
                 }
-                
+
                 return result;
             }
         }
-        
+
         bool Program::specifiesSystemComposition() const {
             return static_cast<bool>(systemCompositionConstruct);
         }
-        
+
         SystemCompositionConstruct const& Program::getSystemCompositionConstruct() const {
             return systemCompositionConstruct.get();
         }
-        
+
         boost::optional<SystemCompositionConstruct> Program::getOptionalSystemCompositionConstruct() const {
             return systemCompositionConstruct;
         }
-        
+
         std::shared_ptr<Composition> Program::getDefaultSystemComposition() const {
             std::shared_ptr<Composition> current = std::make_shared<ModuleComposition>(this->modules.front().getName());
-            
+
             for (uint_fast64_t index = 1; index < this->modules.size(); ++index) {
                 std::shared_ptr<Composition> newComposition = std::make_shared<SynchronizingParallelComposition>(current, std::make_shared<ModuleComposition>(this->modules[index].getName()));
                 current = newComposition;
             }
-            
-            
+
+
             return current;
         }
-        
+
         std::set<std::string> const& Program::getActions() const {
             return this->actions;
         }
-        
+
         std::set<uint_fast64_t> const& Program::getSynchronizingActionIndices() const {
             return this->synchronizingActionIndices;
         }
-        
+
         std::string const& Program::getActionName(uint_fast64_t actionIndex) const {
             auto const& indexNamePair = this->indexToActionMap.find(actionIndex);
             STORM_LOG_THROW(indexNamePair != this->indexToActionMap.end(), storm::exceptions::InvalidArgumentException, "Unknown action index " << actionIndex << ".");
             return indexNamePair->second;
         }
-        
+
         uint_fast64_t Program::getActionIndex(std::string const& actionName) const {
             auto const& nameIndexPair = this->actionToIndexMap.find(actionName);
             STORM_LOG_THROW(nameIndexPair != this->actionToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Unknown action name '" << actionName << "'.");
             return nameIndexPair->second;
         }
-        
+
         bool Program::hasAction(std::string const& actionName) const {
             return this->actionToIndexMap.find(actionName) != this->actionToIndexMap.end();
         }
-        
+
         bool Program::hasAction(uint_fast64_t const& actionIndex) const {
             return this->indexToActionMap.find(actionIndex) != this->indexToActionMap.end();
         }
-        
+
         std::set<uint_fast64_t> const& Program::getModuleIndicesByAction(std::string const& action) const {
             auto const& nameIndexPair = this->actionToIndexMap.find(action);
             STORM_LOG_THROW(nameIndexPair != this->actionToIndexMap.end(), storm::exceptions::OutOfRangeException, "Action name '" << action << "' does not exist.");
             return this->getModuleIndicesByActionIndex(nameIndexPair->second);
         }
-        
+
         std::set<uint_fast64_t> const& Program::getModuleIndicesByActionIndex(uint_fast64_t actionIndex) const {
             auto const& actionModuleSetPair = this->actionIndicesToModuleIndexMap.find(actionIndex);
             STORM_LOG_THROW(actionModuleSetPair != this->actionIndicesToModuleIndexMap.end(), storm::exceptions::OutOfRangeException, "Action name '" << actionIndex << "' does not exist.");
             return actionModuleSetPair->second;
         }
-        
+
         uint_fast64_t Program::getModuleIndexByVariable(std::string const& variableName) const {
             auto const& variableNameToModuleIndexPair = this->variableToModuleIndexMap.find(variableName);
             STORM_LOG_THROW(variableNameToModuleIndexPair != this->variableToModuleIndexMap.end(), storm::exceptions::OutOfRangeException, "Variable '" << variableName << "' does not exist.");
             return variableNameToModuleIndexPair->second;
         }
-        
+
         std::pair<uint_fast64_t, uint_fast64_t> Program::getModuleCommandIndexByGlobalCommandIndex(uint_fast64_t globalCommandIndex) const {
             uint_fast64_t moduleIndex = 0;
             for (auto const& module : modules) {
@@ -663,44 +675,44 @@ namespace storm {
             STORM_LOG_THROW(false, storm::exceptions::OutOfRangeException, "Global command index '" << globalCommandIndex << "' does not exist.");
             return std::pair<uint_fast64_t, uint_fast64_t>(0, 0);
         }
-        
+
         bool Program::hasRewardModel() const {
             return !this->rewardModels.empty();
         }
-        
+
         bool Program::hasRewardModel(std::string const& name) const {
             auto const& nameIndexPair = this->rewardModelToIndexMap.find(name);
             return nameIndexPair != this->rewardModelToIndexMap.end();
         }
-        
+
         std::vector<storm::prism::RewardModel> const& Program::getRewardModels() const {
             return this->rewardModels;
         }
-        
+
         std::size_t Program::getNumberOfRewardModels() const {
             return this->getRewardModels().size();
         }
-        
+
         storm::prism::RewardModel const& Program::getRewardModel(std::string const& name) const {
             auto const& nameIndexPair = this->rewardModelToIndexMap.find(name);
             STORM_LOG_THROW(nameIndexPair != this->rewardModelToIndexMap.end(), storm::exceptions::OutOfRangeException, "Reward model '" << name << "' does not exist.");
             return this->getRewardModels()[nameIndexPair->second];
         }
-        
+
         RewardModel const& Program::getRewardModel(uint_fast64_t index) const {
             STORM_LOG_THROW(this->getNumberOfRewardModels() > index, storm::exceptions::OutOfRangeException, "Reward model with index " << index << " does not exist.");
             return this->rewardModels[index];
         }
-        
+
         bool Program::hasLabel(std::string const& labelName) const {
             auto it = std::find_if(labels.begin(), labels.end(), [&labelName] (storm::prism::Label const& label) { return label.getName() == labelName; } );
             return it != labels.end();
         }
-        
+
         std::vector<Label> const& Program::getLabels() const {
             return this->labels;
         }
-        
+
         std::vector<storm::expressions::Expression> Program::getAllGuards(bool negated) const {
             std::vector<storm::expressions::Expression> allGuards;
             for (auto const& module : modules) {
@@ -710,13 +722,13 @@ namespace storm {
             }
             return allGuards;
         }
-        
+
         storm::expressions::Expression const& Program::getLabelExpression(std::string const& label) const {
             auto const& labelIndexPair = labelToIndexMap.find(label);
             STORM_LOG_THROW(labelIndexPair != labelToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Cannot retrieve expression for unknown label '" << label << "'.");
             return this->labels[labelIndexPair->second].getStatePredicateExpression();
         }
-        
+
         std::map<std::string, storm::expressions::Expression> Program::getLabelToExpressionMapping() const {
             std::map<std::string, storm::expressions::Expression> result;
             for (auto const& label : labels) {
@@ -724,17 +736,17 @@ namespace storm {
             }
             return result;
         }
-        
+
         std::size_t Program::getNumberOfLabels() const {
             return this->getLabels().size();
         }
-        
+
         void Program::addLabel(std::string const& name, storm::expressions::Expression const& statePredicateExpression) {
             auto it = std::find_if(this->labels.begin(), this->labels.end(), [&name] (storm::prism::Label const& label) { return label.getName() == name; });
             STORM_LOG_THROW(it == this->labels.end(), storm::exceptions::InvalidArgumentException, "Cannot add a label '" << name << "', because a label with that name already exists.");
             this->labels.emplace_back(name, statePredicateExpression);
         }
-        
+
         void Program::removeLabel(std::string const& name) {
             auto it = std::find_if(this->labels.begin(), this->labels.end(), [&name] (storm::prism::Label const& label) { return label.getName() == name; });
             STORM_LOG_THROW(it != this->labels.end(), storm::exceptions::InvalidArgumentException, "Canno remove unknown label '" << name << "'.");
@@ -745,11 +757,11 @@ namespace storm {
             this->rewardModels.clear();
             this->rewardModelToIndexMap.clear();
         }
-        
+
         void Program::filterLabels(std::set<std::string> const& labelSet) {
             std::vector<storm::prism::Label> newLabels;
             newLabels.reserve(labelSet.size());
-            
+
             // Now filter the labels by the criterion whether or not their name appears in the given label set.
             for (auto it = labels.begin(), ite = labels.end(); it != ite; ++it) {
                 auto setIt = labelSet.find(it->getName());
@@ -757,7 +769,7 @@ namespace storm {
                     newLabels.emplace_back(*it);
                 }
             }
-            
+
             // Move the new labels in place.
             this->labels = std::move(newLabels);
         }
@@ -769,18 +781,18 @@ namespace storm {
         std::size_t Program::getNumberOfObservationLabels() const {
             return this->observationLabels.size();
         }
-        
+
         Program Program::restrictCommands(storm::storage::FlatSet<uint_fast64_t> const& indexSet) const {
             std::vector<storm::prism::Module> newModules;
             newModules.reserve(this->getNumberOfModules());
-            
+
             for (auto const& module : this->getModules()) {
                 newModules.push_back(module.restrictCommands(indexSet));
             }
-            
-            return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
+
+            return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getPlayers(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
         }
-        
+
         void Program::createMappings() {
             // Build the mappings for constants, global variables, formulas, modules, reward models and labels.
             for (uint_fast64_t constantIndex = 0; constantIndex < this->getNumberOfConstants(); ++constantIndex) {
@@ -801,24 +813,27 @@ namespace storm {
             for (uint_fast64_t moduleIndex = 0; moduleIndex < this->getNumberOfModules(); ++moduleIndex) {
                 this->moduleToIndexMap[this->getModules()[moduleIndex].getName()] = moduleIndex;
             }
+            for (uint_fast64_t playerIndex = 0; playerIndex < this->getNumberOfPlayers(); ++playerIndex) {
+                this->playerToIndexMap[this->getPlayers()[playerIndex].getName()] = playerIndex;
+            }
             for (uint_fast64_t rewardModelIndex = 0; rewardModelIndex < this->getNumberOfRewardModels(); ++rewardModelIndex) {
                 this->rewardModelToIndexMap[this->getRewardModels()[rewardModelIndex].getName()] = rewardModelIndex;
             }
-            
+
             for (auto const& actionIndexPair : this->getActionNameToIndexMapping()) {
                 this->actions.insert(actionIndexPair.first);
                 this->indexToActionMap.emplace(actionIndexPair.second, actionIndexPair.first);
-                
+
                 // Only let all non-zero indices be synchronizing.
                 if (actionIndexPair.second != 0) {
                     this->synchronizingActionIndices.insert(actionIndexPair.second);
                 }
             }
-            
+
             // Build the mapping from action names to module indices so that the lookup can later be performed quickly.
             for (unsigned int moduleIndex = 0; moduleIndex < this->getNumberOfModules(); moduleIndex++) {
                 Module const& module = this->getModule(moduleIndex);
-                
+
                 for (auto const& actionIndex : module.getSynchronizingActionIndices()) {
                     auto const& actionModuleIndicesPair = this->actionIndicesToModuleIndexMap.find(actionIndex);
                     if (actionModuleIndicesPair == this->actionIndicesToModuleIndexMap.end()) {
@@ -826,7 +841,7 @@ namespace storm {
                     }
                     this->actionIndicesToModuleIndexMap[actionIndex].insert(moduleIndex);
                 }
-                
+
                 // Put in the appropriate entries for the mapping from variable names to module index.
                 for (auto const& booleanVariable : module.getBooleanVariables()) {
                     this->variableToModuleIndexMap[booleanVariable.getName()] = moduleIndex;
@@ -838,13 +853,13 @@ namespace storm {
                     this->variableToModuleIndexMap[clockVariable.getName()] = moduleIndex;
                 }
             }
-            
+
         }
-        
+
         Program Program::defineUndefinedConstants(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const {
             // For sanity checking, we keep track of all undefined constants that we define in the course of this procedure.
             std::set<storm::expressions::Variable> definedUndefinedConstants;
-            
+
             std::vector<Constant> newConstants;
             newConstants.reserve(this->getNumberOfConstants());
             for (auto const& constant : this->getConstants()) {
@@ -853,72 +868,72 @@ namespace storm {
                 if (constant.isDefined()) {
                     // Make sure we are not trying to define an already defined constant.
                     STORM_LOG_THROW(constantDefinitions.find(constant.getExpressionVariable()) == constantDefinitions.end(), storm::exceptions::InvalidArgumentException, "Illegally defining already defined constant '" << constant.getName() << "'.");
-                    
+
                     // Now replace the occurrences of undefined constants in its defining expression.
                     newConstants.emplace_back(constant.getExpressionVariable(), constant.getExpression().substitute(constantDefinitions), constant.getFilename(), constant.getLineNumber());
                 } else {
                     auto const& variableExpressionPair = constantDefinitions.find(constant.getExpressionVariable());
-                    
+
                     // If the constant is not defined by the mapping, we leave it like it is.
                     if (variableExpressionPair == constantDefinitions.end()) {
                         newConstants.emplace_back(constant);
                     } else {
                         // Otherwise, we add it to the defined constants and assign it the appropriate expression.
                         definedUndefinedConstants.insert(constant.getExpressionVariable());
-                        
+
                         // Make sure the type of the constant is correct.
                         STORM_LOG_THROW(variableExpressionPair->second.getType() == constant.getType(), storm::exceptions::InvalidArgumentException, "Illegal type of expression defining constant '" << constant.getName() << "'.");
-                        
+
                         // Now create the defined constant.
                         newConstants.emplace_back(constant.getExpressionVariable(), variableExpressionPair->second, constant.getFilename(), constant.getLineNumber());
                     }
                 }
             }
-            
-            return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
+
+            return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getPlayers(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
         }
-        
+
         Program Program::substituteConstants() const {
             return substituteConstantsFormulas(true, false);
         }
-        
+
         Program Program::substituteFormulas() const {
             return substituteConstantsFormulas(false, true);
         }
-        
+
         Program Program::substituteConstantsFormulas(bool substituteConstants, bool substituteFormulas) const {
             // Formulas need to be substituted first. otherwise, constants appearing in formula expressions can not be handled properly
             if (substituteConstants && substituteFormulas) {
                 return this->substituteFormulas().substituteConstants();
             }
-            
+
             // We start by creating the appropriate substitution.
             std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = getConstantsFormulasSubstitution(substituteConstants, substituteFormulas);
-            
+
             std::vector<Constant> newConstants;
             newConstants.reserve(this->getNumberOfConstants());
             for (auto const& oldConstant : this->getConstants()) {
                 newConstants.push_back(oldConstant.substitute(substitution));
             }
-            
+
             std::vector<Formula> newFormulas;
             newFormulas.reserve(this->getNumberOfFormulas());
             for (auto const& oldFormula : this->getFormulas()) {
                 newFormulas.emplace_back(oldFormula.substitute(substitution));
             }
-            
+
             std::vector<BooleanVariable> newBooleanVariables;
             newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables());
             for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
                 newBooleanVariables.emplace_back(booleanVariable.substitute(substitution));
             }
-            
+
             std::vector<IntegerVariable> newIntegerVariables;
             newBooleanVariables.reserve(this->getNumberOfGlobalIntegerVariables());
             for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
                 newIntegerVariables.emplace_back(integerVariable.substitute(substitution));
             }
-            
+
             std::vector<Module> newModules;
             newModules.reserve(this->getNumberOfModules());
             for (auto const& module : this->getModules()) {
@@ -930,18 +945,18 @@ namespace storm {
                     newModules.emplace_back(module.substitute(substitution));
                 }
             }
-            
+
             std::vector<RewardModel> newRewardModels;
             newRewardModels.reserve(this->getNumberOfRewardModels());
             for (auto const& rewardModel : this->getRewardModels()) {
                 newRewardModels.emplace_back(rewardModel.substitute(substitution));
             }
-            
+
             boost::optional<storm::prism::InitialConstruct> newInitialConstruct;
             if (this->hasInitialConstruct()) {
                 newInitialConstruct = this->getInitialConstruct().substitute(substitution);
             }
-            
+
             std::vector<Label> newLabels;
             newLabels.reserve(this->getNumberOfLabels());
             for (auto const& label : this->getLabels()) {
@@ -953,12 +968,12 @@ namespace storm {
             for (auto const& label : this->getObservationLabels()) {
                 newObservationLabels.emplace_back(label.substitute(substitution));
             }
-            
-            return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, this->getActionNameToIndexMapping(), newRewardModels, newLabels, newObservationLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct(), prismCompatibility);
+
+            return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, this->getPlayers(), newModules, this->getActionNameToIndexMapping(), newRewardModels, newLabels, newObservationLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct(), prismCompatibility);
         }
-        
+
         void Program::checkValidity(Program::ValidityCheckLevel lvl) const {
-            
+
             // Start by checking the constant declarations.
             std::set<storm::expressions::Variable> all;
             std::set<storm::expressions::Variable> allGlobals;
@@ -971,7 +986,7 @@ namespace storm {
                     std::set<storm::expressions::Variable> illegalVariables;
                     std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
                     bool isValid = illegalVariables.empty();
-                    
+
                     if (!isValid) {
                         std::vector<std::string> illegalVariableNames;
                         for (auto const& var : illegalVariables) {
@@ -980,25 +995,25 @@ namespace storm {
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << constant.getFilename() << ", line " << constant.getLineNumber() << ": defining expression refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
                 }
-                
+
                 // Record the new identifier for future checks.
                 constants.insert(constant.getExpressionVariable());
                 all.insert(constant.getExpressionVariable());
                 allGlobals.insert(constant.getExpressionVariable());
             }
-            
+
             // Now we check the variable declarations. We start with the global variables.
             std::set<storm::expressions::Variable> variables;
             for (auto const& variable : this->getGlobalBooleanVariables()) {
                 if (variable.hasInitialValue()) {
                     STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
-                    
+
                     // Check the initial value of the variable.
                     std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
                     std::set<storm::expressions::Variable> illegalVariables;
                     std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
                     bool isValid = illegalVariables.empty();
-                    
+
                     if (!isValid) {
                         std::vector<std::string> illegalVariableNames;
                         for (auto const& var : illegalVariables) {
@@ -1007,7 +1022,7 @@ namespace storm {
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
                 }
-                
+
                 // Record the new identifier for future checks.
                 variables.insert(variable.getExpressionVariable());
                 all.insert(variable.getExpressionVariable());
@@ -1020,7 +1035,7 @@ namespace storm {
                 std::set<storm::expressions::Variable> illegalVariables;
                 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
                 bool isValid = illegalVariables.empty();
-                
+
                 if (!isValid) {
                     std::vector<std::string> illegalVariableNames;
                     for (auto const& var : illegalVariables) {
@@ -1028,7 +1043,7 @@ namespace storm {
                     }
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": lower bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                 }
-                
+
                 containedVariables = variable.getLowerBoundExpression().getVariables();
                 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
                 isValid = illegalVariables.empty();
@@ -1039,7 +1054,7 @@ namespace storm {
                     }
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                 }
-                
+
                 if (variable.hasInitialValue()) {
                     STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
 
@@ -1055,14 +1070,14 @@ namespace storm {
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
                 }
-                
+
                 // Record the new identifier for future checks.
                 variables.insert(variable.getExpressionVariable());
                 all.insert(variable.getExpressionVariable());
                 allGlobals.insert(variable.getExpressionVariable());
                 globalVariables.insert(variable.getExpressionVariable());
             }
-            
+
             // Now go through the variables of the modules.
             for (auto const& module : this->getModules()) {
                 for (auto const& variable : module.getBooleanVariables()) {
@@ -1082,7 +1097,7 @@ namespace storm {
                             STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                         }
                     }
-                    
+
                     // Record the new identifier for future checks.
                     variables.insert(variable.getExpressionVariable());
                     all.insert(variable.getExpressionVariable());
@@ -1100,7 +1115,7 @@ namespace storm {
                         }
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": lower bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
-                    
+
                     containedVariables = variable.getLowerBoundExpression().getVariables();
                     illegalVariables.clear();
                     std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
@@ -1112,7 +1127,7 @@ namespace storm {
                         }
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
-                    
+
                     if (variable.hasInitialValue()) {
                         STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
 
@@ -1129,23 +1144,23 @@ namespace storm {
                             STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                         }
                     }
-                    
+
                     // Record the new identifier for future checks.
                     variables.insert(variable.getExpressionVariable());
                     all.insert(variable.getExpressionVariable());
                 }
-                
+
                 for (auto const& variable : module.getClockVariables()) {
                     // Record the new identifier for future checks.
                     variables.insert(variable.getExpressionVariable());
                     all.insert(variable.getExpressionVariable());
                 }
             }
-            
+
             // Create the set of valid identifiers for future checks.
             std::set<storm::expressions::Variable> variablesAndConstants;
             std::set_union(variables.begin(), variables.end(), constants.begin(), constants.end(), std::inserter(variablesAndConstants, variablesAndConstants.begin()));
-            
+
             // Collect the formula placeholders and check formulas
             for (auto const& formula : this->getFormulas()) {
                 std::set<storm::expressions::Variable> containedVariables = formula.getExpression().getVariables();
@@ -1156,7 +1171,7 @@ namespace storm {
                     variablesAndConstants.insert(formula.getExpressionVariable());
                 }
             }
-            
+
             // Check the commands and invariants of the modules.
             bool hasProbabilisticCommand = false;
             bool hasMarkovianCommand = false;
@@ -1173,7 +1188,7 @@ namespace storm {
                 for (auto const& variable : module.getClockVariables()) {
                     legalVariables.insert(variable.getExpressionVariable());
                 }
-                
+
                 if (module.hasInvariant()) {
                     std::set<storm::expressions::Variable> containedVariables = module.getInvariant().getVariables();
                     std::set<storm::expressions::Variable> illegalVariables;
@@ -1188,7 +1203,7 @@ namespace storm {
                     }
                     STORM_LOG_THROW(module.getInvariant().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << module.getFilename() << ", line " << module.getLineNumber() << ": invariant " << module.getInvariant() << " must evaluate to type 'bool'.");
                 }
-                
+
                 for (auto& command : module.getCommands()) {
                     // Check the guard.
                     std::set<storm::expressions::Variable> containedVariables = command.getGuardExpression().getVariables();
@@ -1203,20 +1218,20 @@ namespace storm {
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": guard " << command.getGuardExpression()  << " refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
                     STORM_LOG_THROW(command.getGuardExpression().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": expression for guard must evaluate to type 'bool'.");
-                    
+
                     // Record which types of commands were seen.
                     if (command.isMarkovian()) {
                         hasMarkovianCommand = true;
                     } else {
                         hasProbabilisticCommand = true;
                     }
-                    
+
                     // If the command is Markovian and labeled, we throw an error or raise a warning, depending on
                     // whether or not the PRISM compatibility mode was enabled.
                     if (command.isMarkovian() && command.isLabeled()) {
                         hasLabeledMarkovianCommand = true;
                     }
-                    
+
                     // Check all updates.
                     for (auto const& update : command.getUpdates()) {
                         containedVariables = update.getLikelihoodExpression().getVariables();
@@ -1230,12 +1245,12 @@ namespace storm {
                             }
                             STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": likelihood expression refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                         }
-                        
+
                         // Check all assignments.
                         std::set<storm::expressions::Variable> alreadyAssignedVariables;
                         for (auto const& assignment : update.getAssignments()) {
                             storm::expressions::Variable assignedVariable = manager->getVariable(assignment.getVariableName());
-                            
+
                             if (legalVariables.find(assignedVariable) == legalVariables.end()) {
                                 if (all.find(assignedVariable) != all.end()) {
                                     STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": assignment illegally refers to variable '" << assignment.getVariableName() << "'.");
@@ -1245,14 +1260,14 @@ namespace storm {
                             }
                             STORM_LOG_THROW(alreadyAssignedVariables.find(assignedVariable) == alreadyAssignedVariables.end(), storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": duplicate assignment to variable '" << assignment.getVariableName() << "'.");
                             STORM_LOG_THROW(assignedVariable.getType() == assignment.getExpression().getType() || (assignedVariable.getType().isRationalType() && assignment.getExpression().getType().isNumericalType()), storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": illegally assigning a value of type '" << assignment.getExpression().getType() << "' to variable '" << assignment.getVariableName() << "' of type '" << assignedVariable.getType() << "'.");
-                            
+
                             if (command.isLabeled() && globalVariables.find(assignedVariable) != globalVariables.end()) {
                                 std::pair<storm::expressions::Variable, uint64_t>variableActionIndexPair(assignedVariable, command.getActionIndex());
                                 std::pair<uint64_t,std::string> lineModuleNamePair(command.getLineNumber(), module.getName());
                                 auto insertionResult = writtenGlobalVariables.emplace(variableActionIndexPair, lineModuleNamePair);
                                 STORM_LOG_THROW(insertionResult.second || insertionResult.first->second.second == module.getName(), storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": Syncronizing command with action label '" << command.getActionName() << "' illegally assigns a value to global variable '" << assignedVariable.getName() << "'. Previous assignment to the variable at line " << insertionResult.first->second.first << " in module '" << insertionResult.first->second.second << "'.");
                             }
-                            
+
                             containedVariables = assignment.getExpression().getVariables();
                             illegalVariables.clear();
                             std::set_difference(containedVariables.begin(), containedVariables.end(), variablesAndConstants.begin(), variablesAndConstants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
@@ -1264,14 +1279,14 @@ namespace storm {
                                 }
                                 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": assigned expression refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                             }
-                            
+
                             // Add the current variable to the set of assigned variables (of this update).
                             alreadyAssignedVariables.insert(assignedVariable);
                         }
                     }
                 }
             }
-            
+
             if (hasLabeledMarkovianCommand) {
                 if (prismCompatibility) {
                     STORM_LOG_WARN_COND(false, "The model uses synchronizing Markovian commands. This may lead to unexpected verification results, because of unclear semantics.");
@@ -1279,13 +1294,13 @@ namespace storm {
                     STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "The model uses synchronizing Markovian commands. This may lead to unexpected verification results, because of unclear semantics.");
                 }
             }
-            
+
             if (this->getModelType() == Program::ModelType::DTMC || this->getModelType() == Program::ModelType::MDP) {
                 STORM_LOG_THROW(!hasMarkovianCommand, storm::exceptions::WrongFormatException, "Discrete-time model must not have Markovian commands.");
             } else if (this->getModelType() == Program::ModelType::CTMC) {
                 STORM_LOG_THROW(!hasProbabilisticCommand, storm::exceptions::WrongFormatException, "The input model is a CTMC, but uses probabilistic commands like they are used in PRISM. Please use Markovian commands instead or turn on the PRISM compatibility mode using the flag '-pc'.");
             }
-            
+
             // Now check the reward models.
             for (auto const& rewardModel : this->getRewardModels()) {
                 for (auto const& stateReward : rewardModel.getStateRewards()) {
@@ -1293,57 +1308,57 @@ namespace storm {
                     bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber() << ": state reward expression refers to unknown identifiers.");
                     STORM_LOG_THROW(stateReward.getStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber() << ": state predicate must evaluate to type 'bool'.");
-                    
+
                     containedVariables = stateReward.getRewardValueExpression().getVariables();
                     isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber() << ": state reward value expression refers to unknown identifiers.");
                     STORM_LOG_THROW(stateReward.getRewardValueExpression().hasNumericalType(), storm::exceptions::WrongFormatException, "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber() << ": reward value expression must evaluate to numerical type.");
                 }
-                
+
                 for (auto const& stateActionReward : rewardModel.getStateActionRewards()) {
                     std::set<storm::expressions::Variable> containedVariables = stateActionReward.getStatePredicateExpression().getVariables();
                     bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber() << ": state reward expression refers to unknown identifiers.");
                     STORM_LOG_THROW(stateActionReward.getStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber() << ": state predicate must evaluate to type 'bool'.");
-                    
+
                     containedVariables = stateActionReward.getRewardValueExpression().getVariables();
                     isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber() << ": state reward value expression refers to unknown identifiers.");
                     STORM_LOG_THROW(stateActionReward.getRewardValueExpression().hasNumericalType(), storm::exceptions::WrongFormatException, "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber() << ": reward value expression must evaluate to numerical type.");
                 }
-                
+
                 for (auto const& transitionReward : rewardModel.getTransitionRewards()) {
                     std::set<storm::expressions::Variable> containedVariables = transitionReward.getSourceStatePredicateExpression().getVariables();
                     bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber() << ": state reward expression refers to unknown identifiers.");
                     STORM_LOG_THROW(transitionReward.getSourceStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber() << ": state predicate must evaluate to type 'bool'.");
-                    
+
                     containedVariables = transitionReward.getTargetStatePredicateExpression().getVariables();
                     isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber() << ": state reward expression refers to unknown identifiers.");
                     STORM_LOG_THROW(transitionReward.getTargetStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber() << ": state predicate must evaluate to type 'bool'.");
-                    
-                    
+
+
                     containedVariables = transitionReward.getRewardValueExpression().getVariables();
                     isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber() << ": state reward value expression refers to unknown identifiers.");
                     STORM_LOG_THROW(transitionReward.getRewardValueExpression().hasNumericalType(), storm::exceptions::WrongFormatException, "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber() << ": reward value expression must evaluate to numerical type.");
                 }
             }
-            
+
             // Check the initial states expression.
             if (this->hasInitialConstruct()) {
                 std::set<storm::expressions::Variable> containedIdentifiers = this->getInitialConstruct().getInitialStatesExpression().getVariables();
                 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedIdentifiers.begin(), containedIdentifiers.end());
                 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << this->getInitialConstruct().getFilename() << ", line " << this->getInitialConstruct().getLineNumber() << ": initial construct refers to unknown identifiers.");
             }
-            
+
             // Check the system composition if given.
             if (systemCompositionConstruct) {
                 CompositionValidityChecker checker(*this);
                 checker.check(systemCompositionConstruct.get().getSystemComposition());
             }
-            
+
             // Check the labels.
             for (auto const& label : this->getLabels()) {
                 std::set<storm::expressions::Variable> containedVariables = label.getStatePredicateExpression().getVariables();
@@ -1351,7 +1366,7 @@ namespace storm {
                 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << label.getFilename() << ", line " << label.getLineNumber() << ": label expression refers to unknown identifiers.");
                 STORM_LOG_THROW(label.getStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException, "Error in " << label.getFilename() << ", line " << label.getLineNumber() << ": label predicate must evaluate to type 'bool'.");
             }
-            
+
             if(lvl >= Program::ValidityCheckLevel::READYFORPROCESSING) {
                 // We check for each global variable and each labeled command, whether there is at most one instance writing to that variable.
                 std::set<std::pair<std::string, std::string>> globalBVarsWrittenToByCommand;
@@ -1385,21 +1400,21 @@ namespace storm {
                 }
             }
         }
-        
+
         Program Program::simplify() {
             // Start by substituting the constants, because this will potentially erase some commands or even actions.
             Program substitutedProgram = this->substituteConstantsFormulas();
-            
+
             // As we possibly delete some commands and some actions might be dropped from modules altogether, we need to
             // maintain a list of actions that we need to remove in other modules. For example, if module A loses all [a]
             // commands, we need to delete all [a] commands from all other modules as well. If we do not do that, we will
             // remove the forced synchronization that was there before.
             std::set<uint_fast64_t> actionIndicesToDelete;
-            
+
             std::vector<Module> newModules;
             std::vector<Constant> newConstants = substitutedProgram.getConstants();
             for (auto const& module : substitutedProgram.getModules()) {
-                
+
                 // Discard all commands with a guard equivalent to false and remove identity assignments from the updates.
                 std::vector<Command> newCommands;
                 for (auto const& command : module.getCommands()) {
@@ -1407,7 +1422,7 @@ namespace storm {
                         newCommands.emplace_back(command.simplify());
                     }
                 }
-                
+
                 // Substitute variables by global constants if possible.
                 std::map<storm::expressions::Variable, storm::expressions::Expression> booleanVars;
                 std::map<storm::expressions::Variable, storm::expressions::Expression> integerVars;
@@ -1417,7 +1432,7 @@ namespace storm {
                 for (auto const& variable : module.getIntegerVariables()) {
                     integerVars.emplace(variable.getExpressionVariable(), variable.getInitialValueExpression());
                 }
-                
+
                 // Collect all variables that are being written. These variables cannot be turned to constants.
                 for (auto const& command : newCommands) {
                     // Check all updates.
@@ -1438,7 +1453,7 @@ namespace storm {
                         }
                     }
                 }
-                
+
                 std::vector<storm::prism::BooleanVariable> newBooleanVars;
                 for (auto const& variable : module.getBooleanVariables()) {
                     if (booleanVars.find(variable.getExpressionVariable()) == booleanVars.end()) {
@@ -1451,7 +1466,7 @@ namespace storm {
                         newIntegerVars.push_back(variable);
                     }
                 }
-                
+
                 for (auto const& variable : module.getBooleanVariables()) {
                     if (booleanVars.find(variable.getExpressionVariable()) != booleanVars.end()) {
                         if (variable.hasInitialValue()) {
@@ -1470,36 +1485,36 @@ namespace storm {
                         }
                     }
                 }
-                
+
                 // we currently do not simplify clock variables or invariants
                 newModules.emplace_back(module.getName(), newBooleanVars, newIntegerVars, module.getClockVariables(), module.getInvariant(), newCommands);
-                
+
                 // Determine the set of action indices that have been deleted entirely.
                 std::set_difference(module.getSynchronizingActionIndices().begin(), module.getSynchronizingActionIndices().end(), newModules.back().getSynchronizingActionIndices().begin(), newModules.back().getSynchronizingActionIndices().end(), std::inserter(actionIndicesToDelete, actionIndicesToDelete.begin()));
             }
-            
+
             // If we have to delete whole actions, do so now.
             std::map<std::string, uint_fast64_t> newActionToIndexMap;
             std::vector<RewardModel> newRewardModels;
             if (!actionIndicesToDelete.empty()) {
                 storm::storage::FlatSet<uint_fast64_t> actionsToKeep;
                 std::set_difference(this->getSynchronizingActionIndices().begin(), this->getSynchronizingActionIndices().end(), actionIndicesToDelete.begin(), actionIndicesToDelete.end(), std::inserter(actionsToKeep, actionsToKeep.begin()));
-                
+
                 // Insert the silent action as this is not contained in the synchronizing action indices.
                 actionsToKeep.insert(0);
-                
+
                 std::vector<Module> cleanedModules;
                 cleanedModules.reserve(newModules.size());
                 for (auto const& module : newModules) {
                     cleanedModules.emplace_back(module.restrictActionIndices(actionsToKeep));
                 }
                 newModules = std::move(cleanedModules);
-                
+
                 newRewardModels.reserve(substitutedProgram.getNumberOfRewardModels());
                 for (auto const& rewardModel : substitutedProgram.getRewardModels()) {
                     newRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep));
                 }
-                
+
                 for (auto const& entry : this->getActionNameToIndexMapping()) {
                     if (actionsToKeep.find(entry.second) != actionsToKeep.end()) {
                         newActionToIndexMap.emplace(entry.first, entry.second);
@@ -1512,22 +1527,22 @@ namespace storm {
                 newLabels.emplace_back(label.getName(), label.getStatePredicateExpression().simplify());
             }
 
-            return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), newModules, actionIndicesToDelete.empty() ? getActionNameToIndexMapping() : newActionToIndexMap, actionIndicesToDelete.empty() ? this->getRewardModels() : newRewardModels, newLabels, getObservationLabels(), getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
+            return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), this->getPlayers(), newModules, actionIndicesToDelete.empty() ? getActionNameToIndexMapping() : newActionToIndexMap, actionIndicesToDelete.empty() ? this->getRewardModels() : newRewardModels, newLabels, getObservationLabels(), getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
         }
-        
+
         Program Program::flattenModules(std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const {
             // If the current program has only one module, we can simply return a copy.
             if (this->getNumberOfModules() == 1) {
                 return Program(*this);
             }
-            
+
             STORM_LOG_THROW(this->getModelType() == ModelType::DTMC || this->getModelType() == ModelType::MDP, storm::exceptions::InvalidTypeException, "Unable to flatten modules for model of type '" << this->getModelType() << "'.");
-            
+
             // Otherwise, we need to actually flatten the contained modules.
-            
+
             // Get an SMT solver for computing the possible guard combinations.
             std::unique_ptr<storm::solver::SmtSolver> solver = smtSolverFactory->create(*manager);
-            
+
             // Set up the data we need to gather to create the flat module.
             std::stringstream newModuleName;
             std::vector<storm::prism::BooleanVariable> allBooleanVariables;
@@ -1536,7 +1551,7 @@ namespace storm {
             std::vector<storm::prism::Command> newCommands;
             uint_fast64_t nextCommandIndex = 0;
             uint_fast64_t nextUpdateIndex = 0;
-            
+
             // Assert the values of the constants.
             for (auto const& constant : this->getConstants()) {
                 if (constant.isDefined()) {
@@ -1547,19 +1562,19 @@ namespace storm {
                     }
                 }
             }
-            
+
             // Assert the bounds of the global variables.
             for (auto const& variable : this->getGlobalIntegerVariables()) {
                 solver->add(variable.getExpression() >= variable.getLowerBoundExpression());
                 solver->add(variable.getExpression() <= variable.getUpperBoundExpression());
             }
-            
+
             // Make the global variables local, such that the resulting module covers all occurring variables. Note that
             // this is just for simplicity and is not needed.
             allBooleanVariables.insert(allBooleanVariables.end(), this->getGlobalBooleanVariables().begin(), this->getGlobalBooleanVariables().end());
             allIntegerVariables.insert(allIntegerVariables.end(), this->getGlobalIntegerVariables().begin(), this->getGlobalIntegerVariables().end());
             storm::expressions::Expression newInvariant;
-            
+
             // Now go through the modules, gather the variables, construct the name of the new module and assert the
             // bounds of the discovered variables.
             for (auto const& module : this->getModules()) {
@@ -1567,76 +1582,76 @@ namespace storm {
                 allBooleanVariables.insert(allBooleanVariables.end(), module.getBooleanVariables().begin(), module.getBooleanVariables().end());
                 allIntegerVariables.insert(allIntegerVariables.end(), module.getIntegerVariables().begin(), module.getIntegerVariables().end());
                 allClockVariables.insert(allClockVariables.end(), module.getClockVariables().begin(), module.getClockVariables().end());
-                
+
                 for (auto const& variable : module.getIntegerVariables()) {
                     solver->add(variable.getExpression() >= variable.getLowerBoundExpression());
                     solver->add(variable.getExpression() <= variable.getUpperBoundExpression());
                 }
-                
+
                 if (module.hasInvariant()) {
                     newInvariant = newInvariant.isInitialized() ? (newInvariant && module.getInvariant()) : module.getInvariant();
                 }
-                
+
                 // The commands without a synchronizing action name, can simply be copied (plus adjusting the global
                 // indices of the command and its updates).
                 for (auto const& command : module.getCommands()) {
                     if (!command.isLabeled()) {
                         std::vector<storm::prism::Update> updates;
                         updates.reserve(command.getUpdates().size());
-                        
+
                         for (auto const& update : command.getUpdates()) {
                             updates.push_back(storm::prism::Update(nextUpdateIndex, update.getLikelihoodExpression(), update.getAssignments(), update.getFilename(), 0));
                             ++nextUpdateIndex;
                         }
-                        
+
                         newCommands.push_back(storm::prism::Command(nextCommandIndex, command.isMarkovian(), actionToIndexMap.find("")->second, "", command.getGuardExpression(), updates, command.getFilename(), 0));
                         ++nextCommandIndex;
                     }
                 }
             }
-            
+
             // Save state of solver so that we can always restore the point where we have exactly the constant values
             // and variables bounds on the assertion stack.
             solver->push();
-            
+
             // Now we need to enumerate all possible combinations of synchronizing commands. For this, we iterate over
             // all actions and let the solver enumerate the possible combinations of commands that can be enabled together.
             for (auto const& actionIndex : this->getSynchronizingActionIndices()) {
                 bool noCombinationsForAction = false;
-                
+
                 // Prepare the list that stores for each module the list of commands with the given action.
                 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> possibleCommands;
-                
+
                 for (auto const& module : this->getModules()) {
                     // If the module has no command with this action, we can skip it.
                     if (!module.hasActionIndex(actionIndex)) {
                         continue;
                     }
-                    
+
                     std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
-                    
+
                     // If there is no command even though the module has this action, there is no valid command
                     // combination with this action.
                     if (commandIndices.empty()) {
                         noCombinationsForAction = true;
                         break;
                     }
-                    
+
                     // Prepare empty list of commands for this module.
                     possibleCommands.push_back(std::vector<std::reference_wrapper<storm::prism::Command const>>());
-                    
+
                     // Add references to the commands labeled with the current action.
                     for (auto const& commandIndex : commandIndices) {
                         possibleCommands.back().push_back(module.getCommand(commandIndex));
                     }
                 }
-                
+
                 // If there are no valid combinations for the action, we need to skip the generation of synchronizing
                 // commands.
                 if (!noCombinationsForAction) {
                     // Save the solver state to be able to restore it when this action index is done.
                     solver->push();
-                    
+
                     // Start by creating a fresh auxiliary variable for each command and link it with the guard.
                     std::vector<std::vector<storm::expressions::Variable>> commandVariables(possibleCommands.size());
                     std::vector<storm::expressions::Variable> allCommandVariables;
@@ -1647,14 +1662,14 @@ namespace storm {
                             allCommandVariables.push_back(commandVariables[outerIndex].back());
                             solver->add(implies(commandVariables[outerIndex].back(), possibleCommands[outerIndex][innerIndex].get().getGuardExpression()));
                         }
-                        
+
                         storm::expressions::Expression atLeastOneCommandFromModule = manager->boolean(false);
                         for (auto const& commandVariable : commandVariables[outerIndex]) {
                             atLeastOneCommandFromModule = atLeastOneCommandFromModule || commandVariable;
                         }
                         solver->add(atLeastOneCommandFromModule);
                     }
-                    
+
                     // Now we are in a position to start the enumeration over all command variables. While doing so, we
                     // keep track of previously seen command combinations, because the AllSat procedures are not
                     // always guaranteed to only provide distinct models.
@@ -1662,7 +1677,7 @@ namespace storm {
                     solver->allSat(allCommandVariables, [&] (storm::solver::SmtSolver::ModelReference& modelReference) -> bool {
                         // Now we need to reconstruct the chosen commands from the valuation of the command variables.
                         std::vector<std::vector<std::reference_wrapper<Command const>>> chosenCommands(possibleCommands.size());
-                        
+
                         for (uint_fast64_t outerIndex = 0; outerIndex < commandVariables.size(); ++outerIndex) {
                             for (uint_fast64_t innerIndex = 0; innerIndex < commandVariables[outerIndex].size(); ++innerIndex) {
                                 if (modelReference.getBooleanValue(commandVariables[outerIndex][innerIndex])) {
@@ -1670,14 +1685,14 @@ namespace storm {
                                 }
                             }
                         }
-                        
+
                         // Now that we have retrieved the commands, we need to build their synchronizations and add them
                         // to the flattened module.
                         std::vector<std::vector<std::reference_wrapper<Command const>>::const_iterator> iterators;
                         for (auto const& element : chosenCommands) {
                             iterators.push_back(element.begin());
                         }
-                        
+
                         bool movedAtLeastOneIterator = false;
                         std::vector<std::reference_wrapper<Command const>> commandCombination(chosenCommands.size(), chosenCommands.front().front());
                         std::vector<uint_fast64_t> commandCombinationIndices(iterators.size());
@@ -1686,7 +1701,7 @@ namespace storm {
                                 commandCombination[index] = *iterators[index];
                                 commandCombinationIndices[index] = commandCombination[index].get().getGlobalIndex();
                             }
-                            
+
                             // Only add the command combination if it was not previously seen.
                             auto seenIt = seenCommandCombinations.find(commandCombinationIndices);
                             if (seenIt == seenCommandCombinations.end()) {
@@ -1697,7 +1712,7 @@ namespace storm {
                                 ++nextCommandIndex;
                                 nextUpdateIndex += newCommands.back().getNumberOfUpdates();
                             }
-                            
+
                             movedAtLeastOneIterator = false;
                             for (uint_fast64_t index = 0; index < iterators.size(); ++index) {
                                 ++iterators[index];
@@ -1709,18 +1724,18 @@ namespace storm {
                                 }
                             }
                         } while (movedAtLeastOneIterator);
-                        
+
                         return true;
                     });
-                    
+
                     solver->pop();
                 }
             }
-            
+
             // Finally, we can create the module and the program and return it.
             storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, allClockVariables, newInvariant, newCommands, this->getFilename(), 0);
-            
-            return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility, this->getFilename(), 0, true);
+
+            return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), this->getPlayers(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility, this->getFilename(), 0, true);
         }
 
         std::vector<Constant> Program::usedConstants() const {
@@ -1804,7 +1819,7 @@ namespace storm {
             }
             return res;
         }
-        
+
         std::unordered_map<uint_fast64_t, std::string> Program::buildActionIndexToActionNameMap() const {
             std::unordered_map<uint_fast64_t, std::string> res;
             for(auto const& nameIndexPair : actionToIndexMap) {
@@ -1812,7 +1827,7 @@ namespace storm {
             }
             return res;
         }
-        
+
         std::unordered_map<uint_fast64_t, uint_fast64_t> Program::buildCommandIndexToActionIndex() const {
             std::unordered_map<uint_fast64_t, uint_fast64_t> res;
             for(auto const& m : this->modules) {
@@ -1821,9 +1836,9 @@ namespace storm {
                 }
             }
             return res;
-            
+
         }
-        
+
         Command Program::synchronizeCommands(uint_fast64_t newCommandIndex, uint_fast64_t actionIndex, uint_fast64_t firstUpdateIndex, std::string const& actionName, std::vector<std::reference_wrapper<Command const>> const& commands) const {
             // To construct the synchronous product of the commands, we need to store a list of its updates.
             std::vector<storm::prism::Update> newUpdates;
@@ -1832,13 +1847,13 @@ namespace storm {
                 numberOfUpdates *= commands[i].get().getNumberOfUpdates();
             }
             newUpdates.reserve(numberOfUpdates);
-            
+
             // Initialize all update iterators.
             std::vector<std::vector<storm::prism::Update>::const_iterator> updateIterators;
             for (uint_fast64_t i = 0; i < commands.size(); ++i) {
                 updateIterators.push_back(commands[i].get().getUpdates().cbegin());
             }
-            
+
             bool doneUpdates = false;
             do {
                 // We create the new likelihood expression by multiplying the particapting updates' expressions.
@@ -1846,17 +1861,17 @@ namespace storm {
                 for (uint_fast64_t i = 1; i < updateIterators.size(); ++i) {
                     newLikelihoodExpression = newLikelihoodExpression * updateIterators[i]->getLikelihoodExpression();
                 }
-                
+
                 // Now concatenate all assignments of all participating updates.
                 std::vector<storm::prism::Assignment> newAssignments;
                 for (uint_fast64_t i = 0; i < updateIterators.size(); ++i) {
                     newAssignments.insert(newAssignments.end(), updateIterators[i]->getAssignments().begin(), updateIterators[i]->getAssignments().end());
                 }
-                
+
                 // Then we are ready to create the new update.
                 newUpdates.push_back(storm::prism::Update(firstUpdateIndex, newLikelihoodExpression, newAssignments, this->getFilename(), 0));
                 ++firstUpdateIndex;
-                
+
                 // Now check whether there is some update combination we have not yet explored.
                 bool movedIterator = false;
                 for (int_fast64_t j = updateIterators.size() - 1; j >= 0; --j) {
@@ -1869,18 +1884,18 @@ namespace storm {
                         updateIterators[j] = commands[j].get().getUpdates().cbegin();
                     }
                 }
-                
+
                 doneUpdates = !movedIterator;
             } while (!doneUpdates);
-            
+
             storm::expressions::Expression newGuard = commands[0].get().getGuardExpression();
             for (uint_fast64_t i = 1; i < commands.size(); ++i) {
                 newGuard = newGuard && commands[i].get().getGuardExpression();
             }
-            
+
             return Command(newCommandIndex, false, actionIndex, actionName, newGuard, newUpdates, this->getFilename(), 0);
         }
-        
+
         storm::jani::Model Program::toJani(bool allVariablesGlobal, std::string suffix) const {
             ToJaniConverter converter;
             auto janiModel = converter.convert(*this, allVariablesGlobal, {}, suffix);
@@ -1903,7 +1918,7 @@ namespace storm {
             if (converter.labelsWereRenamed() || converter.rewardModelsWereRenamed()) {
                 newProperties = converter.applyRenaming(properties);
             } else {
-                newProperties = properties;  // Nothing to be done here. Notice that the copy operation is suboptimal. 
+                newProperties = properties;  // Nothing to be done here. Notice that the copy operation is suboptimal.
             }
             return std::make_pair(janiModel, newProperties);
         }
@@ -1911,7 +1926,7 @@ namespace storm {
         storm::expressions::ExpressionManager& Program::getManager() const {
             return *this->manager;
         }
-        
+
         void Program::createMissingInitialValues() {
             for (auto& variable : globalBooleanVariables) {
                 if (!variable.hasInitialValue()) {
@@ -1924,7 +1939,7 @@ namespace storm {
                 }
             }
         }
-        
+
         std::ostream& operator<<(std::ostream& out, Program::ModelType const& type) {
             switch (type) {
                 case Program::ModelType::UNDEFINED: out << "undefined"; break;
@@ -1935,17 +1950,22 @@ namespace storm {
                 case Program::ModelType::MA: out << "ma"; break;
                 case Program::ModelType::POMDP: out << "pomdp"; break;
                 case Program::ModelType::PTA: out << "pta"; break;
+                case Program::ModelType::SMG: out << "smg"; break;
             }
             return out;
         }
-        
+
         std::ostream& operator<<(std::ostream& stream, Program const& program) {
             stream << program.getModelType() << std::endl;
             for (auto const& constant : program.getConstants()) {
                 stream << constant << std::endl;
             }
             stream << std::endl;
-            
+
+            for (auto const& player : program.getPlayers()) {
+                stream << player << std::endl;
+            }
+
             for (auto const& variable : program.getGlobalBooleanVariables()) {
                 stream << "global " << variable << std::endl;
             }
@@ -1953,36 +1973,36 @@ namespace storm {
                 stream << "global " << variable << std::endl;
             }
             stream << std::endl;
-            
+
             for (auto const& formula : program.getFormulas()) {
                 stream << formula << std::endl;
             }
             stream << std::endl;
-            
+
             for (auto const& module : program.getModules()) {
                 stream << module << std::endl;
             }
-            
+
             for (auto const& rewardModel : program.getRewardModels()) {
                 stream << rewardModel << std::endl;
             }
-            
+
             for (auto const& label : program.getLabels()) {
                 stream << label << std::endl;
             }
-            
+
             if (program.hasInitialConstruct()) {
                 stream << program.getInitialConstruct() << std::endl;
             }
-            
+
             if (program.specifiesSystemComposition()) {
                 stream << program.getSystemCompositionConstruct();
             }
-            
+
             return stream;
         }
-        
-        
-        
+
+
+
     } // namespace prism
 } // namepsace storm
diff --git a/src/storm/storage/prism/Program.h b/src/storm/storage/prism/Program.h
index 0860dd913..095f164ff 100644
--- a/src/storm/storage/prism/Program.h
+++ b/src/storm/storage/prism/Program.h
@@ -15,6 +15,7 @@
 #include "storm/storage/prism/SystemCompositionConstruct.h"
 #include "storm/storage/prism/InitialConstruct.h"
 #include "storm/storage/prism/Composition.h"
+#include "storm/storage/prism/Player.h"
 #include "storm/storage/BoostTypes.h"
 #include "storm/utility/solver.h"
 #include "storm/utility/OsDetection.h"
@@ -24,17 +25,17 @@ namespace storm {
         class Model;
         class Property;
     }
-    
+
     namespace prism {
         class Program : public LocatedInformation {
         public:
             /*!
              * An enum for the different model types.
              */
-            enum class ModelType {UNDEFINED, DTMC, CTMC, MDP, CTMDP, MA, POMDP, PTA};
-            
+            enum class ModelType {UNDEFINED, DTMC, CTMC, MDP, CTMDP, MA, POMDP, PTA, SMG};
+
             enum class ValidityCheckLevel  : unsigned {VALIDINPUT = 0, READYFORPROCESSING = 1};
-            
+
             /*!
              * Creates a program with the given model type, undefined constants, global variables, modules, reward
              * models, labels and initial states.
@@ -57,8 +58,8 @@ namespace storm {
              * @param lineNumber The line number in which the program is defined.
              * @param finalModel If set to true, the program is checked for input-validity, as well as some post-processing.
              */
-            Program(std::shared_ptr<storm::expressions::ExpressionManager> manager, ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Module> const& modules, std::map<std::string, uint_fast64_t> const& actionToIndexMap, std::vector<RewardModel> const& rewardModels, std::vector<Label> const& labels, std::vector<ObservationLabel> const& observationLabels, boost::optional<InitialConstruct> const& initialConstruct, boost::optional<SystemCompositionConstruct> const& compositionConstruct, bool prismCompatibility, std::string const& filename = "", uint_fast64_t lineNumber = 0, bool finalModel = true);
-            
+            Program(std::shared_ptr<storm::expressions::ExpressionManager> manager, ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Player> const& players, std::vector<Module> const& modules, std::map<std::string, uint_fast64_t> const& actionToIndexMap, std::vector<RewardModel> const& rewardModels, std::vector<Label> const& labels, std::vector<ObservationLabel> const& observationLabels, boost::optional<InitialConstruct> const& initialConstruct, boost::optional<SystemCompositionConstruct> const& compositionConstruct, bool prismCompatibility, std::string const& filename = "", uint_fast64_t lineNumber = 0, bool finalModel = true);
+
             // Provide default implementations for constructors and assignments.
             Program() = default;
             Program(Program const& other) = default;
@@ -72,14 +73,14 @@ namespace storm {
              * @return The type of the model.
              */
             ModelType getModelType() const;
-            
+
             /*!
              * Retrieves whether the model is a discrete-time model, i.e. a DTMC or an MDP.
              *
              * @return True iff the model is a discrete-time model.
              */
             bool isDiscreteTimeModel() const;
-            
+
             /*!
              * Retrieves whether the model is one without nondeterministic choices, i.e. a DTMC or a CTMC.
              */
@@ -102,10 +103,10 @@ namespace storm {
              * That is, undefined constants may only appear in the probability expressions of updates as well as in the
              * values in reward models.
              *
-             * @return True iff the undefined constants are graph-preserving. 
+             * @return True iff the undefined constants are graph-preserving.
              */
             bool undefinedConstantsAreGraphPreserving() const;
-            
+
             /*!
              * Retrieves the undefined constants in the program.
              *
@@ -127,7 +128,7 @@ namespace storm {
              * @return True iff the constant exists in the program.
              */
             bool hasConstant(std::string const& constantName) const;
-            
+
             /*!
              * Retrieves the constant with the given name if it exists.
              *
@@ -135,33 +136,33 @@ namespace storm {
              * @return The constant with the given name if it exists.
              */
             Constant const& getConstant(std::string const& constantName) const;
-            
+
             /*!
              * Retrieves a mapping of all defined constants to their defining expressions.
              *
              * @return A mapping from constants to their 'values'.
              */
             std::map<storm::expressions::Variable, storm::expressions::Expression> getConstantsSubstitution() const;
-            
+
             /*!
              * Retrieves a mapping of all formula variables to their defining expressions.
              *
              * @return A mapping from constants to their 'values'.
              */
             std::map<storm::expressions::Variable, storm::expressions::Expression> getFormulasSubstitution() const;
-            
+
             /*!
              * Retrieves a mapping of all defined constants and formula variables to their defining expressions
              *
              * @return A mapping from constants and formulas to their expressions.
              */
             std::map<storm::expressions::Variable, storm::expressions::Expression> getConstantsFormulasSubstitution(bool getConstantsSubstitution = true, bool getFormulasSubstitution = true) const;
-            
+
             /*!
              * Applies the renaming of a renamed module to the given substitution.
              */
             std::map<storm::expressions::Variable, storm::expressions::Expression> getSubstitutionForRenamedModule(Module const& renamedModule, std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const;
-            
+
             /*!
              * Gets the renaming of a module after flattening all renamings.
              * Note that the base of a renamed module might again be a renamed module.
@@ -174,7 +175,7 @@ namespace storm {
              * @return The constants defined in the program.
              */
             std::vector<Constant> const& getConstants() const;
-            
+
             /*!
              * Retrieves the number of all constants defined in the program.
              *
@@ -195,20 +196,20 @@ namespace storm {
 
             /*!
              * Retrieves whether a global Boolean variable with the given name exists
-             * 
+             *
              * @param variableName The name of the variable
              * @return true iff a global variable of type Boolean with the given name exists.
              */
             bool globalBooleanVariableExists(std::string const& variableName) const;
-            
+
             /**
              * Retrieves whether a global Integer variable with the given name exists
-             * 
+             *
              * @param variableName The name of the variable
              * @return true iff a global variable of type Integer with the given name exists.
              */
             bool globalIntegerVariableExists(std::string const& variableName) const;
-            
+
             /*!
              * Retrieves the global boolean variables of the program.
              *
@@ -223,7 +224,7 @@ namespace storm {
              * @return The global boolean variable with the given name.
              */
             BooleanVariable const& getGlobalBooleanVariable(std::string const& variableName) const;
-            
+
             /*!
              * Retrieves the global integer variables of the program.
              *
@@ -245,21 +246,21 @@ namespace storm {
              * @return The set of expression variables used by this program.
              */
             std::set<storm::expressions::Variable> getAllExpressionVariables() const;
-            
+
             /*!
              * Retrieves a list of expressions that characterize the legal ranges of all variables.
              *
              * @return A list of expressions that characterize the legal ranges of all variables.
              */
             std::vector<storm::expressions::Expression> getAllRangeExpressions() const;
-            
+
             /*!
              * Retrieves the number of global boolean variables of the program.
              *
              * @return The number of global boolean variables of the program.
              */
             std::size_t getNumberOfGlobalBooleanVariables() const;
-            
+
             /*!
              * Retrieves the number of global integer variables of the program.
              *
@@ -273,21 +274,21 @@ namespace storm {
              * @return The formulas defined in the program.
              */
             std::vector<Formula> const& getFormulas() const;
-            
+
             /*!
              * Retrieves the number of formulas in the program.
              *
              * @return The number of formulas in the program.
              */
             std::size_t getNumberOfFormulas() const;
-            
+
             /*!
              * Retrieves the number of modules in the program.
              *
              * @return The number of modules in the program.
              */
             std::size_t getNumberOfModules() const;
-            
+
             /*!
              * Retrieves the module with the given index.
              *
@@ -302,7 +303,7 @@ namespace storm {
              * @return True iff a module with the given name exists.
              */
             bool hasModule(std::string const& moduleName) const;
-            
+
             /*!
              * Retrieves the module with the given name.
              *
@@ -310,26 +311,47 @@ namespace storm {
              * @return The module with the given name.
              */
             Module const& getModule(std::string const& moduleName) const;
-            
+
             /*!
              * Retrieves all modules of the program.
              *
              * @return All modules of the program.
              */
             std::vector<Module> const& getModules() const;
-            
+
+            /*!
+             * Retrieves the players of the program.
+             *
+             * @return The players of the program.
+             */
+            std::vector<Player> const& getPlayers() const;
+
+            /*!
+             * Retrieves the number of players in the program.
+             *
+             * @return The number of players in the program.
+             */
+            std::size_t getNumberOfPlayers() const;
+
+            /*!
+             * Retrieves the index of the player in the program.
+             *
+             * @return The index of the player in the program.
+             */
+            uint_fast32_t const& getIndexOfPlayer(std::string playerName) const;
+
             /*!
              * Retrieves the mapping of action names to their indices.
              *
              * @return The mapping of action names to their indices.
              */
             std::map<std::string, uint_fast64_t> const& getActionNameToIndexMapping() const;
-            
+
             /*!
              * Retrieves whether the program specifies an initial construct.
              */
             bool hasInitialConstruct() const;
-            
+
             /*!
              * Retrieves the initial construct of the program.
              *
@@ -350,7 +372,7 @@ namespace storm {
              * @return an expression characterizing the initial states.
              */
             storm::expressions::Expression getInitialStatesExpression() const;
-            
+
             /*!
              * Retrieves whether the program specifies a system composition in terms of process algebra operations over
              * the modules.
@@ -358,42 +380,42 @@ namespace storm {
              * @return True iff the program specifies a system composition.
              */
             bool specifiesSystemComposition() const;
-            
+
             /*!
              * If the program specifies a system composition construct, this method retrieves it.
              *
              * @return The system composition construct as specified by the program.
              */
             SystemCompositionConstruct const& getSystemCompositionConstruct() const;
-            
+
             /*!
              * Retrieves the system composition construct (if any) and none otherwise.
              *
              * @return The system composition construct specified by the program or none.
              */
             boost::optional<SystemCompositionConstruct> getOptionalSystemCompositionConstruct() const;
-            
+
             /*!
              * Retrieves the default system composition for this program.
              *
              * @return The default system composition.
              */
             std::shared_ptr<Composition> getDefaultSystemComposition() const;
-            
+
             /*!
              * Retrieves the set of actions present in the program.
              *
              * @return The set of actions present in the program.
              */
             std::set<std::string> const& getActions() const;
-            
+
             /*!
              * Retrieves the set of synchronizing action indices present in the program.
              *
              * @return The set of synchronizing action indices present in the program.
              */
             std::set<uint_fast64_t> const& getSynchronizingActionIndices() const;
-            
+
             /*!
              * Retrieves the action name of the given action index.
              *
@@ -401,7 +423,7 @@ namespace storm {
              * @return The name of the action.
              */
             std::string const& getActionName(uint_fast64_t actionIndex) const;
-            
+
             /*!
              * Retrieves the index of the action with the given name.
              *
@@ -409,7 +431,7 @@ namespace storm {
              * @return The index of the action.
              */
             uint_fast64_t getActionIndex(std::string const& actionName) const;
-            
+
             /*!
              * Retrieves whether the program has an action with the given name.
              *
@@ -423,7 +445,7 @@ namespace storm {
              * @return True iff the program has an action with the given index.
              */
             bool hasAction(uint_fast64_t const& actionIndex) const;
-            
+
             /*!
              * Retrieves the indices of all modules within this program that contain commands that are labelled with the
              * given action.
@@ -441,7 +463,7 @@ namespace storm {
              * @return A set of indices of all matching modules.
              */
             std::set<uint_fast64_t> const& getModuleIndicesByActionIndex(uint_fast64_t actionIndex) const;
-            
+
             /*!
              * Retrieves the index of the module in which the given variable name was declared.
              *
@@ -449,7 +471,7 @@ namespace storm {
              * @return The index of the module in which the given variable name was declared.
              */
             uint_fast64_t getModuleIndexByVariable(std::string const& variableName) const;
-            
+
             /*!
              * Retrieves the index of the module and the (local) index of the command with the given global command index.
              *
@@ -474,7 +496,7 @@ namespace storm {
              * @return True iff the program has at least one reward model.
              */
             bool hasRewardModel() const;
-            
+
             /*!
              * Retrieves whether the program has a reward model with the given name.
              *
@@ -482,21 +504,21 @@ namespace storm {
              * @return True iff the program has a reward model with the given name.
              */
             bool hasRewardModel(std::string const& name) const;
-            
+
             /*!
              * Retrieves the reward models of the program.
              *
              * @return The reward models of the program.
              */
             std::vector<RewardModel> const& getRewardModels() const;
-            
+
             /*!
              * Retrieves the number of reward models in the program.
              *
              * @return The number of reward models in the program.
              */
             std::size_t getNumberOfRewardModels() const;
-            
+
             /*!
              * Retrieves the reward model with the given name.
              *
@@ -504,7 +526,7 @@ namespace storm {
              * @return The reward model with the given name.
              */
             RewardModel const& getRewardModel(std::string const& rewardModelName) const;
-            
+
             /*!
              * Retrieves the reward model with the given index.
              *
@@ -512,7 +534,7 @@ namespace storm {
              * @return The reward model with the given index.
              */
             RewardModel const& getRewardModel(uint_fast64_t index) const;
-            
+
             /*!
              * Checks whether the program has a label with the given name.
              *
@@ -520,7 +542,7 @@ namespace storm {
              * @return True iff the label of the program.
              */
             bool hasLabel(std::string const& labelName) const;
-            
+
             /*!
              * Retrieves all labels that are defined by the probabilitic program.
              *
@@ -535,21 +557,21 @@ namespace storm {
              * @return All guards appearing in the program.
              */
             std::vector<storm::expressions::Expression> getAllGuards(bool negated = false) const;
-            
+
             /*!
              * Retrieves the expression associated with the given label, if it exists.
              *
              * @param labelName The name of the label to retrieve.
              */
             storm::expressions::Expression const& getLabelExpression(std::string const& label) const;
-            
+
             /*!
              * Retrieves a mapping from all labels in the program to their defining expressions.
              *
              * @return A mapping from label names to their expressions.
              */
             std::map<std::string, storm::expressions::Expression> getLabelToExpressionMapping() const;
-            
+
             /*!
              * Retrieves the number of labels in the program.
              *
@@ -564,14 +586,14 @@ namespace storm {
              * @param statePredicateExpression The predicate that is described by the label.
              */
             void addLabel(std::string const& name, storm::expressions::Expression const& statePredicateExpression);
-            
+
             /*!
              * Removes the label with the given name from the program.
              *
              * @param name The name of a label that exists within the program.
              */
             void removeLabel(std::string const& name);
-            
+
             /*!
              * Removes all labels that are not contained in the given set from the program. Note: no check is performed
              * as to whether or not the given label names actually exist.
@@ -595,14 +617,14 @@ namespace storm {
              * @return The number of labels in the program.
              */
             std::size_t getNumberOfObservationLabels() const;
-            
+
             /*!
              * Creates a new program that drops all commands whose indices are not in the given set.
              *
              * @param indexSet The set of indices for which to keep the commands.
              */
             Program restrictCommands(storm::storage::FlatSet<uint_fast64_t> const& indexSet) const;
-            
+
             /*!
              * Defines the undefined constants according to the given map and returns the resulting program.
              *
@@ -612,7 +634,7 @@ namespace storm {
              * definitions.
              */
             Program defineUndefinedConstants(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const;
-            
+
             /*!
              * Substitutes all constants appearing in the expressions of the program by their defining expressions. For
              * this to work, all constants need to be defined prior to calling this.
@@ -620,7 +642,7 @@ namespace storm {
              * @return The resulting program that only contains expressions over variables of the program (and maybe formulas).
              */
             Program substituteConstants() const;
-            
+
             /*!
              * Substitutes all formulas appearing in the expressions of the program by their defining expressions.
              *
@@ -628,7 +650,7 @@ namespace storm {
              * @return The resulting program that only contains expressions over variables of the program (and maybe constants).
              */
             Program substituteFormulas() const;
-            
+
             /*!
              * Substitutes all constants and/or formulas appearing in the expressions of the program by their defining expressions. For
              * this to work, all constants need to be defined prior to calling this.
@@ -636,19 +658,19 @@ namespace storm {
              * @return The resulting program that only contains expressions over variables of the program.
              */
             Program substituteConstantsFormulas(bool substituteConstants = true, bool substituteFormulas = true) const;
-            
+
             /**
-             * Entry point for static analysis for simplify. As we use the same expression manager, we recommend to not use the original program any further. 
+             * Entry point for static analysis for simplify. As we use the same expression manager, we recommend to not use the original program any further.
              * @return A simplified, equivalent program.
              */
             Program simplify();
-            
+
             /*!
              * Checks the validity of the program. If the program is not valid, an exception is thrown with a message
              * that indicates the source of the problem.
              */
             void checkValidity(Program::ValidityCheckLevel lvl = Program::ValidityCheckLevel::READYFORPROCESSING) const;
-            
+
             /*!
              * Creates an equivalent program that contains exactly one module.
              *
@@ -656,16 +678,16 @@ namespace storm {
              * @return The resulting program.
              */
             Program flattenModules(std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory = std::shared_ptr<storm::utility::solver::SmtSolverFactory>(new storm::utility::solver::SmtSolverFactory())) const;
-            
+
             friend std::ostream& operator<<(std::ostream& stream, Program const& program);
-            
+
             /*!
              * Retrieves the manager responsible for the expressions of this program.
              *
              * @return The manager responsible for the expressions of this program.
              */
             storm::expressions::ExpressionManager& getManager() const;
-            
+
             std::unordered_map<uint_fast64_t, std::string> buildCommandIndexToActionNameMap() const;
 
             std::unordered_map<uint_fast64_t, uint_fast64_t> buildCommandIndexToActionIndex() const;
@@ -676,14 +698,14 @@ namespace storm {
              * Converts the PRISM model into an equivalent JANI model.
              */
             storm::jani::Model toJani(bool allVariablesGlobal = true, std::string suffix = "") const;
-            
+
             /*!
              * Converts the PRISM model into an equivalent JANI model and if labels or reward models had
              * to be renamed in the process, the renamings are applied to the given properties
              * @return The jani model of this and either the new set of properties or an empty vector if no renamings were necessary
              */
             std::pair<storm::jani::Model, std::vector<storm::jani::Property>> toJani(std::vector<storm::jani::Property> const& properties, bool allVariablesGlobal = true, std::string suffix = "") const;
-            
+
         private:
             /*!
              * This function builds a command that corresponds to the synchronization of the given list of commands.
@@ -696,95 +718,101 @@ namespace storm {
              * @return The resulting command.
              */
             Command synchronizeCommands(uint_fast64_t newCommandIndex, uint_fast64_t actionIndex, uint_fast64_t firstUpdateIndex, std::string const& actionName, std::vector<std::reference_wrapper<Command const>> const& commands) const;
-            
+
             /*!
              * Equips all global variables without initial values with initial values based on their type.
              */
             void createMissingInitialValues();
-            
+
             // The manager responsible for the variables/expressions of the program.
             std::shared_ptr<storm::expressions::ExpressionManager> manager;
-            
+
             // Creates the internal mappings.
             void createMappings();
-            
+
             // The type of the model.
             ModelType modelType;
-            
+
             // The constants of the program.
             std::vector<Constant> constants;
-            
+
             // A mapping from constant names to their corresponding indices.
             std::map<std::string, uint_fast64_t> constantToIndexMap;
 
             // The global boolean variables.
             std::vector<BooleanVariable> globalBooleanVariables;
-            
+
             // A mapping from global boolean variable names to their corresponding indices.
             std::map<std::string, uint_fast64_t> globalBooleanVariableToIndexMap;
-            
+
             // The global integer variables.
             std::vector<IntegerVariable> globalIntegerVariables;
-            
+
             // A mapping from global integer variable names to their corresponding indices.
             std::map<std::string, uint_fast64_t> globalIntegerVariableToIndexMap;
-            
+
             // The formulas defined in the program.
             std::vector<Formula> formulas;
-            
+
             // A mapping of formula names to their corresponding indices.
             std::map<std::string, uint_fast64_t> formulaToIndexMap;
-            
+
             // The modules associated with the program.
             std::vector<Module> modules;
-            
+
             // A mapping of module names to their indices.
             std::map<std::string, uint_fast64_t> moduleToIndexMap;
-            
+
+            // The players associated with the program.
+            std::vector<Player> players;
+
+            // A mapping of player names to their indices.
+            std::map<std::string, uint_fast64_t> playerToIndexMap;
+
             // The reward models associated with the program.
             std::vector<RewardModel> rewardModels;
-            
+
             // A mapping of reward models to their indices.
             std::map<std::string, uint_fast64_t> rewardModelToIndexMap;
-            
+
             // The initial construct of the program.
             boost::optional<InitialConstruct> initialConstruct;
-            
+
             // If set, this specifies the way the modules are composed to obtain the full system.
             boost::optional<SystemCompositionConstruct> systemCompositionConstruct;
-            
+
             // The labels that are defined for this model.
             std::vector<Label> labels;
-            
+
             // A mapping from labels to their indices.
             std::map<std::string, uint_fast64_t> labelToIndexMap;
 
             // Observation labels
             std::vector<ObservationLabel> observationLabels;
-            
+
             // A mapping from action names to their indices.
             std::map<std::string, uint_fast64_t> actionToIndexMap;
 
             // A mapping from action indices to their names.
             std::map<uint_fast64_t, std::string> indexToActionMap;
-            
+
             // The set of actions present in this program.
             std::set<std::string> actions;
 
             // The set of synchronizing actions present in this program.
             std::set<uint_fast64_t> synchronizingActionIndices;
-            
+
             // A map of actions to the set of modules containing commands labelled with this action.
             std::map<uint_fast64_t, std::set<uint_fast64_t>> actionIndicesToModuleIndexMap;
-            
+
             // A mapping from variable names to the modules in which they were declared.
             std::map<std::string, uint_fast64_t> variableToModuleIndexMap;
 
             bool prismCompatibility;
         };
-        
+
         std::ostream& operator<<(std::ostream& out, Program::ModelType const& type);
-        
+
     } // namespace prism
 } // namespace storm
 
diff --git a/src/storm/storage/sparse/ModelComponents.h b/src/storm/storage/sparse/ModelComponents.h
index ca325b73c..29ae3d14b 100644
--- a/src/storm/storage/sparse/ModelComponents.h
+++ b/src/storm/storage/sparse/ModelComponents.h
@@ -21,35 +21,37 @@
 namespace storm {
     namespace storage {
         namespace sparse {
-            
+
             template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
             struct ModelComponents {
-                
+
                 ModelComponents(storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
                                 storm::models::sparse::StateLabeling const& stateLabeling = storm::models::sparse::StateLabeling(),
                                 std::unordered_map<std::string, RewardModelType> const& rewardModels =  std::unordered_map<std::string, RewardModelType>(),
                                 bool rateTransitions = false,
                                 boost::optional<storm::storage::BitVector> const& markovianStates = boost::none,
-                                boost::optional<storm::storage::SparseMatrix<storm::storage::sparse::state_type>> const& player1Matrix = boost::none)
-                        : transitionMatrix(transitionMatrix), stateLabeling(stateLabeling), rewardModels(rewardModels), rateTransitions(rateTransitions), markovianStates(markovianStates), player1Matrix(player1Matrix) {
+                                boost::optional<storm::storage::SparseMatrix<storm::storage::sparse::state_type>> const& player1Matrix = boost::none,
+                                boost::optional<std::vector<uint_fast32_t>> const& playerActionIndices = boost::none)
+                        : transitionMatrix(transitionMatrix), stateLabeling(stateLabeling), rewardModels(rewardModels), rateTransitions(rateTransitions), markovianStates(markovianStates), player1Matrix(player1Matrix), playerActionIndices(playerActionIndices) {
                     // Intentionally left empty
                 }
-              
+
                 ModelComponents(storm::storage::SparseMatrix<ValueType>&& transitionMatrix = storm::storage::SparseMatrix<ValueType>(),
                                 storm::models::sparse::StateLabeling&& stateLabeling = storm::models::sparse::StateLabeling(),
                                 std::unordered_map<std::string, RewardModelType>&& rewardModels =  std::unordered_map<std::string, RewardModelType>(),
                                 bool rateTransitions = false,
                                 boost::optional<storm::storage::BitVector>&& markovianStates = boost::none,
-                                boost::optional<storm::storage::SparseMatrix<storm::storage::sparse::state_type>>&& player1Matrix = boost::none)
-                        : transitionMatrix(std::move(transitionMatrix)), stateLabeling(std::move(stateLabeling)), rewardModels(std::move(rewardModels)), rateTransitions(rateTransitions), markovianStates(std::move(markovianStates)), player1Matrix(std::move(player1Matrix)) {
+                                boost::optional<storm::storage::SparseMatrix<storm::storage::sparse::state_type>>&& player1Matrix = boost::none,
+                                boost::optional<std::vector<uint_fast32_t>>&& playerActionIndices = boost::none)
+                        : transitionMatrix(std::move(transitionMatrix)), stateLabeling(std::move(stateLabeling)), rewardModels(std::move(rewardModels)), rateTransitions(rateTransitions), markovianStates(std::move(markovianStates)), player1Matrix(std::move(player1Matrix)), playerActionIndices(std::move(playerActionIndices)) {
                     // Intentionally left empty
                 }
-                
-                
-                
-                
+
+
+
+
                 // General components (applicable for all model types):
-                
+
                 // The transition matrix.
                 storm::storage::SparseMatrix<ValueType> transitionMatrix;
                 // The state labeling.
@@ -80,7 +82,11 @@ namespace storm {
                 // Stochastic two player game specific components:
                 // The matrix of player 1 choices (needed for stochastic two player games
                 boost::optional<storm::storage::SparseMatrix<storm::storage::sparse::state_type>> player1Matrix;
+
+                // Stochastic multiplayer game specific components:
+                // The vector mapping state choices to players
+                boost::optional<std::vector<uint_fast32_t>> playerActionIndices;
             };
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/storm/utility/builder.cpp b/src/storm/utility/builder.cpp
index 481ed8020..0caa0edb3 100644
--- a/src/storm/utility/builder.cpp
+++ b/src/storm/utility/builder.cpp
@@ -6,13 +6,14 @@
 #include "storm/models/sparse/Mdp.h"
 #include "storm/models/sparse/Pomdp.h"
 #include "storm/models/sparse/MarkovAutomaton.h"
+#include "storm/models/sparse/Smg.h"
 
 #include "storm/exceptions/InvalidModelException.h"
 
 namespace storm {
     namespace utility {
         namespace builder {
-            
+
             template<typename ValueType, typename RewardModelType>
             std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents<ValueType, RewardModelType>&& components) {
                 switch (modelType) {
@@ -28,10 +29,12 @@ namespace storm {
                         return std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>>(std::move(components));
                     case storm::models::ModelType::S2pg:
                         return std::make_shared<storm::models::sparse::StochasticTwoPlayerGame<ValueType, RewardModelType>>(std::move(components));
+                    case storm::models::ModelType::Smg:
+                        return std::make_shared<storm::models::sparse::Smg<ValueType, RewardModelType>>(std::move(components));
                 }
                 STORM_LOG_THROW(false, storm::exceptions::InvalidModelException, "Unknown model type");
             }
-            
+
             template std::shared_ptr<storm::models::sparse::Model<double>> buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents<double>&& components);
             template std::shared_ptr<storm::models::sparse::Model<double, storm::models::sparse::StandardRewardModel<storm::Interval>>> buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents<double, storm::models::sparse::StandardRewardModel<storm::Interval>>&& components);
             template std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents<storm::RationalNumber>&& components);