/// <summary> /// Run the machine /// </summary> /// <param name="x">The input to run the machine on.</param> /// <returns>True if the machine halts in the accept state.</returns> /// <remarks>The first move the machine makes is to fill the first tape (tape 0) with the blank symbol followed by the input.</remarks> public new bool Run(IEnumerable <char> x) { var tapes = Enumerable.Range(0, Tapes).Select(n => new List <char>(Alphabet.Blank)).ToList(); // Fill the first tape with the input foreach (var c in x) { if (!Alphabet.Contains(c)) { return(false); } if (c == Alphabet.EmptyString) { continue; } tapes[0].Add(c); } try { return(Run(tapes, InitialState, Enumerable.Range(0, Tapes).Select(n => 0).ToArray()).Result); } catch (StackOverflowException) { return(false); // infinite loop, reject } }
/// <summary> /// Run the machine /// </summary> /// <param name="x">The input to run the machine on.</param> /// <param name="o">The completed tape contents</param> /// <returns>True if the machine halts in the accept state.</returns> /// <remarks>The first move the machine makes is to fill the tape with the blank symbol followed by the input.</remarks> public bool Run(IEnumerable <char> x, out char[] o) { var tape = new List <char>() { Alphabet.Blank }; // Fill the tape with the input foreach (var c in x) { if (!Alphabet.Contains(c)) { o = new char[0]; return(false); } if (c == Alphabet.EmptyString) { continue; } tape.Add(c); } try { var res = Run(tape, InitialState, 0).Result; o = res.Item2; return(res.Item1); } catch (StackOverflowException) { o = new char[0]; return(false); // infinite loop, reject } }
/// <param name="q">The set of states</param> /// <param name="a">The language alphabet</param> /// <param name="g">The stack alphabet</param> /// <param name="d">The transition function containing Transition and PushdownTransition objects</param> /// <param name="q0">The initial state</param> /// <param name="f">The set of accepting states</param> /// <exception cref="ArgumentException"></exception> public PushdownAutomaton(States q, Alphabet a, StackAlphabet g, PushdownTransitionFunction d, State q0, AcceptingStates f) { States = q; Alphabet = a; StackAlphabet = g; Transitions = d; InitialState = q0; AcceptingStates = f; if (States.Count == 0) { throw new ArgumentException("The set of states cannot be empty."); } if (!States.Contains(InitialState)) { throw new ArgumentException("The inital state does not exist in the set of states!"); } foreach (var s in AcceptingStates) { if (!States.Contains(s)) { throw new ArgumentException($"The accepting state {s} is not in the set of states!"); } } foreach (var t in Transitions) { if (!States.Contains(t.P) || !States.Contains(t.Q) || (!Alphabet.Contains(t.A) && t.A != Alphabet.EmptyString) || (!StackAlphabet.Contains(t.Top) && t.Top != Alphabet.Wildcard && t.Top != Alphabet.EmptyString)) { throw new ArgumentException($"Invalid transition {t}"); } if (t.Replace.Length == 1 && ((t.Replace[0] != Alphabet.Wildcard && t.Replace[0] != Alphabet.EmptyString) && !StackAlphabet.Contains(t.Replace[0]))) { throw new ArgumentException($"Invalid replace char for transition {t}"); } if (t.Replace.Length > 1 && Array.Exists(t.Replace, x => !StackAlphabet.Contains(x))) { throw new ArgumentException($"Invalid replace char sequence for transition {t}"); } } }
private async Task <bool> Run(char[] x, State p, int i) { for (; i < x.Length; i++) { if (!Alphabet.Contains(x[i])) { return(false); } if (x[i] == Alphabet.EmptyString) { continue; } // get possible transitions var q = Transitions[p, x[i]]; if (q.Length == 0) // nothing to do, stop { return(false); } if (q.Length == 1) { p = q[0].Q; // switch states if (q[0].A == Alphabet.EmptyString) { i--; // Don't increment on null transition! } } else // we have a choice { var tasks = new Task <bool> [q.Length]; // check each path asynchronously for (var j = 0; j < q.Length; j++) { tasks[j] = Run(x, q[j].Q, q[j].A == Alphabet.EmptyString ? i : i + 1); } var result = false; // check the result foreach (var t in tasks) { result = result || await t; } return(result); // if one of them is successful, this branch accepts } } // No more moves! if (p.Accepting) { return(true); } // check for lambda transitions var r = Transitions[p, Alphabet.EmptyString]; var lambdas = new Task <bool> [r.Length]; for (var k = 0; k < r.Length; k++) { lambdas[k] = Run(x, r[k].Q, i); } var accept = false; foreach (var t in lambdas) { accept = accept || await t; } return(accept); }
private async Task <bool> Run(char[] x, State p, int i, Stack <char> stack) { for (; i < x.Length; i++) { if (!Alphabet.Contains(x[i])) { return(false); } if (x[i] == Alphabet.EmptyString) { continue; } // Get possible transitions var q = Transitions[p, x[i], stack.Peek()]; if (q.Length == 0) // nothing to do, stop { return(false); } if (q.Length == 1) { // try to update the stack. if we are out of bounds, reject try { stack = updateStack(stack, q[0].Top, q[0].Replace); } catch (Exception) { return(false); } p = q[0].Q; if (q[0].A == Alphabet.EmptyString) { i--; // Don't increment on null transition! } } else { var tasks = new Task <bool> [q.Length]; // check each path asynchronously for (var j = 0; j < q.Length; j++) { var s = new Stack <char>(stack); try { s = updateStack(s, q[j].Top, q[j].Replace); } catch (Exception) { continue; } tasks[j] = Run(x, q[j].Q, q[j].A == Alphabet.EmptyString ? i : i + 1, s); } var result = false; foreach (var t in tasks) { result = result || (t != null && await t); } return(result); } } // No more moves! if (p.Accepting) { return(true); } // check for lambda transitions var r = Transitions[p, Alphabet.EmptyString, stack.Peek()]; var lambdas = new Task <bool> [r.Length]; for (var k = 0; k < r.Length; k++) { var s = new Stack <char>(stack); try { s = updateStack(s, r[k].Top, r[k].Replace); } catch (Exception) { continue; } lambdas[k] = Run(x, r[k].Q, i, s); } var accept = false; foreach (var t in lambdas) { accept = accept || (t != null && await t); } return(accept); }