26template<
typename ValueType>
32template<
typename ValueType>
34 std::vector<ValueType>
const& exitRates)
37template<
typename ValueType>
47template<
typename ValueType>
56 if (trivialResult.first) {
57 return trivialResult.second;
63 method == storm::solver::LraMethod::ValueIteration) {
64 method = storm::solver::LraMethod::GainBiasEquations;
66 <<
" as the solution technique for long-run properties to guarantee exact results. If you want to override this, please "
67 "explicitly specify a different LRA method.");
69 method = storm::solver::LraMethod::ValueIteration;
71 <<
" as the solution technique for long-run properties to guarantee sound results. If you want to override this, please "
72 "explicitly specify a different LRA method.");
75 if (method == storm::solver::LraMethod::ValueIteration) {
77 }
else if (method == storm::solver::LraMethod::LraDistributionEquations) {
82 "Unsupported lra method selected. Defaulting to " <<
storm::solver::toString(storm::solver::LraMethod::GainBiasEquations) <<
".");
87template<
typename ValueType>
95 for (
auto const& element : component) {
98 "Unexpected choice index at state " << state <<
" of deterministic model.");
100 stateValueGetter(state) + (this->
isContinuousTime() ? (*this->
_exitRates)[state] * actionValueGetter(state) : actionValueGetter(state));
104 }
else if (val != curr) {
116 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"The requested Method for LRA computation is not supported for parametric models.");
118template<
typename ValueType>
131 return viHelper.performValueIteration(env, stateValueGetter, actionValueGetter, this->
_exitRates);
137 return viHelper.performValueIteration(env, stateValueGetter, actionValueGetter);
141template<
typename ValueType>
158 std::unordered_map<uint64_t, uint64_t> toLocalIndexMap;
159 uint64_t localIndex = 0;
160 for (
auto const& globalIndex : bscc) {
161 toLocalIndexMap[globalIndex] = localIndex;
167 if (subEnv.solver().getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological) {
169 subEnv.solver().setLinearEquationSolverType(subEnv.solver().topological().getUnderlyingEquationSolverType(),
170 subEnv.solver().topological().isUnderlyingEquationSolverTypeSetFromDefault());
176 bool isEquationSystemFormat =
179 std::vector<ValueType> eqSysVector;
180 eqSysVector.reserve(bscc.
size());
184 for (
auto const& globalState : bscc) {
187 if (isEquationSystemFormat) {
190 }
else if (row > 0) {
196 if (isEquationSystemFormat) {
197 builder.addDiagonalEntry(row, rateAtState);
203 uint64_t col = toLocalIndexMap[entry.getColumn()];
208 entryValue = entry.getValue() * rateAtState;
209 if (isEquationSystemFormat) {
210 entryValue = -entryValue;
212 builder.addNextValue(row, col, entryValue);
214 eqSysVector.push_back(stateValuesGetter(globalState) + rateAtState * actionValuesGetter(globalState));
221 auto requirements =
solver->getRequirements(subEnv);
222 STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
223 "Solver requirements " + requirements.getEnabledRequirementsAsString() +
" not checked.");
230 solver->solveEquations(subEnv, eqSysSol, eqSysVector);
236 return std::pair<ValueType, std::vector<ValueType>>(std::move(gain), std::move(eqSysSol));
239template<
typename ValueType>
243 if (bscc.
size() == 1) {
262 "Unexpected algorithm for steady state distribution computation.");
267template<
typename ValueType>
272 bsccAsBitVector.
set(bscc.
begin(), bscc.
end(),
true);
275 uint64_t
const proxyState = *bsccAsBitVector.
rbegin();
276 bsccAsBitVector.
set(proxyState,
false);
281 std::vector<ValueType> initialValues;
282 initialValues.reserve(bscc.
size() - 1);
284 auto entryIt = row.begin();
285 auto const entryItEnd = row.end();
286 for (
auto state : bsccAsBitVector) {
287 if (entryIt != entryItEnd && state == entryIt->getColumn()) {
288 initialValues.push_back(entryIt->getValue());
294 STORM_LOG_ASSERT(entryIt == entryItEnd || entryIt->getColumn() == proxyState,
"Unexpected matrix row.");
296 if (evtEnv.solver().isForceSoundness()) {
297 auto prec = evtEnv.solver().getPrecisionOfLinearEquationSolver(evtEnv.solver().getLinearEquationSolverType());
298 if (prec.first.is_initialized()) {
299 auto requiredPrecision = *prec.first;
311 evtEnv.solver().setLinearEquationSolverPrecision(eps, prec.second);
314 auto visitingTimes = visittimesHelper.computeExpectedVisitingTimes(evtEnv, bsccAsBitVector, initialValues);
316 bsccAsBitVector.
set(proxyState,
true);
320 auto resultIt = visitingTimes.begin();
321 for (
auto state : bsccAsBitVector) {
323 sumOfVisitingTimes += *resultIt;
330 return visitingTimes;
333template<
typename ValueType>
341 if (env.solver().getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological) {
343 env.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingEquationSolverType(),
344 env.solver().topological().isUnderlyingEquationSolverTypeSetFromDefault());
348 "Sound computations are not properly implemented for this computation. You might get incorrect results.");
356 std::unordered_map<uint64_t, uint64_t> toLocalIndexMap;
358 uint64_t localIndex = 0;
359 for (
auto const& globalIndex : bscc) {
360 bsccStates.
set(globalIndex,
true);
361 toLocalIndexMap[globalIndex] = localIndex;
366 auto auxMatrix = this->
_transitionMatrix.getSubmatrix(
false, bsccStates, bsccStates,
true);
368 for (
auto const& globalIndex : bscc) {
370 for (
auto& entry : auxMatrix.getRow(row)) {
371 if (entry.getColumn() == row) {
375 entry.setValue(entry.getValue() * rateAtState);
380 assert(row == auxMatrix.getRowCount());
383 auxMatrix = auxMatrix.transpose();
388 if (isFixpointFormat) {
390 for (row = 0; row < auxMatrix.getRowCount(); ++row) {
391 for (
auto& entry : auxMatrix.getRow(row)) {
392 if (entry.getColumn() == row) {
403 uint64_t lastRow = auxMatrix.getRowCount() - 1;
404 for (
auto& entry : auxMatrix.getRow(lastRow)) {
405 entry.setColumn(col);
406 if (isFixpointFormat) {
407 if (col == lastRow) {
418 for (; col <= lastRow; ++col) {
419 if (isFixpointFormat) {
420 if (col != lastRow) {
435 auto requirements =
solver->getRequirements(env);
436 requirements.clearLowerBounds();
437 requirements.clearUpperBounds();
438 STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
439 "Solver requirements " + requirements.getEnabledRequirementsAsString() +
" not checked.");
442 solver->solveEquations(env, steadyStateDistr, bsccEquationSystemRightSide);
446 if (!env.solver().isForceExact()) {
451 return steadyStateDistr;
454template<
typename ValueType>
463 auto solIt = steadyStateDistr.begin();
464 for (
auto const& globalState : bscc) {
466 result += (*solIt) * (stateValuesGetter(globalState) + (*this->
_exitRates)[globalState] * actionValuesGetter(globalState));
468 result += (*solIt) * (stateValuesGetter(globalState) + actionValuesGetter(globalState));
472 assert(solIt == steadyStateDistr.end());
474 return std::pair<ValueType, std::vector<ValueType>>(std::move(result), std::move(steadyStateDistr));
477template<
typename ValueType>
479 std::vector<ValueType>
const& bsccLraValues, std::vector<uint64_t>
const& inputStateToBsccIndexMap,
storm::storage::BitVector const& statesNotInComponent,
480 bool asEquationSystem) {
485 auto sspMatrix = this->
_transitionMatrix.getSubmatrix(
false, statesNotInComponent, statesNotInComponent, asEquationSystem);
486 if (asEquationSystem) {
487 sspMatrix.convertToEquationSystem();
491 std::vector<ValueType> rhs;
492 rhs.reserve(sspMatrix.getRowCount());
493 for (
auto state : statesNotInComponent) {
496 if (!statesNotInComponent.
get(transition.getColumn())) {
498 stateValue += transition.getValue() * bsccLraValues[inputStateToBsccIndexMap[transition.getColumn()]];
501 rhs.push_back(std::move(stateValue));
504 return std::make_pair(std::move(sspMatrix), std::move(rhs));
507template<
typename ValueType>
509 std::vector<ValueType>
const& componentLraValues) {
520 std::vector<uint64_t> stateIndexMap(this->
_transitionMatrix.getRowGroupCount(), std::numeric_limits<uint64_t>::max());
524 statesInComponents.
set(state);
525 stateIndexMap[state] = currentComponentIndex;
529 uint64_t numberOfNonComponentStates = 0;
531 for (
auto nonComponentState : statesNotInComponent) {
532 stateIndexMap[nonComponentState] = numberOfNonComponentStates;
533 ++numberOfNonComponentStates;
537 std::vector<ValueType> sspValues;
538 if (numberOfNonComponentStates > 0) {
541 auto sspMatrixVector =
buildSspMatrixVector(componentLraValues, stateIndexMap, statesNotInComponent, isEqSysFormat);
542 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>>
solver = linearEquationSolverFactory.
create(env, sspMatrixVector.first);
543 auto lowerUpperBounds = std::minmax_element(componentLraValues.begin(), componentLraValues.end());
544 solver->setBounds(*lowerUpperBounds.first, *lowerUpperBounds.second);
546 auto requirements =
solver->getRequirements(env);
547 requirements.clearUpperBounds();
548 requirements.clearLowerBounds();
549 STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
550 "Solver requirements " + requirements.getEnabledRequirementsAsString() +
" not checked.");
551 sspValues.assign(sspMatrixVector.first.getRowCount(),
553 solver->solveEquations(env, sspValues, sspMatrixVector.second);
558 for (uint64_t state = 0; state < stateIndexMap.size(); ++state) {
559 if (statesNotInComponent.
get(state)) {
560 result[state] = sspValues[stateIndexMap[state]];
562 result[state] = componentLraValues[stateIndexMap[state]];
568template<
typename ValueType>
575template<
typename ValueType>
577 uint64_t
const& initialState) {
579 "Invlid initial state index: " << initialState <<
". Have only " << this->_transitionMatrix.getRowGroupCount() <<
" states.");
585template<
typename ValueType>
595 if (prec.first.is_initialized()) {
596 auto requiredPrecision = *prec.first;
617 auto const& scalingFactor = bsccReachProbs[currentComponentIndex];
622 auto bsccDistrIt = bsccDistr.begin();
623 for (
auto const& element : component) {
625 steadyStateDistr[state] = *bsccDistrIt;
628 STORM_LOG_ASSERT(bsccDistrIt == bsccDistr.end(),
"Unexpected number of entries in bscc distribution");
630 return steadyStateDistr;
633template<
typename ValueType>
635 std::vector<ValueType>
const& toBsccProbabilities) {
641 std::vector<storm::RationalFunction>
const& ) {
643 "Computing upper bounds for expected visiting times over rational functions is not supported.");
646template<
typename ValueType>
652 std::vector<ValueType> bsccReachProbs;
654 STORM_LOG_ASSERT(numBSCCs == 1,
"Found 0 BSCCs in a Markov chain. This should not be possible.");
670 return bsccReachProbs;
673template<
typename ValueType>
685 bool const hasNonBsccStates = !nonBsccStates.
empty();
688 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>>
solver;
689 if (hasNonBsccStates) {
691 bool isEquationSystemFormat =
693 auto subMatrix = this->
_transitionMatrix.getSubmatrix(
false, nonBsccStates, nonBsccStates, isEquationSystemFormat);
694 if (isEquationSystemFormat) {
695 subMatrix.convertToEquationSystem();
697 solver = linearEquationSolverFactory.
create(env, std::move(subMatrix));
700 auto requirements =
solver->getRequirements(env);
701 requirements.clearLowerBounds();
702 requirements.clearUpperBounds();
703 STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
704 "Solver requirements " + requirements.getEnabledRequirementsAsString() +
" not checked.");
705 solver->setCachingEnabled(
true);
712 auto& bsccVal = bsccReachProbs[currentComponentIndex];
716 bsccVal += initialDistributionGetter(state);
719 if (hasNonBsccStates) {
721 bsccAsBitVector.
set(bscc.begin(), bscc.end(),
true);
723 std::vector<ValueType> eqSysRhs;
725 for (
auto state : nonBsccStates) {
726 eqSysRhs.push_back(this->
_transitionMatrix.getConstrainedRowSum(state, bsccAsBitVector));
728 std::vector<ValueType> eqSysSolution(eqSysRhs.size());
729 solver->solveEquations(env, eqSysSolution, eqSysRhs);
731 uint64_t subsysState = 0;
732 for (
auto globalState : nonBsccStates) {
733 bsccVal += initialDistributionGetter(globalState) * eqSysSolution[subsysState];
738 return bsccReachProbs;
741template<
typename ValueType>
751 auto expVisitTimes = visittimesHelper.computeExpectedVisitingTimes(env, initialDistributionGetter);
761 auto& bsccVal = bsccReachProbs[currentComponentIndex];
764 bsccVal += initialDistributionGetter(state);
766 if (nonBsccStates.
get(pred.getColumn())) {
767 bsccVal += pred.getValue() * expVisitTimes[pred.getColumn()];
772 return bsccReachProbs;
SolverEnvironment & solver()
ModelCheckerEnvironment & modelchecker()
storm::RationalNumber const & getAperiodicFactor() const
bool const & isDetLraMethodSetFromDefault() const
storm::RationalNumber const & getPrecision() const
bool const & getRelativeTerminationCriterion() const
storm::solver::LraMethod const & getDetLraMethod() const
SteadyStateDistributionAlgorithm getSteadyStateDistributionAlgorithm() const
storm::solver::EquationSolverType const & getLinearEquationSolverType() const
void setLinearEquationSolverPrecision(boost::optional< storm::RationalNumber > const &newPrecision, boost::optional< bool > const &relativePrecision=boost::none)
bool isForceExact() const
LongRunAverageSolverEnvironment & lra()
bool isForceSoundness() const
std::pair< boost::optional< storm::RationalNumber >, boost::optional< bool > > getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const &solverType) const
static std::vector< ValueType > computeUpperBoundOnExpectedVisitingTimes(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< ValueType > const &oneStepTargetProbabilities)
Computes for each state an upper bound for the maximal expected times each state is visited.
bool isProduceSchedulerSet() const
Helper class for model checking queries that depend on the long run behavior of the (nondeterministic...
SparseDeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix< ValueType > const &transitionMatrix)
Initializes the helper for a discrete time model (i.e.
ValueType computeLraForBsccVi(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::StronglyConnectedComponent const &bscc)
As computeLraForComponent but uses value iteration as a solution method (independent of what is set i...
std::pair< ValueType, std::vector< ValueType > > computeLraForBsccGainBias(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::StronglyConnectedComponent const &bscc)
As computeLraForComponent but solves a linear equation system encoding gain and bias (independent of ...
virtual ValueType computeLraForComponent(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::StronglyConnectedComponent const &component) override
std::pair< ValueType, std::vector< ValueType > > computeLraForBsccSteadyStateDistr(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::StronglyConnectedComponent const &bscc)
As computeLraForComponent but does the computation by computing the long run average (steady state) d...
std::pair< storm::storage::SparseMatrix< ValueType >, std::vector< ValueType > > buildSspMatrixVector(std::vector< ValueType > const &bsccLraValues, std::vector< uint64_t > const &inputStateToBsccIndexMap, storm::storage::BitVector const &statesNotInComponent, bool asEquationSystem)
virtual void createDecomposition() override
std::pair< bool, ValueType > computeLraForTrivialBscc(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::StronglyConnectedComponent const &bscc)
SparseInfiniteHorizonHelper< ValueType, true >::ValueGetter ValueGetter
Function mapping from indices to values.
virtual std::vector< ValueType > buildAndSolveSsp(Environment const &env, std::vector< ValueType > const &mecLraValues) override
std::vector< ValueType > computeLongRunAverageStateDistribution(Environment const &env)
Computes the long run average state distribution, i.e., a vector that assigns for each state s the av...
std::vector< ValueType > computeSteadyStateDistrForBsccEVTs(Environment const &env, storm::storage::StronglyConnectedComponent const &bscc)
std::vector< ValueType > computeSteadyStateDistrForBscc(Environment const &env, storm::storage::StronglyConnectedComponent const &bscc)
Computes the long run average (steady state) distribution for the given BSCC.
std::vector< ValueType > computeBsccReachabilityProbabilitiesClassic(Environment const &env, ValueGetter const &initialDistributionGetter)
std::vector< ValueType > computeBsccReachabilityProbabilitiesEVTs(Environment const &env, ValueGetter const &initialDistributionGetter)
std::vector< ValueType > computeBsccReachabilityProbabilities(Environment const &env, ValueGetter const &initialDistributionGetter)
Computes for each BSCC the probability to reach that SCC assuming the given distribution over initial...
std::vector< ValueType > computeSteadyStateDistrForBsccEqSys(Environment const &env, storm::storage::StronglyConnectedComponent const &bscc)
Helper class for computing for each state the expected number of times to visit that state assuming a...
bool isContinuousTime() const
SparseInfiniteHorizonHelper(storm::storage::SparseMatrix< ValueType > const &transitionMatrix)
storm::storage::SparseMatrix< ValueType > const * _backwardTransitions
storm::storage::SparseMatrix< ValueType > const & _transitionMatrix
storm::storage::Decomposition< LongRunComponentType > const * _longRunComponentDecomposition
void createBackwardTransitions()
std::vector< ValueType > const * _exitRates
std::unique_ptr< storm::storage::Decomposition< LongRunComponentType > > _computedLongRunComponentDecomposition
storm::storage::BitVector const * _markovianStates
Helper class that performs iterations of the value iteration method.
virtual std::unique_ptr< LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const &env) const
Retrieves the problem format that the solver expects if it was created with the current settings.
A bit vector that is internally represented as a vector of 64-bit values.
const_reverse_iterator rbegin() const
Returns a reverse iterator to the indices of the set bits in the bit vector.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
A class that can be used to build a sparse matrix by adding value by value.
A class that holds a possibly non-square matrix in the compressed row storage format.
std::size_t size() const
Retrieves the number of states in this SCC.
iterator begin()
Returns an iterator to the states in this SCC.
iterator end()
Returns an iterator that points one past the end of the states in this SCC.
This class represents a strongly connected component, i.e., a set of states such that every state can...
#define STORM_LOG_INFO(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
uint64_t getComponentElementState(typename storm::storage::StronglyConnectedComponent::value_type const &element)
Auxiliary functions that deal with the different kinds of components (MECs on potentially nondetermin...
uint64_t const * getComponentElementChoicesBegin(typename storm::storage::StronglyConnectedComponent::value_type const &element)
std::vector< ValueType > computeUpperBoundsForExpectedVisitingTimes(storm::storage::SparseMatrix< ValueType > const &nonBsccMatrix, std::vector< ValueType > const &toBsccProbabilities)
std::string toString(GurobiSolverMethod const &method)
Yields a string representation of the GurobiSolverMethod.
void scaleVectorInPlace(std::vector< ValueType1 > &target, ValueType2 const &factor)
Multiplies each element of the given vector with the given factor and writes the result into the vect...
bool isOne(ValueType const &a)
ValueType sqrt(ValueType const &number)
TargetType convertNumber(SourceType const &number)
carl::RationalFunction< Polynomial, true > RationalFunction
static const bool IsExact
StronglyConnectedComponentDecompositionOptions & onlyBottomSccs(bool value=true)
Sets if only bottom SCCs, i.e. SCCs in which all states have no way of leaving the SCC),...