You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
11 KiB
366 lines
11 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// 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 pta;
|
|
|
|
import java.util.*;
|
|
|
|
import prism.*;
|
|
import explicit.*;
|
|
|
|
public class ForwardsReach
|
|
{
|
|
// Log for output
|
|
protected PrismLog mainLog;
|
|
|
|
// PTA target info
|
|
protected BitSet targetLocs;
|
|
protected Constraint targetConstraint;
|
|
|
|
// Extra information associated with reachability graph
|
|
protected BitSet target; // Bit set specifying target states
|
|
protected List<Integer> initialStates; // Initial states
|
|
|
|
// Constructors
|
|
|
|
public ForwardsReach()
|
|
{
|
|
this(new PrismPrintStreamLog(System.out));
|
|
}
|
|
|
|
public ForwardsReach(PrismLog log)
|
|
{
|
|
this.mainLog = log;
|
|
}
|
|
|
|
// Accessors for other info generated during construction of reachability graph
|
|
|
|
public BitSet getTarget()
|
|
{
|
|
return target;
|
|
}
|
|
|
|
public List<Integer> getInitialStates()
|
|
{
|
|
return initialStates;
|
|
}
|
|
|
|
/**
|
|
* Build a reachability graph based on a forwards PTA traversal.
|
|
* All zones in the symbolic states in the graph are guaranteed to be convex (i.e. DBMs).
|
|
* The set of target states found and the (singleton) set of initial states are stored separately
|
|
* and can be obtained subsequently using getTarget() and getInitialStates().
|
|
*/
|
|
public ReachabilityGraph buildForwardsGraph(PTA pta, BitSet targetLocs, Constraint targetConstraint)
|
|
throws PrismException
|
|
{
|
|
boolean formats10 = true;
|
|
|
|
if (formats10)
|
|
return buildForwardsGraphFormats10(pta, targetLocs, targetConstraint);
|
|
else
|
|
return buildForwardsGraphFormats09(pta, targetLocs, targetConstraint);
|
|
}
|
|
|
|
/**
|
|
* Implementation of {@link #buildForwardsGraph} using FORMATS'10 definition.
|
|
*/
|
|
private ReachabilityGraph buildForwardsGraphFormats10(PTA pta, BitSet targetLocs, Constraint targetConstraint)
|
|
throws PrismException
|
|
{
|
|
Zone z;
|
|
LocZone init, lz, lz2;
|
|
LinkedList<LocZone> X;
|
|
IndexedSet<LocZone> Yset;
|
|
//LocZoneSetOld Zset;
|
|
ReachabilityGraph graph;
|
|
int src, dest, count;
|
|
long timer, timerProgress;
|
|
boolean progressDisplayed;
|
|
|
|
// Store target info
|
|
this.targetLocs = targetLocs;
|
|
this.targetConstraint = targetConstraint;
|
|
|
|
// Starting reachability...
|
|
mainLog.println("\nBuilding forwards reachability graph...");
|
|
timer = timerProgress = System.currentTimeMillis();
|
|
progressDisplayed = false;
|
|
|
|
// Re-compute max clock constraint value if required
|
|
if (targetConstraint != null)
|
|
pta.recomputeMaxClockConstraint(targetConstraint);
|
|
|
|
// Initialise data structures
|
|
graph = new ReachabilityGraph(pta);
|
|
Yset = new IndexedSet<LocZone>();
|
|
X = new LinkedList<LocZone>();
|
|
target = new BitSet();
|
|
|
|
// Build initial symbolic state (NB: assume initial location = 0)
|
|
z = DBM.createZero(pta);
|
|
init = new LocZone(0, z);
|
|
|
|
// Reachability loop
|
|
Yset.add(init);
|
|
X.add(init);
|
|
src = -1;
|
|
// While there are unexplored symbolic states (in X)...
|
|
while (!X.isEmpty()) {
|
|
// Pick next state to explore
|
|
// X is a list containing states in order found
|
|
// (so we know index of lz is src+1)
|
|
lz = X.removeFirst();
|
|
src++;
|
|
// Compute timed post for this zone (NB: do this before checking if target)
|
|
lz = lz.deepCopy();
|
|
lz.tPost(pta);
|
|
// Is this a target state?
|
|
if (targetLocs.get(lz.loc) && (targetConstraint == null || lz.zone.isSatisfied(targetConstraint))) {
|
|
target.set(src);
|
|
// Add null for this state (no need to store info)
|
|
graph.addState();
|
|
continue;
|
|
}
|
|
// Otherwise, explore this symbolic state
|
|
// First, check there is at least one transition
|
|
// (don't want deadlocks in non-target states)
|
|
if (pta.getTransitions(lz.loc).size() == 0) {
|
|
throw new PrismException("Deadlock (no transitions) in PTA at location \"" + pta.getLocationNameString(lz.loc) + "\"");
|
|
}
|
|
// Add current state to reachability graph
|
|
graph.addState();
|
|
// For each outgoing transition...
|
|
for (Transition transition : pta.getTransitions(lz.loc)) {
|
|
int[] dests = new int[transition.getNumEdges()];
|
|
boolean enabled = false;
|
|
boolean unenabled = false;
|
|
count = 0;
|
|
for (Edge edge : transition.getEdges()) {
|
|
// Do "discrete post" for this edge
|
|
// (followed by c-closure)
|
|
lz2 = lz.deepCopy();
|
|
lz2.dPost(edge);
|
|
lz2.cClosure(pta);
|
|
// If non-empty, create edge, also adding state to X if new
|
|
if (!lz2.zone.isEmpty()) {
|
|
if (Yset.add(lz2)) {
|
|
X.add(lz2);
|
|
}
|
|
dest = Yset.getIndexOfLastAdd();
|
|
enabled = true;
|
|
dests[count] = dest;
|
|
} else {
|
|
unenabled = true;
|
|
dests[count] = -1;
|
|
}
|
|
count++;
|
|
}
|
|
if (enabled) {
|
|
if (unenabled)
|
|
throw new PrismException("Badly formed PTA: state " + src);
|
|
graph.addTransition(src, transition, dests, null);
|
|
}
|
|
}
|
|
// Check for deadlock (transitions exist but not enabled)
|
|
if (graph.trans.get(src).size() == 0) {
|
|
throw new PrismException("Deadlock (no enabled transitions) in PTA at location \"" + pta.getLocationNameString(lz.loc) + "\"");
|
|
}
|
|
// Print some progress info occasionally
|
|
if (System.currentTimeMillis() - timerProgress > 3000) {
|
|
if (!progressDisplayed) {
|
|
mainLog.print("Number of states so far:");
|
|
progressDisplayed = true;
|
|
}
|
|
mainLog.print(" " + Yset.size());
|
|
mainLog.flush();
|
|
timerProgress = System.currentTimeMillis();
|
|
}
|
|
}
|
|
|
|
// Tidy up progress display
|
|
if (progressDisplayed)
|
|
mainLog.println(" " + Yset.size());
|
|
|
|
// Convert state set to ArrayList and store
|
|
graph.states = Yset.toArrayList();
|
|
|
|
// Always have a single initial state 0 after this construction
|
|
initialStates = new ArrayList<Integer>();
|
|
initialStates.add(0);
|
|
|
|
// Reachability complete
|
|
timer = System.currentTimeMillis() - timer;
|
|
mainLog.println("Graph constructed in " + (timer / 1000.0) + " secs.");
|
|
mainLog.print("Graph: " + graph.states.size() + " symbolic states");
|
|
mainLog.println("), " + target.cardinality() + " target states");
|
|
|
|
// Print a warning if there are no target states
|
|
if (target.cardinality() == 0)
|
|
mainLog.println("Warning: There are no target states.");
|
|
|
|
return graph;
|
|
}
|
|
|
|
/**
|
|
* Implementation of {@link #buildForwardsGraph} using FORMATS'09 definition.
|
|
*/
|
|
private ReachabilityGraph buildForwardsGraphFormats09(PTA pta, BitSet targetLocs, Constraint targetConstraint)
|
|
throws PrismException
|
|
{
|
|
Zone z;
|
|
LocZone init, lz, lz2;
|
|
LinkedList<LocZone> Y;
|
|
IndexedSet<LocZone> Zset;
|
|
//LocZoneSetOld Zset;
|
|
ReachabilityGraph graph;
|
|
int cMax;
|
|
int src, dest, count;
|
|
long timer, timerProgress;
|
|
boolean progressDisplayed;
|
|
|
|
// Store target info
|
|
this.targetLocs = targetLocs;
|
|
this.targetConstraint = targetConstraint;
|
|
|
|
// Starting reachability...
|
|
mainLog.println("\nBuilding forwards reachability graph...");
|
|
timer = timerProgress = System.currentTimeMillis();
|
|
progressDisplayed = false;
|
|
|
|
// Compute max clock constraint value
|
|
if (targetConstraint != null)
|
|
pta.recomputeMaxClockConstraint(targetConstraint);
|
|
cMax = pta.getMaxClockConstraint();
|
|
|
|
// Initialise data structures
|
|
graph = new ReachabilityGraph(pta);
|
|
//Zset = new LocZoneSetOld();
|
|
Zset = new IndexedSet<LocZone>();
|
|
Y = new LinkedList<LocZone>();
|
|
target = new BitSet();
|
|
|
|
// Build initial symbolic state (NB: assume initial location = 0)
|
|
z = DBM.createZero(pta);
|
|
init = new LocZone(0, z);
|
|
// And do tpost/c-closure
|
|
init.tPost(pta);
|
|
init.cClosure(pta);
|
|
|
|
// Reachability loop
|
|
Zset.add(init);
|
|
Y.add(init);
|
|
src = -1;
|
|
// While there are unexplored symbolic states (in Y)...
|
|
while (!Y.isEmpty()) {
|
|
// Pick next state to explore
|
|
// Y is a list containing states in order found
|
|
// (so we know index of lz is src)
|
|
lz = Y.removeFirst();
|
|
src++;
|
|
// Is this a target state?
|
|
if (targetLocs.get(lz.loc) && (targetConstraint == null || lz.zone.isSatisfied(targetConstraint))) {
|
|
target.set(src);
|
|
// Add null for this state (no need to store info)
|
|
graph.addState();
|
|
continue;
|
|
}
|
|
// Otherwise, explore this symbolic state
|
|
// First, check there is at least one transition
|
|
// (don't want deadlocks in non-target states)
|
|
if (pta.getTransitions(lz.loc).size() == 0) {
|
|
throw new PrismException("PTA deadlocks in location \"" + pta.getLocationNameString(lz.loc) + "\"");
|
|
}
|
|
// For each outgoing transition...
|
|
graph.addState();
|
|
for (Transition transition : pta.getTransitions(lz.loc)) {
|
|
int[] dests = new int[transition.getNumEdges()];
|
|
boolean enabled = false;
|
|
boolean unenabled = false;
|
|
count = 0;
|
|
for (Edge edge : transition.getEdges()) {
|
|
// Build "post" zone for this edge
|
|
// (dpost, then tpost, then c-closure)
|
|
lz2 = lz.deepCopy();
|
|
lz2.dPost(edge);
|
|
lz2.tPost(pta);
|
|
lz2.cClosure(pta);
|
|
// If non-empty, create edge, also adding state to Y if new
|
|
if (!lz2.zone.isEmpty()) {
|
|
if (Zset.add(lz2)) {
|
|
Y.add(lz2);
|
|
}
|
|
dest = Zset.getIndexOfLastAdd();
|
|
enabled = true;
|
|
dests[count] = dest;
|
|
} else {
|
|
unenabled = true;
|
|
dests[count] = -1;
|
|
}
|
|
count++;
|
|
}
|
|
if (enabled) {
|
|
if (unenabled)
|
|
throw new PrismException("Badly formed PTA: state " + src);
|
|
graph.addTransition(src, transition, dests, null);
|
|
}
|
|
}
|
|
// Print some progress info occasionally
|
|
if (System.currentTimeMillis() - timerProgress > 3000) {
|
|
if (!progressDisplayed) {
|
|
mainLog.print("Number of states so far:");
|
|
progressDisplayed = true;
|
|
}
|
|
mainLog.print(" " + Zset.size());
|
|
mainLog.flush();
|
|
timerProgress = System.currentTimeMillis();
|
|
}
|
|
}
|
|
|
|
// Tidy up progress display
|
|
if (progressDisplayed)
|
|
mainLog.println(" " + Zset.size());
|
|
|
|
// Convert state set to ArrayList and store
|
|
graph.states = Zset.toArrayList();
|
|
|
|
// Always have a single initial state 0 after this construction
|
|
initialStates = new ArrayList<Integer>();
|
|
initialStates.add(0);
|
|
|
|
// Reachability complete
|
|
timer = System.currentTimeMillis() - timer;
|
|
mainLog.println("Graph constructed in " + (timer / 1000.0) + " secs.");
|
|
mainLog.print("Graph: " + graph.states.size() + " symbolic states");
|
|
mainLog.println("), " + target.cardinality() + " target states");
|
|
|
|
// Print a warning if there are no target states
|
|
if (target.cardinality() == 0)
|
|
mainLog.println("Warning: There are no target states.");
|
|
|
|
return graph;
|
|
}
|
|
}
|