public static FA Single(Integers terminal) { var start = new State(); var end = new State(); start.Add(terminal, end); return(FA.From(start, end)); }
public static FA Plus(FA fa) { var clone = fa.ToNfa(true); Debug.Assert(clone.Final != null); clone.Final.Add(clone.Start); return(clone); }
public static FA None() { var start = new State(); var illegal = new State(); start.Add(Integers.Any, illegal); illegal.Add(Integers.Any, illegal); return(FA.From(start, start)); }
public static FA Negate(FA dfa) { EnsureDfa(dfa); for (var i = 0; i < dfa.States.Count; ++i) { dfa.States[i].IsFinal = !dfa.States[i].IsFinal; } return(dfa); }
public static FA Or(FA first, params FA[] nexts) { var fa = first; foreach (var next in nexts) { fa = fa.Or(next); } return(fa); }
public static FA Concat(FA fa, FA other) { var first = fa.ToNfa(true); Debug.Assert(first.Final != null); other = other.ToNfa(true); Debug.Assert(other.Final != null); first.Final.Add(other.Start); return(FA.From(first.Start, other.Final)); }
public FA Minimize(FA dfa) { EnsureDfa(dfa); dfa = MergeStates(dfa); dfa = MergeTransitions(dfa); var result = From(dfa.Start); EnsureDfa(result); return(result); }
private static void EnsureDfa(FA dfa) { if (dfa.Final != null) { throw new Exception("DFA: dfa.Final must be null"); } if (!dfa.Finals.Any()) { throw new Exception("DFA: no final state"); } if (dfa.States.Count < 1) { throw new Exception("DFA: at least on state"); } EnsureDfaTransitions(dfa); }
public static FA From(string sequence) { Debug.Assert(!string.IsNullOrEmpty(sequence)); var start = new State(); var current = start; var next = (State?)null; foreach (var ch in sequence) { next = new State(); current.Add(Integers.From(ch), next); current = next; } Debug.Assert(next != null); return(FA.From(start, next)); }
public static FA Or(FA fa, FA other) { var first = fa.ToNfa(true); Debug.Assert(first.Final != null); var second = other.ToNfa(true); Debug.Assert(second.Final != null); var newEnd = new State(); first.Start.Add(second.Start); first.Final.Add(newEnd); second.Final.Add(newEnd); return(FA.From(first.Start, newEnd)); }
public static FA Build(FA dfa1, FA dfa2, Func <State, State, bool> isFinal) { EnsureDfa(dfa1); EnsureDfa(dfa2); dfa1 = Complete(dfa1); dfa2 = Complete(dfa2); EnsureComplete(dfa1); EnsureComplete(dfa2); var cross = new State[dfa1.States.Count, dfa2.States.Count]; var t1 = dfa1.States.Select(s => GetTransitions(s)).ToList(); var t2 = dfa2.States.Select(s => GetTransitions(s)).ToList(); for (var n1 = 0; n1 < dfa1.States.Count; n1 += 1) { for (var n2 = 0; n2 < dfa2.States.Count; n2 += 1) { cross[n1, n2] = new State(isFinal(dfa1.States[n1], dfa2.States[n2])); } } for (var n1 = 0; n1 < dfa1.States.Count; n1 += 1) { for (var n2 = 0; n2 < dfa2.States.Count; n2 += 1) { var state = cross[n1, n2]; var ctranses = GetMerge(t1[n1], t2[n2]); foreach (var ctrans in ctranses) { state.Add(Codepoints.From(ctrans.Range.Min, ctrans.Range.Max), cross[ctrans.Target1, ctrans.Target2]); } } } var dfa = From(cross[0, 0]); EnsureComplete(dfa); return(dfa.RemoveDead().Minimize()); }
public static FA ToNfa(FA dfa) { if (dfa.Final != null) { return(dfa); } dfa.Final = new State(); foreach (var final in dfa.Finals) { final.Add(dfa.Final); } dfa.Final.Id = dfa.States.Count; dfa.States.Add(dfa.Final); foreach (var state in dfa.States) { state.IsFinal = false; } return(dfa); }
private static void EnsureComplete(FA dfa) { EnsureDfa(dfa); foreach (var state in dfa.States) { var all = new Integers(); var sum = 0; foreach (var transition in state.Transitions) { sum += transition.Set.Cardinality; all.Add(transition.Set); } if (!UnicodeSets.IsAny(all)) { throw new Exception("DFA: incomplete transition set (DFA is not `complete´)"); } if (sum != all.Cardinality) { throw new Exception("DFA: overlapping transitions (DFA is not `sane´)"); } } }
private static void EnsureDfa(FA dfa) { if (dfa.Final != null) { throw new Exception("DFA: dfa.Final must be null"); } if (!dfa.Finals.Any()) { throw new Exception("DFA: no final state"); } if (dfa.States.Count < 1) { throw new Exception("DFA: at least on state"); } for (var i = 0; i < dfa.States.Count; ++i) { if (dfa.States[i].Id != i) { throw new Exception("DFA: not properly numbered"); } } EnsureDfaTransitions(dfa); }
public static FA Complete(FA dfa) { EnsureDfa(dfa); State?sink = null; foreach (var state in dfa.States) { var rest = UnicodeSets.Any(); foreach (var transition in state.Transitions) { rest = rest.ExceptWith(transition.Set); } if (!rest.IsEmpty) { if (sink == null) { sink = new State(); sink.Add(Integers.Any, sink); } state.Add(Integers.From(rest), sink); } } if (sink != null) { sink.Id = dfa.States.Count; dfa.States.Add(sink); } EnsureComplete(dfa); return(dfa); }
public static FA ToDfa(FA nfa) { if (nfa.Final == null) { EnsureDfa(nfa); return(nfa); } var once = new UniqueQueue <Closure>(); var start = new Closure(nfa.Start, nfa.Final); once.Enqueue(start); while (once.Count > 0) { var closure = once.Dequeue(); var transitions = closure.UnambiguateTransitions(); foreach (var transition in transitions) { var terminal = transition.Key; var targets = transition.Value; var targetClosure = new Closure(targets, nfa.Final); once.Enqueue(targetClosure, out targetClosure); var target = targetClosure.DfaState; closure.DfaState.Add(Integers.From(terminal), target); } } var dfa = From(start.DfaState); EnsureDfa(dfa); return(dfa); }
public FA Difference(FA other, bool cloned = false) { return(Operations.Difference(CloneIf(cloned), other.CloneIf(cloned))); }
public FA Substract(FA other, bool cloned = false) { return(Operations.Substract(CloneIf(cloned), other.CloneIf(cloned))); }
public static FA Build(FA dfa1, FA dfa2, Func <State, State, bool> isFinal) { EnsureDfa(dfa1); EnsureDfa(dfa2); dfa1 = Complete(dfa1); dfa2 = Complete(dfa2); EnsureComplete(dfa1); EnsureComplete(dfa2); var cross = new State[dfa1.States.Count, dfa2.States.Count]; var t1 = dfa1.States.Select(s => GetTransitions(s)).ToList(); var t2 = dfa2.States.Select(s => GetTransitions(s)).ToList(); for (var n1 = 0; n1 < dfa1.States.Count; n1 += 1) { var state1 = dfa1.States[n1]; for (var n2 = 0; n2 < dfa2.States.Count; n2 += 1) { var state2 = dfa2.States[n2]; var newState = new State(isFinal(state1, state2)); if (state1.IsPayload && !state2.IsPayload) { newState.AddPayload(state1); } else if (!state1.IsPayload && state2.IsPayload) { newState.AddPayload(state2); } else if (state1.IsPayload && state2.IsPayload) { Debug.Assert(true); #if true if (state1.Transitions.Count == 1 && state1.Transitions[0].Set.IsAny) { newState.AddPayload(state1); } else if (state2.Transitions.Count == 1 && state2.Transitions[0].Set.IsAny) { newState.AddPayload(state2); } else { if (state1.Payload > state2.Payload) { newState.AddPayload(state1); } else { newState.AddPayload(state2); } //throw new InternalException("missing tie break"); } #endif } cross[n1, n2] = newState; } } for (var n1 = 0; n1 < dfa1.States.Count; n1 += 1) { for (var n2 = 0; n2 < dfa2.States.Count; n2 += 1) { var state = cross[n1, n2]; var ctranses = GetMerge(t1[n1], t2[n2]); foreach (var ctrans in ctranses) { state.Add(Integers.From(ctrans.Range.Min, ctrans.Range.Max), cross[ctrans.Target1, ctrans.Target2]); } } } var dfa = From(cross[0, 0]); EnsureComplete(dfa); dfa = dfa.RemoveDead(); dfa = dfa.Minimize(); dfa = dfa.RemoveDead(); return(dfa); }
public static FA Difference(FA dfa1, FA dfa2) { return(CrossBuilder.Build(dfa1, dfa2, (s1, s2) => s1.Final && !s2.Final)); }
public static FA Intersect(FA dfa1, FA dfa2) { return(CrossBuilder.Build(dfa1, dfa2, (s1, s2) => s1.Final && s2.Final)); }
public static FA Union(FA dfa1, FA dfa2) { return(CrossBuilder.Build(dfa1, dfa2, (s1, s2) => s1.Final || s2.Final)); }
public static FA RemoveDead(FA dfa) { EnsureDfa(dfa); var closures = new Dictionary <State, HashSet <State> >(); void Initial(State state) { var set = new HashSet <State>() { state }; foreach (var transition in state.Transitions) { set.Add(transition.Target); } closures.Add(state, set); } bool Close(State state) { var set = closures[state]; var before = set.Count; foreach (var buddy in set.Where(s => s != state).ToList()) { var buddySet = closures[buddy]; set.UnionWith(buddySet); } var after = set.Count; return(after > before); } foreach (var state in dfa.States) { Initial(state); } var added = true; while (added) { added = false; foreach (var state in dfa.States) { added = added || Close(state); } } var dead = new HashSet <State>(); foreach (var state in dfa.States) { var set = closures[state]; if (set.All(s => !s.Final)) { dead.UnionWith(set); } } return(RemoveDead(dfa, dead)); }
public FA And(FA other) => Builder.Concat(this, other);
public static FA Substract(FA dfa1, FA dfa2) { return(CrossBuilder.Build(dfa1, dfa2, (s1, s2) => s1.IsFinal && !s2.IsFinal)); }
public static FA Minimize(FA dfa) { return(new Minimizer().Minimize(dfa)); }
public FA Minimize(FA dfa) { EnsureDfa(dfa); dfa = Complete(dfa); EnsureComplete(dfa); var s = dfa.States; var n = s.Count; var table = new bool[n, n]; for (var i = 0; i < n; ++i) { for (var j = 0; j < n; ++j) { if (i >= j) { continue; } table[i, j] = s[i].Final && !s[j].Final || !s[i].Final && s[j].Final || s[i].Final && s[j].Final && s[i].Payload != s[j].Payload; } } bool more = true; while (more) { more = false; for (var i = 0; i < n; ++i) { for (var j = 0; j < n; ++j) { if (i >= j) { continue; } if (!table[i, j]) { foreach (var ti in s[i].Transitions) { foreach (var tj in s[j].Transitions) { if (ti.Set.Overlaps(tj.Set)) { var si = ti.Target.Id; var sj = tj.Target.Id; if (si == sj) { continue; } if (si > sj) { var tmp = si; si = sj; sj = tmp; Debug.Assert(si < sj); } var before = more; if (table[si, sj]) { var isij = table[i, j]; more = more || !table[i, j]; if (!before && more) { Debug.Assert(true); } table[i, j] = true; } } } } } } } } var combines = new List <StateSet>(); for (var i = 0; i < n; ++i) { for (var j = 0; j < n; ++j) { if (i >= j) { continue; } if (!table[i, j]) { combines.Add(new StateSet { s[i], s[j] }); } } } var current = 0; while (current < combines.Count) { for (var i = current + 1; i < combines.Count;) { if (combines[current].Overlaps(combines[i])) { combines[current].Add(combines[i]); combines.RemoveAt(i); } else { i += 1; } } current += 1; } foreach (var set in combines) { var premium = set.First(); var remove = set.Skip(1).ToList(); foreach (var state in s) { foreach (var transition in state.Transitions) { if (remove.Contains(transition.Target)) { transition.Retarget(premium); } } } EnsureDistinctTransitions(premium); } var mini = From(dfa.Start); mini = MergeTransitions(mini); return(mini); }
public FA Union(FA other, bool cloned = false) { return(Operations.Union(CloneIf(cloned), other.CloneIf(cloned))); }
private FA MergeStates(FA dfa) { // // https://en.wikipedia.org/wiki/DFA_minimization // Hopcroft's algorithm // #if true var nons = new StateSet(dfa.Nons.ToList()); var all = dfa.States.ToList(); var partitions = new List <StateSet> { nons }; var working = new List <StateSet> { nons }; var fgroups = from state in dfa.Finals group state by state.Payload; foreach (var fgroup in fgroups) { partitions.Add(new StateSet(fgroup)); } #else var finals = new StateSet(dfa.Finals.ToList()); var nons = new StateSet(dfa.Nons.ToList()); var all = dfa.States.ToList(); var partitions = new List <StateSet> { finals, nons }; var working = new List <StateSet> { finals }; #endif var terminals = new HashSet <Integers>(all.SelectMany(state => state.Transitions).Select(transition => transition.Set)); while (working.Count > 0) { var a = working[0]; working.RemoveAt(0); foreach (var terminal in terminals) { var x = new StateSet(); foreach (var state in all) { foreach (var transition in state.Transitions) { if (transition.Set.Overlaps(terminal)) { if (a.Contains(transition.Target)) { x.Add(state); break; } } } } var i = 0; while (i < partitions.Count) { var y = partitions[i]; var x_intersect_y = x.IntersectWith(y); var y_without_x = y.ExceptWith(x); if (x_intersect_y.IsEmpty || y_without_x.IsEmpty) { i += 1; continue; } partitions[i] = x_intersect_y; i += 1; partitions.Insert(i, y_without_x); i += 1; var j = 0; while (j < working.Count) { if (working[j] == y) { working.RemoveAt(j); working.Add(x_intersect_y); working.Add(y_without_x); break; } j += 1; } if (j == working.Count) { // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (x_intersect_y.Count <= y_without_x.Count) { working.Add(x_intersect_y); } else { working.Add(y_without_x); } } } } } foreach (var partition in partitions) { if (partition.Count >= 1) { #if true var groups = from s in partition group s by s.Payload; foreach (var group in groups) { List <State> dfaStates = group.ToList(); var premium = dfaStates.First(); var remove = dfaStates.Skip(1).ToList(); foreach (var state in all) { foreach (var transition in state.Transitions) { if (remove.Contains(transition.Target)) { transition.Retarget(premium); } } } EnsureDistinctTransitions(premium); } #else List <State> dfaStates = partition.ToList(); var premium = dfaStates.First(); var remove = dfaStates.Skip(1).ToList(); foreach (var state in all) { foreach (var transition in state.Transitions) { if (remove.Contains(transition.Target)) { transition.Retarget(premium); } } } EnsureDistinctTransitions(premium); #endif } } var result = FA.From(dfa.Start); EnsureDfa(result); return(result); }
public FA Intersect(FA other, bool cloned = false) { return(Operations.Intersect(CloneIf(cloned), other.CloneIf(cloned))); }