|
|
@ -191,7 +191,7 @@ namespace storm { |
|
|
|
std::vector<ValueType> newSubresult = std::vector<ValueType>(relevantStates.getNumberOfSetBits()); |
|
|
|
storm::utility::vector::setVectorValues(newSubresult, statesWithProbabilityGreater0NonPsi % relevantStates, subresult); |
|
|
|
storm::utility::vector::setVectorValues(newSubresult, psiStates % relevantStates, storm::utility::one<ValueType>()); |
|
|
|
|
|
|
|
|
|
|
|
// Then compute the transient probabilities of being in such a state after t time units. For this,
|
|
|
|
// we must re-uniformize the CTMC, so we need to compute the second uniformized matrix.
|
|
|
|
uniformizationRate = storm::utility::zero<ValueType>(); |
|
|
@ -346,7 +346,7 @@ namespace storm { |
|
|
|
weight = std::get<3>(foxGlynnResult)[index - std::get<0>(foxGlynnResult)]; |
|
|
|
storm::utility::vector::applyPointwise(result, values, result, addAndScale); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
@ -408,7 +408,7 @@ namespace storm { |
|
|
|
} |
|
|
|
uniformizationRate *= 1.02; |
|
|
|
STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); |
|
|
|
|
|
|
|
|
|
|
|
storm::storage::SparseMatrix<ValueType> uniformizedMatrix = this->computeUniformizedMatrix(this->getModel().getTransitionMatrix(), storm::storage::BitVector(this->getModel().getNumberOfStates(), true), uniformizationRate, this->getModel().getExitRateVector()); |
|
|
|
|
|
|
|
// Compute the total state reward vector.
|
|
|
@ -477,7 +477,7 @@ namespace storm { |
|
|
|
std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<ValueType>::computeLongRunAverage(storm::logic::StateFormula const& stateFormula, bool qualitative, boost::optional<storm::logic::OptimalityType> const& optimalityType) { |
|
|
|
std::unique_ptr<CheckResult> subResultPointer = this->check(stateFormula); |
|
|
|
ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); |
|
|
|
|
|
|
|
|
|
|
|
storm::storage::SparseMatrix<ValueType> probabilityMatrix = this->computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()); |
|
|
|
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(computeLongRunAverageHelper(probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector(), qualitative, *linearEquationSolverFactory))); |
|
|
|
} |
|
|
@ -502,12 +502,13 @@ namespace storm { |
|
|
|
ValueType one = storm::utility::one<ValueType>(); |
|
|
|
ValueType zero = storm::utility::zero<ValueType>(); |
|
|
|
|
|
|
|
// Prepare the vector holding the LRA values for each of the BSCCs.
|
|
|
|
std::vector<ValueType> bsccLra(bsccDecomposition.size(), zero); |
|
|
|
|
|
|
|
// First we check which states are in BSCCs.
|
|
|
|
storm::storage::BitVector statesInBsccs(numOfStates); |
|
|
|
storm::storage::BitVector firstStatesInBsccs(numOfStates); |
|
|
|
|
|
|
|
std::vector<uint_fast64_t> stateToBsccIndexMap(transitionMatrix.getColumnCount()); |
|
|
|
|
|
|
|
for (uint_fast64_t currentBsccIndex = 0; currentBsccIndex < bsccDecomposition.size(); ++currentBsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[currentBsccIndex]; |
|
|
|
|
|
|
@ -518,99 +519,125 @@ namespace storm { |
|
|
|
if (first) { |
|
|
|
firstStatesInBsccs.set(state); |
|
|
|
} |
|
|
|
stateToBsccIndexMap[state] = currentBsccIndex; |
|
|
|
first = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
firstStatesInBsccs = firstStatesInBsccs % statesInBsccs; |
|
|
|
storm::storage::BitVector statesNotInBsccs = ~statesInBsccs; |
|
|
|
|
|
|
|
// Then we construct an equation system that yields the steady state probabilities for all states in BSCCs.
|
|
|
|
storm::storage::SparseMatrix<ValueType> bsccEquationSystem = transitionMatrix.getSubmatrix(false, statesInBsccs, statesInBsccs, true); |
|
|
|
// Prepare a vector holding the index within all states that are in BSCCs for every state.
|
|
|
|
std::vector<uint_fast64_t> indexInStatesInBsccs; |
|
|
|
|
|
|
|
// Since in the fix point equation, we need to multiply the vector from the left, we convert this to a
|
|
|
|
// multiplication from the right by transposing the system.
|
|
|
|
bsccEquationSystem = bsccEquationSystem.transpose(false, true); |
|
|
|
// Prepare a vector that maps the index within the set of all states in BSCCs to the index of the containing BSCC.
|
|
|
|
std::vector<uint_fast64_t> stateToBsccIndexMap; |
|
|
|
|
|
|
|
// Create an auxiliary structure that makes it easy to look up the indices within the set of BSCC states.
|
|
|
|
uint_fast64_t lastIndex = 0; |
|
|
|
uint_fast64_t currentNumberOfSetBits = 0; |
|
|
|
std::vector<uint_fast64_t> indexInStatesInBsccs; |
|
|
|
indexInStatesInBsccs.reserve(transitionMatrix.getRowCount()); |
|
|
|
for (auto index : statesInBsccs) { |
|
|
|
while (lastIndex <= index) { |
|
|
|
indexInStatesInBsccs.push_back(currentNumberOfSetBits); |
|
|
|
++lastIndex; |
|
|
|
if (!statesInBsccs.empty()) { |
|
|
|
firstStatesInBsccs = firstStatesInBsccs % statesInBsccs; |
|
|
|
|
|
|
|
// Then we construct an equation system that yields the steady state probabilities for all states in BSCCs.
|
|
|
|
storm::storage::SparseMatrix<ValueType> bsccEquationSystem = transitionMatrix.getSubmatrix(false, statesInBsccs, statesInBsccs, true); |
|
|
|
|
|
|
|
// Since in the fix point equation, we need to multiply the vector from the left, we convert this to a
|
|
|
|
// multiplication from the right by transposing the system.
|
|
|
|
bsccEquationSystem = bsccEquationSystem.transpose(false, true); |
|
|
|
|
|
|
|
// Create an auxiliary structure that makes it easy to look up the indices within the set of BSCC states.
|
|
|
|
uint_fast64_t lastIndex = 0; |
|
|
|
uint_fast64_t currentNumberOfSetBits = 0; |
|
|
|
indexInStatesInBsccs.reserve(transitionMatrix.getRowCount()); |
|
|
|
for (auto index : statesInBsccs) { |
|
|
|
while (lastIndex <= index) { |
|
|
|
indexInStatesInBsccs.push_back(currentNumberOfSetBits); |
|
|
|
++lastIndex; |
|
|
|
} |
|
|
|
++currentNumberOfSetBits; |
|
|
|
} |
|
|
|
++currentNumberOfSetBits; |
|
|
|
} |
|
|
|
|
|
|
|
// Now build the final equation system matrix.
|
|
|
|
storm::storage::SparseMatrixBuilder<ValueType> builder; |
|
|
|
uint_fast64_t currentBsccIndex = 0; |
|
|
|
for (uint_fast64_t row = 0; row < bsccEquationSystem.getRowCount(); ++row) { |
|
|
|
// If the current row is the first one belonging to a BSCC, we substitute it by the constraint that the
|
|
|
|
// values for states of this BSCC must sum to one.
|
|
|
|
if (firstStatesInBsccs.get(row)) { |
|
|
|
|
|
|
|
stateToBsccIndexMap.resize(statesInBsccs.getNumberOfSetBits()); |
|
|
|
for (uint_fast64_t currentBsccIndex = 0; currentBsccIndex < bsccDecomposition.size(); ++currentBsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[currentBsccIndex]; |
|
|
|
|
|
|
|
for (auto const& state : bscc) { |
|
|
|
builder.addNextValue(row, indexInStatesInBsccs[state], one); |
|
|
|
stateToBsccIndexMap[indexInStatesInBsccs[state]] = currentBsccIndex; |
|
|
|
} |
|
|
|
++currentBsccIndex; |
|
|
|
} else { |
|
|
|
// Otherwise, we copy the row, and subtract 1 from the diagonal.
|
|
|
|
for (auto& entry : bsccEquationSystem.getRow(row)) { |
|
|
|
if (entry.getColumn() == row) { |
|
|
|
builder.addNextValue(row, entry.getColumn(), entry.getValue() - one); |
|
|
|
} else { |
|
|
|
builder.addNextValue(row, entry.getColumn(), entry.getValue()); |
|
|
|
} |
|
|
|
|
|
|
|
// Now build the final equation system matrix, the initial guess and the right-hand side in one go.
|
|
|
|
std::vector<ValueType> bsccEquationSystemRightSide(bsccEquationSystem.getColumnCount(), zero); |
|
|
|
storm::storage::SparseMatrixBuilder<ValueType> builder; |
|
|
|
for (uint_fast64_t row = 0; row < bsccEquationSystem.getRowCount(); ++row) { |
|
|
|
|
|
|
|
// If the current row is the first one belonging to a BSCC, we substitute it by the constraint that the
|
|
|
|
// values for states of this BSCC must sum to one. However, in order to have a non-zero value on the
|
|
|
|
// diagonal, we add the constraint of the BSCC that produces a 1 on the diagonal.
|
|
|
|
if (firstStatesInBsccs.get(row)) { |
|
|
|
uint_fast64_t requiredBscc = stateToBsccIndexMap[row]; |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[requiredBscc]; |
|
|
|
|
|
|
|
for (auto const& state : bscc) { |
|
|
|
builder.addNextValue(row, indexInStatesInBsccs[state], one); |
|
|
|
} |
|
|
|
|
|
|
|
bsccEquationSystemRightSide[row] = one; |
|
|
|
|
|
|
|
} else { |
|
|
|
// Otherwise, we copy the row, and subtract 1 from the diagonal.
|
|
|
|
for (auto& entry : bsccEquationSystem.getRow(row)) { |
|
|
|
if (entry.getColumn() == row) { |
|
|
|
builder.addNextValue(row, entry.getColumn(), entry.getValue() - one); |
|
|
|
} else { |
|
|
|
builder.addNextValue(row, entry.getColumn(), entry.getValue()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bsccEquationSystem = builder.build(); |
|
|
|
|
|
|
|
std::vector<ValueType> bsccEquationSystemRightSide(bsccEquationSystem.getColumnCount(), zero); |
|
|
|
storm::utility::vector::setVectorValues(bsccEquationSystemRightSide, firstStatesInBsccs, one); |
|
|
|
|
|
|
|
// As an initial guess, we take the uniform distribution over all states of the containing BSCC.
|
|
|
|
std::vector<ValueType> bsccEquationSystemSolution(bsccEquationSystem.getColumnCount(), zero); |
|
|
|
for (uint_fast64_t currentBsccIndex = 0; currentBsccIndex < bsccDecomposition.size(); ++currentBsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[currentBsccIndex]; |
|
|
|
|
|
|
|
for (auto const& state : bscc) { |
|
|
|
bsccEquationSystemSolution[indexInStatesInBsccs[state]] = one / bscc.size(); |
|
|
|
// Create the initial guess for the LRAs. We take a uniform distribution over all states in a BSCC.
|
|
|
|
std::vector<ValueType> bsccEquationSystemSolution(bsccEquationSystem.getColumnCount(), zero); |
|
|
|
for (uint_fast64_t bsccIndex = 0; bsccIndex < bsccDecomposition.size(); ++bsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[bsccIndex]; |
|
|
|
|
|
|
|
for (auto const& state : bscc) { |
|
|
|
bsccEquationSystemSolution[indexInStatesInBsccs[state]] = one / bscc.size(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
{ |
|
|
|
std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create(bsccEquationSystem); |
|
|
|
solver->solveEquationSystem(bsccEquationSystemSolution, bsccEquationSystemRightSide); |
|
|
|
} |
|
|
|
|
|
|
|
// If exit rates were given, we need to 'fix' the results to also account for the timing behaviour.
|
|
|
|
if (exitRateVector != nullptr) { |
|
|
|
std::vector<ValueType> bsccTotalValue(bsccDecomposition.size(), zero); |
|
|
|
std::size_t i = 0; |
|
|
|
for (auto stateIter = statesInBsccs.begin(); stateIter != statesInBsccs.end(); ++i, ++stateIter) { |
|
|
|
bsccTotalValue[stateToBsccIndexMap[*stateIter]] += bsccEquationSystemSolution[i] * (one / (*exitRateVector)[*stateIter]); |
|
|
|
|
|
|
|
bsccEquationSystem = builder.build(); |
|
|
|
|
|
|
|
{ |
|
|
|
std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create(bsccEquationSystem); |
|
|
|
solver->solveEquationSystem(bsccEquationSystemSolution, bsccEquationSystemRightSide); |
|
|
|
} |
|
|
|
|
|
|
|
i = 0; |
|
|
|
for (auto stateIter = statesInBsccs.begin(); stateIter != statesInBsccs.end(); ++i, ++stateIter) { |
|
|
|
bsccEquationSystemSolution[i] = (bsccEquationSystemSolution[i] * (one / (*exitRateVector)[*stateIter])) / bsccTotalValue[stateToBsccIndexMap[*stateIter]]; |
|
|
|
// If exit rates were given, we need to 'fix' the results to also account for the timing behaviour.
|
|
|
|
if (exitRateVector != nullptr) { |
|
|
|
std::vector<ValueType> bsccTotalValue(bsccDecomposition.size(), zero); |
|
|
|
for (auto stateIter = statesInBsccs.begin(); stateIter != statesInBsccs.end(); ++stateIter) { |
|
|
|
bsccTotalValue[stateToBsccIndexMap[indexInStatesInBsccs[*stateIter]]] += bsccEquationSystemSolution[indexInStatesInBsccs[*stateIter]] * (one / (*exitRateVector)[*stateIter]); |
|
|
|
} |
|
|
|
|
|
|
|
for (auto stateIter = statesInBsccs.begin(); stateIter != statesInBsccs.end(); ++stateIter) { |
|
|
|
bsccEquationSystemSolution[indexInStatesInBsccs[*stateIter]] = (bsccEquationSystemSolution[indexInStatesInBsccs[*stateIter]] * (one / (*exitRateVector)[*stateIter])) / bsccTotalValue[stateToBsccIndexMap[indexInStatesInBsccs[*stateIter]]]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Calculate LRA Value for each BSCC from steady state distribution in BSCCs.
|
|
|
|
std::vector<ValueType> bsccLra(bsccDecomposition.size(), zero); |
|
|
|
size_t i = 0; |
|
|
|
for (auto stateIter = statesInBsccs.begin(); stateIter != statesInBsccs.end(); ++i, ++stateIter) { |
|
|
|
if (psiStates.get(*stateIter)) { |
|
|
|
bsccLra[stateToBsccIndexMap[*stateIter]] += bsccEquationSystemSolution[i]; |
|
|
|
// Calculate LRA Value for each BSCC from steady state distribution in BSCCs.
|
|
|
|
for (uint_fast64_t bsccIndex = 0; bsccIndex < bsccDecomposition.size(); ++bsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[bsccIndex]; |
|
|
|
|
|
|
|
for (auto const& state : bscc) { |
|
|
|
if (psiStates.get(state)) { |
|
|
|
bsccLra[stateToBsccIndexMap[indexInStatesInBsccs[state]]] += bsccEquationSystemSolution[indexInStatesInBsccs[state]]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
for (uint_fast64_t bsccIndex = 0; bsccIndex < bsccDecomposition.size(); ++bsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[bsccIndex]; |
|
|
|
|
|
|
|
// At this point, all BSCCs are known to contain exactly one state, which is why we can set all values
|
|
|
|
// directly (based on whether or not the contained state is a psi state).
|
|
|
|
if (psiStates.get(*bscc.begin())) { |
|
|
|
bsccLra[bsccIndex] = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -628,7 +655,7 @@ namespace storm { |
|
|
|
ValueType reward = zero; |
|
|
|
for (auto entry : transitionMatrix.getRow(state)) { |
|
|
|
if (statesInBsccs.get(entry.getColumn())) { |
|
|
|
reward += entry.getValue() * bsccLra[stateToBsccIndexMap[entry.getColumn()]]; |
|
|
|
reward += entry.getValue() * bsccLra[stateToBsccIndexMap[indexInStatesInBsccs[entry.getColumn()]]]; |
|
|
|
} |
|
|
|
} |
|
|
|
rewardRightSide.push_back(reward); |
|
|
@ -648,18 +675,21 @@ namespace storm { |
|
|
|
// Fill the result vector.
|
|
|
|
std::vector<ValueType> result(numOfStates); |
|
|
|
auto rewardSolutionIter = rewardSolution.begin(); |
|
|
|
for (size_t state = 0; state < numOfStates; ++state) { |
|
|
|
if (statesInBsccs.get(state)) { |
|
|
|
// Assign the value of the bscc the state is in.
|
|
|
|
result[state] = bsccLra[stateToBsccIndexMap[state]]; |
|
|
|
} else { |
|
|
|
STORM_LOG_ASSERT(rewardSolutionIter != rewardSolution.end(), "Too few elements in solution."); |
|
|
|
// Take the value from the reward computation. Since the n-th state not in any bscc is the n-th
|
|
|
|
// entry in rewardSolution we can just take the next value from the iterator.
|
|
|
|
result[state] = *rewardSolutionIter; |
|
|
|
++rewardSolutionIter; |
|
|
|
|
|
|
|
for (uint_fast64_t bsccIndex = 0; bsccIndex < bsccDecomposition.size(); ++bsccIndex) { |
|
|
|
storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[bsccIndex]; |
|
|
|
|
|
|
|
for (auto const& state : bscc) { |
|
|
|
result[state] = bsccLra[bsccIndex]; |
|
|
|
} |
|
|
|
} |
|
|
|
for (auto state : statesNotInBsccs) { |
|
|
|
STORM_LOG_ASSERT(rewardSolutionIter != rewardSolution.end(), "Too few elements in solution."); |
|
|
|
// Take the value from the reward computation. Since the n-th state not in any bscc is the n-th
|
|
|
|
// entry in rewardSolution we can just take the next value from the iterator.
|
|
|
|
result[state] = *rewardSolutionIter; |
|
|
|
++rewardSolutionIter; |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|