31template<
typename SparseModelType>
32std::shared_ptr<SparseModelType> eliminateConstantDeterministicStates(SparseModelType
const& model,
bool preserveParametricTransitions,
33 storm::storage::BitVector
const& consideredStates,
34 std::optional<std::string>
const& rewardModelName) {
35 storm::storage::SparseMatrix<typename SparseModelType::ValueType>
const& sparseMatrix = model.getTransitionMatrix();
36 auto backwardsSparseMatrix = sparseMatrix.
transpose();
39 std::vector<typename SparseModelType::ValueType> actionRewards;
40 if (rewardModelName) {
41 actionRewards = model.getRewardModel(*rewardModelName).getTotalRewardVector(sparseMatrix);
43 actionRewards = std::vector<typename SparseModelType::ValueType>(model.getTransitionMatrix().getRowCount(),
48 storm::storage::BitVector selectedStates = consideredStates;
49 for (uint64_t state : consideredStates) {
52 for (
auto const& entry : sparseMatrix.
getRowGroup(state)) {
54 selectedStates.
set(state,
false);
58 if (preserveParametricTransitions) {
59 for (
auto const& entry : backwardsSparseMatrix.getRowGroup(state)) {
61 selectedStates.
set(state,
false);
67 selectedStates.
set(state,
false);
72 storm::storage::FlexibleSparseMatrix<typename SparseModelType::ValueType> flexibleMatrix(sparseMatrix);
73 storm::storage::FlexibleSparseMatrix<typename SparseModelType::ValueType> flexibleBackwardTransitions(backwardsSparseMatrix,
true);
74 storm::solver::stateelimination::NondeterministicModelStateEliminator<typename SparseModelType::ValueType> stateEliminator(
75 flexibleMatrix, flexibleBackwardTransitions, actionRewards);
76 for (uint64_t state : selectedStates) {
77 stateEliminator.eliminateState(state,
true);
79 selectedStates.complement();
80 auto keptRows = sparseMatrix.
getRowFilter(selectedStates);
81 storm::storage::SparseMatrix<typename SparseModelType::ValueType> newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates);
84 std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels;
85 if (rewardModelName) {
87 rewardModels.insert(std::make_pair(*rewardModelName,
typename SparseModelType::RewardModelType(std::nullopt, std::move(actionRewards))));
90 return std::make_shared<SparseModelType>(std::move(newTransitionMatrix), model.getStateLabeling().getSubLabeling(selectedStates), std::move(rewardModels));
103template<
typename SparseModelType>
104std::shared_ptr<SparseModelType> eliminateNeutralEndComponents(SparseModelType
const& model, storm::storage::BitVector
const& ignoredStates,
105 std::optional<std::string>
const& rewardModelName) {
107 storm::storage::BitVector possibleECActions(model.getNumberOfChoices(),
true);
108 for (
auto state : ignoredStates) {
109 for (uint64_t
const actionIndex : model.getTransitionMatrix().getRowGroupIndices(state)) {
110 possibleECActions.set(actionIndex,
false);
115 std::vector<typename SparseModelType::ValueType> actionRewards;
116 if (rewardModelName) {
117 actionRewards = model.getRewardModel(*rewardModelName).getTotalRewardVector(model.getTransitionMatrix());
118 uint64_t actionIndex = 0;
119 for (
auto const& actionReward : actionRewards) {
121 possibleECActions.set(actionIndex,
false);
129 model.getTransitionMatrix(), storm::storage::BitVector(model.getNumberOfStates(),
true), possibleECActions,
130 storm::storage::BitVector(model.getNumberOfStates(),
false));
133 std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels;
134 if (rewardModelName) {
135 std::vector<typename SparseModelType::ValueType> newActionRewards(ecEliminatorResult.matrix.getRowCount());
137 rewardModels.insert(std::make_pair(*rewardModelName,
typename SparseModelType::RewardModelType(std::nullopt, std::move(newActionRewards))));
141 storm::models::sparse::StateLabeling labeling(ecEliminatorResult.matrix.getRowGroupCount());
142 for (
auto const& label : model.getStateLabeling().getLabels()) {
143 auto const& origStatesWithLabel = model.getStates(label);
144 storm::storage::BitVector newStatesWithLabel(ecEliminatorResult.matrix.getRowGroupCount(),
false);
145 for (
auto const& origState : origStatesWithLabel) {
146 newStatesWithLabel.set(ecEliminatorResult.oldToNewStateMapping[origState],
true);
148 labeling.addLabel(label, std::move(newStatesWithLabel));
151 return std::make_shared<SparseModelType>(std::move(ecEliminatorResult.matrix), std::move(labeling), std::move(rewardModels));
156template<
typename SparseModelType>
161template<
typename SparseModelType>
163 static_assert(std::is_same_v<SparseModelType, storm::models::sparse::Dtmc<storm::RationalFunction>> ||
164 std::is_same_v<SparseModelType, storm::models::sparse::Mdp<storm::RationalFunction>>,
165 "SparseParametricModelSimplifier is only implemented for parametric DTMCs and MDPs.");
167 simplifiedModel =
nullptr;
168 simplifiedFormula =
nullptr;
172 STORM_LOG_DEBUG(
"Simplification not possible because the formula is not supported. Formula: " << formula);
176 STORM_LOG_THROW(!originalModel.isNondeterministicModel() || operatorFormula.hasOptimalityType() || operatorFormula.hasBound(),
177 storm::exceptions::InvalidPropertyException,
178 "The formula " << formula <<
" is not supported for nondeterministic models. It must either have an optimality type or a bound.");
179 bool const minimizing = originalModel.isNondeterministicModel() &&
182 bool enableStateElimination =
false;
183 bool enableEndComponentElimination =
false;
184 std::optional<std::string> rewardModelName;
185 if (operatorFormula.isProbabilityOperatorFormula()) {
186 if (operatorFormula.getSubformula().isUntilFormula()) {
189 auto eventuallyFormula = std::make_shared<storm::logic::EventuallyFormula const>(
191 simplifiedFormula = std::make_shared<storm::logic::ProbabilityOperatorFormula const>(eventuallyFormula, operatorFormula.getOperatorInformation());
192 enableStateElimination =
true;
193 enableEndComponentElimination = originalModel.isNondeterministicModel() && !minimizing;
194 }
else if (operatorFormula.getSubformula().isReachabilityProbabilityFormula()) {
195 enableStateElimination =
true;
196 enableEndComponentElimination = originalModel.isNondeterministicModel() && !minimizing;
197 }
else if (operatorFormula.getSubformula().isBoundedUntilFormula()) {
198 auto const& boundedUntilFormula = operatorFormula.getSubformula().asBoundedUntilFormula();
200 if (!boundedUntilFormula.isMultiDimensional() && !boundedUntilFormula.getTimeBoundReference().isRewardBound()) {
203 auto newBoundedUntilFormula = std::make_shared<storm::logic::BoundedUntilFormula const>(
205 boundedUntilFormula.getLowerBoundAsOptionalTimeBound(), boundedUntilFormula.getUpperBoundAsOptionalTimeBound(),
208 std::make_shared<storm::logic::ProbabilityOperatorFormula const>(newBoundedUntilFormula, operatorFormula.getOperatorInformation());
212 }
else if (operatorFormula.isRewardOperatorFormula()) {
213 if (operatorFormula.asRewardOperatorFormula().hasRewardModelName()) {
214 rewardModelName = operatorFormula.asRewardOperatorFormula().getRewardModelName();
215 STORM_LOG_THROW(originalModel.hasRewardModel(*rewardModelName), storm::exceptions::InvalidPropertyException,
216 "The reward model specified by formula " << formula <<
" is not available in the given model.");
218 STORM_LOG_THROW(originalModel.hasUniqueRewardModel(), storm::exceptions::InvalidPropertyException,
219 "The formula " << formula <<
" does not specify a reward model and the reward model is not unique.");
220 rewardModelName = originalModel.getUniqueRewardModelName();
222 if (operatorFormula.getSubformula().isReachabilityRewardFormula()) {
223 enableStateElimination =
true;
224 enableEndComponentElimination = originalModel.isNondeterministicModel() && minimizing;
225 }
else if (operatorFormula.getSubformula().isCumulativeRewardFormula()) {
227 if (
auto const& cumulativeRewardFormula = operatorFormula.getSubformula().asCumulativeRewardFormula();
228 !cumulativeRewardFormula.isMultiDimensional() && !cumulativeRewardFormula.getTimeBoundReference().isRewardBound()) {
230 boost::optional<storm::logic::RewardAccumulation> rewAcc;
231 if (cumulativeRewardFormula.hasRewardAccumulation()) {
232 rewAcc = cumulativeRewardFormula.getRewardAccumulation();
234 storm::logic::TimeBound timeBound(cumulativeRewardFormula.isBoundStrict(), cumulativeRewardFormula.getBound());
235 auto newCumulativeRewardFormula =
236 std::make_shared<storm::logic::CumulativeRewardFormula const>(timeBound, cumulativeRewardFormula.getTimeBoundReference(), rewAcc);
237 simplifiedFormula = std::make_shared<storm::logic::RewardOperatorFormula const>(newCumulativeRewardFormula, rewardModelName.value(),
238 operatorFormula.getOperatorInformation());
245 if (!simplifiedFormula) {
246 simplifiedFormula = formula.
clone();
254 STORM_LOG_DEBUG(
"Simplification not possible because the goal state merger does not support it.");
257 simplifiedModel = mergerResult->model->template as<SparseModelType>();
260 std::string bottomLabel =
"";
261 if (enableEndComponentElimination) {
264 if (mergerResult->targetState) {
265 bottomStates.
set(*mergerResult->targetState,
true);
267 if (mergerResult->sinkState) {
268 bottomStates.
set(*mergerResult->sinkState,
true);
270 bottomLabel = simplifiedModel->getStateLabeling().addUniqueLabel(
"bottom", std::move(bottomStates));
272 if (enableStateElimination) {
275 if (mergerResult->targetState) {
276 considerForElimination.
set(*mergerResult->targetState,
false);
278 if (mergerResult->sinkState) {
279 considerForElimination.
set(*mergerResult->sinkState,
false);
281 simplifiedModel = eliminateConstantDeterministicStates(*simplifiedModel, preserveParametricTransitions, considerForElimination, rewardModelName);
283 if (enableEndComponentElimination) {
285 simplifiedModel = eliminateNeutralEndComponents(*simplifiedModel, simplifiedModel->getStates(bottomLabel), rewardModelName);
291template<
typename SparseModelType>
293 STORM_LOG_THROW(simplifiedModel, storm::exceptions::InvalidStateException,
"Tried to get the simplified model but simplification was not invoked before.");
294 return simplifiedModel;
297template<
typename SparseModelType>
299 STORM_LOG_THROW(simplifiedFormula, storm::exceptions::InvalidStateException,
300 "Tried to get the simplified formula but simplification was not invoked before.");
301 return simplifiedFormula;
304template<
typename SparseModelType>
306 this->preserveParametricTransitions = preserveParametricTransitions;
309template<
typename SparseModelType>
311 return this->preserveParametricTransitions;
A bit vector that is internally represented as a vector of 64-bit values.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
const_rows getRowGroup(index_type rowGroup) const
Returns an object representing the given row group.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowGroupSize(index_type group) const
Returns the size of the given row group.
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
storm::storage::BitVector getRowFilter(storm::storage::BitVector const &groupConstraint) const
Returns a bitvector representing the set of rows, with all indices set that correspond to one of the ...
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_THROW(cond, exception, message)
bool isLowerBound(ComparisonType t)
bool constexpr minimize(OptimizationDirection d)
void selectVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Selects the elements from a vector at the specified positions and writes them consecutively into anot...
void filterVectorInPlace(std::vector< Type > &v, storm::storage::BitVector const &filter)
bool isConstant(ValueType const &)
bool isZero(ValueType const &a)