|
|
|
@ -11,10 +11,8 @@ import automata.finite.State; |
|
|
|
import explicit.rewards.MCRewards; |
|
|
|
import explicit.rewards.MDPRewards; |
|
|
|
import explicit.rewards.Rewards; |
|
|
|
import parser.ast.AccumulationFactor; |
|
|
|
import parser.ast.ExpressionAccumulation; |
|
|
|
import parser.ast.ExpressionRegular; |
|
|
|
import prism.IntegerBound; |
|
|
|
import prism.PrismException; |
|
|
|
|
|
|
|
/** |
|
|
|
@ -163,7 +161,8 @@ public class AccumulationProductRegular<M extends Model> extends AccumulationPro |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
private boolean isFinalTrack(AccumulationTrack<State> track, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException { |
|
|
|
@Override |
|
|
|
protected boolean isFinalTrack(AccumulationTrack<State> track, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException { |
|
|
|
boolean isFinal = false; |
|
|
|
if ( track != null ) { |
|
|
|
isFinal = automaton.isAcceptingState(track.getComponent()); |
|
|
|
@ -172,106 +171,13 @@ public class AccumulationProductRegular<M extends Model> extends AccumulationPro |
|
|
|
return isFinal; |
|
|
|
} |
|
|
|
|
|
|
|
private boolean isGoodAccState(AccumulationState<State> state, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException { |
|
|
|
return state.hasGoodTrack(); |
|
|
|
@Override |
|
|
|
protected State getInitialComponent() { |
|
|
|
return automaton.getInitialState(); |
|
|
|
} |
|
|
|
|
|
|
|
private boolean isGoodTrack(AccumulationTrack<State> track, ExpressionAccumulation accexp, ProbModelChecker mc) throws PrismException { |
|
|
|
mc.getLog().println("Checking " + track + " for goodness..."); |
|
|
|
// Only final tracks can be good |
|
|
|
mc.getLog().println("Final? " + isFinalTrack(track,accexp,mc)); |
|
|
|
if (!isFinalTrack(track,accexp,mc)) { return false; } |
|
|
|
boolean isGood = false; |
|
|
|
|
|
|
|
//System.out.println("Final: " + track); |
|
|
|
|
|
|
|
// Collect the weight linear combination, factor*weight+... |
|
|
|
int lhs = 0; |
|
|
|
int factorNr = 0; |
|
|
|
for (AccumulationFactor factor : accexp.getConstraint().getFactors()) { |
|
|
|
lhs += factor.getFactor().evaluateInt(mc.getConstantValues()) |
|
|
|
* track.getWeight(factorNr); |
|
|
|
} |
|
|
|
|
|
|
|
// Check the bound |
|
|
|
IntegerBound rhs = IntegerBound.fromTemporalOperatorBound(accexp.getConstraint().getBound(), mc.getConstantValues(), true); |
|
|
|
|
|
|
|
// For DIA operators, we just check the bound. |
|
|
|
// For BOX operators, we check the INVERTED bound. |
|
|
|
switch(accexp.getSymbol()) { |
|
|
|
case ACCBOXMINUS: |
|
|
|
case ACCBOXPLUS: |
|
|
|
if (!rhs.isInBounds(lhs)) { |
|
|
|
isGood = true; |
|
|
|
} |
|
|
|
break; |
|
|
|
case ACCDIAMINUS: |
|
|
|
case ACCDIAPLUS: |
|
|
|
if (rhs.isInBounds(lhs)) { |
|
|
|
isGood = true; |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
throw new RuntimeException("Oh boy!"); |
|
|
|
} |
|
|
|
|
|
|
|
mc.getLog().println("Good? " + lhs + rhs + " : " + isGood); |
|
|
|
|
|
|
|
return isGood; |
|
|
|
} |
|
|
|
|
|
|
|
private AccumulationState<State> updateAccumulationState(final int modelFromStateId, |
|
|
|
final AccumulationState<State> accstate, final ExpressionAccumulation accexp, |
|
|
|
final double[] weights, final ProbModelChecker mc) throws PrismException { |
|
|
|
// We have the current accumulation state, the current model id and the accumulation expression. |
|
|
|
|
|
|
|
// Get the old tracker and tracks. |
|
|
|
AccumulationTracker<State> oldTracker = trackers.getById(accstate.getTrackerId()); |
|
|
|
ArrayList<AccumulationTrack<State>> oldTracks = oldTracker.getTracks(); |
|
|
|
|
|
|
|
BitSet oldGoodTracks = accstate.getGoodTracks(); |
|
|
|
BitSet newGoodTracks = (BitSet) oldGoodTracks.clone(); |
|
|
|
|
|
|
|
// This restart will be... |
|
|
|
int newLastRestartNr = accstate.getNextRestartNr(); |
|
|
|
mc.getLog().print(newLastRestartNr); |
|
|
|
|
|
|
|
// Build the new tracks. |
|
|
|
ArrayList<AccumulationTrack<State>> newTracks = new ArrayList<>(); |
|
|
|
|
|
|
|
int trackNr = 0; |
|
|
|
for(AccumulationTrack<State> oldTrack : oldTracks) { |
|
|
|
AccumulationTrack<State> newTrack; |
|
|
|
|
|
|
|
// restart or advance |
|
|
|
if(trackNr == newLastRestartNr) { |
|
|
|
//assert oldTrack == null : "Track " + newLastRestartNr + " is not null!"; |
|
|
|
newTrack = new AccumulationTrack<State>(numberOfWeights, automaton.getInitialState()); //TODO: off-by-one? |
|
|
|
newGoodTracks.clear(trackNr); |
|
|
|
} else if (oldTrack == null) { |
|
|
|
newTrack = null; |
|
|
|
} else { |
|
|
|
assert oldTrack != null; |
|
|
|
newTrack = updateTrackRegular(modelFromStateId, oldTrack, accexp, weights, mc); |
|
|
|
} |
|
|
|
|
|
|
|
// check whether the track is good |
|
|
|
if(!newGoodTracks.get(trackNr)) { |
|
|
|
newGoodTracks.set(trackNr, isGoodTrack(newTrack, accexp, mc)); |
|
|
|
} |
|
|
|
|
|
|
|
newTracks.add(newTrack); |
|
|
|
trackNr++; |
|
|
|
} |
|
|
|
|
|
|
|
AccumulationTracker<State> newTracker = new AccumulationTracker<>(newTracks); |
|
|
|
|
|
|
|
|
|
|
|
int newTrackerId = trackers.findOrAdd(newTracker); |
|
|
|
|
|
|
|
return new AccumulationState<State>(newTrackerId, newLastRestartNr, numberOfTracks, newGoodTracks); |
|
|
|
} |
|
|
|
private AccumulationTrack<State> updateTrackRegular(Integer modelFromStateId, AccumulationTrack<State> track, ExpressionAccumulation accexp, double[] weights, StateModelChecker mc) { |
|
|
|
@Override |
|
|
|
protected AccumulationTrack<State> updateTrack(Integer modelFromStateId, AccumulationTrack<State> track, ExpressionAccumulation accexp, double[] weights, StateModelChecker mc) { |
|
|
|
State currentState = track.getComponent(); |
|
|
|
|
|
|
|
// Build EdgeLabel from labels. |
|
|
|
@ -345,7 +251,8 @@ public class AccumulationProductRegular<M extends Model> extends AccumulationPro |
|
|
|
automaton = nfa.determinize(); |
|
|
|
automaton.trim(); // This should remove cycles. |
|
|
|
|
|
|
|
nfa.exportToDotFile("DEBUG-automaton-nfa.dot"); |
|
|
|
//DEBUG |
|
|
|
//nfa.exportToDotFile("DEBUG-automaton-nfa.dot"); |
|
|
|
|
|
|
|
if (!automaton.isAcyclic()) { |
|
|
|
throw new PrismException("Cannot handle cyclic automata!"); |
|
|
|
|