25template<
typename ModelType,
typename BlockDataType>
28 this->preserveSingleFormula(
model, formula);
31template<
typename ModelType,
typename BlockDataType>
33 std::vector<std::shared_ptr<storm::logic::Formula const>>
const& formulas,
36 if (formulas.empty()) {
37 this->respectedAtomicPropositions = model.getStateLabeling().getLabels();
38 this->keepRewards = true;
40 if (formulas.size() == 1) {
41 this->preserveSingleFormula(model, *formulas.front());
43 for (auto const& formula : formulas) {
44 preserveFormula(*formula);
49template<
typename ModelType,
typename BlockDataType>
55template<
typename ModelType,
typename BlockDataType>
60template<
typename ModelType,
typename BlockDataType>
83template<
typename ModelType,
typename BlockDataType>
84void BisimulationDecomposition<ModelType, BlockDataType>::Options::preserveSingleFormula(ModelType
const&
model,
storm::logic::Formula const& formula) {
100 this->checkAndSetMeasureDrivenInitialPartition(
model, formula);
103template<
typename ModelType,
typename BlockDataType>
104void BisimulationDecomposition<ModelType, BlockDataType>::Options::checkAndSetMeasureDrivenInitialPartition(ModelType
const&
model,
106 std::shared_ptr<storm::logic::Formula const> newFormula = formula.
asSharedPointer();
114 optimalityType = OptimizationDirection::Maximize;
116 optimalityType = OptimizationDirection::Minimize;
126 optimalityType = OptimizationDirection::Maximize;
128 optimalityType = OptimizationDirection::Minimize;
134 std::shared_ptr<storm::logic::Formula const> leftSubformula = std::make_shared<storm::logic::BooleanLiteralFormula>(
true);
135 std::shared_ptr<storm::logic::Formula const> rightSubformula;
136 if (newFormula->isUntilFormula()) {
137 leftSubformula = newFormula->asUntilFormula().getLeftSubformula().asSharedPointer();
138 rightSubformula = newFormula->asUntilFormula().getRightSubformula().asSharedPointer();
140 measureDrivenInitialPartition =
true;
142 }
else if (newFormula->isEventuallyFormula()) {
143 rightSubformula = newFormula->asEventuallyFormula().getSubformula().asSharedPointer();
145 measureDrivenInitialPartition =
true;
149 if (measureDrivenInitialPartition) {
150 storm::modelchecker::SparsePropositionalModelChecker<ModelType> checker(
model);
151 std::unique_ptr<storm::modelchecker::CheckResult> phiStatesCheckResult = checker.check(*leftSubformula);
152 std::unique_ptr<storm::modelchecker::CheckResult> psiStatesCheckResult = checker.check(*rightSubformula);
155 phiStates = phiStatesCheckResult->template asExplicitQualitativeCheckResult<SolutionType>().getTruthValuesVector();
156 psiStates = psiStatesCheckResult->template asExplicitQualitativeCheckResult<SolutionType>().getTruthValuesVector();
158 optimalityType.reset();
162template<
typename ModelType,
typename BlockDataType>
164 std::vector<std::shared_ptr<storm::logic::AtomicExpressionFormula const>>
const& expressions,
165 std::vector<std::shared_ptr<storm::logic::AtomicLabelFormula const>>
const& labels) {
166 std::set<std::string> labelsToRespect;
167 for (
auto const& labelFormula : labels) {
168 labelsToRespect.insert(labelFormula->getLabel());
170 for (
auto const& expressionFormula : expressions) {
171 labelsToRespect.insert(expressionFormula->toString());
173 if (!respectedAtomicPropositions) {
174 respectedAtomicPropositions = labelsToRespect;
176 respectedAtomicPropositions.value().insert(labelsToRespect.begin(), labelsToRespect.end());
180template<
typename ModelType,
typename BlockDataType>
186template<
typename ModelType,
typename BlockDataType>
192 "Bisimulation currently only supports models with at most one reward model.");
194 storm::exceptions::IllegalFunctionCallException,
195 "Bisimulation is currently supported for models with state or action rewards only. Consider converting the transition rewards to state "
196 "rewards (via suitable function calls).");
198 "Weak bisimulation cannot preserve bounded properties.");
200 "Weak bisimulation cannot preserve discounted properties.");
208template<
typename ModelType,
typename BlockDataType>
210 std::chrono::high_resolution_clock::time_point totalStart = std::chrono::high_resolution_clock::now();
212 std::chrono::high_resolution_clock::time_point initialPartitionStart = std::chrono::high_resolution_clock::now();
214 if (
options.measureDrivenInitialPartition) {
215 STORM_LOG_THROW(
options.phiStates, storm::exceptions::InvalidOptionException,
"Unable to compute measure-driven initial partition without phi states.");
216 STORM_LOG_THROW(
options.psiStates, storm::exceptions::InvalidOptionException,
"Unable to compute measure-driven initial partition without psi states.");
222 std::chrono::high_resolution_clock::duration initialPartitionTime = std::chrono::high_resolution_clock::now() - initialPartitionStart;
226 std::chrono::high_resolution_clock::time_point refinementStart = std::chrono::high_resolution_clock::now();
228 std::chrono::high_resolution_clock::duration refinementTime = std::chrono::high_resolution_clock::now() - refinementStart;
230 std::chrono::high_resolution_clock::time_point extractionStart = std::chrono::high_resolution_clock::now();
232 std::chrono::high_resolution_clock::duration extractionTime = std::chrono::high_resolution_clock::now() - extractionStart;
234 std::chrono::high_resolution_clock::time_point quotientBuildStart = std::chrono::high_resolution_clock::now();
238 std::chrono::high_resolution_clock::duration quotientBuildTime = std::chrono::high_resolution_clock::now() - quotientBuildStart;
240 std::chrono::high_resolution_clock::duration totalTime = std::chrono::high_resolution_clock::now() - totalStart;
243 std::chrono::milliseconds initialPartitionTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(initialPartitionTime);
244 std::chrono::milliseconds refinementTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(refinementTime);
245 std::chrono::milliseconds extractionTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(extractionTime);
246 std::chrono::milliseconds quotientBuildTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(quotientBuildTime);
247 std::chrono::milliseconds totalTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(totalTime);
249 STORM_LOG_STATISTICS(
" * time for initial partition: " << initialPartitionTimeInMilliseconds.count() <<
"ms\n");
251 STORM_LOG_STATISTICS(
" * time for extraction: " << extractionTimeInMilliseconds.count() <<
"ms\n");
252 STORM_LOG_STATISTICS(
" * time for building quotient: " << quotientBuildTimeInMilliseconds.count() <<
"ms\n");
258template<
typename ModelType,
typename BlockDataType>
261 std::vector<Block<BlockDataType>*> splitterQueue;
263 block->data().setSplitter();
264 splitterQueue.push_back(block.get());
268 uint_fast64_t iterations = 0;
269 while (!splitterQueue.empty()) {
275 std::sort(splitterQueue.begin(), splitterQueue.end(),
278 splitterQueue.pop_back();
279 splitter->
data().setSplitter(
false);
285 STORM_LOG_INFO(
"Performed " << iterations <<
" iterations of partition refinement before abort.\n");
286 STORM_LOG_THROW(
false, storm::exceptions::AbortException,
"Aborted in bisimulation computation.");
292template<
typename ModelType,
typename BlockDataType>
295 "Unable to retrieve quotient model from bisimulation decomposition, because it was not built.");
299template<
typename ModelType,
typename BlockDataType>
301 auto const& rewardModel =
model.getUniqueRewardModel();
302 if (rewardModel.hasStateRewards()) {
305 if (rewardModel.hasStateActionRewards()) {
306 if (
model.isNondeterministicModel()) {
307 std::vector<std::set<ValueType>> actionRewards;
308 actionRewards.reserve(
model.getNumberOfStates());
310 std::set<ValueType> rewardsAtState;
311 for (
auto choice =
model.getTransitionMatrix().getRowGroupIndices()[state];
312 choice <
model.getTransitionMatrix().getRowGroupIndices()[state + 1]; ++choice) {
313 rewardsAtState.insert(rewardModel.getStateActionReward(choice));
315 actionRewards.push_back(std::move(rewardsAtState));
324template<
typename ModelType,
typename BlockDataType>
327 return rewardVector[a] < rewardVector[b];
331template<
typename ModelType,
typename BlockDataType>
334 return actionRewards[a] < actionRewards[b];
338template<
typename ModelType,
typename BlockDataType>
342 for (
auto const& label :
options.respectedAtomicPropositions.value()) {
343 if (label ==
"init") {
351 if (
options.getKeepRewards() &&
model.hasRewardModel()) {
356template<
typename ModelType,
typename BlockDataType>
360 std::optional<storm::storage::sparse::state_type> representativePsiState;
361 if (!
options.psiStates.value().empty()) {
362 representativePsiState = *
options.psiStates.value().begin();
366 model.getNumberOfStates(), statesWithProbability01.first,
367 options.getBounded() ||
options.getKeepRewards() ?
options.psiStates.value() : statesWithProbability01.second, representativePsiState);
371 if (
options.getKeepRewards() &&
model.hasRewardModel()) {
376template<
typename ModelType,
typename BlockDataType>
381template<
typename ModelType,
typename BlockDataType>
386 for (
auto const& blockPtr :
partition.getBlocks()) {
This class is the superclass of all decompositions of a sparse model into its bisimulation quotient.
storm::storage::SparseMatrix< ValueType > backwardTransitions
virtual void buildQuotient()=0
virtual void refinePartitionBasedOnSplitter(bisimulation::Block< bisimulation::DeterministicBlockData > &splitter, std::vector< bisimulation::Block< bisimulation::DeterministicBlockData > * > &splitterVector)=0
storm::utility::ConstantsComparator< ValueType > comparator
std::shared_ptr< ModelType > getQuotient() const
Retrieves the quotient of the model under the computed bisimulation.
std::shared_ptr< ModelType > quotient
void performPartitionRefinement()
virtual void splitInitialPartitionBasedOnRewards()
Splits the initial partition based on the (unique) reward model of the current model.
virtual void splitInitialPartitionBasedOnActionRewards(std::vector< std::set< ValueType > > const &rewardVector)
Splits the initial partition based on the given vector of action rewards.
BisimulationDecomposition(ModelType const &model, Options const &options)
Decomposes the given model into equivalence classes of a bisimulation.
storm::storage::bisimulation::Partition< BlockDataType > partition
void computeBisimulationDecomposition()
Computes the decomposition of the model into bisimulation equivalence classes.
ModelType::ValueType ValueType
void extractDecompositionBlocks()
virtual std::pair< storm::storage::BitVector, storm::storage::BitVector > getStatesWithProbability01()=0
Computes the set of states with probability 0/1 for satisfying phi until psi.
virtual void initializeMeasureDrivenPartition()
Creates the measure-driven initial partition for reaching psi states from phi states.
virtual void initializeLabelBasedPartition()
Initializes the initial partition based on all respected labels.
virtual void initialize()
A function that can initialize auxiliary data structures.
std::vector< block_type > blocks
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_INFO(message)
#define STORM_LOG_STATISTICS(message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
FragmentSpecification propositional()
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
typename detail::IntervalMetaProgrammingHelper< ValueType >::BaseType IntervalBaseType
Helper to access the type in which interval boundaries are stored.
void preserveFormula(storm::logic::Formula const &formula)
Changes the options in a way that the given formula is preserved.
static Options preservingAllLabels(ValueType const &tolerance)
Creates an object representing the options necessary to obtain the quotient that respects all atomic ...
bool measureDrivenInitialPartition
std::optional< storm::storage::BitVector > phiStates
Options(ModelType const &model, storm::logic::Formula const &formula, ValueType const &tolerance)
Creates an object representing the options necessary to obtain the quotient while still preserving th...
std::optional< std::set< std::string > > respectedAtomicPropositions
An optional set of strings that indicate which of the atomic propositions of the model are to be resp...
std::optional< storm::storage::BitVector > psiStates