23namespace modelchecker {
 
   25template<
typename ValueType>
 
   27    : transitionMatrix(transitionMatrix),
 
   31      nonBsccStates(transitionMatrix.getRowCount(), false) {
 
 
   35template<
typename ValueType>
 
   37                                                                                          std::vector<ValueType> 
const& exitRates)
 
   38    : transitionMatrix(transitionMatrix),
 
   42      nonBsccStates(transitionMatrix.getRowCount(), false) {
 
 
   47template<
typename ValueType>
 
   49    STORM_LOG_WARN_COND(!backwardTransitions, 
"Backward transition matrix was provided but it was already computed or provided before.");
 
   50    backwardTransitions.reset(providedBackwardTransitions);
 
 
   53template<
typename ValueType>
 
   56    STORM_LOG_WARN_COND(!sccDecomposition, 
"SCC Decomposition was provided but it was already computed or provided before.");
 
   57    sccDecomposition.reset(decomposition);
 
 
   60template<
typename ValueType>
 
   65    ValueType 
const p = storm::utility::one<ValueType>() / storm::utility::convertNumber<ValueType, uint64_t>(initialStates.
getNumberOfSetBits());
 
   66    std::vector<ValueType> result(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
 
   68    computeExpectedVisitingTimes(env, result);
 
 
   72template<
typename ValueType>
 
   74    STORM_LOG_ASSERT(initialState < transitionMatrix.getRowCount(), 
"Invalid initial state index.");
 
   75    std::vector<ValueType> result(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
 
   76    result[initialState] = storm::utility::one<ValueType>();
 
   77    computeExpectedVisitingTimes(env, result);
 
 
   81template<
typename ValueType>
 
   84    std::vector<ValueType> result;
 
   85    result.reserve(transitionMatrix.getRowCount());
 
   86    for (uint64_t s = 0; s != transitionMatrix.getRowCount(); ++s) {
 
   87        result.push_back(initialStateValueGetter(s));
 
   89    computeExpectedVisitingTimes(env, result);
 
 
   93template<
typename ValueType>
 
   95    STORM_LOG_ASSERT(stateValues.size() == transitionMatrix.getRowCount(), 
"Dimension missmatch.");
 
   96    createBackwardTransitions();
 
   97    createDecomposition(env);
 
   98    createNonBsccStateVector();
 
  102    auto isLeavingTransition = [&sccAsBitVector](
auto const& e) { 
return !sccAsBitVector.
get(e.getColumn()); };
 
  103    auto isLeavingTransitionWithNonZeroValue = [&isLeavingTransition, &stateValues](
auto const& e) {
 
  106    auto isReachableInState = [
this, &isLeavingTransitionWithNonZeroValue, &stateValues](uint64_t state) {
 
  110        auto row = this->backwardTransitions->getRow(state);
 
  111        return std::any_of(row.begin(), row.end(), isLeavingTransitionWithNonZeroValue);
 
  117        auto sccEnv = getEnvironmentForSolver(env, 
true);
 
  123        uint64_t sccIndex = 0;
 
  124        auto sccItEnd = std::make_reverse_iterator(sccDecomposition->begin());
 
  125        for (
auto sccIt = std::make_reverse_iterator(sccDecomposition->end()); sccIt != sccItEnd; ++sccIt) {
 
  126            auto const& scc = *sccIt;
 
  127            if (scc.size() == 1) {
 
  128                processSingletonScc(*scc.begin(), stateValues);
 
  130                sccAsBitVector.
set(scc.begin(), scc.end(), 
true);
 
  131                if (sccAsBitVector.
isSubsetOf(nonBsccStates)) {
 
  133                    auto sccResult = computeValueForStateSet(sccEnv, sccAsBitVector, stateValues);
 
  137                    if (std::any_of(sccAsBitVector.
begin(), sccAsBitVector.
end(), isReachableInState)) {
 
  143                sccAsBitVector.
clear();
 
  148                STORM_LOG_WARN(
"Visiting times computation aborted after analyzing " << sccIndex << 
"/" << this->computedSccDecomposition->size() << 
" SCCs.");
 
  154        if (!nonBsccStates.empty()) {
 
  156            Environment adjustedEnv = getEnvironmentForSolver(env, 
false);
 
  157            auto result = computeValueForStateSet(adjustedEnv, nonBsccStates, stateValues);
 
  162        auto sccItEnd = std::make_reverse_iterator(sccDecomposition->begin());
 
  163        for (
auto sccIt = std::make_reverse_iterator(sccDecomposition->end()); sccIt != sccItEnd; ++sccIt) {
 
  164            auto const& scc = *sccIt;
 
  165            sccAsBitVector.
set(scc.begin(), scc.end(), 
true);
 
  166            if (sccAsBitVector.
isSubsetOf(~nonBsccStates)) {
 
  168                if (std::any_of(sccAsBitVector.
begin(), sccAsBitVector.
end(), isReachableInState)) {
 
  176            sccAsBitVector.
clear();
 
  180    if (isContinuousTime()) {
 
 
  189template<
typename ValueType>
 
  194template<
typename ValueType>
 
  195void SparseDeterministicVisitingTimesHelper<ValueType>::createBackwardTransitions() {
 
  196    if (!this->backwardTransitions) {
 
  197        this->computedBackwardTransitions =
 
  198            std::make_unique<storm::storage::SparseMatrix<ValueType>>(transitionMatrix.transpose(
true, 
false));  
 
  199        this->backwardTransitions.reset(*this->computedBackwardTransitions);
 
  203template<
typename ValueType>
 
  204void SparseDeterministicVisitingTimesHelper<ValueType>::createDecomposition(Environment 
const& env) {
 
  205    if (this->sccDecomposition && !this->sccDecomposition->hasSccDepth() && env.solver().isForceSoundness()) {
 
  207        STORM_LOG_WARN(
"Recomputing SCC Decomposition because the currently available decomposition is computed without SCCDepths.");
 
  208        this->computedSccDecomposition.reset();
 
  209        this->sccDecomposition.reset();
 
  212    if (!this->sccDecomposition) {
 
  216        this->computedSccDecomposition = std::make_unique<storm::storage::StronglyConnectedComponentDecomposition<ValueType>>(this->transitionMatrix, options);
 
  217        this->sccDecomposition.reset(*this->computedSccDecomposition);
 
  221template<
typename ValueType>
 
  222void SparseDeterministicVisitingTimesHelper<ValueType>::createNonBsccStateVector() {
 
  225    auto isLeavingTransition = [&sccAsBitVector](
auto const& e) { 
return !sccAsBitVector.get(e.getColumn()); };
 
  226    auto isExitState = [
this, &isLeavingTransition](uint64_t state) {
 
  227        auto row = this->transitionMatrix.getRow(state);
 
  228        return std::any_of(row.begin(), row.end(), isLeavingTransition);
 
  231    auto sccItEnd = std::make_reverse_iterator(sccDecomposition->begin());
 
  232    for (
auto sccIt = std::make_reverse_iterator(sccDecomposition->end()); sccIt != sccItEnd; ++sccIt) {
 
  233        auto const& scc = *sccIt;
 
  234        sccAsBitVector.set(scc.begin(), scc.end(), 
true);
 
  235        if (std::any_of(sccAsBitVector.begin(), sccAsBitVector.end(), isExitState)) {
 
  237            nonBsccStates = nonBsccStates | sccAsBitVector;
 
  239        sccAsBitVector.clear();
 
  244std::vector<storm::RationalFunction> SparseDeterministicVisitingTimesHelper<storm::RationalFunction>::computeUpperBounds(
 
  247                    "Computing upper bounds for expected visiting times over rational functions is not supported.");
 
  250template<
typename ValueType>
 
  251std::vector<ValueType> SparseDeterministicVisitingTimesHelper<ValueType>::computeUpperBounds(
storm::storage::BitVector const& stateSetAsBitvector)
 const {
 
  253    std::vector<ValueType> leavingTransitions = transitionMatrix.getConstrainedRowGroupSumVector(stateSetAsBitvector, ~stateSetAsBitvector);
 
  260        subTransitionMatrix, leavingTransitions);
 
  264template<
typename ValueType>
 
  270        newEnv = getEnvironmentForTopologicalSolver(env);
 
  274    if (isContinuousTime()) {
 
  275        auto prec = newEnv.solver().getPrecisionOfLinearEquationSolver(newEnv.solver().getLinearEquationSolverType());
 
  277        bool needAdaptPrecision =
 
  279            !newEnv.solver().getPrecisionOfLinearEquationSolver(newEnv.solver().getLinearEquationSolverType()).second.get();  
 
  284            "The precision for the current solver type is not adjusted for this solving method. Ensure that this is correct for topological computation.");
 
  286        if (needAdaptPrecision) {
 
  288            ValueType min = *std::min_element(exitRates->begin(), exitRates->end());
 
  290                            "An error occurred during the adjustment of the precision. Min. rate = " << min);
 
  291            newEnv.solver().setLinearEquationSolverPrecision(
 
  292                static_cast<storm::RationalNumber
>(prec.first.get() * storm::utility::convertNumber<storm::RationalNumber>(min)));
 
  296    auto prec = newEnv.solver().getPrecisionOfLinearEquationSolver(newEnv.solver().getLinearEquationSolverType());
 
  297    if (prec.first.is_initialized()) {
 
  298        STORM_LOG_INFO(
"Precision for EVTs computation: " << storm::utility::convertNumber<double>(prec.first.get()) << 
" (exact: " << prec.first.get() << 
")" 
  305template<
typename ValueType>
 
  312    auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType());
 
  314    bool singletonSCCs = 
true;  
 
  316    auto sccItEnd = std::make_reverse_iterator(sccDecomposition->begin());
 
  317    for (
auto sccIt = std::make_reverse_iterator(sccDecomposition->end()); sccIt != sccItEnd; ++sccIt) {
 
  318        auto const& scc = *sccIt;
 
  319        sccAsBitVector.set(scc.begin(), scc.end(), 
true);
 
  320        if (sccAsBitVector.isSubsetOf(nonBsccStates)) {
 
  322            if (sccAsBitVector.getNumberOfSetBits() > 1) {
 
  323                singletonSCCs = 
false;
 
  327        sccAsBitVector.clear();
 
  330    bool needAdaptPrecision = env.
solver().
isForceSoundness() && subEnvPrec.first.is_initialized() && subEnvPrec.second.is_initialized() &&
 
  335        !needAdaptPrecision || subEnv.solver().getLinearEquationSolverType() == storm::solver::EquationSolverType::Native,
 
  336        "The precision for the current solver type is not adjusted for this solving method. Ensure that this is correct for topological computation.");
 
  338    if (needAdaptPrecision && subEnvPrec.second.get()) {
 
  339        STORM_LOG_ASSERT(sccDecomposition->hasSccDepth(), 
"Did not compute the longest SCC chain size although it is needed.");
 
  342        auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType());
 
  344        double scaledPrecision1 = 1 - std::pow(1 - storm::utility::convertNumber<double>(subEnvPrec.first.get()), 1.0 / sccDecomposition->getMaxSccDepth());
 
  347        subEnv.solver().setLinearEquationSolverPrecision(storm::utility::convertNumber<storm::RationalNumber>(scaledPrecision1));
 
  349    } 
else if (needAdaptPrecision && !subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType()).second.get()) {
 
  354        if (sccDecomposition->getMaxSccDepth() > 1) {
 
  362            uint_fast64_t maxNumInc = 0;
 
  365            ValueType boundEVT = storm::utility::zero<ValueType>();
 
  367            auto sccItEnd = std::make_reverse_iterator(sccDecomposition->begin());
 
  368            for (
auto sccIt = std::make_reverse_iterator(sccDecomposition->end()); sccIt != sccItEnd; ++sccIt) {
 
  369                auto const& scc = *sccIt;
 
  370                sccAsBitVector.set(scc.begin(), scc.end(), 
true);
 
  371                if (sccAsBitVector.isSubsetOf(nonBsccStates)) {
 
  375                    auto toSccMatrix = transitionMatrix.getSubmatrix(
false, ~sccAsBitVector, sccAsBitVector);
 
  376                    uint_fast64_t localNumInc =
 
  377                        std::count_if(toSccMatrix.begin(), toSccMatrix.end(), [](
auto const& e) { return !storm::utility::isZero(e.getValue()); });
 
  378                    maxNumInc = std::max(maxNumInc, localNumInc);
 
  382                    std::vector<ValueType> upperBounds = computeUpperBounds(sccAsBitVector);
 
  383                    boundEVT = std::max(boundEVT, (*std::max_element(upperBounds.begin(), upperBounds.end())));
 
  385                    sccAsBitVector.clear();
 
  389            storm::RationalNumber 
one = storm::RationalNumber(1);
 
  392            if (maxNumInc != 0) {
 
  395                for (uint64_t i = 1; 
i < sccDecomposition->getMaxSccDepth(); 
i++) {
 
  397                                        storm::utility::convertNumber<storm::RationalNumber>(boundEVT);
 
  400            subEnv.solver().setLinearEquationSolverPrecision(
static_cast<storm::RationalNumber
>(subEnvPrec.first.get() / scale));
 
  407template<
typename ValueType>
 
  408void SparseDeterministicVisitingTimesHelper<ValueType>::processSingletonScc(uint64_t sccState, std::vector<ValueType>& stateValues)
 const {
 
  409    auto& stateVal = stateValues[sccState];
 
  410    auto forwardRow = transitionMatrix.getRow(sccState);
 
  411    auto backwardRow = backwardTransitions->getRow(sccState);
 
  412    if (forwardRow.getNumberOfEntries() == 1 && forwardRow.begin()->getColumn() == sccState) {
 
  415                                                             [&stateValues](
auto const& e) { return !storm::utility::isZero(stateValues[e.getColumn()]); })) {
 
  416            stateVal = storm::utility::infinity<ValueType>();
 
  420        ValueType divisor = storm::utility::one<ValueType>();
 
  421        for (
auto const& entry : backwardRow) {
 
  422            if (entry.getColumn() == sccState) {
 
  424                divisor -= entry.getValue();
 
  426                stateVal += entry.getValue() * stateValues[entry.getColumn()];
 
  433template<
typename ValueType>
 
  434std::vector<ValueType> SparseDeterministicVisitingTimesHelper<ValueType>::computeValueForStateSet(
storm::Environment const& env,
 
  436                                                                                                  std::vector<ValueType> 
const& stateValues)
 const {
 
  439    auto valIt = sccVector.begin();
 
  440    for (
auto sccState : stateSetAsBitvector) {
 
  441        for (
auto const& entry : backwardTransitions->getRow(sccState)) {
 
  442            if (!stateSetAsBitvector.
get(entry.getColumn())) {
 
  443                (*valIt) += entry.getValue() * stateValues[entry.getColumn()];
 
  448    return computeExpectedVisitingTimes(env, stateSetAsBitvector, sccVector);
 
  451template<
typename ValueType>
 
  454                                                                                                       std::vector<ValueType> 
const& initialValues)
 const {
 
  457    if (initialValues.empty()) {  
 
  472    auto sccMatrix = backwardTransitions->getSubmatrix(
false, subsystem, subsystem, !isFixpointFormat);
 
  473    if (!isFixpointFormat) {
 
  474        sccMatrix.convertToEquationSystem();
 
  478    auto solver = linearEquationSolverFactory.
create(env, std::move(sccMatrix));
 
  479    solver->setLowerBound(storm::utility::zero<ValueType>());
 
  480    auto req = solver->getRequirements(env);
 
  481    req.clearLowerBounds();
 
  482    if (req.upperBounds().isCritical()) {
 
  484        std::vector<ValueType> upperBounds = computeUpperBounds(subsystem);
 
  485        solver->setUpperBounds(upperBounds);
 
  486        req.clearUpperBounds();
 
  489    if (req.acyclic().isCritical()) {
 
  491                        "The solver requires an acyclic model, but the model is not acyclic.");
 
  495    STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
 
  496                    "Solver requirements " + req.getEnabledRequirementsAsString() + 
" not checked.");
 
  497    std::vector<ValueType> eqSysValues(initialValues.size());
 
  498    solver->solveEquations(env, eqSysValues, initialValues);
 
 
SolverEnvironment & solver()
 
TopologicalSolverEnvironment & topological()
 
storm::solver::EquationSolverType const & getLinearEquationSolverType() const
 
bool isForceSoundness() const
 
storm::solver::EquationSolverType const & getUnderlyingEquationSolverType() const
 
bool const & isUnderlyingEquationSolverTypeSetFromDefault() 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.
 
Helper class for computing for each state the expected number of times to visit that state assuming a...
 
std::vector< ValueType > computeExpectedVisitingTimes(Environment const &env, storm::storage::BitVector const &initialStates)
Computes for each state the expected number of times we are visiting that state assuming the given in...
 
void provideSCCDecomposition(storm::storage::StronglyConnectedComponentDecomposition< ValueType > const &decomposition)
Provides the decomposition into SCCs that can be used during the computation.
 
void provideBackwardTransitions(storm::storage::SparseMatrix< ValueType > const &backwardTransitions)
Provides the backward transitions that can be used during the computation.
 
std::function< ValueType(uint64_t)> ValueGetter
Function mapping from indices to values.
 
SparseDeterministicVisitingTimesHelper(storm::storage::SparseMatrix< ValueType > const &transitionMatrix)
Initializes the helper for a DTMC.
 
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_iterator end() const
Returns an iterator pointing at the element past the back of the bit vector.
 
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
 
void clear()
Removes all set bits from the bit vector.
 
bool isSubsetOf(BitVector const &other) const
Checks whether all bits that are set in the current bit vector are also set in the given 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.
 
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
 
size_t size() const
Retrieves the number of bits this bit vector can store.
 
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 holds a possibly non-square matrix in the compressed row storage format.
 
bool isProbabilistic() const
Checks for each row whether it sums to one.
 
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
 
This class represents the decomposition of a graph-like structure into its strongly connected compone...
 
A class that provides convenience operations to display run times.
 
bool updateProgress(uint64_t count)
Updates the progress to the current count and prints it if the delay passed.
 
void setMaxCount(uint64_t maxCount)
Sets the maximal possible count.
 
void startNewMeasurement(uint64_t startCount)
Starts a new measurement, dropping all progress information collected so far.
 
#define STORM_LOG_INFO(message)
 
#define STORM_LOG_WARN(message)
 
#define STORM_LOG_ASSERT(cond, message)
 
#define STORM_LOG_WARN_COND(cond, message)
 
#define STORM_LOG_THROW(cond, exception, message)
 
bool scale(int exp, storm::RationalNumber &r, storm::RationalNumber acc)
 
SFTBDDChecker::ValueType ValueType
 
bool hasCycle(storm::storage::SparseMatrix< T > const &transitionMatrix, boost::optional< storm::storage::BitVector > const &subsystem)
Returns true if the graph represented by the given matrix has a cycle.
 
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
 
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Sets the provided values at the provided positions in the given vector.
 
void applyPointwise(std::vector< InValueType1 > const &firstOperand, std::vector< InValueType2 > const &secondOperand, std::vector< OutValueType > &target, Operation f=Operation())
Applies the given operation pointwise on the two given vectors and writes the result to the third vec...
 
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
 
bool isOne(ValueType const &a)
 
ValueType min(ValueType const &first, ValueType const &second)
 
bool isZero(ValueType const &a)
 
ValueType pow(ValueType const &value, int_fast64_t exponent)
 
bool isInfinity(ValueType const &a)
 
constexpr NullRefType NullRef
 
StronglyConnectedComponentDecompositionOptions & computeSccDepths(bool value=true)
Sets if scc depths can be retrieved.
 
StronglyConnectedComponentDecompositionOptions & forceTopologicalSort(bool value=true)
Enforces that the returned SCCs are sorted in a topological order.