Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BinaryDtmcTransformer.cpp
Go to the documentation of this file.
2
3#include <queue>
4
13
14namespace storm {
15namespace transformer {
16std::shared_ptr<storm::models::sparse::Dtmc<RationalFunction>> BinaryDtmcTransformer::transform(storm::models::sparse::Dtmc<RationalFunction> const& dtmc,
17 bool keepStateValuations) const {
18 auto data = transformTransitions(dtmc);
20 components.stateLabeling = transformStateLabeling(dtmc, data);
21 for (auto const& rewModel : dtmc.getRewardModels()) {
22 components.rewardModels.emplace(rewModel.first, transformRewardModel(dtmc, rewModel.second, data));
23 }
24 components.transitionMatrix = std::move(data.simpleMatrix);
25 if (keepStateValuations && dtmc.hasStateValuations()) {
26 components.stateValuations = dtmc.getStateValuations().selectEntities(data.simpleStateToOriginalState);
27 }
28
29 return std::make_shared<storm::models::sparse::Dtmc<RationalFunction>>(std::move(components.transitionMatrix), std::move(components.stateLabeling),
30 std::move(components.rewardModels));
31}
32
34 uint64_t state;
35 std::vector<storage::MatrixEntry<uint64_t, RationalFunction>> row;
36};
37
38namespace {
39
50std::shared_ptr<RawPolynomialCache> cacheOf(Polynomial const& polynomial) {
51 auto cache = polynomial.pCache();
52 if (!cache) {
53 // The polynomial was never factored, so there is nothing to share. This is only expected for constant
54 // polynomials.
55 STORM_LOG_ASSERT(polynomial.isConstant(), "Expected a non-constant polynomial to carry a cache.");
56 return std::make_shared<RawPolynomialCache>();
57 }
58 return cache;
59}
60
70RationalFunction toRationalFunction(RawPolynomial const& numerator, Polynomial const& denominator, std::shared_ptr<RawPolynomialCache> const& cache) {
71 STORM_LOG_ASSERT(!denominator.pCache() || denominator.pCache() == cache, "Expected the denominator to share the cache of the numerator.");
72 return RationalFunction(Polynomial(numerator, cache), denominator);
73}
74
84std::shared_ptr<RawPolynomialCache> cacheOfModel(storm::models::sparse::Dtmc<RationalFunction> const& model) {
85 for (auto const& entry : model.getTransitionMatrix()) {
86 if (!entry.getValue().isConstant()) {
87 return cacheOf(entry.getValue().nominator());
88 }
89 }
90 return std::make_shared<RawPolynomialCache>();
91}
92
93} // namespace
94
95typename BinaryDtmcTransformer::TransformationData BinaryDtmcTransformer::transformTransitions(
96 storm::models::sparse::Dtmc<RationalFunction> const& dtmc) const {
97 auto const& matrix = dtmc.getTransitionMatrix();
98
99 // All polynomials of the model share a single factorization cache, which the polynomials created below reuse.
100 auto const cache = cacheOfModel(dtmc);
101
102 // Initialize a FIFO Queue that stores the start and the end of each row
103 std::queue<StateWithRow> queue;
104 for (uint64_t state = 0; state < matrix.getRowCount(); ++state) {
105 std::vector<storage::MatrixEntry<uint64_t, RationalFunction>> diyRow;
106 for (auto const& entry : matrix.getRow(state)) {
107 diyRow.push_back(entry);
108 }
109 queue.emplace(StateWithRow{state, diyRow});
110 }
111
112 storm::storage::SparseMatrixBuilder<RationalFunction> builder;
113 uint64_t currRow = 0;
114 uint64_t currAuxState = queue.size();
115 std::vector<uint64_t> origStates;
116
117 while (!queue.empty()) {
118 auto stateWithRow = std::move(queue.front());
119 queue.pop();
120
121 std::set<RationalFunctionVariable> variablesInRow;
122
123 for (auto const& entry : stateWithRow.row) {
124 for (auto const& variable : entry.getValue().gatherVariables()) {
125 variablesInRow.emplace(variable);
126 }
127 }
128
129 if (variablesInRow.size() == 0) {
130 // Insert the row directly
131 for (auto const& entry : stateWithRow.row) {
132 builder.addNextValue(currRow, entry.getColumn(), entry.getValue());
133 }
134 ++currRow;
135 } else if (variablesInRow.size() == 1) {
136 auto parameter = *variablesInRow.begin();
137 auto parameterPol = RawPolynomial(parameter);
138 auto oneMinusParameter = RawPolynomial(1) - parameterPol;
139
140 std::vector<storage::MatrixEntry<uint64_t, RationalFunction>> outgoing;
141 // p * .. state
142 std::vector<storage::MatrixEntry<uint64_t, RationalFunction>> newStateLeft;
143 // (1-p) * .. state
144 std::vector<storage::MatrixEntry<uint64_t, RationalFunction>> newStateRight;
145
146 RationalFunction sumOfLeftBranch;
147 RationalFunction sumOfRightBranch;
148
149 for (auto const& entry : stateWithRow.row) {
150 if (entry.getValue().isConstant()) {
151 outgoing.push_back(entry);
152 }
153 auto nominator = entry.getValue().nominator();
154 auto denominator = entry.getValue().denominator();
155 auto byP = RawPolynomial(nominator).divideBy(parameterPol);
156 if (byP.remainder.isZero()) {
157 auto probability = toRationalFunction(byP.quotient, denominator, cache);
158 newStateLeft.push_back(storage::MatrixEntry<uint64_t, RationalFunction>(entry.getColumn(), probability));
159 sumOfLeftBranch += probability;
160 continue;
161 }
162 auto byOneMinusP = RawPolynomial(nominator).divideBy(oneMinusParameter);
163 if (byOneMinusP.remainder.isZero()) {
164 auto probability = toRationalFunction(byOneMinusP.quotient, denominator, cache);
165 newStateRight.push_back(storage::MatrixEntry<uint64_t, RationalFunction>(entry.getColumn(), probability));
166 sumOfRightBranch += probability;
167 continue;
168 }
169 STORM_LOG_ERROR("Invalid transition!");
170 }
171 sumOfLeftBranch.simplify();
172 sumOfRightBranch.simplify();
173 for (auto& entry : newStateLeft) {
174 entry.setValue(entry.getValue() / sumOfLeftBranch);
175 }
176 for (auto& entry : newStateRight) {
177 entry.setValue(entry.getValue() / sumOfRightBranch);
178 }
179
180 auto parameterPolynomial = Polynomial(RawPolynomial(parameter), cache);
181
182 queue.push(StateWithRow{currAuxState, newStateLeft});
183 outgoing.push_back(storage::MatrixEntry<uint64_t, RationalFunction>(currAuxState, (sumOfLeftBranch)*RationalFunction(parameterPolynomial)));
184 ++currAuxState;
185 queue.push(StateWithRow{currAuxState, newStateRight});
186 outgoing.push_back(storage::MatrixEntry<uint64_t, RationalFunction>(
187 currAuxState, (sumOfRightBranch) * (utility::one<RationalFunction>() - RationalFunction(parameterPolynomial))));
188 ++currAuxState;
189
190 for (auto const& entry : outgoing) {
191 builder.addNextValue(currRow, entry.getColumn(), entry.getValue());
192 }
193 ++currRow;
194 } else {
195 STORM_LOG_ERROR("More than one variable in row " << currRow << "!");
196 }
197 origStates.push_back(stateWithRow.state);
198 }
199 TransformationData result;
200 result.simpleMatrix = builder.build(currRow, currAuxState, currAuxState);
201 result.simpleStateToOriginalState = std::move(origStates);
202 return result;
203}
204
205storm::models::sparse::StateLabeling BinaryDtmcTransformer::transformStateLabeling(storm::models::sparse::Dtmc<RationalFunction> const& dtmc,
206 TransformationData const& data) const {
207 storm::models::sparse::StateLabeling labeling(data.simpleMatrix.getRowCount());
208 for (auto const& labelName : dtmc.getStateLabeling().getLabels()) {
209 storm::storage::BitVector newStates = dtmc.getStateLabeling().getStates(labelName);
210 newStates.resize(data.simpleMatrix.getRowCount(), false);
211 if (labelName != "init") {
212 for (uint64_t newState = dtmc.getNumberOfStates(); newState < data.simpleMatrix.getRowCount(); ++newState) {
213 newStates.set(newState, newStates[data.simpleStateToOriginalState[newState]]);
214 }
215 }
216 labeling.addLabel(labelName, std::move(newStates));
217 }
218 return labeling;
219}
220
221storm::models::sparse::StandardRewardModel<RationalFunction> BinaryDtmcTransformer::transformRewardModel(
222 storm::models::sparse::Dtmc<RationalFunction> const& dtmc, storm::models::sparse::StandardRewardModel<RationalFunction> const& rewardModel,
223 TransformationData const& data) const {
224 std::optional<std::vector<RationalFunction>> stateRewards, actionRewards;
225 STORM_LOG_THROW(rewardModel.hasStateActionRewards(), storm::exceptions::NotSupportedException, "Only state rewards supported.");
226 if (rewardModel.hasStateRewards()) {
227 stateRewards = rewardModel.getStateRewardVector();
228 stateRewards->resize(data.simpleMatrix.getRowCount(), storm::utility::zero<RationalFunction>());
229 }
230 return storm::models::sparse::StandardRewardModel<RationalFunction>(std::move(stateRewards), std::move(actionRewards));
231}
232} // namespace transformer
233} // namespace storm
This class represents a discrete-time Markov chain.
Definition Dtmc.h:16
std::set< std::string > getLabels() const
Retrieves the set of labels contained in this labeling.
storm::storage::SparseMatrix< ValueType > const & getTransitionMatrix() const
Retrieves the matrix representing the transitions of the model.
Definition Model.cpp:226
std::unordered_map< std::string, RewardModelType > const & getRewardModels() const
Retrieves the reward models.
Definition Model.cpp:728
bool hasStateValuations() const
Retrieves whether this model was build with state valuations.
Definition Model.cpp:378
storm::storage::sparse::Valuations const & getStateValuations() const
Retrieves the valuations of the states of the model.
Definition Model.cpp:383
storm::models::sparse::StateLabeling const & getStateLabeling() const
Returns the state labeling associated with this model.
Definition Model.cpp:348
virtual uint_fast64_t getNumberOfStates() const override
Returns the number of states of the model.
Definition Model.cpp:191
std::vector< ValueType > const & getStateRewardVector() const
Retrieves the state rewards of the reward model.
bool hasStateRewards() const
Retrieves whether the reward model has state rewards.
bool hasStateActionRewards() const
Retrieves whether the reward model has state-action rewards.
storm::storage::BitVector const & getStates(std::string const &label) const
Returns the labeling of states associated with the given label.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
Valuations selectEntities(storm::storage::BitVector const &selectedEntities) const
Derive new valuations from this by selecting the given entities.
std::shared_ptr< storm::models::sparse::Dtmc< RationalFunction > > transform(storm::models::sparse::Dtmc< RationalFunction > const &dtmc, bool keepStateValuations=false) const
Transforms a pDTMC that has linear transitions (e.g.
#define STORM_LOG_ERROR(message)
Definition logging.h:36
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
NumberTraits< RationalType >::IntegerType denominator(RationalType const &number)
ValueType zero()
Definition constants.cpp:26
ValueType one()
Definition constants.cpp:21
carl::FactorizedPolynomial< RawPolynomial > Polynomial
carl::RationalFunction< Polynomial, true > RationalFunction
carl::MultivariatePolynomial< RationalFunctionCoefficient > RawPolynomial
std::unordered_map< std::string, RewardModelType > rewardModels
storm::storage::SparseMatrix< ValueType > transitionMatrix
storm::models::sparse::StateLabeling stateLabeling
std::optional< storm::storage::sparse::Valuations > stateValuations
std::vector< storage::MatrixEntry< uint64_t, RationalFunction > > row