allow_mutation
/// <summary> /// Returns an automaton that accepts the union of the languages of the given /// automata. /// <para/> /// Complexity: linear in number of states. /// </summary> public static Automaton Union(Automaton a1, Automaton a2) { if ((a1.IsSingleton && a2.IsSingleton && a1.singleton.Equals(a2.singleton, StringComparison.Ordinal)) || a1 == a2) { return(a1.CloneIfRequired()); } if (a1 == a2) { a1 = a1.CloneExpanded(); a2 = a2.CloneExpanded(); } else { a1 = a1.CloneExpandedIfRequired(); a2 = a2.CloneExpandedIfRequired(); } State s = new State(); s.AddEpsilon(a1.initial); s.AddEpsilon(a2.initial); a1.initial = s; a1.deterministic = false; //a1.clearHashCode(); a1.ClearNumberedStates(); a1.CheckMinimizeAlways(); return(a1); }
/// <summary> /// Returns a (deterministic) automaton that accepts the intersection of the /// language of <paramref name="a1"/> and the complement of the language of /// <paramref name="a2"/>. As a side-effect, the automata may be determinized, if not /// already deterministic. /// <para/> /// Complexity: quadratic in number of states (if already deterministic). /// </summary> public static Automaton Minus(Automaton a1, Automaton a2) { if (BasicOperations.IsEmpty(a1) || a1 == a2) { return(BasicAutomata.MakeEmpty()); } if (BasicOperations.IsEmpty(a2)) { return(a1.CloneIfRequired()); } if (a1.IsSingleton) { if (BasicOperations.Run(a2, a1.singleton)) { return(BasicAutomata.MakeEmpty()); } else { return(a1.CloneIfRequired()); } } return(Intersection(a1, a2.Complement())); }
/// <summary> /// Returns an automaton that accepts the intersection of the languages of the /// given automata. Never modifies the input automata languages. /// <para/> /// Complexity: quadratic in number of states. /// </summary> public static Automaton Intersection(Automaton a1, Automaton a2) { if (a1.IsSingleton) { if (BasicOperations.Run(a2, a1.singleton)) { return(a1.CloneIfRequired()); } else { return(BasicAutomata.MakeEmpty()); } } if (a2.IsSingleton) { if (BasicOperations.Run(a1, a2.singleton)) { return(a2.CloneIfRequired()); } else { return(BasicAutomata.MakeEmpty()); } } if (a1 == a2) { return(a1.CloneIfRequired()); } Transition[][] transitions1 = a1.GetSortedTransitions(); Transition[][] transitions2 = a2.GetSortedTransitions(); Automaton c = new Automaton(); LinkedList <StatePair> worklist = new LinkedList <StatePair>(); Dictionary <StatePair, StatePair> newstates = new Dictionary <StatePair, StatePair>(); StatePair p = new StatePair(c.initial, a1.initial, a2.initial); worklist.AddLast(p); newstates[p] = p; while (worklist.Count > 0) { p = worklist.First.Value; worklist.Remove(p); p.s.accept = p.S1.accept && p.S2.accept; Transition[] t1 = transitions1[p.S1.number]; Transition[] t2 = transitions2[p.S2.number]; for (int n1 = 0, b2 = 0; n1 < t1.Length; n1++) { while (b2 < t2.Length && t2[b2].max < t1[n1].min) { b2++; } for (int n2 = b2; n2 < t2.Length && t1[n1].max >= t2[n2].min; n2++) { if (t2[n2].max >= t1[n1].min) { StatePair q = new StatePair(t1[n1].to, t2[n2].to); StatePair r; newstates.TryGetValue(q, out r); if (r == null) { q.s = new State(); worklist.AddLast(q); newstates[q] = q; r = q; } int min = t1[n1].min > t2[n2].min ? t1[n1].min : t2[n2].min; int max = t1[n1].max < t2[n2].max ? t1[n1].max : t2[n2].max; p.s.AddTransition(new Transition(min, max, r.s)); } } } } c.deterministic = a1.deterministic && a2.deterministic; c.RemoveDeadTransitions(); c.CheckMinimizeAlways(); return(c); }