/// <summary> /// Counts the number of nodes (both terminals and nonterminals) in the BDD. /// </summary> public int CountNodes() { if (IsLeaf) { return(1); } HashSet <BDD> visited = new HashSet <BDD>(); SimpleStack <BDD> stack = new SimpleStack <BDD>(); stack.Push(this); visited.Add(this); while (stack.IsNonempty) { BDD a = stack.Pop(); if (!a.IsLeaf) { if (visited.Add(a.One)) { stack.Push(a.One); } if (visited.Add(a.Zero)) { stack.Push(a.Zero); } } } return(visited.Count); }
/// <summary> /// Computes (number of nonterminals, number of terminals) in the underlying directed acyclic graph. /// </summary> public Tuple <int, int> GetSize() { int nrNodes = 0; int nrLeaves = 0; HashSet <BDG <T, S> > done = new HashSet <BDG <T, S> >(); SimpleStack <BDG <T, S> > stack = new SimpleStack <BDG <T, S> >(); stack.Push(this); done.Add(this); while (stack.IsNonempty) { var bdg = stack.Pop(); if (bdg.IsLeaf) { nrLeaves += 1; } else { if (done.Add(bdg.TrueCase)) { stack.Push(bdg.TrueCase); } if (done.Add(bdg.FalseCase)) { stack.Push(bdg.FalseCase); } nrNodes += 1; } } return(new Tuple <int, int>(nrNodes, nrLeaves)); }
/// <summary> /// Based on MinimizeMoore method/technique. /// </summary> void Initialize() { var fa = aut; var currLayer = new SimpleStack <Tuple <int, int> >(); var nextLayer = new SimpleStack <Tuple <int, int> >(); //any pair of states (p,q) where one state is final and the other is not are distinguished by //the empty list represented by null, this set of distinguishing sequences is trivially suffix-closed foreach (var p in fa.GetStates()) { if (!fa.IsFinalState(p)) { foreach (var q in fa.GetFinalStates()) { var pair = MkPair(p, q); if (!distinguisher.ContainsKey(pair)) { //the empty sequence distinguishes the states distinguisherConcrete[pair] = ""; //List<Pair> pairs; //if (!distinguishingStringsMap.TryGetValue("", out pairs)) //{ // pairs = new List<Tuple<int, int>>(); // distinguishingStringsMap[""] = pairs; // distinguishingStringsSeq.Add(""); //} //pairs.Add(pair); distinguisher[pair] = null; nextLayer.Push(pair); } } } } //if a target pair of states is distinguished by some sequence //then any pair entering those states is also distinguished by extending that sequence //work breadth-first to maintain shortest witnesses while (nextLayer.IsNonempty) { var tmp = currLayer; currLayer = nextLayer; nextLayer = new SimpleStack <Tuple <int, int> >(); while (currLayer.IsNonempty) { var targetpair = currLayer.Pop(); foreach (var m1 in fa.GetMovesTo(targetpair.Item1)) { foreach (var m2 in fa.GetMovesTo(targetpair.Item2)) { if (m1.SourceState != m2.SourceState) { var psi = solver.MkAnd(m1.Label, m2.Label); if (solver.IsSatisfiable(psi)) { var sourcepair = MkPair(m1.SourceState, m2.SourceState); if (!distinguisher.ContainsKey(sourcepair)) { //add a new distinguishing sequence for the source pair //it extends a sequence of the target pair //thus the sequences remain suffix-closed if (concretize != null) { #region when concretization function is given precompute concrete distinguishers char c; if (!selectedCharacterMap.TryGetValue(psi, out c)) { c = concretize(psi); selectedCharacterMap[psi] = c; } var s = c + distinguisherConcrete[targetpair]; distinguisherConcrete[sourcepair] = s; //List<Pair> pairs; //if (!distinguishingStringsMap.TryGetValue(s, out pairs)) //{ // pairs = new List<Tuple<int, int>>(); // distinguishingStringsMap[s] = pairs; // distinguishingStringsSeq.Add(s); //} //pairs.Add(sourcepair); #endregion } var list = new ConsList <T>(psi, distinguisher[targetpair]); distinguisher[sourcepair] = list; nextLayer.Push(sourcepair); } } } } } } } }
public STb <FUNC, TERM, SORT> Compose() { var stack = new SimpleStack <Tuple <int, int> >(); int stateId = 1; var stateIdMap = new Dictionary <Tuple <int, int>, int>(); var revStateIdMap = new Dictionary <int, Tuple <int, int> >(); var q0A_x_q0B = new Tuple <int, int>(A.InitialState, B.InitialState); stack.Push(q0A_x_q0B); stateIdMap[q0A_x_q0B] = 0; revStateIdMap[0] = q0A_x_q0B; Func <int, int, int> ComposeStates = (x, y) => { var xy = new Tuple <int, int>(x, y); int q; if (stateIdMap.TryGetValue(xy, out q)) { return(q); } else { q = stateId; stateId += 1; stateIdMap[xy] = q; revStateIdMap[q] = xy; stack.Push(xy); return(q); } }; var A2B = new STb <FUNC, TERM, SORT>(solver, A.Name + "2" + B.Name, A.InputSort, B.OutputSort, regSort, JoinRegs(A.InitialRegister, B.InitialRegister), 0); //create normal composed rules while (stack.IsNonempty) { var qA_x_qB = stack.Pop(); var qA = qA_x_qB.Item1; var qB = qA_x_qB.Item2; var ruleA = A.GetRuleFrom(qA); if (ruleA.IsNotUndef) { var qAB_rule = Comp(solver.True, ruleA, qB, ComposeStates, false); A2B.AssignRule(stateIdMap[qA_x_qB], qAB_rule); } else { A2B.AssignRule(stateIdMap[qA_x_qB], UndefRule <TERM> .Default); } } foreach (var qAB in A2B.States) { var qA_x_qB = revStateIdMap[qAB]; var qA = qA_x_qB.Item1; var qB = qA_x_qB.Item2; var ruleA = A.GetFinalRuleFrom(qA); if (ruleA.IsNotUndef) { var qAB_Frule = Comp(solver.True, ruleA, qB, (p, q) => qAB, true); A2B.AssignFinalRule(qAB, qAB_Frule); } } A2B.EliminateDeadends(); //Func<Rule<TERM>, Rule<TERM>> ReplaceWithEpsilon = (r) => // { // }; //var aut = A2B.ToST(true).automaton.RelpaceAllGuards(ReplaceWithEpsilon); return(A2B); }
//public List<Move<Rule<T>>> CoveredMoves //{ // get { return covered_moves; } //} public void Explore() { var seen_states = new HashSet <int>(); seen_states.Add(stb.InitialState); var stack = new SimpleStack <Tuple <int, T> >(); var stack_next = new SimpleStack <Tuple <int, T> >(); var seen_next = new HashSet <Tuple <int, T> >(); stack_next.Push(new Tuple <int, T>(stb.InitialState, stb.InitialRegister)); while (stack_next.IsNonempty) { foreach (var p_r in seen_next) { seen_states.Add(p_r.Item1); } var tmp = stack; stack = stack_next; stack_next = tmp; seen_next.Clear(); while (stack.IsNonempty) { var q_r = stack.Pop(); var q = q_r.Item1; var r_in = q_r.Item2; foreach (var dir_move in moves[q]) { var move = dir_move.Item3; var guard1 = Z.ApplySubstitution(move.Label.Guard, stb.RegVar, r_in); var witness = Z.MainSolver.FindOneMember(Z.MkAnd(guard1, Z.MkEq(stb.InputVar, stb.InputVar))); if (witness != null) { var r_out = Z.Simplify(Z.ApplySubstitution(move.Label.Update, stb.InputVar, witness.Value, stb.RegVar, r_in)); var p_r = new Tuple <int, T>(move.TargetState, r_out); if (!exploredSteps.ContainsKey(q)) { exploredSteps[q] = new Dictionary <Tuple <T, T>, Tuple <int, T> >(); } exploredSteps[q][new Tuple <T, T>(witness.Value, r_in)] = p_r; if (!seen_states.Contains(move.TargetState)) { if (seen_next.Add(p_r)) { stack_next.Push(p_r); } } } else //the move is inaccessible from this state (and register value) since guard1 is unsatisfiable { uncovered_moves.Add(dir_move); } } foreach (var dir_fmove in final_moves[q]) { var fmove = dir_fmove.Item3; var guard1 = Z.Simplify(Z.ApplySubstitution(fmove.Label.Guard, stb.RegVar, r_in)); if (guard1.Equals(stb.Solver.False)) { uncovered_final_moves.Add(dir_fmove); } } } } }
/// <summary> /// Generate method code for a given BDD with given methid as method name /// </summary> private static void GenerateCodeForBDD(StringBuilder code, BDD pred, string methid) { Dictionary <BDD, int> idMap = new Dictionary <BDD, int>(); int nextLabelId = 0; Func <BDD, int> getId = bdd => { int bddid; if (!idMap.TryGetValue(bdd, out bddid)) { bddid = nextLabelId++; idMap[bdd] = bddid; } return(bddid); }; HashSet <BDD> done = new HashSet <BDD>(); SimpleStack <BDD> todo = new SimpleStack <BDD>(); todo.Push(pred); done.Add(pred); StringBuilder leaves = new StringBuilder(); while (todo.IsNonempty) { var bdd = todo.Pop(); if (bdd.IsLeaf) { leaves.Append(String.Format("\r\n P{0}_{1}: return {2};", methid, getId(bdd), bdd.IsEmpty ? "false" : "true")); } else { BDD exit = !bdd.Zero.IsLeaf && (bdd.Zero.Zero == bdd.One || bdd.Zero.One == bdd.One) ? bdd.One : bdd.Zero; BDD continuation = bdd; int zeros = 0; int ones = 0; while (true) { if (exit == continuation.Zero) { zeros |= 1 << continuation.Ordinal; continuation = continuation.One; } else if (exit == continuation.One) { ones |= 1 << continuation.Ordinal; continuation = continuation.Zero; } else { break; } } var anyZero = string.Format("(c & 0x{0:X}) != 0x{0:X}", zeros); var anyOne = string.Format("(c & 0x{0:X}) != 0", ones); var exitCondition = zeros == 0 ? anyOne : ones == 0 ? anyZero : string.Format("({0}) || ({1})", anyOne, anyZero); code.Append(string.Format(@" ")); if (bdd != pred) { code.Append(string.Format("P{0}_{1}: ", methid, getId(bdd))); } code.Append(string.Format("if ({2}) goto P{0}_{3}; else goto P{0}_{4};", methid, getId(bdd), exitCondition, getId(exit), getId(continuation))); if (done.Add(exit)) { todo.Push(exit); } if (done.Add(continuation)) { todo.Push(continuation); } } } code.Append(leaves.ToString()); }
/// <summary> /// Explores the PDA and converts it into an automaton, /// only stacks up to bounded depth are considered. /// </summary> /// <param name="stackDepth">upper bound on reached stack depth, nonpositive value means unbounded and may cause nontermination</param> public Automaton <T> Explore(int stackDepth = 0) { var moves = new List <Move <T> >(); var stateMap = new Dictionary <Tuple <int, Sequence <S> >, int>(); var configMap = new Dictionary <int, Tuple <int, Sequence <S> > >(); var finalStates = new HashSet <int>(); int q0 = 0; var config0 = new Tuple <int, Sequence <S> >(this.automaton.InitialState, new Sequence <S>(this.initialStackSymbol)); int nextStateId = 1; stateMap[config0] = q0; configMap[q0] = config0; if (automaton.IsFinalState(this.automaton.InitialState)) { finalStates.Add(q0); } var movemap = new Dictionary <Tuple <int, int>, T>(); Action <int, int, T> AddMove = (source, target, pred) => { var key = new Tuple <int, int>(source, target); T psi; if (movemap.TryGetValue(key, out psi)) { movemap[key] = this.terminalAlgebra.MkOr(psi, pred); } else { movemap[key] = pred; } }; var frontier = new SimpleStack <int>(); frontier.Push(q0); while (frontier.IsNonempty) { int q = frontier.Pop(); var config = configMap[q]; foreach (var move in automaton.GetMovesFrom(config.Item1)) { if (stackDepth < 1 || (config.Item2.Length - 1 + move.Label.PushSymbols.Length) <= stackDepth) { var pop = move.Label.PopSymbol; var push = move.Label.PushSymbols; if (config.Item2.First.Equals(pop)) { var targetConfig = new Tuple <int, Sequence <S> >(move.TargetState, push.Append(config.Item2.Rest())); int target; if (!stateMap.TryGetValue(targetConfig, out target)) { target = nextStateId++; stateMap[targetConfig] = target; configMap[target] = targetConfig; frontier.Push(target); if (automaton.IsFinalState(move.TargetState)) { finalStates.Add(target); } } Move <T> newmove; if (move.Label.InputIsEpsilon) { newmove = Move <T> .Epsilon(q, target); moves.Add(newmove); } else { //accumulate predicates for transitions AddMove(q, target, move.Label.Input); } } } } } foreach (var entry in movemap) { moves.Add(Move <T> .Create(entry.Key.Item1, entry.Key.Item2, entry.Value)); } var res = Automaton <T> .Create(this.terminalAlgebra, q0, finalStates, moves, false, true); return(res); }
PushdownAutomaton <S, T> Intersect1(IMinimalAutomaton <T> nfa) { //depth first product construction, PDA may have epsilon moves var stateIdMap = new Dictionary <Pair, int>(); int nextStateId = 1; var stack = new SimpleStack <Pair>(); var moves = new List <Move <PushdownLabel <S, T> > >(); var states = new List <int>(); var finalstates = new List <int>(); #region GetState: push the pair to stack if the state id was new and update final states as needed Func <Pair, int> GetState = (pair) => { int id; if (!stateIdMap.TryGetValue(pair, out id)) { id = nextStateId; nextStateId += 1; stateIdMap[pair] = id; stack.Push(pair); states.Add(id); if (this.automaton.IsFinalState(pair.Item1) && nfa.IsFinalState(pair.Item2)) { finalstates.Add(id); } } return(id); }; #endregion var initPair = new Pair(this.automaton.InitialState, nfa.InitialState); int initState = GetState(initPair); #region compute the product transitions with depth-first search while (stack.IsNonempty) { var sourcePair = stack.Pop(); var source = stateIdMap[sourcePair]; var pda_state = sourcePair.Item1; var aut_state = sourcePair.Item2; foreach (var pda_move in this.automaton.GetMovesFrom(pda_state)) { if (pda_move.IsEpsilon || pda_move.Label.InputIsEpsilon) { var targetPair = new Pair(pda_move.TargetState, aut_state); int target = GetState(targetPair); moves.Add(Move <PushdownLabel <S, T> > .Create(source, target, pda_move.Label)); } else { //assuming here that the automaton does not have epsilons foreach (var aut_move in nfa.GetMovesFrom(aut_state)) { if (aut_move.IsEpsilon) { throw new AutomataException(AutomataExceptionKind.AutomatonIsNotEpsilonfree); } var cond = nfa.Algebra.MkAnd(aut_move.Label, pda_move.Label.Input); //if the joint condition is not satisfiable then the //joint move does effectively not exist if (nfa.Algebra.IsSatisfiable(cond)) { var targetPair = new Pair(pda_move.TargetState, aut_move.TargetState); int target = GetState(targetPair); var label = new PushdownLabel <S, T>(cond, pda_move.Label.PushAndPop); var jointmove = Move <PushdownLabel <S, T> > .Create(source, target, label); moves.Add(jointmove); } } } } } #endregion //note: automaton creation eliminates unreachable states and deadend states from the product var productAutom = Automaton <PushdownLabel <S, T> > .Create(null, initState, finalstates, moves, true, true); var product = new PushdownAutomaton <S, T>(nfa.Algebra, productAutom, this.stackSymbols, this.initialStackSymbol); return(product); }
/// <summary> /// Algorithm 'saturate' in Figure 1 from Finkel-Willems-Wolper paper /// 'A Direct Symbolic Approach to Model Checking PushDown Systems' /// </summary> /// <returns></returns> internal HashSet <Trans> Saturate() { var hash = new HashSet <Trans>(); var stack = new SimpleStack <Trans>(); foreach (var q in this.Q) { stack.Push(MkTrans(q, q)); } var direct = new Dictionary <Trans, SimpleStack <Trans> >(); var trans = new Dictionary <Trans, SimpleStack <Tuple <Trans, Trans> > >(); Func <Trans, SimpleStack <Trans> > Direct = (t) => { SimpleStack <Trans> t_stack; if (!direct.TryGetValue(t, out t_stack)) { t_stack = new SimpleStack <Trans>(); direct[t] = t_stack; } return(t_stack); }; Func <Trans, SimpleStack <Tuple <Trans, Trans> > > Transfer = (t) => { SimpleStack <Tuple <Trans, Trans> > t_trans; if (!trans.TryGetValue(t, out t_trans)) { t_trans = new SimpleStack <Tuple <Trans, Trans> >(); trans[t] = t_trans; } return(t_trans); }; foreach (var a in pda.stackSymbols) { foreach (var push in pushMap[a]) { foreach (var pop in popMap[a]) { //push_pop goes from target of push to source of pop var push_pop = MkTrans(push.Item2, pop.SourceState); //edge goes from source of push to target of pop var edge = MkTrans(push.Item1, pop.TargetState); Direct(push_pop).Push(edge); } } } foreach (var q in Q) { foreach (var p in Q) { var qp = MkTrans(q, p); var qp_trans = Transfer(qp); foreach (var t in Q) { var pt = MkTrans(p, t); var qt = MkTrans(q, t); var pt_qt = new Tuple <Trans, Trans>(pt, qt); var tq = MkTrans(t, q); var tp = MkTrans(t, p); var tq_tp = new Tuple <Trans, Trans>(tq, tp); qp_trans.Push(pt_qt); qp_trans.Push(tq_tp); } } } while (stack.IsNonempty) { var alpha = stack.Pop(); hash.Add(alpha); stack.PushAll(direct[alpha]); foreach (var pair in Transfer(alpha)) { if (hash.Contains(pair.Item1)) { stack.Push(pair.Item2); } else { Direct(pair.Item1).Push(pair.Item2); } } } return(hash); }