Browse Source
symbolic: MDPQuotient transformation for computing the quotient MDP given an equivalence relation on the states
symbolic: MDPQuotient transformation for computing the quotient MDP given an equivalence relation on the states
git-svn-id: https://www.prismmodelchecker.org/svn/prism/prism/trunk@11949 bbc10eb1-c90d-0410-af57-cb519fbb1720master
1 changed files with 601 additions and 0 deletions
@ -0,0 +1,601 @@ |
|||
//============================================================================== |
|||
// |
|||
// Copyright (c) 2016- |
|||
// Authors: |
|||
// * Joachim Klein <klein@tcs.inf.tu-dresden.de> |
|||
// |
|||
//------------------------------------------------------------------------------ |
|||
// |
|||
// This file is part of PRISM. |
|||
// |
|||
// PRISM is free software; you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation; either version 2 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// PRISM is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with PRISM; if not, write to the Free Software Foundation, |
|||
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
// |
|||
//============================================================================== |
|||
|
|||
|
|||
package prism; |
|||
|
|||
import java.util.List; |
|||
|
|||
import jdd.JDD; |
|||
import jdd.JDDNode; |
|||
import jdd.JDDVars; |
|||
import jdd.SanityJDD; |
|||
|
|||
/** |
|||
* Transformation for obtaining the quotient MDP for an MDP, given an |
|||
* equivalence relation. |
|||
* <br> |
|||
* Given a list of equivalent classes (have to be disjoint, but don't need |
|||
* to cover the whole state space), each class is collapsed to a single state, |
|||
* the representative for the class. |
|||
* <br> |
|||
* Transitions from and to a state in an equivalence class are attached |
|||
* to the representative instead. |
|||
* To allow a symbolic treatment, several new non-deterministic choice |
|||
* variables are introduced, yielding action labels of the form (t,s,alpha): |
|||
* <ul> |
|||
* <li>(!tau, 0, alpha) corresponds to an action alpha in the original model (not originating |
|||
* from a state in an equivalence class)</li> |
|||
* <li>(tau, s, alpha) corresponds to an action alpha that originated from state s in some equivalence class</li> |
|||
* </ul> |
|||
* Self-loop actions on the representative, i.e., actions where the representative is the |
|||
* only successor, are removed in most cases. They are only retained if the representative |
|||
* would become a deadlock state otherwise. |
|||
* <br> |
|||
* Rewards are handled as follows: |
|||
* <ul> |
|||
* <li>State rewards for all states in equivalence classes are set to zero</li> |
|||
* <li>Transition rewards for all state-action pairs where all successors |
|||
* remain in the equivalence class are set to zero as well (this is visible for the self-loops on |
|||
* representatives that would be deadlocks otherwise)</li> |
|||
* </ul> |
|||
* <br> |
|||
* Labels attached to the original model are currently effectively stripped, |
|||
* i.e., they are replaced with JDD.ZERO. In the future, more advanced treatment |
|||
* may be added. |
|||
* <br> |
|||
* Note as well that evaluating expressions in the quotient model will not lead to correct results. |
|||
*/ |
|||
public class MDPQuotient implements ModelTransformation<NondetModel,NondetModel> |
|||
{ |
|||
private NondetModel originalModel; |
|||
private NondetModel transformedModel; |
|||
private MDPQuotientOperator transform; |
|||
private JDDNode transformedStatesOfInterest; |
|||
|
|||
/** Private constructor */ |
|||
private MDPQuotient(NondetModel originalModel, NondetModel transformedModel, MDPQuotientOperator transform, JDDNode transformedStatesOfInterest) |
|||
{ |
|||
this.originalModel = originalModel; |
|||
this.transformedModel = transformedModel; |
|||
this.transform = transform; |
|||
this.transformedStatesOfInterest = transformedStatesOfInterest; |
|||
} |
|||
|
|||
@Override |
|||
public NondetModel getOriginalModel() |
|||
{ |
|||
return originalModel; |
|||
} |
|||
|
|||
@Override |
|||
public NondetModel getTransformedModel() |
|||
{ |
|||
return transformedModel; |
|||
} |
|||
|
|||
@Override |
|||
public void clear() |
|||
{ |
|||
transformedModel.clear(); |
|||
transform.clear(); |
|||
JDD.Deref(transformedStatesOfInterest); |
|||
} |
|||
|
|||
@Override |
|||
public StateValues projectToOriginalModel(StateValues svTransformedModel) throws PrismException |
|||
{ |
|||
StateValuesMTBDD sv = svTransformedModel.convertToStateValuesMTBDD(); |
|||
JDDNode v = sv.getJDDNode().copy(); |
|||
sv.clear(); |
|||
|
|||
v = transform.liftFromRepresentatives(v); |
|||
|
|||
return new StateValuesMTBDD(v, transform.originalModel); |
|||
} |
|||
|
|||
/** Map the given state set from the original model to the quotient model */ |
|||
public JDDNode mapStateSetToQuotient(JDDNode S) |
|||
{ |
|||
return transform.mapStateSet(S); |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedStatesOfInterest() |
|||
{ |
|||
return transformedStatesOfInterest; |
|||
} |
|||
|
|||
/** |
|||
* Compute the quotient MDP, collapsing each maximal end component (MEC) to a single state. |
|||
* Only collapses MECs contained in {@code restrict}. |
|||
* |
|||
* <br>[ REFs: <i>result</i>, DEREFs: restrict ] |
|||
*/ |
|||
public static MDPQuotient mecQuotient(PrismComponent parent, final NondetModel model, JDDNode restrict, JDDNode statesOfInterest) throws PrismException |
|||
{ |
|||
ECComputer ec = ECComputer.createECComputer(parent, model); |
|||
ec.computeMECStates(restrict); |
|||
JDD.Deref(restrict); |
|||
|
|||
return transform(parent, model, ec.getMECStates(), statesOfInterest); |
|||
} |
|||
|
|||
/** |
|||
* Compute the quotient MDP for the given list of equivalence classes (the classes have to be disjoint). |
|||
* |
|||
* <br>[ REFs: <i>result</i>, DEREFs: equivalenceClasses, statesOfInterest ] |
|||
*/ |
|||
public static MDPQuotient transform(PrismComponent parent, final NondetModel model, List<JDDNode> equivalentClasses, JDDNode statesOfInterest) |
|||
throws PrismException |
|||
{ |
|||
final MDPQuotientOperator transform = new MDPQuotientOperator(parent, model, equivalentClasses); |
|||
final JDDNode transformedStatesOfInterest = transform.mapStateSet(statesOfInterest); |
|||
|
|||
final NondetModel quotient = model.getTransformed(transform); |
|||
|
|||
return new MDPQuotient(model, quotient, transform, transformedStatesOfInterest); |
|||
} |
|||
|
|||
/** The transformation operator for the MDPQuotient operation. */ |
|||
public static class MDPQuotientOperator extends NondetModelTransformationOperator { |
|||
/** the list of equivalence classes */ |
|||
private List<JDDNode> equivalentClasses; |
|||
|
|||
/** |
|||
* A symbolic mapping (0/1-ADD) from states (row vars) to their representative (col vars) |
|||
* in the quotient model.<br> |
|||
* For states in equivalence classes map to the representative, states not contained in |
|||
* an equivalent class are mapped to themselves. |
|||
*/ |
|||
private JDDNode map; |
|||
|
|||
/** State set: states contained in equivalence classes */ |
|||
private JDDNode inEC; |
|||
|
|||
/** State set: states not contained in equivalence classes */ |
|||
private JDDNode notInEC; |
|||
|
|||
/** State set: representative states for equivalence classes */ |
|||
private JDDNode representatives = JDD.Constant(0); |
|||
|
|||
/** |
|||
* n JDDVars, where n = number of row vars in the original model. |
|||
* Used to store the original originating state of a transition in |
|||
* the quotient model. |
|||
*/ |
|||
private JDDVars actFromStates; |
|||
|
|||
/** Set of (s,alpha) where all successors are again in the same equivalence class */ |
|||
private JDDNode stateActionsInsideECs; |
|||
|
|||
/** The transition relation of the quotient model */ |
|||
private JDDNode newTrans; |
|||
/** The 0/1-transition relation of the quotient model */ |
|||
private JDDNode newTrans01; |
|||
/** Self loops on quotient representative states that are not to be dropped */ |
|||
private JDDNode ecRemainingSelfLoops = JDD.Constant(0); |
|||
|
|||
/** New transition matrix already computed? */ |
|||
private boolean computed = false; |
|||
|
|||
/** The parent prism component (for logging) */ |
|||
private PrismComponent parent; |
|||
|
|||
/** Debug: Verbose output? */ |
|||
private boolean verbose = false; |
|||
|
|||
/** Constructor */ |
|||
public MDPQuotientOperator(PrismComponent parent, NondetModel model, List<JDDNode> equivalentClasses) |
|||
{ |
|||
super(model); |
|||
|
|||
this.equivalentClasses = equivalentClasses; |
|||
this.parent = parent; |
|||
|
|||
map = JDD.Constant(0); |
|||
inEC = JDD.Constant(0); |
|||
stateActionsInsideECs = JDD.Constant(0); |
|||
|
|||
for (JDDNode ec : equivalentClasses) { |
|||
// determine representative for the EC |
|||
JDDNode rep = JDD.RestrictToFirst(ec.copy(), model.getAllDDRowVars()); |
|||
// map = { s in EC } -> representative' |
|||
map = JDD.Or(map, JDD.And(ec.copy(), |
|||
JDD.PermuteVariables(rep.copy(), |
|||
model.getAllDDRowVars(), |
|||
model.getAllDDColVars()))); |
|||
// remember all states in ECs |
|||
inEC = JDD.Or(inEC, ec.copy()); |
|||
representatives = JDD.Or(representatives, rep); |
|||
|
|||
JDDNode ecCol = JDD.PermuteVariables(ec.copy(), model.getAllDDRowVars(), model.getAllDDColVars()); |
|||
JDDNode transFromEC01 = JDD.And(ec.copy(), model.getTrans01().copy()); |
|||
JDDNode selfLoop = JDD.Times(transFromEC01.copy(), ecCol.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), selfLoop.copy(), "selfLoop"); |
|||
JDDNode stateActionWithSelfLoop = JDD.ThereExists(selfLoop, originalModel.getAllDDColVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionWithSelfLoop.copy(), "stateActionWithSelfLoop"); |
|||
|
|||
// from the state action pairs with self loop, find those that also go somewhere |
|||
// else |
|||
JDDNode stateActionElse = JDD.And(stateActionWithSelfLoop.copy(), transFromEC01.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionElse.copy(), "stateActionElse"); |
|||
stateActionElse = JDD.And(stateActionElse, JDD.Not(ecCol.copy())); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionElse.copy(), "stateActionElse (2)"); |
|||
stateActionElse = JDD.ThereExists(stateActionElse, originalModel.getAllDDColVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionElse.copy(), "stateActionElse (3)"); |
|||
JDDNode stateActionWithOnlySelfLoop = JDD.And(stateActionWithSelfLoop, JDD.Not(stateActionElse)); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionWithOnlySelfLoop.copy(), "stateActionOnlySelfLoop"); |
|||
|
|||
stateActionsInsideECs = JDD.Or(stateActionsInsideECs, stateActionWithOnlySelfLoop); |
|||
|
|||
JDD.Deref(ecCol, transFromEC01); |
|||
} |
|||
|
|||
// all states not in EC |
|||
notInEC = JDD.And(model.getReach().copy(), |
|||
JDD.Not(inEC.copy())); |
|||
|
|||
// map all states not in EC to themselves |
|||
map = JDD.ITE(notInEC.copy(), |
|||
JDD.Identity(model.getAllDDRowVars(), model.getAllDDColVars()), |
|||
map); |
|||
} |
|||
|
|||
@Override |
|||
public void clear() |
|||
{ |
|||
for (JDDNode ec : equivalentClasses) { |
|||
JDD.Deref(ec); |
|||
} |
|||
JDD.Deref(map); |
|||
JDD.Deref(inEC); |
|||
JDD.Deref(notInEC); |
|||
JDD.Deref(representatives); |
|||
JDD.Deref(stateActionsInsideECs); |
|||
JDD.Deref(ecRemainingSelfLoops); |
|||
if (newTrans != null) JDD.Deref(newTrans); |
|||
if (newTrans01 != null) JDD.Deref(newTrans01); |
|||
if (actFromStates != null) |
|||
actFromStates.derefAll(); |
|||
super.clear(); |
|||
} |
|||
|
|||
@Override |
|||
public int getExtraStateVariableCount() |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
@Override |
|||
public int getExtraActionVariableCount() |
|||
{ |
|||
// 1 bit (tau) for normal vs special action (leaving a representative), |
|||
// numDDRowVar bits to remember original originating state |
|||
// for the states leaving a representative |
|||
return originalModel.getNumDDRowVars() + 1; |
|||
} |
|||
|
|||
@Override |
|||
public void hookExtraActionVariableAllocation(JDDVars extraActionVars) |
|||
{ |
|||
// call super to store extraActionVars |
|||
super.hookExtraActionVariableAllocation(extraActionVars); |
|||
|
|||
// initialize actFromStates |
|||
actFromStates = new JDDVars(); |
|||
for (int i = 1; i < extraActionVars.n(); i++) { |
|||
actFromStates.addVar(extraActionVars.getVar(i).copy()); |
|||
} |
|||
} |
|||
|
|||
/** Get the tau action variable */ |
|||
public JDDNode getTauVar() |
|||
{ |
|||
return extraActionVars.getVar(0).copy(); |
|||
} |
|||
|
|||
/** Get the marker for a tau action */ |
|||
public JDDNode tau() |
|||
{ |
|||
return getTauVar(); |
|||
} |
|||
|
|||
/** Get the marker for a non-tau action (!tau & zeros for all other extra action vars) */ |
|||
public JDDNode notTau() |
|||
{ |
|||
JDDNode notTau = JDD.Not(getTauVar()); |
|||
notTau = JDD.And(notTau, actFromStates.allZero()); |
|||
return notTau; |
|||
} |
|||
|
|||
private void compute() throws PrismException |
|||
{ |
|||
JDDNode trans = originalModel.getTrans().copy(); |
|||
|
|||
// first run: collapse the target state ECs |
|||
|
|||
if (verbose) parent.mainLog.println("Collapsing target states"); |
|||
for (JDDNode ec : equivalentClasses) { |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), trans.copy(), "trans"); |
|||
JDDNode ecCol = JDD.PermuteVariables(ec.copy(), originalModel.getAllDDRowVars(), originalModel.getAllDDColVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), ec.copy(), "EC"); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), ecCol.copy(), "EC'"); |
|||
|
|||
JDDNode representative = JDD.RestrictToFirst(ec.copy(), originalModel.getAllDDRowVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), representative.copy(), "rep"); |
|||
JDDNode representativeCol = JDD.PermuteVariables(representative.copy(), originalModel.getAllDDRowVars(), originalModel.getAllDDColVars()); |
|||
|
|||
JDDNode transToEC = JDD.Times(trans.copy(), ecCol.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transToEC.copy(), "transToEC"); |
|||
transToEC = JDD.SumAbstract(transToEC, originalModel.getAllDDColVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transToEC.copy(), "transToEC (2)"); |
|||
transToEC = JDD.Times(transToEC, representativeCol.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transToEC.copy(), "transToEC (3)"); |
|||
|
|||
trans = JDD.ITE(ecCol, transToEC, trans); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), trans.copy(), "trans''"); |
|||
|
|||
JDD.Deref(representative, representativeCol); |
|||
} |
|||
|
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), trans.copy(), "trans (after collapsing target states)"); |
|||
|
|||
newTrans = JDD.Constant(0); |
|||
if (verbose) parent.mainLog.println("\nCollapsing from states"); |
|||
for (JDDNode ec : equivalentClasses) { |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), ec.copy(), "EC"); |
|||
|
|||
JDDNode representative = JDD.RestrictToFirst(ec.copy(), originalModel.getAllDDRowVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), representative.copy(), "rep"); |
|||
JDDNode representativeCol = JDD.PermuteVariables(representative.copy(), originalModel.getAllDDRowVars(), originalModel.getAllDDColVars()); |
|||
|
|||
JDDNode transFromEC = JDD.Times(ec.copy(), trans.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transFromEC.copy(), "transFromEC"); |
|||
|
|||
// shift from states to actFromEC |
|||
transFromEC = JDD.PermuteVariables(transFromEC, originalModel.getAllDDRowVars(), actFromStates); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transFromEC.copy(), "transFromEC (2)"); |
|||
transFromEC = JDD.Times(tau(), representative.copy(), transFromEC); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transFromEC.copy(), "transFromEC (3)"); |
|||
|
|||
// remove self-loop actions back to the EC, |
|||
// i.e. actions representative,a where all successors go back to |
|||
// the representative |
|||
JDDNode transFromEC01 = JDD.GreaterThan(transFromEC.copy(), 0); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transFromEC01.copy(), "transFromEC01"); |
|||
JDDNode selfLoop = JDD.Times(transFromEC01.copy(), representativeCol.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), selfLoop.copy(), "selfLoop"); |
|||
JDDNode stateActionWithSelfLoop = JDD.ThereExists(selfLoop, originalModel.getAllDDColVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionWithSelfLoop.copy(), "stateActionWithSelfLoop"); |
|||
|
|||
// from the state action pairs with self loop, find those that also go somewhere |
|||
// else |
|||
JDDNode stateActionElse = JDD.And(stateActionWithSelfLoop.copy(), transFromEC01.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionElse.copy(), "stateActionElse"); |
|||
stateActionElse = JDD.And(stateActionElse, JDD.Not(representativeCol.copy())); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionElse.copy(), "stateActionElse (2)"); |
|||
stateActionElse = JDD.ThereExists(stateActionElse, originalModel.getAllDDColVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionElse.copy(), "stateActionElse (3)"); |
|||
JDDNode stateActionWithOnlySelfLoop = JDD.And(stateActionWithSelfLoop, JDD.Not(stateActionElse)); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionWithOnlySelfLoop.copy(), "stateActionOnlySelfLoop"); |
|||
|
|||
// find states where removing those actions would lead to deadlocks |
|||
JDDNode trans01Removed = JDD.Times(transFromEC01, JDD.Not(stateActionWithOnlySelfLoop.copy())); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), trans01Removed.copy(), "trans01Removed"); |
|||
JDDNode notDeadlocked = JDD.ThereExists(trans01Removed, originalModel.getAllDDColVars()); |
|||
notDeadlocked = JDD.ThereExists(notDeadlocked, originalModel.getAllDDNondetVars()); |
|||
notDeadlocked = JDD.ThereExists(notDeadlocked, extraActionVars); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), notDeadlocked.copy(), "notDeadlocked"); |
|||
|
|||
JDDNode stateActionsToRemove = JDD.And(stateActionWithOnlySelfLoop.copy(), notDeadlocked); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), stateActionsToRemove.copy(), "stateActionsToRemove"); |
|||
transFromEC = JDD.Times(transFromEC, JDD.Not(stateActionsToRemove.copy())); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transFromEC.copy(), "transFromEC"); |
|||
|
|||
JDDNode selfLoopRemaining = JDD.And(stateActionWithOnlySelfLoop, JDD.Not(stateActionsToRemove)); |
|||
ecRemainingSelfLoops = JDD.Or(ecRemainingSelfLoops, selfLoopRemaining); |
|||
|
|||
newTrans = JDD.Apply(JDD.MAX, newTrans, transFromEC); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), newTrans.copy(), "newTrans"); |
|||
|
|||
JDD.Deref(representative, representativeCol); |
|||
} |
|||
|
|||
JDDNode transUntouched = JDD.Times(trans.copy(), notInEC.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transUntouched.copy(), "transUntouched"); |
|||
transUntouched = JDD.Times(transUntouched, notTau()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transUntouched.copy(), "transUntouched (2)"); |
|||
newTrans = JDD.Apply(JDD.MAX, newTrans, transUntouched); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), newTrans.copy(), "newTrans"); |
|||
|
|||
newTrans01 = JDD.GreaterThan(newTrans.copy(), 0); |
|||
|
|||
JDD.Deref(trans); |
|||
|
|||
computed = true; |
|||
} |
|||
|
|||
/** |
|||
* Maps a state set from the original model to the corresponding state set |
|||
* in the quotient model. |
|||
* [ REFS: <i>result</i>, DEREFS: s ] |
|||
*/ |
|||
public JDDNode mapStateSet(JDDNode S) |
|||
{ |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), S.copy(), "S"); |
|||
JDDNode mapped = JDD.And(S, map.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), mapped.copy(), "mapped"); |
|||
|
|||
mapped = JDD.ThereExists(mapped, originalModel.getAllDDRowVars()); |
|||
mapped = JDD.PermuteVariables(mapped, originalModel.getAllDDColVars(), originalModel.getAllDDRowVars()); |
|||
|
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), mapped.copy(), "mapped (result)"); |
|||
return mapped; |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedTrans() throws PrismException |
|||
{ |
|||
if (!computed) compute(); |
|||
return newTrans.copy(); |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedStart() throws PrismException |
|||
{ |
|||
return mapStateSet(originalModel.getStart().copy()); |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedStateReward(JDDNode rew) throws PrismException |
|||
{ |
|||
if (!computed) compute(); |
|||
|
|||
if (SanityJDD.enabled) { |
|||
SanityJDD.checkIsDDOverVars(rew, originalModel.getAllDDRowVars()); |
|||
} |
|||
|
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rew.copy(), "state rew"); |
|||
// set state rewards for all EC states to zero |
|||
JDDNode result = JDD.Times(rew.copy(), JDD.Not(inEC.copy())); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), result.copy(), "state rew (transformed)"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedTransReward(JDDNode rew) throws PrismException |
|||
{ |
|||
if (!computed) compute(); |
|||
|
|||
if (SanityJDD.enabled) { |
|||
SanityJDD.checkIsDDOverVars(rew, originalModel.getAllDDRowVars(), originalModel.getAllDDNondetVars(), originalModel.getAllDDColVars()); |
|||
} |
|||
|
|||
// outgoing actions from ECs |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rew.copy(), "trans rew"); |
|||
JDDNode rewFromEC = JDD.Times(rew.copy(), inEC.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (1)"); |
|||
rewFromEC = JDD.PermuteVariables(rewFromEC, originalModel.getAllDDRowVars(), actFromStates); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (2)"); |
|||
rewFromEC = JDD.Times(tau(), rewFromEC); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (3)"); |
|||
rewFromEC = JDD.PermuteVariables(rewFromEC, originalModel.getAllDDColVars(), originalModel.getAllDDRowVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (4)"); |
|||
rewFromEC = JDD.Times(rewFromEC, map.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (5)"); |
|||
rewFromEC = JDD.SumAbstract(rewFromEC, originalModel.getAllDDRowVars()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (6)"); |
|||
rewFromEC = JDD.Times(rewFromEC, newTrans01.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (7)"); |
|||
|
|||
// for the remaining self loops from ECs (to avoid deadlocks), we strip the |
|||
// transition rewards |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), ecRemainingSelfLoops.copy(), "ecRemainingSelfLoops"); |
|||
rewFromEC = JDD.Times(rewFromEC, JDD.Not(ecRemainingSelfLoops.copy())); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rewFromEC.copy(), "rewFromEC (8)"); |
|||
|
|||
// transformedRew is the combination of the outgoing actions from the ECs |
|||
// and the original actions (tagged with notTau) |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), rew.copy(), "trans rew"); |
|||
JDDNode transformedRew = JDD.Apply(JDD.MAX, JDD.Times(notTau(), rew.copy()), rewFromEC); |
|||
transformedRew = JDD.Times(transformedRew, newTrans01.copy()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transformedRew.copy(), "transformedRew"); |
|||
|
|||
return transformedRew; |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedTransActions() |
|||
{ |
|||
if (originalModel.getTransActions() == null) { |
|||
return null; |
|||
} |
|||
|
|||
JDDNode transActionsNormal = originalModel.getTransActions().copy(); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transActionsNormal.copy(), "transActionsNormal (1)"); |
|||
transActionsNormal = JDD.Times(transActionsNormal, notTau()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transActionsNormal.copy(), "transActionsNormal (2)"); |
|||
|
|||
JDDNode transActionsFromEC = originalModel.getTransActions().copy(); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transActionsFromEC.copy(), "transActionsFromEC (1)"); |
|||
// shift from states to actFromEC |
|||
transActionsFromEC = JDD.PermuteVariables(transActionsFromEC, originalModel.getAllDDRowVars(), actFromStates); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transActionsFromEC.copy(), "transActionsFromEC (2)"); |
|||
transActionsFromEC = JDD.Times(transActionsFromEC, tau()); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transActionsFromEC.copy(), "transActionsFromEC (3)"); |
|||
|
|||
JDDNode transformedTransActions = JDD.Apply(JDD.MAX, transActionsNormal, transActionsFromEC); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transformedTransActions.copy(), "transformedTransActions"); |
|||
|
|||
transformedTransActions = JDD.Times(transformedTransActions, JDD.ThereExists(newTrans01.copy(), originalModel.getAllDDColVars())); |
|||
|
|||
//transformedTransActions = JDD.Times(transformedTransActions, newTrans01); |
|||
if (verbose) JDD.PrintMinterms(parent.getLog(), transformedTransActions.copy(), "transformedTransActions"); |
|||
|
|||
return transformedTransActions; |
|||
} |
|||
|
|||
@Override |
|||
public JDDNode getTransformedLabelStates(JDDNode oldLabelStates, JDDNode transformedReach) |
|||
{ |
|||
// we always return 'false' here, as it's difficult to decide how to label |
|||
// the representative states if not all the states in the EC are labelled |
|||
// the same |
|||
return JDD.Constant(0); |
|||
} |
|||
|
|||
/** Provide the set of reachable states */ |
|||
public JDDNode getReachableStates() |
|||
{ |
|||
// reachable states in the quotient MDP: |
|||
// remove non-representative states contained in ECs |
|||
// from the reachable states in the original model |
|||
JDDNode removed = JDD.And(inEC.copy(), JDD.Not(representatives.copy())); |
|||
JDDNode newReach = JDD.And(originalModel.getReach().copy(), JDD.Not(removed)); |
|||
|
|||
return newReach; |
|||
} |
|||
|
|||
/** |
|||
* Lift an ADD over row variables from the quotient model to the original model, |
|||
* by copying the values from the representatives to the other states in the EC. |
|||
*/ |
|||
public JDDNode liftFromRepresentatives(JDDNode n) |
|||
{ |
|||
// we first shift the result to the column variables |
|||
JDDNode result = JDD.PermuteVariables(n, originalModel.getAllDDRowVars(), originalModel.getAllDDColVars()); |
|||
// combine with the map. we now have (state,representative) -> value |
|||
result = JDD.Times(result, map.copy()); |
|||
// as there is exactly one representative per state, we can abstract using SumAbstract |
|||
// (works for positive and negative values) |
|||
result = JDD.SumAbstract(result, originalModel.getAllDDColVars()); |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue