diff --git a/prism/src/jltl2ba/SimpleLTL.java b/prism/src/jltl2ba/SimpleLTL.java index ca59b7b6..2585417f 100644 --- a/prism/src/jltl2ba/SimpleLTL.java +++ b/prism/src/jltl2ba/SimpleLTL.java @@ -947,6 +947,13 @@ public class SimpleLTL { // b.print_spin(System.out, apset); NBA nba = b.toNBA(apset); // nba.print(System.out); + + // jltl2ba should never produce disjoint NBA, + // i.e., where some states are not reachable + // from the intial state, so we want to fail + // later if the NBA is discovered to be disjoint: + nba.setFailIfDisjoint(true); + return nba; } diff --git a/prism/src/jltl2dstar/GraphAlgorithms.java b/prism/src/jltl2dstar/GraphAlgorithms.java index b7442095..a954222d 100644 --- a/prism/src/jltl2dstar/GraphAlgorithms.java +++ b/prism/src/jltl2dstar/GraphAlgorithms.java @@ -90,14 +90,14 @@ public class GraphAlgorithms { return; } - if (!disjoint) { - int start_idx = start_state.getName(); - visit(start_idx); - } else { + int start_idx = start_state.getName(); + visit(start_idx); + if (disjoint) { // The Graph may be disjoint -> restart DFS on every not yet visited state for (int v = 0; v < _graph.size(); ++v) { if (_dfs_data.get(v) == null) { - // not yet visited + // not yet visited, i.e., not reachable from the start state + _result.setGraphIsDisjoint(); visit(v); } } diff --git a/prism/src/jltl2dstar/NBA.java b/prism/src/jltl2dstar/NBA.java index 222e780b..155ad23b 100644 --- a/prism/src/jltl2dstar/NBA.java +++ b/prism/src/jltl2dstar/NBA.java @@ -55,6 +55,12 @@ public class NBA implements Iterable { /** The states that are accepting (final) */ private MyBitSet _final_states; + /** + * Flag, telling whether to fail later on if the NBA is discovered + * to be disjoint, as this is indicative of a malfunctioning + * NBA generator. + */ + private boolean _fail_if_disjoint = false; /** * Constructor. @@ -259,7 +265,19 @@ public class NBA implements Iterable { { return _state_count; } - + + /** Set fail_if_disjoint flag */ + public void setFailIfDisjoint(boolean value) + { + _fail_if_disjoint = value; + } + + /** Get fail_if_disjoint flag */ + public boolean getFailIfDisjoint() + { + return _fail_if_disjoint; + } + /** * Create a new state. * @return the index of the new state diff --git a/prism/src/jltl2dstar/NBAAnalysis.java b/prism/src/jltl2dstar/NBAAnalysis.java index 566ce701..d37a23f9 100644 --- a/prism/src/jltl2dstar/NBAAnalysis.java +++ b/prism/src/jltl2dstar/NBAAnalysis.java @@ -108,6 +108,14 @@ public class NBAAnalysis { return _nba.getFinalStates(); } + /** + * Returns true if the NBA is disjoint, i.e., there are states + * that are not reachable from the initial state + */ + public boolean isNBADisjoint() { + return getSCCs().getGraphIsDisjoint(); + } + /** Get the reachability analysis for the NBA * @return vector of BitSets representing the set of state which are reachable from a given state. */ diff --git a/prism/src/jltl2dstar/SCCs.java b/prism/src/jltl2dstar/SCCs.java index fbc4283e..c6346d50 100644 --- a/prism/src/jltl2dstar/SCCs.java +++ b/prism/src/jltl2dstar/SCCs.java @@ -37,6 +37,7 @@ public class SCCs { public Vector _dag; public Vector _topological_order; public Vector _reachability; + public boolean _graph_is_disjoint; /** Constructor */ @@ -46,6 +47,7 @@ public class SCCs { _dag = new Vector(); _topological_order = new Vector(); _reachability = new Vector(); + _graph_is_disjoint = false; } /** Get the states that are in SCC scc_index */ @@ -131,4 +133,14 @@ public class SCCs { } _state_to_scc.set(state, new Integer(scc)); } + + /** Set flag that the graph was discovered to be disjoint */ + public void setGraphIsDisjoint() { + _graph_is_disjoint = true; + } + + /** Get flag wether the graph was discovered to be disjoint */ + public boolean getGraphIsDisjoint() { + return _graph_is_disjoint; + } } diff --git a/prism/src/jltl2dstar/SafrasAlgorithm.java b/prism/src/jltl2dstar/SafrasAlgorithm.java index 4eb1407c..aff9fb47 100644 --- a/prism/src/jltl2dstar/SafrasAlgorithm.java +++ b/prism/src/jltl2dstar/SafrasAlgorithm.java @@ -51,10 +51,18 @@ public class SafrasAlgorithm { * @param nba The NBA * @param options The options for Safra's algorithm */ - public SafrasAlgorithm(NBA nba, Options_Safra options) { + public SafrasAlgorithm(NBA nba, Options_Safra options) throws PrismException { _options = options; _nba_analysis = new NBAAnalysis(nba); _nba = nba; + + if (_nba.getFailIfDisjoint() && _nba_analysis.isNBADisjoint()) { + throw new PrismException("The NBA generated for the LTL formula was discovered to be disjoint,\n" + + "i.e., some states were not reachable from the initial state. This likely\n" + + "indicates a problem in the translation. Please report the formula to the\n" + + "PRISM developers"); + } + _NODES = 2 * nba.getStateCount(); stv_reorder = null; _next = new Vector(); @@ -462,7 +470,7 @@ public class SafrasAlgorithm { _node_order[child.getID()] = i++; MyBitSet label_this = child.getLabeling(); - for (int setbit = label_this.nextSetBit(0); i >= 0; i = label_this.nextSetBit(i+1)) { + for (int setbit = label_this.nextSetBit(0); setbit >= 0; setbit = label_this.nextSetBit(setbit+1)) { reachable_this.or(_nba_reachability.get(setbit)); } // std::cerr << "reachability_this: "<