/* 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> /// 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> /// 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); } }
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="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(); } }