15template<
typename ValueType>
20template<
typename ValueType>
25template<
typename ValueType>
30template<
typename ValueType>
37template<
typename ValueType>
39 localA = std::make_unique<storm::storage::SparseMatrix<ValueType>>(std::move(A));
40 this->A = localA.get();
44template<
typename ValueType>
50 STORM_LOG_ASSERT(this->longestSccChainSize,
"Did not compute the longest SCC chain size although it is needed.");
51 auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType());
52 storm::RationalNumber
const prec = subEnvPrec.first.get();
54 if (subEnvPrec.second.is_initialized() && subEnvPrec.second.get()) {
59 subEnv.solver().setLinearEquationSolverPrecision(
static_cast<storm::RationalNumber
>(prec / divisor));
64template<
typename ValueType>
66 std::vector<ValueType>
const& b)
const {
68 bool needAdaptPrecision =
72 if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) {
75 createSortedSccDecomposition(needAdaptPrecision);
78 << sccSw <<
". Found " << this->sortedSccDecomposition->size() <<
" SCC(s) containing a total of " << x.size()
79 <<
" states. Average SCC size is "
80 <<
static_cast<double>(this->getMatrixRowCount()) /
static_cast<double>(this->sortedSccDecomposition->size()) <<
".");
84 needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->getMatrixRowCount());
86 storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision);
88 if (this->longestSccChainSize) {
89 STORM_LOG_INFO(
"Longest SCC chain size is " << this->longestSccChainSize.get() <<
".");
93 bool returnValue =
true;
97 bool allSccsExact =
true;
98 bool allSccsPrecise =
true;
99 if (this->sortedSccDecomposition->size() == 1) {
100 if (
auto const& scc = *this->sortedSccDecomposition->begin(); scc.size() == 1) {
102 returnValue = solveTrivialScc(*scc.begin(), x, b);
104 returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b);
105 allSccsExact = this->sccSolver->hasExactSolutionBounds();
106 allSccsPrecise = lastSccMetPrecision(sccSolverEnvironment, x);
110 std::optional<storm::storage::BitVector> newRelevantValues;
112 this->sortedSccDecomposition->size() < this->A->getRowGroupCount()) {
115 std::vector<uint64_t> rowGroupToScc = this->sortedSccDecomposition->computeStateToSccIndexMap(this->A->getRowGroupCount());
116 for (uint64_t rowGroup = 0; rowGroup < this->A->getRowGroupCount(); ++rowGroup) {
117 auto currScc = rowGroupToScc[rowGroup];
118 for (
auto const& successor : this->A->getRowGroup(rowGroup)) {
119 if (rowGroupToScc[successor.getColumn()] != currScc) {
120 newRelevantValues->set(successor.getColumn(),
true);
126 uint64_t sccIndex = 0;
130 for (
auto const& scc : *this->sortedSccDecomposition) {
131 if (scc.size() == 1) {
132 returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue;
134 for (
auto const& state : scc) {
135 sccAsBitVector.
set(state,
true);
137 bool sccMetPrecision =
false;
138 returnValue = solveScc(sccSolverEnvironment, scc, sccAsBitVector, x, b, newRelevantValues, sccMetPrecision) && returnValue;
139 allSccsExact = allSccsExact && this->sccSolver->hasExactSolutionBounds();
140 allSccsPrecise = allSccsPrecise && sccMetPrecision;
142 if (scc.size() * 64 < sccAsBitVector.
size()) {
143 for (
auto const& state : scc) {
144 sccAsBitVector.
set(state,
false);
147 sccAsBitVector.
clear();
153 STORM_LOG_WARN(
"Topological solver aborted after analyzing " << sccIndex <<
"/" << this->sortedSccDecomposition->size() <<
" SCCs.");
160 if (returnValue && !aborted) {
161 trySetSolutionBounds(env, x, allSccsExact, allSccsPrecise && needAdaptPrecision);
171template<
typename ValueType>
172void TopologicalLinearEquationSolver<ValueType>::trySetSolutionBounds(
Environment const& env, std::vector<ValueType>
const& x,
bool allSccsExact,
173 bool allSccsPrecise)
const {
175 this->setSolutionBoundsExact(x);
178 if constexpr (std::is_same_v<ValueType, storm::RationalFunction>) {
183 if (!allSccsPrecise || !precision.first.is_initialized()) {
187 precision.second.is_initialized() && precision.second.get());
191template<
typename ValueType>
192bool TopologicalLinearEquationSolver<ValueType>::lastSccMetPrecision(Environment
const& sccSolverEnvironment, std::vector<ValueType>
const& sccValues)
const {
193 if constexpr (std::is_same_v<ValueType, storm::RationalFunction>) {
196 auto const precision = sccSolverEnvironment.solver().getPrecisionOfLinearEquationSolver(sccSolverEnvironment.solver().getLinearEquationSolverType());
197 if (!precision.first.is_initialized()) {
201 precision.second.is_initialized() && precision.second.get());
205template<
typename ValueType>
206void TopologicalLinearEquationSolver<ValueType>::createSortedSccDecomposition(
bool needLongestChainSize)
const {
208 this->sortedSccDecomposition = std::make_unique<storm::storage::StronglyConnectedComponentDecomposition<ValueType>>(
209 *this->A, storm::storage::StronglyConnectedComponentDecompositionOptions().forceTopologicalSort().computeSccDepths(needLongestChainSize));
210 if (needLongestChainSize) {
211 this->longestSccChainSize = this->sortedSccDecomposition->getMaxSccDepth() + 1;
215template<
typename ValueType>
216bool TopologicalLinearEquationSolver<ValueType>::solveTrivialScc(uint64_t
const& sccState, std::vector<ValueType>& globalX,
217 std::vector<ValueType>
const& globalB)
const {
219 xi = globalB[sccState];
220 bool hasDiagonalEntry =
false;
222 for (
auto const& entry : this->A->getRow(sccState)) {
223 if (entry.getColumn() == sccState) {
225 hasDiagonalEntry =
true;
228 xi += entry.getValue() * globalX[entry.getColumn()];
232 if (hasDiagonalEntry) {
235 "State " << sccState <<
" has a selfloop with probability '1-(" << denominator <<
")'. This could be an indication for numerical issues.");
245template<
typename ValueType>
246bool TopologicalLinearEquationSolver<ValueType>::solveFullyConnectedEquationSystem(storm::Environment
const& sccSolverEnvironment, std::vector<ValueType>& x,
247 std::vector<ValueType>
const& b)
const {
248 if (!this->sccSolver) {
250 this->sccSolver->setCachingEnabled(
true);
252 if (this->hasRelevantValues()) {
253 this->sccSolver->setRelevantValues(this->getRelevantValues());
255 this->sccSolver->setBoundsFromOtherSolver(*
this);
258 storm::storage::SparseMatrix<ValueType> eqSysA(*this->A,
true);
259 eqSysA.convertToEquationSystem();
260 this->sccSolver->setMatrix(std::move(eqSysA));
262 this->sccSolver->setMatrix(*this->A);
265 return this->sccSolver->solveEquations(sccSolverEnvironment, x, b);
268template<
typename ValueType>
269bool TopologicalLinearEquationSolver<ValueType>::solveScc(storm::Environment
const& sccSolverEnvironment, storm::storage::StronglyConnectedComponent
const& scc,
270 storm::storage::BitVector
const& sccAsBitVector, std::vector<ValueType>& globalX,
271 std::vector<ValueType>
const& globalB,
272 std::optional<storm::storage::BitVector>
const& globalRelevantValues,
bool& metPrecision)
const {
274 auto restrictToScc = [&scc](std::vector<ValueType>
const& globalVector) {
275 std::vector<ValueType> result;
276 result.reserve(scc.
size());
277 for (uint64_t
const state : scc) {
278 result.push_back(globalVector[state]);
284 if (!this->sccSolver) {
286 this->sccSolver->setCachingEnabled(
true);
288 if (!this->sccSubmatrixBuilder) {
289 this->sccSubmatrixBuilder = std::make_unique<storm::storage::SubmatrixBuilder<ValueType>>(*this->A);
291 if (globalRelevantValues) {
292 storm::storage::BitVector sccRelevantValues(scc.size(),
false);
293 uint64_t sccState = 0;
294 for (uint64_t
const state : scc) {
295 sccRelevantValues.set(sccState++, globalRelevantValues->get(state));
297 this->sccSolver->setRelevantValues(std::move(sccRelevantValues));
302 storm::storage::SparseMatrix<ValueType> sccA = this->sccSubmatrixBuilder->getByRowGroupConstraint(scc, scc, asEquationSystem);
303 if (asEquationSystem) {
306 this->sccSolver->setMatrix(std::move(sccA));
309 auto sccX = restrictToScc(globalX);
312 std::vector<ValueType> sccB;
313 sccB.reserve(scc.size());
314 for (uint64_t
const row : scc) {
316 for (
auto const& entry : this->A->getRow(row)) {
317 if (!sccAsBitVector.
get(entry.getColumn())) {
318 bi += entry.getValue() * globalX[entry.getColumn()];
321 sccB.push_back(std::move(bi));
325 if (this->hasLowerBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Global)) {
326 this->sccSolver->setLowerBound(this->getLowerBound());
327 }
else if (this->hasLowerBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Local)) {
328 this->sccSolver->setLowerBounds(restrictToScc(this->getLowerBounds()));
330 if (this->hasUpperBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Global)) {
331 this->sccSolver->setUpperBound(this->getUpperBound());
332 }
else if (this->hasUpperBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Local)) {
333 this->sccSolver->setUpperBounds(restrictToScc(this->getUpperBounds()));
336 bool returnvalue = this->sccSolver->solveEquations(sccSolverEnvironment, sccX, sccB);
337 metPrecision = lastSccMetPrecision(sccSolverEnvironment, sccX);
340 uint64_t sccState = 0;
341 for (uint64_t
const state : scc) {
342 globalX[state] = std::move(sccX[sccState++]);
347template<
typename ValueType>
352template<
typename ValueType>
358template<
typename ValueType>
360 sortedSccDecomposition.reset();
361 longestSccChainSize = boost::none;
363 sccSubmatrixBuilder.reset();
367template<
typename ValueType>
368uint64_t TopologicalLinearEquationSolver<ValueType>::getMatrixRowCount()
const {
369 return this->A->getRowCount();
372template<
typename ValueType>
373uint64_t TopologicalLinearEquationSolver<ValueType>::getMatrixColumnCount()
const {
374 return this->A->getColumnCount();
377template<
typename ValueType>
379 auto solver = std::make_unique<storm::solver::TopologicalLinearEquationSolver<ValueType>>();
384template<
typename ValueType>
386 return std::make_unique<TopologicalLinearEquationSolverFactory<ValueType>>(*this);
SolverEnvironment & solver()
TopologicalSolverEnvironment & topological()
uint64_t getShowProgressDelay() const
bool isForceSoundness() const
std::pair< boost::optional< storm::RationalNumber >, boost::optional< bool > > getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const &solverType) const
bool isVerboseSet() const
storm::solver::EquationSolverType const & getUnderlyingEquationSolverType() const
bool isExtendRelevantValues() const
bool const & isUnderlyingEquationSolverTypeSetFromDefault() const
storm::storage::BitVector const & getRelevantValues() const
virtual std::unique_ptr< LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
LinearEquationSolverRequirements getRequirements(Environment const &env) const
Retrieves the requirements of the solver if it was created with the current settings.
virtual void clearCache() const
bool isCachingEnabled() const
Retrieves whether some of the generated data during solver calls should be cached.
virtual std::unique_ptr< LinearEquationSolverFactory< ValueType > > clone() const override
Creates a copy of this factory.
virtual std::unique_ptr< storm::solver::LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const &env) const override
Retrieves the format in which this solver expects to solve equations.
virtual bool internalSolveEquations(storm::Environment const &env, std::vector< ValueType > &x, std::vector< ValueType > const &b) const override
virtual void setMatrix(storm::storage::SparseMatrix< ValueType > const &A) override
virtual LinearEquationSolverRequirements getRequirements(Environment const &env) const override
Retrieves the requirements of the solver under the current settings.
TopologicalLinearEquationSolver()
virtual void clearCache() const override
A bit vector that is internally represented as a vector of 64-bit values.
void clear()
Removes all set bits from the bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
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.
void convertToEquationSystem()
Transforms the matrix into an equation system.
std::size_t size() const
Retrieves the number of states in this SCC.
A class that provides convenience operations to display run times.
bool updateProgress(uint64_t count)
Updates the progress to the current count and logs it (on the progress log channel) if the delay pass...
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.
A class that provides convenience operations to display run times.
void stop()
Stop stopwatch and add measured time to total time.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
#define STORM_LOG_WARN_COND_DEBUG(cond, message)
SFTBDDChecker::ValueType ValueType
LinearEquationSolverProblemFormat
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
bool isOne(ValueType const &a)
NumberTraits< RationalType >::IntegerType denominator(RationalType const &number)
bool isAlmostZero(ValueType const &a)
bool isZero(ValueType const &a)
TargetType convertNumber(SourceType const &number)
static const bool IsExact