internal static double[] GetExpectations(Graph graph,/*int[] sources,*/ HSet targets, int nStates) { double[] ret = ValueIteration(graph, targets, nStates); //ValueIteration(graph,sources,targets,nStates); if(ret==null) return graph.GetDistancesToAcceptingStates(targets.ToArray(typeof(int))as int[]); //return graph.GetDistancesToAcceptingStates(sources,targets.ToArray(typeof(int))as int[]); else return ret; }
/// <summary> /// Get all states in the given finite automaton from which no accepting state is reachable. /// </summary> /// <param name="fa">given finite automaton</param> /// <returns>all dead states in the finite automaton</returns> public static Set <Term> GetDeadStates(FSM fa) { //build a graph from fa Dictionary <Term, int> stateToVertexMap = new Dictionary <Term, int>(); stateToVertexMap[fa.InitialState] = 0; int i = 1; foreach (Term state in fa.States.Remove(fa.InitialState)) { stateToVertexMap[state] = i++; } //create edges that correspond to the transitions GraphTraversals.Edge[] edges = new GraphTraversals.Edge[fa.Transitions.Count]; Triple <Term, CompoundTerm, Term>[] transitions = new Triple <Term, CompoundTerm, Term> [fa.Transitions.Count]; i = 0; foreach (Triple <Term, CompoundTerm, Term> trans in fa.Transitions) { edges[i] = new GraphTraversals.Edge(stateToVertexMap[trans.First], stateToVertexMap[trans.Third], i); transitions[i++] = trans; } GraphTraversals.Graph g = new GraphTraversals.Graph(0, edges, new GraphTraversals.Edge[] { }, GraphTraversals.WeakClosureEnum.DoNotClose); int[] acceptingVertices = new int[fa.AcceptingStates.Count]; i = 0; foreach (Term accState in fa.AcceptingStates) { acceptingVertices[i++] = stateToVertexMap[accState]; } GraphTraversals.HSet deadVertices = g.DeadStates(acceptingVertices); return(fa.States.Select(delegate(Term state) { return deadVertices.Contains(stateToVertexMap[state]); })); }
/// <summary> /// Get all states in the given finite automaton from which no accepting state is reachable. /// </summary> /// <param name="fa">given finite automaton</param> /// <returns>all dead states in the finite automaton</returns> public static Set<Term> GetDeadStates(FSM fa) { //build a graph from fa Dictionary<Term, int> stateToVertexMap = new Dictionary<Term, int>(); stateToVertexMap[fa.InitialState] = 0; int i = 1; foreach (Term state in fa.States.Remove(fa.InitialState)) stateToVertexMap[state] = i++; //create edges that correspond to the transitions GraphTraversals.Edge[] edges = new GraphTraversals.Edge[fa.Transitions.Count]; Triple<Term, CompoundTerm, Term>[] transitions = new Triple<Term, CompoundTerm, Term>[fa.Transitions.Count]; i = 0; foreach (Triple<Term, CompoundTerm, Term> trans in fa.Transitions) { edges[i] = new GraphTraversals.Edge(stateToVertexMap[trans.First], stateToVertexMap[trans.Third], i); transitions[i++] = trans; } GraphTraversals.Graph g = new GraphTraversals.Graph(0, edges, new GraphTraversals.Edge[] { }, GraphTraversals.WeakClosureEnum.DoNotClose); int[] acceptingVertices = new int[fa.AcceptingStates.Count]; i = 0; foreach (Term accState in fa.AcceptingStates) acceptingVertices[i++] = stateToVertexMap[accState]; GraphTraversals.HSet deadVertices = g.DeadStates(acceptingVertices); return fa.States.Select(delegate(Term state) { return deadVertices.Contains(stateToVertexMap[state]); }); }
public static Sequence<Sequence<CompoundTerm>> GenerateTestSequences(FSM fa) { //Eliminate dead states from the fa Set<Term> deadStates = GetDeadStates(fa); Set<Term> aliveStates = fa.States.Difference(deadStates); Set<Triple<Term, CompoundTerm, Term>> aliveTransitions = fa.Transitions.Select(delegate(Triple<Term, CompoundTerm, Term> trans) { return aliveStates.Contains(trans.First) && aliveStates.Contains(trans.Third); }); if (aliveTransitions.IsEmpty) //test suite cannot be generated return Sequence<Sequence<CompoundTerm>>.EmptySequence; //Build a graph from the alive transitions Term[] states = new Term[aliveStates.Count]; Dictionary<Term, int> stateToVertexMap = new Dictionary<Term, int>(); states[0] = fa.InitialState; stateToVertexMap[fa.InitialState] = 0; int i = 1; foreach (Term state in aliveStates.Remove(fa.InitialState)) { states[i] = state; stateToVertexMap[state] = i++; } //create edges that must be traversed GraphTraversals.Edge[] mustEdges = new GraphTraversals.Edge[aliveTransitions.Count]; Triple<Term, CompoundTerm, Term>[] mustTransitions = new Triple<Term, CompoundTerm, Term>[aliveTransitions.Count]; i = 0; foreach (Triple<Term, CompoundTerm, Term> trans in aliveTransitions) { GraphTraversals.Edge edge = new GraphTraversals.Edge(stateToVertexMap[trans.First], stateToVertexMap[trans.Third], i); mustEdges[i] = edge; mustTransitions[i++] = trans; } //add an optional edge with label -1 from every accepting state //to the initial state, this corresponds to a reset action GraphTraversals.Edge[] optionalEdges = new GraphTraversals.Edge[fa.AcceptingStates.Count]; i = 0; foreach (Term accState in fa.AcceptingStates) { int accVertex = stateToVertexMap[accState]; optionalEdges[i++] = new GraphTraversals.Edge(accVertex, 0, -1); //-1 = reset } //at this point it is known that g is strongly connected and has no dead states //so a postman tour exists, compute a postman tour GraphTraversals.Graph g = new GraphTraversals.Graph(0, mustEdges, optionalEdges, GraphTraversals.WeakClosureEnum.DoNotClose); List<GraphTraversals.Edge> postmanTour = new List<GraphTraversals.Edge>(g.GetRuralChinesePostmanTour()); #region normalize the tour so that it ends in an accepting state and has a reset at the end as a "watchdog" //if the last edge has not label -1, i.e. the edge leading back //to the initial state is not a reset edge from an accepting state //and the last state is not an accepting state //then extend the path to an accepting state, from the beginning of the path //notice that there must be at least one accepting state, so such an extesion //is indeed possible GraphTraversals.Edge lastEdge = postmanTour[postmanTour.Count - 1]; if (lastEdge.label >= 0) //if the last edge is a reset, we are done { //the last edge leads back to the initial state, because this is a tour if (fa.AcceptingStates.Contains(fa.InitialState)) postmanTour.Add(new GraphTraversals.Edge(0, 0, -1)); //add a watchdog else { //create an extesion to the tour from the initial state to the first accepting state List<GraphTraversals.Edge> extension = new List<GraphTraversals.Edge>(); foreach (GraphTraversals.Edge edge in postmanTour) { extension.Add(edge); if (fa.AcceptingStates.Contains(states[edge.target])) { //the end state of the edge is accepting, so we are done extension.Add(new GraphTraversals.Edge(0, 0, -1)); //add a watchdog break; } } postmanTour.AddRange(extension); } } #endregion #region break up the tour into sequences of transition ids separated by the reset edge List<List<int>> paths = new List<List<int>>(); List<int> path = new List<int>(); for (int k = 0; k < postmanTour.Count; k++) { //presense of the watchdog at the end of the tour is assumed here GraphTraversals.Edge edge = postmanTour[k]; if (edge.label < 0) //encountered reset, end of path { paths.Add(path); path = new List<int>(); } else { path.Add(edge.label); } } #endregion #region map the paths into action sequences Sequence<Sequence<CompoundTerm>> res = Sequence<Sequence<CompoundTerm>>.EmptySequence; foreach (List<int> path1 in paths) { Sequence<CompoundTerm> transSeq = Sequence<CompoundTerm>.EmptySequence; foreach (int transId in path1) transSeq = transSeq.AddLast(mustTransitions[transId].Second); res = res.AddLast(transSeq); } #endregion return res; }
/// <summary> /// Creates a graph from a file. /// </summary> /// <param name="fileName"></param> /// <returns></returns> internal static Graph CreateFromFile(string fileName) { StreamReader sr=new StreamReader(fileName); if(sr.BaseStream.CanRead==false) { sr.Close(); return null; } sr.ReadLine(); //swallow start vertex int initVertex= Int32.Parse(sr.ReadLine()); ArrayList must=new ArrayList(); sr.ReadLine();//swallow "must" RBMap edgeProbs=new RBMap(); string s=sr.ReadLine(); while(s!="optional"){ //string [] split=s.Split(' '); must.Add(ReadEdge(s,edgeProbs)); s=sr.ReadLine(); } //"optional" has been swallowed already s=sr.ReadLine(); ArrayList opt=new ArrayList(); while(s.StartsWith("nond vertices")==false){ opt.Add(ReadEdge(s,edgeProbs)); s=sr.ReadLine(); } string [] spl=s.Split(' '); ArrayList nondVertices=new ArrayList(); for(int i=2;i<spl.Length;i++){ if(!String.IsNullOrEmpty(spl[i])) nondVertices.Add(Int32.Parse(spl[i])); } Graph g=new Graph(initVertex,must.ToArray(typeof(Edge)) as Edge[], opt.ToArray(typeof(Edge)) as Edge[], nondVertices.ToArray(typeof(int)) as int[],WeakClosureEnum.DoNotClose); g.edgeProbabilities=edgeProbs; return g; }
internal Pred(Graph g,int v) { this.graph=g; this.vert=v; }
public static Sequence <Sequence <CompoundTerm> > GenerateTestSequences(FSM fa) { //Eliminate dead states from the fa Set <Term> deadStates = GetDeadStates(fa); Set <Term> aliveStates = fa.States.Difference(deadStates); Set <Triple <Term, CompoundTerm, Term> > aliveTransitions = fa.Transitions.Select(delegate(Triple <Term, CompoundTerm, Term> trans) { return(aliveStates.Contains(trans.First) && aliveStates.Contains(trans.Third)); }); if (aliveTransitions.IsEmpty) //test suite cannot be generated { return(Sequence <Sequence <CompoundTerm> > .EmptySequence); } //Build a graph from the alive transitions Term[] states = new Term[aliveStates.Count]; Dictionary <Term, int> stateToVertexMap = new Dictionary <Term, int>(); states[0] = fa.InitialState; stateToVertexMap[fa.InitialState] = 0; int i = 1; foreach (Term state in aliveStates.Remove(fa.InitialState)) { states[i] = state; stateToVertexMap[state] = i++; } //create edges that must be traversed GraphTraversals.Edge[] mustEdges = new GraphTraversals.Edge[aliveTransitions.Count]; Triple <Term, CompoundTerm, Term>[] mustTransitions = new Triple <Term, CompoundTerm, Term> [aliveTransitions.Count]; i = 0; foreach (Triple <Term, CompoundTerm, Term> trans in aliveTransitions) { GraphTraversals.Edge edge = new GraphTraversals.Edge(stateToVertexMap[trans.First], stateToVertexMap[trans.Third], i); mustEdges[i] = edge; mustTransitions[i++] = trans; } //add an optional edge with label -1 from every accepting state //to the initial state, this corresponds to a reset action GraphTraversals.Edge[] optionalEdges = new GraphTraversals.Edge[fa.AcceptingStates.Count]; i = 0; foreach (Term accState in fa.AcceptingStates) { int accVertex = stateToVertexMap[accState]; optionalEdges[i++] = new GraphTraversals.Edge(accVertex, 0, -1); //-1 = reset } //at this point it is known that g is strongly connected and has no dead states //so a postman tour exists, compute a postman tour GraphTraversals.Graph g = new GraphTraversals.Graph(0, mustEdges, optionalEdges, GraphTraversals.WeakClosureEnum.DoNotClose); List <GraphTraversals.Edge> postmanTour = new List <GraphTraversals.Edge>(g.GetRuralChinesePostmanTour()); #region normalize the tour so that it ends in an accepting state and has a reset at the end as a "watchdog" //if the last edge has not label -1, i.e. the edge leading back //to the initial state is not a reset edge from an accepting state //and the last state is not an accepting state //then extend the path to an accepting state, from the beginning of the path //notice that there must be at least one accepting state, so such an extesion //is indeed possible GraphTraversals.Edge lastEdge = postmanTour[postmanTour.Count - 1]; if (lastEdge.label >= 0) //if the last edge is a reset, we are done { //the last edge leads back to the initial state, because this is a tour if (fa.AcceptingStates.Contains(fa.InitialState)) { postmanTour.Add(new GraphTraversals.Edge(0, 0, -1)); //add a watchdog } else { //create an extesion to the tour from the initial state to the first accepting state List <GraphTraversals.Edge> extension = new List <GraphTraversals.Edge>(); foreach (GraphTraversals.Edge edge in postmanTour) { extension.Add(edge); if (fa.AcceptingStates.Contains(states[edge.target])) { //the end state of the edge is accepting, so we are done extension.Add(new GraphTraversals.Edge(0, 0, -1)); //add a watchdog break; } } postmanTour.AddRange(extension); } } #endregion #region break up the tour into sequences of transition ids separated by the reset edge List <List <int> > paths = new List <List <int> >(); List <int> path = new List <int>(); for (int k = 0; k < postmanTour.Count; k++) { //presense of the watchdog at the end of the tour is assumed here GraphTraversals.Edge edge = postmanTour[k]; if (edge.label < 0) //encountered reset, end of path { paths.Add(path); path = new List <int>(); } else { path.Add(edge.label); } } #endregion #region map the paths into action sequences Sequence <Sequence <CompoundTerm> > res = Sequence <Sequence <CompoundTerm> > .EmptySequence; foreach (List <int> path1 in paths) { Sequence <CompoundTerm> transSeq = Sequence <CompoundTerm> .EmptySequence; foreach (int transId in path1) { transSeq = transSeq.AddLast(mustTransitions[transId].Second); } res = res.AddLast(transSeq); } #endregion return(res); }
internal static EdgesAndExpectations GetStaticStrategy(Graph graph, int[] sources, HSet targets, int nStates, int resetCost, int []deadStates) { foreach(int t in targets){ foreach(Edge l in graph.EdgesAtVertex(t)) l.weight=0; } //fix the edges weights foreach(Edge l in graph.MustEdges){ if(l.target>=nStates) l.weight=0; } foreach(Edge l in graph.OptionalEdges) l.weight=resetCost; if(graph.NumberOfVertices>1000){//Value iteration becomes too slow return graph.GetStaticStrategyWithDistancesToAcceptingStates(sources, targets.ToArray(typeof(int)) as int[]); } HSet deadStatesSet=new HSet(deadStates); //create reachableGraph bool []reachableVerts=new bool[graph.NumberOfVertices]; //we have to walk backwards from the targets avoiding dead states graph.InitBackwardEdges(); foreach(int i in targets) reachableVerts[i]=true; System.Collections.Queue queue=new System.Collections.Queue(targets); while(queue.Count>0) { int i=(int)queue.Dequeue(); foreach(int v in graph.Pred(i)) { if(!reachableVerts[v] && !deadStatesSet.Contains(v)) { queue.Enqueue(v); reachableVerts[v]=true; } } } int numberOfReachableVerts=0; foreach(bool b in reachableVerts) if(b) numberOfReachableVerts++; Edge[] strategyEdges; double [] expectations; if(numberOfReachableVerts==graph.NumberOfVertices) { expectations=GetExpectations(graph,/* sources,*/targets,nStates); if(expectations==null) return new EdgesAndExpectations(); strategyEdges=new Edge[nStates]; for(int i=0;i<nStates&&i<graph.NumberOfVertices;i++){ if(targets.Contains(i)||deadStatesSet.Contains(i)) continue; double min=Single.MaxValue; Edge stEdge=null; foreach(Edge l in graph.EdgesAtVertex(i)){ int j=l.target; if(expectations[j]<min){ min=expectations[j]; stEdge=l; } } strategyEdges[i]=stEdge; } } else { //numberOfReachableVerts<graph.NumberOfVertices) int [] graphToRG=new int[graph.NumberOfVertices]; //reachable graph to graph int [] rGToGraph=new int[numberOfReachableVerts]; int count=0; int rNStates=0; for(int i=0;i<reachableVerts.Length;i++) if(reachableVerts[i]) { graphToRG[i]=count; rGToGraph[count]=i; count++; if(i<nStates) rNStates++; } System.Collections.ArrayList mustEdges=new System.Collections.ArrayList(); foreach(Edge l in graph.MustEdges) { if( reachableVerts[l.source]&& reachableVerts[l.target]) { Edge ml=new Edge(graphToRG[l.source],graphToRG[l.target], l.label,l.weight); mustEdges.Add(ml); } } System.Collections.ArrayList nondVerts=new System.Collections.ArrayList(); for(int i=nStates;i<graph.NumberOfVertices;i++) { if(reachableVerts[i]) nondVerts.Add(graphToRG[i]); } Graph rGraph=new Graph(0,mustEdges.ToArray(typeof(Edge)) as Edge[],new Edge[0], nondVerts.ToArray(typeof(int)) as int[],true,WeakClosureEnum.DoNotClose); int []rSources=new int[sources.Length]; int c=0; foreach(int s in sources) { rSources[c++]=graphToRG[s]; } HSet rTargets=new HSet(); foreach(int s in targets) { if( reachableVerts[s]) { rTargets.Insert(graphToRG[s]); } } double []rExpectations=GetExpectations(rGraph,/*rSources,*/ rTargets,rNStates); if(rExpectations==null) return new EdgesAndExpectations(); strategyEdges=new Edge[nStates]; for(int i=0;i<nStates;i++){ if(!reachableVerts[i]) continue; if(targets.Contains(i)||deadStatesSet.Contains(i)) continue; double min=Single.MaxValue; Edge stEdge=null; foreach(Edge l in graph.EdgesAtVertex(i)){ int j=l.target; if(reachableVerts[j]) if(rExpectations[graphToRG[j]]<min){ min=rExpectations[graphToRG[j]]; stEdge=l; } } strategyEdges[i]=stEdge; } expectations=new double[graph.NumberOfVertices]; if(expectations==null) return new EdgesAndExpectations(); for(int i=0;i<expectations.Length;i++) expectations[i]=Int32.MaxValue; for(int i=0;i<rExpectations.Length;i++) expectations[rGToGraph[i]]=rExpectations[i]; } graph.CleanTheStrategy(strategyEdges,sources); return new EdgesAndExpectations(strategyEdges, expectations); }
//ValueIteration(Graph graph,int[] sources,HSet targets,int nStates) /* From "Play to test" Value iteration is the most widely used algorithm for solving discounted Markov decision problems (see e.g. [21]). Reachability games give rise to non-discounted Markov decision problems. Nevertheless the value iteration algorithm applies; this is a practical approach for computing strategies for transient test graphs. Test graphs, modified by inserting a zero-cost edge (0; 0), correspond to a subclass of negative stationary Markov decision processes (MDPs) with an infinite horizon, where rewards are negative and thus regarded as costs, strategies are stationary, i.e. time independent, and there is no finite upper bound on the number of steps in the process. The optimization criterion for our strategies corresponds to the expected total reward criterion, rather than the expected discounted reward criterion used in discounted Markov decision problems. Let G = (V;E; V a; V p; g; p; c) be a test graph modified by inserting a zero-cost edge (0; 0). The classical value iteration algorithm works as follows on G. Value iteration Let n = 0 and let M0 be the zero vector with coordinates V so that every M0[u] = 0. Given n and Mn, we compute Mn+1 (and then increment n): Mn+1[u] ={ min {c(u,v) +Mn[v]:(u,v) in E} if u is an active state} or sum {p(u,v)*(c(u,v) +Mn[v]); if u is a choice point Value iteration for negative MDPs with the expected total reward criterion, or negative Markov decision problems for short, does not in general converge to an optimal solution, even if one exists. However, if there exists a strategy for which the the expected cost is finite for all states [21, Assumption 7.3.1], then value iteration does converge for negative Markov decision problems [21, Theorem 7.3.10]. In light of lemmas 2 and 3, this implies that value iteration converges for transient test graphs. Let us make this more precise, as a corollary of Theorem 7.3.10 in [21]. */ //nStates marks the end of active states, choice points start after that static double[] ValueIteration(Graph graph, HSet targets, int nStates) { graph.InitEdgeProbabilities(); double[]v0=new double[graph.NumberOfVertices]; double[]v1=new double[graph.NumberOfVertices]; double eps=1.0E-6; double delta; double[] v=v0; //double[] vnew=v1; // CheckTransience(graph,targets); int nOfIter=0; do{ delta=0; for(int i=0;i<nStates&&i<graph.NumberOfVertices;i++){ if(targets.Contains(i)) continue; double min=Double.MaxValue; foreach(Edge l in graph.EdgesAtVertex(i)){ double r=((double)l.weight)+v[l.target]; if(r<min) min=r; } if(min!=Double.MaxValue){ v1[i]=min; if(delta<min-v[i]) delta=min-v[i]; } } for(int i=nStates;i<graph.NumberOfVertices;i++){ if(targets.Contains(i)) continue; double r=0; foreach(Edge l in graph.EdgesAtVertex(i)) r+=graph.EdgeProbability(l)*(((double)l.weight)+v[l.target]); v1[i]=r; if(delta<r-v[i]) delta=r-v[i]; } nOfIter++; //swap v and v1 double[] vtmp=v; v=v1; v1=vtmp; } while(delta>eps && nOfIter<10000); if(delta>eps){ return null; //the result is erroneous } return v; }
static void CheckTransience(Graph graph,HSet targets) { Queue q=new Queue(); bool[] reached=new bool[graph.NumberOfVertices]; foreach(int v in targets){ reached[v]=true; q.Enqueue(v); } while(q.Count>0){ int v=(int)q.Dequeue(); foreach(int u in new Pred(graph,v)){ if(reached[u]==false){ reached[u]=true; q.Enqueue(u); } } } foreach(bool b in reached) if(!b) throw new InvalidOperationException("some vertex has not been reached"); }