From 0cd148c60020bf5f3adbbaf23e6aedb52e3cb331 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 18 Sep 2015 21:19:49 +0200 Subject: [PATCH] fixed more bugs. however, a test still fails, because the abstraction is wrong Former-commit-id: 6e326acaf3c89621f0e6861736ca6d7f60c99a85 --- .../prism/menu_games/AbstractCommand.cpp | 22 +- .../prism/menu_games/AbstractProgram.cpp | 2 + .../prism/menu_games/VariablePartition.cpp | 69 ++++--- .../abstraction/PrismMenuGameTest.cpp | 193 +++++++++++++++++- 4 files changed, 237 insertions(+), 49 deletions(-) diff --git a/src/storage/prism/menu_games/AbstractCommand.cpp b/src/storage/prism/menu_games/AbstractCommand.cpp index 267ee38b6..bd019a4a9 100644 --- a/src/storage/prism/menu_games/AbstractCommand.cpp +++ b/src/storage/prism/menu_games/AbstractCommand.cpp @@ -56,9 +56,8 @@ namespace storm { bool recomputeDd = this->relevantPredicatesChanged(newRelevantPredicates); if (!recomputeDd) { // If the new predicates are unrelated to the BDD of this command, we need to multiply their identities. - for (auto predicateIndex : predicates) { - cachedDd.first &= ddInformation.predicateIdentities[predicateIndex]; - } + cachedDd.first &= computeMissingGlobalIdentities(); + cachedDd.first.toAdd().exportToDot("cmd" + std::to_string(command.get().getGlobalIndex()) + ".dot"); } else { // If the DD needs recomputation, it is because of new relevant predicates, so we need to assert the appropriate clauses in the solver. addMissingPredicates(newRelevantPredicates); @@ -71,12 +70,11 @@ namespace storm { template void AbstractCommand::recomputeCachedBdd() { STORM_LOG_TRACE("Recomputing BDD for command " << command.get()); - std::cout << "recomputing " << command.get() << std::endl; - + // Create a mapping from source state DDs to their distributions. std::unordered_map, std::vector>> sourceToDistributionsMap; uint_fast64_t modelCounter = 0; - smtSolver->allSat(decisionVariables, [&sourceToDistributionsMap,this,&modelCounter] (storm::solver::SmtSolver::ModelReference const& model) { sourceToDistributionsMap[getSourceStateBdd(model)].push_back(getDistributionBdd(model)); ++modelCounter; std::cout << "model cnt: " << modelCounter << std::endl; return true; } ); + smtSolver->allSat(decisionVariables, [&sourceToDistributionsMap,this,&modelCounter] (storm::solver::SmtSolver::ModelReference const& model) { sourceToDistributionsMap[getSourceStateBdd(model)].push_back(getDistributionBdd(model)); return true; } ); // Now we search for the maximal number of choices of player 2 to determine how many DD variables we // need to encode the nondeterminism. @@ -112,6 +110,7 @@ namespace storm { STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); // Cache the result. + resultBdd.toAdd().exportToDot("cmd" + std::to_string(command.get().getGlobalIndex()) + ".dot"); cachedDd = std::make_pair(resultBdd, numberOfVariablesNeeded); } @@ -122,11 +121,6 @@ namespace storm { // To start with, all predicates related to the guard are relevant source predicates. result.first = variablePartition.getExpressionsUsingVariables(command.get().getGuardExpression().getVariables()); - std::cout << "using" << std::endl; - for (auto const& el : result.first) { - std::cout << expressionInformation.predicates[el] << std::endl; - } - std::set assignedVariables; for (auto const& assignment : assignments) { // Also, variables appearing on the right-hand side of an assignment are relevant for source state. @@ -144,12 +138,6 @@ namespace storm { auto const& predicatesRelatedToAssignedVariable = variablePartition.getRelatedExpressions(assignedVariables); - std::cout << variablePartition << std::endl; - std::cout << "related" << std::endl; - for (auto const& el : predicatesRelatedToAssignedVariable) { - std::cout << expressionInformation.predicates[el] << std::endl; - } - result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); return result; diff --git a/src/storage/prism/menu_games/AbstractProgram.cpp b/src/storage/prism/menu_games/AbstractProgram.cpp index c515a9074..476b18aac 100644 --- a/src/storage/prism/menu_games/AbstractProgram.cpp +++ b/src/storage/prism/menu_games/AbstractProgram.cpp @@ -69,6 +69,8 @@ namespace storm { template void AbstractProgram::refine(std::vector const& predicates) { + std::cout << " >>>> refine <<<<<<" << std::endl; + // Add the predicates to the global list of predicates. uint_fast64_t firstNewPredicateIndex = expressionInformation.predicates.size(); expressionInformation.predicates.insert(expressionInformation.predicates.end(), predicates.begin(), predicates.end()); diff --git a/src/storage/prism/menu_games/VariablePartition.cpp b/src/storage/prism/menu_games/VariablePartition.cpp index fc69ac1a4..f48df618f 100644 --- a/src/storage/prism/menu_games/VariablePartition.cpp +++ b/src/storage/prism/menu_games/VariablePartition.cpp @@ -15,6 +15,7 @@ namespace storm { this->variableToBlockMapping[variable] = currentBlock; this->variableToExpressionsMapping[variable] = std::set(); variableBlocks[currentBlock].insert(variable); + ++currentBlock; } // Add all expressions, which might relate some variables. @@ -67,35 +68,42 @@ namespace storm { } void VariablePartition::mergeBlocks(std::set const& blocksToMerge) { - // Determine which block to keep (to merge the other blocks into). - uint_fast64_t blockToKeep = *blocksToMerge.begin(); - // Merge all blocks into the block to keep. std::vector> newVariableBlocks; std::vector> newExpressionBlocks; + + std::set::const_iterator blocksToMergeIt = blocksToMerge.begin(); + std::set::const_iterator blocksToMergeIte = blocksToMerge.end(); + + // Determine which block to keep (to merge the other blocks into). + uint_fast64_t blockToKeep = *blocksToMergeIt; + ++blocksToMergeIt; + for (uint_fast64_t blockIndex = 0; blockIndex < variableBlocks.size(); ++blockIndex) { - - // If the block is the one into which the others are to be merged, we do so. - if (blockIndex == blockToKeep) { - for (auto const& blockToMerge : blocksToMerge) { - if (blockToMerge == blockToKeep) { - continue; - } - - variableBlocks[blockToKeep].insert(variableBlocks[blockToMerge].begin(), variableBlocks[blockToMerge].end()); - expressionBlocks[blockToKeep].insert(expressionBlocks[blockToMerge].begin(), expressionBlocks[blockToMerge].end()); + // If the block is the next one to merge into the block to keep, do so now. + if (blocksToMergeIt != blocksToMergeIte && *blocksToMergeIt == blockIndex && blockIndex != blockToKeep) { + // Adjust the mapping for all variables of the old block. + for (auto const& variable : variableBlocks[blockIndex]) { + variableToBlockMapping[variable] = blockToKeep; + } + + newVariableBlocks[blockToKeep].insert(variableBlocks[blockIndex].begin(), variableBlocks[blockIndex].end()); + newExpressionBlocks[blockToKeep].insert(expressionBlocks[blockIndex].begin(), expressionBlocks[blockIndex].end()); + ++blocksToMergeIt; + } else { + // Otherwise just move the current block to the new partition. + newVariableBlocks.emplace_back(std::move(variableBlocks[blockIndex])); + newExpressionBlocks.emplace_back(std::move(expressionBlocks[blockIndex])); + + // Adjust the mapping for all variables of the old block. + for (auto const& variable : variableBlocks[blockIndex]) { + variableToBlockMapping[variable] = newVariableBlocks.size() - 1; } } - - // Adjust the mapping for all variables we are moving to the new block. - for (auto const& variable : variableBlocks[blockIndex]) { - variableToBlockMapping[variable] = newVariableBlocks.size(); - } - - // Move the current block to the new partition. - newVariableBlocks.emplace_back(std::move(variableBlocks[blockIndex])); - newExpressionBlocks.emplace_back(std::move(expressionBlocks[blockIndex])); } + + variableBlocks = std::move(newVariableBlocks); + expressionBlocks = std::move(newExpressionBlocks); } std::set const& VariablePartition::getBlockOfVariable(storm::expressions::Variable const& variable) const { @@ -157,12 +165,23 @@ namespace storm { std::ostream& operator<<(std::ostream& out, VariablePartition const& partition) { std::vector blocks; - for (auto const& block : partition.variableBlocks) { + for (uint_fast64_t index = 0; index < partition.variableBlocks.size(); ++index) { + auto const& variableBlock = partition.variableBlocks[index]; + auto const& expressionBlock = partition.expressionBlocks[index]; + std::vector variablesInBlock; - for (auto const& variable : block) { + for (auto const& variable : variableBlock) { variablesInBlock.push_back(variable.getName()); } - blocks.push_back("[" + boost::algorithm::join(variablesInBlock, ", ") + "]"); + + std::vector expressionsInBlock; + for (auto const& expression : expressionBlock) { + std::stringstream stream; + stream << partition.expressions[expression]; + expressionsInBlock.push_back(stream.str()); + } + + blocks.push_back("<[" + boost::algorithm::join(variablesInBlock, ", ") + "], [" + boost::algorithm::join(expressionsInBlock, ", ") + "]>"); } out << "{"; diff --git a/test/functional/abstraction/PrismMenuGameTest.cpp b/test/functional/abstraction/PrismMenuGameTest.cpp index 8fdd03cdd..26b41e87a 100644 --- a/test/functional/abstraction/PrismMenuGameTest.cpp +++ b/test/functional/abstraction/PrismMenuGameTest.cpp @@ -193,12 +193,10 @@ TEST(PrismMenuGame, CrowdsFullAbstractionTest) { storm::dd::Add abstraction; ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); - EXPECT_EQ(46, abstraction.getNodeCount()); - storm::dd::Bdd reachableStatesInAbstraction; ASSERT_NO_THROW(reachableStatesInAbstraction = abstractProgram.getReachableStates()); - EXPECT_EQ(13, reachableStatesInAbstraction.getNonZeroCount()); + EXPECT_EQ(8607, reachableStatesInAbstraction.getNonZeroCount()); } TEST(PrismMenuGame, TwoDiceAbstractionTest) { @@ -240,8 +238,66 @@ TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest) { ASSERT_NO_THROW(abstractProgram.refine({manager.getVariableExpression("d1") + manager.getVariableExpression("d2") == manager.integer(7)})); ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); + + EXPECT_EQ(95, abstraction.getNodeCount()); + + storm::dd::Bdd reachableStatesInAbstraction; + ASSERT_NO_THROW(reachableStatesInAbstraction = abstractProgram.getReachableStates()); +} - EXPECT_EQ(107, abstraction.getNodeCount()); +TEST(PrismMenuGame, TwoDiceFullAbstractionTest) { + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); + program = program.substituteConstants(); + program = program.flattenModules(std::make_unique()); + + std::vector initialPredicates; + storm::expressions::ExpressionManager& manager = program.getManager(); + + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(7)); + + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("d1") == manager.integer(6)); + + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(7)); + + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("d2") == manager.integer(6)); + + storm::prism::menu_games::AbstractProgram abstractProgram(program.getManager(), program, initialPredicates, std::make_unique(), false); + + storm::dd::Add abstraction; + ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); + + EXPECT_EQ(1635, abstraction.getNodeCount()); + + storm::dd::Bdd reachableStatesInAbstraction; + ASSERT_NO_THROW(reachableStatesInAbstraction = abstractProgram.getReachableStates()); + + EXPECT_EQ(169, reachableStatesInAbstraction.getNonZeroCount()); } TEST(PrismMenuGame, WlanAbstractionTest) { @@ -261,7 +317,7 @@ TEST(PrismMenuGame, WlanAbstractionTest) { storm::dd::Add abstraction; ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); - EXPECT_EQ(219, abstraction.getNodeCount()); + EXPECT_EQ(221, abstraction.getNodeCount()); } TEST(PrismMenuGame, WlanAbstractionAndRefinementTest) { @@ -281,12 +337,135 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest) { storm::dd::Add abstraction; ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); - EXPECT_EQ(219, abstraction.getNodeCount()); + EXPECT_EQ(221, abstraction.getNodeCount()); ASSERT_NO_THROW(abstractProgram.refine({manager.getVariableExpression("backoff1") < manager.integer(7)})); ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); - EXPECT_EQ(292, abstraction.getNodeCount()); + EXPECT_EQ(287, abstraction.getNodeCount()); +} + +TEST(PrismMenuGame, WlanFullAbstractionTest) { + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm"); + program = program.substituteConstants(); + program = program.flattenModules(std::make_unique()); + + std::vector initialPredicates; + storm::expressions::ExpressionManager& manager = program.getManager(); + + initialPredicates.push_back(manager.getVariableExpression("col") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("col") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("col") == manager.integer(2)); + + initialPredicates.push_back(manager.getVariableExpression("c1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("c1") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("c1") == manager.integer(2)); + + initialPredicates.push_back(manager.getVariableExpression("c2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("c2") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("c2") == manager.integer(2)); + + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("x1") == manager.integer(7)); + + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(7)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(8)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(9)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(10)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(11)); + initialPredicates.push_back(manager.getVariableExpression("s1") == manager.integer(12)); + + initialPredicates.push_back(manager.getVariableExpression("slot1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("slot1") == manager.integer(1)); + + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(7)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(8)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(9)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(10)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(11)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(12)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(13)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(14)); + initialPredicates.push_back(manager.getVariableExpression("backoff1") == manager.integer(15)); + + initialPredicates.push_back(manager.getVariableExpression("bc1") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("bc1") == manager.integer(1)); + + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("x2") == manager.integer(7)); + + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(7)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(8)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(9)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(10)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(11)); + initialPredicates.push_back(manager.getVariableExpression("s2") == manager.integer(12)); + + initialPredicates.push_back(manager.getVariableExpression("slot2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("slot2") == manager.integer(1)); + + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(1)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(2)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(3)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(4)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(5)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(6)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(7)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(8)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(9)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(10)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(11)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(12)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(13)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(14)); + initialPredicates.push_back(manager.getVariableExpression("backoff2") == manager.integer(15)); + + initialPredicates.push_back(manager.getVariableExpression("bc2") == manager.integer(0)); + initialPredicates.push_back(manager.getVariableExpression("bc2") == manager.integer(1)); + + storm::prism::menu_games::AbstractProgram abstractProgram(program.getManager(), program, initialPredicates, std::make_unique(), false); + + storm::dd::Add abstraction; + ASSERT_NO_THROW(abstraction = abstractProgram.getAbstractAdd()); + + EXPECT_EQ(2861, abstraction.getNodeCount()); + + storm::dd::Bdd reachableStatesInAbstraction; + ASSERT_NO_THROW(reachableStatesInAbstraction = abstractProgram.getReachableStates()); + + EXPECT_EQ(37, reachableStatesInAbstraction.getNonZeroCount()); } #endif \ No newline at end of file