public override void Refine(SSA <SYMBOL> m, SSA <SYMBOL> x) { int inc; if (boundInc == Config.BoundInc.One) { inc = 1; } else { SSA <SYMBOL> ssa; if (boundInc == Config.BoundInc.M) { ssa = m; } else { ssa = x; } inc = ssa.States.Count(); if (halveBoundInc) { inc /= 2; } } bound += inc; }
/// <summary> /// ARMC constructor. /// </summary> /// <param name="config">Configuration.</param> public ARMC(Config config) : this(SSA <SYMBOL> .Parse(config.InitFilePath), SSA <SYMBOL> .Parse(config.BadFilePath), config.TauFilePaths.Select(path => SST <SYMBOL> .Parse(path)).ToArray(), config) { }
public FiniteLengthAbstraction(Config config, SSA <SYMBOL> init = null, SSA <SYMBOL> bad = null, SST <SYMBOL>[] tau = null) { if (config.InitialBound == Config.InitBound.One) { bound = 1; } else { SSA <SYMBOL> ssa; if (config.InitialBound == Config.InitBound.Init) { ssa = init ?? SSA <SYMBOL> .Parse(config.InitFilePath); } else { ssa = bad ?? SSA <SYMBOL> .Parse(config.BadFilePath); } bound = ssa.States.Count(); if (config.HalveInitialBound) { bound /= 2; } } forward = (config.LanguageDirection == Config.Direction.Forward); trace = config.TraceLanguages; boundInc = config.BoundIncrement; halveBoundInc = config.HalveBoundIncrement; }
public override bool StatesAreEquivalent(SSA <SYMBOL> m, int q1, int q2) { Func <int, int, SSA <SYMBOL> > boundedLang = trace ? (forward ? (Func <int, int, SSA <SYMBOL> >)m.BoundedForwardTraceLanguage : m.BoundedBackwardTraceLanguage) : (forward ? (Func <int, int, SSA <SYMBOL> >)m.BoundedForwardStateLanguage : m.BoundedBackwardStateLanguage); return(boundedLang(q1, bound) == boundedLang(q2, bound)); }
/// <summary> /// Checks if L(M1) does not equal L(M2). /// </summary> /// <remarks> /// Compares references if either SSA is null. /// </remarks> public static bool operator !=(SSA <SYMBOL> m1, SSA <SYMBOL> m2) { if (object.ReferenceEquals(m1, null) || object.ReferenceEquals(m2, null)) { return(!object.ReferenceEquals(m1, m2)); } return(!SSA <SYMBOL> .Equivalent(m1, m2)); }
public override bool Equals(object obj) { SSA <SYMBOL> m = obj as SSA <SYMBOL>; if (m != null) { return(this.automaton.Equals(m.automaton)); } return(this.automaton.Equals(obj)); }
public SSA <SYMBOL> BoundedLanguage(int n) { var m = new SSA <SYMBOL>( 0, Enumerable.Range(0, n + 1), Enumerable.Range(0, n).Select(s => new Move <Predicate <SYMBOL> >(s, s + 1, Predicate <SYMBOL> .True)), new Set <SYMBOL>(Alphabet) ); return(Product(this, m)); }
public PredicateAbstraction(Config config, SSA <SYMBOL> init = null, SSA <SYMBOL> bad = null, SST <SYMBOL>[] taus = null) { var initPreds = new List <SSA <SYMBOL> >(); /* add Init? */ if (config.InitialPredicate == Config.InitPred.Init || config.InitialPredicate == Config.InitPred.Both) { initPreds.Add(init ?? SSA <SYMBOL> .Parse(config.InitFilePath)); } /* add Bad? */ if (config.InitialPredicate == Config.InitPred.Bad || config.InitialPredicate == Config.InitPred.Both) { initPreds.Add(bad ?? SSA <SYMBOL> .Parse(config.BadFilePath)); } /* add transducer domains and/or ranges? */ SST <SYMBOL>[] ssts = taus ?? config.TauFilePaths.Select(path => SST <SYMBOL> .Parse(path)).ToArray(); if (config.IncludeGuard) { foreach (SST <SYMBOL> sst in ssts) { initPreds.Add(sst.Domain()); } } if (config.IncludeAction) { foreach (SST <SYMBOL> sst in ssts) { initPreds.Add(sst.Range()); } } /* ensure that the automata contain no epsilon transitions and have disjunct sets of states */ predicateAutomata = new Set <SSA <SYMBOL> >(); int offset = 0; foreach (SSA <SYMBOL> pred in initPreds) { SSA <SYMBOL> normPred = pred.RemoveEpsilons().Normalize(offset); predicateAutomata.Add(normPred); offset += normPred.States.Count(); } forward = (config.LanguageDirection == Config.Direction.Forward); heuristic = config.Heuristic; ignoredLabels = new Set <int>(); // remains empty if no heuristic used }
public override SSA <SYMBOL> Collapse(SSA <SYMBOL> m) { m = m.RemoveEpsilons(); Dictionary <int, Set <int> > labels = MakeLabels(m); if (heuristic.HasValue) { /* remove ignored states from labels */ foreach (int state in new List <int>(labels.Keys)) { labels[state] -= ignoredLabels; } } return(m.Collapse((_, q1, q2) => labels[q1] == labels[q2])); }
/* Collapse method ignores this in favour of more efficient alternative */ public override bool StatesAreEquivalent(SSA <SYMBOL> m, int q1, int q2) { Func <int, SSA <SYMBOL> > stateLang = forward ? (Func <int, SSA <SYMBOL> >)m.ForwardStateLanguage : m.BackwardStateLanguage; SSA <SYMBOL> m1 = stateLang(q1); SSA <SYMBOL> m2 = stateLang(q2); foreach (SSA <SYMBOL> pa in predicateAutomata) { stateLang = forward ? (Func <int, SSA <SYMBOL> >)pa.ForwardStateLanguage : pa.BackwardStateLanguage; foreach (int state in pa.States) { SSA <SYMBOL> p = stateLang(state); if (SSA <SYMBOL> .ProductIsEmpty(p, m1) != SSA <SYMBOL> .ProductIsEmpty(p, m2)) { return(false); } } } return(true); }
/// <summary> /// Print the counterexample (SSAs). /// </summary> /// <param name="counterexample">Counterexample.</param> /// <param name="directory">Output directory path.</param> public void PrintCounterexample(Counterexample <SYMBOL> counterexample, string directory) { int i = 0; foreach (var pair in counterexample.Ms) { SSA <SYMBOL> m = pair.Item1; SSA <SYMBOL> mAlpha = pair.Item2; PrintAutomaton(m, directory, "M" + i.ToString()); if (mAlpha != null) { PrintAutomaton(mAlpha, directory, "M" + i.ToString() + "+"); } i++; } i = 0; foreach (SSA <SYMBOL> x in counterexample.Xs) { PrintAutomaton(x, directory, "X" + i.ToString()); i++; } }
/// <summary> /// Checks if L(this) is a superset of L(M). /// </summary> public bool IsSupersetOf(SSA <SYMBOL> m) { return(m.IsSubsetOf(this)); }
/// <summary> /// Checks if L(this) is a subset of L(M). If not, produces witness. /// </summary> public bool IsSubsetOf(SSA <SYMBOL> m, out List <Predicate <SYMBOL> > witness) { return(!(Automaton <Predicate <SYMBOL> > .CheckDifference(this.automaton, m.automaton, 0, out witness))); }
/// <summary> /// Checks if L(this) is a subset of L(M). /// </summary> public bool IsSubsetOf(SSA <SYMBOL> m) { List <Predicate <SYMBOL> > witness; return(IsSubsetOf(m, out witness)); }
/// <summary> /// Checks if L(M1) equals L(M2). If not, produces witness. /// </summary> public static bool Equivalent(SSA <SYMBOL> m1, SSA <SYMBOL> m2, out List <Predicate <SYMBOL> > witness) { return(m1.automaton.IsEquivalentWith(m2.automaton, out witness)); }
/// <summary> /// ARMC constructor. /// </summary> /// <param name="init">SSA representing initial states.</param> /// <param name="bad">SSA representing bad states.</param> /// <param name="tau">SST representing transition.</param> /// <param name="configFileName">Configuration file path.</param> public ARMC(SSA <SYMBOL> init, SSA <SYMBOL> bad, SST <SYMBOL> tau, string configFileName) : this(init, bad, new SST <SYMBOL>[] { tau }, new Config(configFileName)) { }
/// <summary> /// Checks if the intersection of L(M1) and L(M2) is an empty language. If not, produces witness. /// </summary> public static bool ProductIsEmpty(SSA <SYMBOL> m1, SSA <SYMBOL> m2, out List <Predicate <SYMBOL> > witness) { return(!Automaton <Predicate <SYMBOL> > .CheckProduct(m1.automaton, m2.automaton, 0, out witness)); }
/// <summary> /// ARMC constructor. /// </summary> /// <param name="init">SSA representing initial states.</param> /// <param name="bad">SSA representing bad states.</param> /// <param name="taus">SSTs whose composition represents transition.</param> /// <param name="config">Configuration.</param> public ARMC(SSA <SYMBOL> init, SSA <SYMBOL> bad, SST <SYMBOL>[] taus, Config config) { /* merge alphabets */ Set <SYMBOL> alphabet = init.Alphabet + bad.Alphabet + taus.Select(tau => tau.Alphabet).Aggregate(Set <SYMBOL> .Union); init.Alphabet = alphabet; bad.Alphabet = alphabet; for (int i = 0; i < taus.Length; i++) { taus[i].Alphabet = alphabet; } if (config.PredicateLanguages == config.FiniteLengthLanguages) // sanity check { throw ConfigException.AbstractionNotChosen(); } this.init = init; this.bad = bad; this.tau = SST <SYMBOL> .Union(taus); this.tauInv = tau.Invert(); this.abstr = config.PredicateLanguages ? (Abstraction <SYMBOL>) new PredicateAbstraction <SYMBOL>(config, init, bad, taus) : new FiniteLengthAbstraction <SYMBOL>(config, init, bad, taus); this.verbose = config.Verbose; this.printAutomata = config.PrintAutomata; this.outputDir = config.OutputDirectory; this.format = config.AutomataFormat; this.imgExt = (config.ImageFormat == null) ? "" : config.ImageFormat.ToString(); this.timeout = config.Timeout.Ticks; this.stopwatch = new Stopwatch(); this.loops = 0; if (outputDir != "") { /* clear output directory */ DirectoryInfo dirInfo = Directory.CreateDirectory(outputDir); foreach (FileInfo fi in dirInfo.EnumerateFiles()) { fi.Delete(); } foreach (DirectoryInfo di in dirInfo.EnumerateDirectories()) { di.Delete(true); } } if (printAutomata) { /* print input automata and configuration */ string dir = Path.Combine(outputDir, "armc-input"); Directory.CreateDirectory(dir); PrintAutomaton(init, dir, "init"); PrintAutomaton(bad, dir, "bad"); PrintAutomaton(tau, dir, "tau"); if (taus.Length > 1) // no point in only printing tau1 { for (int i = 0; i < taus.Length; i++) { PrintAutomaton(taus[i], dir, "tau" + (i + 1).ToString()); } } PrintAutomaton(tauInv, dir, "tau-inv"); config.Write(Path.Combine(dir, "armc.properties")); } if (config.ComputationDirection == Config.Direction.Backward) { /* reverse direction, i.e. check if tauInv*(bad) & init is empty */ this.init = bad; this.bad = init; this.tauInv = tau; this.tau = tau.Invert(); } if (!SSA <SYMBOL> .ProductIsEmpty(init, bad)) // no point in further verification { if (printAutomata) { string dir = Path.Combine(outputDir, "armc-counterexample"); Directory.CreateDirectory(dir); PrintAutomaton(init & bad, dir, "initXbad"); } throw ARMCException.InitialPropertyViolation(); } }
/* label automaton states by predicate states whose forward/backward languages intersect */ private Dictionary <int, Set <int> > MakeLabels(SSA <SYMBOL> m) { var labels = new Dictionary <int, Set <int> >(m.States.Count()); foreach (int state in m.States) { labels[state] = new Set <int>(); } var stack = new Stack <Tuple <int, int> >(); foreach (SSA <SYMBOL> pred in predicateAutomata) { if (m.Algebra.Alphabet != pred.Algebra.Alphabet) { throw SSAException.IncompatibleAlphabets(); } } Func <int, IEnumerable <Move <Predicate <SYMBOL> > > > getMoves = forward ? (Func <int, IEnumerable <Move <Predicate <SYMBOL> > > >)m.GetMovesTo : m.GetMovesFrom; foreach (SSA <SYMBOL> pred in predicateAutomata) { if (forward) { foreach (int mState in m.FinalStates) { foreach (int pState in pred.FinalStates) { stack.Push(new Tuple <int, int>(mState, pState)); } } } else { stack.Push(new Tuple <int, int>(m.InitialState, pred.InitialState)); } while (stack.Count > 0) { var pair = stack.Pop(); int mState = pair.Item1; int pState = pair.Item2; labels[mState].Add(pair.Item2); foreach (var mMove in getMoves(mState)) { int state = forward ? mMove.SourceState : mMove.TargetState; foreach (var pMove in (forward ? pred.GetMovesTo(pState) : pred.GetMovesFrom(pState))) { if (!m.Algebra.IsSatisfiable(mMove.Label & pMove.Label)) { continue; } int stateLabel = forward ? pMove.SourceState : pMove.TargetState; if (!labels[state].Contains(stateLabel)) { stack.Push(new Tuple <int, int>(state, stateLabel)); } } } } } return(labels); }
public override void Refine(SSA <SYMBOL> m, SSA <SYMBOL> x) { int offset = predicateAutomata.Sum(pred => pred.States.Count()); x = x.RemoveEpsilons().Normalize(offset); predicateAutomata.Add(x); if (heuristic.HasValue) { var xStates = new Set <int>(x.States); /* find important states (appear in labels) */ Dictionary <int, Set <int> > labels = MakeLabels(m); var importantStates = new Set <int>(); foreach (int mState in m.States) { foreach (int xState in labels[mState]) { if (xState < offset || xState >= xStates.Count + offset) { continue; } importantStates.Add(xState); } } if (((Config.PredHeuristic)heuristic) == Config.PredHeuristic.KeyStates) { /* try to find one key state among important states */ foreach (int state in importantStates) { /* try ignoring all but one state */ ignoredLabels += xStates; ignoredLabels.Remove(state); /* check if the collapsed automaton still intersects */ if (SSA <SYMBOL> .ProductIsEmpty(Collapse(m), x)) { return; } /* failed, restore temporarily ignored states */ ignoredLabels -= xStates; } /* couldn't find just one key state, try to find two */ foreach (int state1 in importantStates) { foreach (int state2 in importantStates.Where(s => s != state1)) { ignoredLabels += xStates; ignoredLabels.Remove(state1); ignoredLabels.Remove(state2); if (SSA <SYMBOL> .ProductIsEmpty(Collapse(m), x)) { return; } ignoredLabels -= xStates; } } /* fall back on important states heuristic */ } /* ignore all unimportant states */ ignoredLabels += xStates - importantStates; } }
/// <summary> /// ARMC constructor. /// </summary> /// <param name="init">SSA representing initial states.</param> /// <param name="bad">SSA representing bad states.</param> /// <param name="tau">SST representing transition.</param> /// <param name="config">Configuration.</param> public ARMC(SSA <SYMBOL> init, SSA <SYMBOL> bad, SST <SYMBOL> tau, Config config) : this(init, bad, new SST <SYMBOL>[] { tau }, config) { }
/// <summary> /// Checks if L(this) is a superset of L(M). If not, produces witness. /// </summary> public bool IsSupersetOf(SSA <SYMBOL> m, out List <Predicate <SYMBOL> > witness) { return(m.IsSubsetOf(this, out witness)); }
/// <summary> /// Checks if L(this) is a proper superset of L(M). /// </summary> public bool IsProperSupersetOf(SSA <SYMBOL> m) { return(m.IsSubsetOf(this) && !this.IsSubsetOf(m)); }
/// <summary> /// Performs one step (inner loop) of ARMC. /// </summary> /// <returns>Verification result, or <code>null</code> if undecided.</returns> /// <param name="counterexample">Counterexample (if encountered, i.e. <code>false</code> returned).</param> public bool?VerifyStep(out Counterexample <SYMBOL> counterexample) { var ssas = new Stack <Tuple <SSA <SYMBOL>, SSA <SYMBOL> > >(); SSA <SYMBOL> m; SSA <SYMBOL> ml; SSA <SYMBOL> mAlpha = null; SSA <SYMBOL> x; var xs = new Stack <SSA <SYMBOL> >(); int i = 0; int l = 0; string ext = "." + format.ToString().ToLower(); string dir = Path.Combine(outputDir, "armc-loop-" + loops.ToString()); stopwatch.Start(); if (printAutomata) { Directory.CreateDirectory(dir); abstr.Print(dir, this); } counterexample = null; m = init; if (printAutomata) { PrintAutomaton(m, dir, "M0"); } while (true) { if (verbose) { Log("\r" + loops.ToString() + "." + i.ToString()); } if (i > 0 && !SSA <SYMBOL> .ProductIsEmpty(m, bad)) { if (verbose) { LogLine(": counterexample encountered"); } l = i; x = m & bad; x.Name = "<i>X</i><sub>" + l.ToString() + "</sub>"; if (printAutomata) { PrintAutomaton(x, dir, "X" + l.ToString()); } ml = m; xs.Push(x); break; } mAlpha = abstr.Collapse(m).Determinize().Minimize(); mAlpha.Name = "<i>M</i><sub>" + i.ToString() + "</sub><sup>α</sup>"; if (printAutomata) { PrintAutomaton(mAlpha, dir, "M" + i.ToString() + "+"); } if (i > 0 && mAlpha == ssas.Peek().Item2) { stopwatch.Stop(); if (verbose) { LogLine(": fixpoint reached"); LogLine("time = " + stopwatch.Elapsed.ToString()); } return(true); } if (timeout > 0 && stopwatch.ElapsedTicks > timeout) { stopwatch.Stop(); if (verbose) { LogLine(": timeout (" + stopwatch.Elapsed.ToString() + ")"); } throw ARMCException.Timeout(); } ssas.Push(Tuple.Create(m, mAlpha)); i++; m = tau.Apply(mAlpha).Determinize().Minimize(); m.Name = "<i>M</i><sub>" + i.ToString() + "</sub>"; if (printAutomata) { PrintAutomaton(m, dir, "M" + i.ToString()); } } bool spurious = false; foreach (var pair in ssas) { m = pair.Item1; mAlpha = pair.Item2; i--; if (verbose) { Log("\r" + loops.ToString() + "." + l.ToString() + "-" + i.ToString()); } x = (tauInv.Apply(x) & mAlpha).Determinize().Minimize(); x.Name = "<i>X</i><sub>" + i.ToString() + "</sub>"; xs.Push(x); if (printAutomata) { PrintAutomaton(x, dir, "X" + i.ToString()); } if (SSA <SYMBOL> .ProductIsEmpty(x, m)) { spurious = true; break; } } stopwatch.Stop(); if (spurious) { if (verbose) { LogLine(": counterexample is spurious"); } abstr.Refine(m, x); return(null); } else { if (verbose) { LogLine(": counterexample is real"); LogLine("time = " + stopwatch.Elapsed.ToString()); } List <Tuple <SSA <SYMBOL>, SSA <SYMBOL> > > ms = ssas.ToList(); ms.Reverse(); ms.Add(new Tuple <SSA <SYMBOL>, SSA <SYMBOL> >(ml, null)); counterexample = new Counterexample <SYMBOL> { Ms = ms, Xs = xs.ToList() }; return(false); } }
/// <summary> /// Checks if the intersection of L(M1) and L(M2) is an empty language. /// </summary> public static bool ProductIsEmpty(SSA <SYMBOL> m1, SSA <SYMBOL> m2) { List <Predicate <SYMBOL> > witness; return(SSA <SYMBOL> .ProductIsEmpty(m1, m2, out witness)); }
/// <summary> /// Constructs SSA accepting L(this) minus L(M2). /// </summary> public SSA <SYMBOL> Minus(SSA <SYMBOL> m) { return(new SSA <SYMBOL>(this.automaton.Minus(m.automaton))); }
/// <summary> /// Checks if L(M1) equals L(M2). /// </summary> public static bool Equivalent(SSA <SYMBOL> m1, SSA <SYMBOL> m2) { return(m1.automaton.IsEquivalentWith(m2.automaton)); }
/// <summary> /// ARMC constructor. /// </summary> /// <param name="init">SSA representing initial states.</param> /// <param name="bad">SSA representing bad states.</param> /// <param name="tau">SST representing transition.</param> public ARMC(SSA <SYMBOL> init, SSA <SYMBOL> bad, SST <SYMBOL> tau) : this(init, bad, new SST <SYMBOL>[] { tau }, new Config()) { }
/// <summary> /// Applies this transducer to automaton M in order to create a new automaton /// that accepts the translations of all words in L(M). /// </summary> public SSA <SYMBOL> Apply(SSA <SYMBOL> m) { if (this.Algebra.Alphabet != m.Algebra.Alphabet) { throw SSTException.IncompatibleAlphabets(); } m = m.RemoveEpsilons(); Automaton <Label <SYMBOL> > tau = this.automaton; var stack = new Stack <Tuple <int, int> >(); var finalStates = new List <int>(); var moves = new List <Move <Predicate <SYMBOL> > >(); var stateDict = new Dictionary <Tuple <int, int>, int>(); int id = 0; var init = new Tuple <int, int>(tau.InitialState, m.InitialState); stateDict[init] = id++; // initial state will be 0 stack.Push(init); Action <Tuple <int, int>, Tuple <int, int>, Predicate <SYMBOL> > addMove = (sourcePair, targetPair, label) => { int targetState; if (!stateDict.TryGetValue(targetPair, out targetState)) { stateDict[targetPair] = targetState = id++; stack.Push(targetPair); } moves.Add(new Move <Predicate <SYMBOL> >(stateDict[sourcePair], targetState, label)); }; while (stack.Count > 0) { Tuple <int, int> sourcePair = stack.Pop(); int tauState = sourcePair.Item1; int mState = sourcePair.Item2; foreach (Move <Label <SYMBOL> > tauMove in tau.GetMovesFrom(tauState)) { if (tauMove.Label.Input == null) { addMove( sourcePair, new Tuple <int, int>(tauMove.TargetState, mState), tauMove.Label.IsIdentity ? null : tauMove.Label.Output ); continue; } foreach (Move <Predicate <SYMBOL> > mMove in m.GetMovesFrom(mState)) { if (!m.Algebra.IsSatisfiable(tauMove.Label.Input & mMove.Label)) { continue; } Predicate <SYMBOL> newLabel; if (tauMove.Label.IsIdentity) { newLabel = tauMove.Label.Input & mMove.Label; } else { newLabel = tauMove.Label.Output; if (newLabel != null && !m.Algebra.IsSatisfiable(newLabel)) { continue; } } addMove( sourcePair, new Tuple <int, int>(tauMove.TargetState, mMove.TargetState), newLabel ); } } } foreach (var pair in stateDict) { if (tau.IsFinalState(pair.Key.Item1) && m.IsFinalState(pair.Key.Item2)) { finalStates.Add(pair.Value); } } return(new SSA <SYMBOL>(0, finalStates, moves, m.Algebra.Alphabet)); }
/// <summary> /// Constructs SSA accepting union of L(M1) and L(M2). /// </summary> public static SSA <SYMBOL> Sum(SSA <SYMBOL> m1, SSA <SYMBOL> m2) { return(new SSA <SYMBOL>(Automaton <Predicate <SYMBOL> > .MkSum(m1.automaton, m2.automaton))); }