27 auto const& weakData = quotientData.weakData;
29 STORM_LOG_ASSERT(isWeak == weakData.has_value(),
"Weak bisimulation data must be given for (and only for) weak bisimulation.");
30 bool const useSignature = quotientData.signatureData.has_value();
31 bool const isNondeterministic = model.isNondeterministicModel();
32 STORM_LOG_ASSERT(useSignature || !isNondeterministic,
"Signature data is required for nondeterministic models.");
33 auto const& toQuotientState = quotientData.toQuotientState;
34 auto const& toRepresentativeState = quotientData.toRepresentativeState;
35 auto const& toRepresentativeChoice = useSignature ? quotientData.signatureData->toRepresentativeChoice : quotientData.toRepresentativeState;
37 uint64_t
const numberOfQuotientStates = toRepresentativeState.size();
38 uint64_t
const numberOfQuotientChoices = toRepresentativeChoice.size();
39 STORM_LOG_ASSERT(isNondeterministic || numberOfQuotientStates == numberOfQuotientChoices,
"Unexpected choice count.");
47 auto getQuotientRow = [&model, &useSignature, "ientData, &toRepresentativeChoice, &toQuotientState, &isWeak,
48 &weakData](uint64_t
const quotientChoice) -> std::map<uint64_t, ValueType> {
50 return quotientData.signatureData->quotientChoiceDistributions[quotientChoice];
52 uint64_t
const representative = toRepresentativeChoice[quotientChoice];
53 uint64_t
const ownQuotientState = toQuotientState[representative];
55 if (weakData->divergentStates.get(representative)) {
62 "Weak bisimulation quotient: The representative of a non-divergent block is silent.");
64 std::map<uint64_t, ValueType> quotientRow;
65 for (
auto const& entry : model.getTransitionMatrix().getRow(representative)) {
66 if (
auto const ret = quotientRow.emplace(toQuotientState[entry.getColumn()], entry.getValue()); !ret.second) {
67 ret.first->second += entry.getValue();
71 if (isWeak && !weakData->stepSensitiveStates.get(representative)) {
73 if (
auto const ownBlockIt = quotientRow.find(ownQuotientState); ownBlockIt != quotientRow.end()) {
74 quotientRow.erase(ownBlockIt);
77 STORM_LOG_THROW(!quotientRow.empty(), storm::exceptions::UnexpectedException,
78 "Weak bisimulation quotient: the representative of a non-divergent block cannot leave its block.");
79 if (model.isDiscreteTimeModel()) {
84 for (
auto const& [_, value] : quotientRow) {
87 for (
auto& [_, value] : quotientRow) {
98 isNondeterministic ? numberOfQuotientStates : 0);
99 for (uint64_t quotientState = 0, quotientChoice = 0; quotientState < numberOfQuotientStates; ++quotientState) {
100 if (isNondeterministic) {
101 builder.newRowGroup(quotientChoice);
103 uint64_t
const quotientChoiceEnd = useSignature ? quotientData.signatureData->quotientChoiceGroupIndices[quotientState + 1] : quotientChoice + 1;
104 for (; quotientChoice < quotientChoiceEnd; ++quotientChoice) {
105 for (
auto const& [column, value] : getQuotientRow(quotientChoice)) {
106 builder.addNextValue(quotientChoice, column, value);
119 for (
auto const i : model.getStateLabeling().getStates(
"init")) {
120 init.
set(toQuotientState[i],
true);
122 stateLabeling.addLabel(
"init", std::move(init));
126 for (
auto const& l : preservationInformation.preservedStateLabels) {
130 auto const& in = model.getStateLabeling().getStates(l);
132 for (uint64_t quotientState = 0; quotientState < numberOfQuotientStates; ++quotientState) {
133 if (in.get(toRepresentativeState[quotientState])) {
134 out.
set(quotientState,
true);
137 stateLabeling.addLabel(l, std::move(out));
142 if (model.hasStateValuations()) {
143 components.
stateValuations = model.getStateValuations().selectEntities(toRepresentativeState);
147 if (!preservationInformation.preservedChoiceLabels.empty()) {
148 STORM_LOG_ASSERT(model.hasChoiceLabeling(),
"Model has no choice labeling but bisimulation preserved some.");
150 for (
auto const& l : preservationInformation.preservedChoiceLabels) {
151 auto const& in = model.getChoiceLabeling().getChoices(l);
153 for (uint64_t quotientChoice = 0; quotientChoice < numberOfQuotientChoices; ++quotientChoice) {
154 if (in.get(toRepresentativeChoice[quotientChoice])) {
155 out.
set(quotientChoice,
true);
163 if (model.hasChoiceOrigins() && options.preserveChoiceOrigins) {
164 components.
choiceOrigins = model.getChoiceOrigins()->selectChoices(toRepresentativeChoice);
168 for (
auto const& r : preservationInformation.preservedRewardModels) {
169 std::optional<std::vector<ValueType>> stateRewards, stateActionRewards;
170 auto const& rm = model.getRewardModel(r);
171 if (rm.hasStateRewards()) {
172 stateRewards.emplace();
173 stateRewards->reserve(numberOfQuotientStates);
174 for (
auto const representativeState : toRepresentativeState) {
175 stateRewards->push_back(rm.getStateReward(representativeState));
178 if (rm.hasStateActionRewards()) {
179 stateActionRewards.emplace();
180 stateActionRewards->reserve(numberOfQuotientChoices);
181 for (
auto const representativeChoice : toRepresentativeChoice) {
182 stateActionRewards->push_back(rm.getStateActionReward(representativeChoice));
185 STORM_LOG_THROW(!rm.hasTransitionRewards(), storm::exceptions::NotSupportedException,
"Transition rewards are not supported for quotient construction");
191 if (model.isOfType(Ctmc)) {
193 }
else if (model.isOfType(MarkovAutomaton)) {
194 auto const& ma = model.template as<storm::models::sparse::MarkovAutomaton<ValueType>>();
197 for (uint64_t quotientState = 0; quotientState < numberOfQuotientStates; ++quotientState) {
198 auto const representativeState = toRepresentativeState[quotientState];
199 if (ma->isMarkovianState(representativeState)) {
203 components.
exitRates.value()[quotientState] = ma->getExitRate(representativeState);
208 "The model type " << model.getType() <<
" is not supported for quotient construction.");