# Pushdown Automata This example illustrates the construction of a Pushdown Automaton. Although simplistic, it demonstrates how Pushdown Automata can be seen as Network Automata. A Pushdown Automaton can be thought of as a Network Automaton with a single node. Pushdown Automata are more powerful than Finite State Machines (though less powerful than Turing Machines). They differ from Finite State Machines by having access to a memory, in the form of a stack. In this example, a Pushdown Automaton (PDA) is constructed for the language _L = {anbn | n > 0}_. The PDA is defined by four states: _q0_ (the initial state), _q1_, _q2_, and _q3_ (the final/accepting state). The input alphabet consists of the symbols _a_ and _b_. The stack alphabet consists of the symbols _a_, _b_, and _Z_, where _Z_ represents the bottom of the stack. In the diagram above, the first character in the transition represents the input, while the "X / Y" notation means: replace the symbol "X" on the top of the stack with the symbol "Y". When "Y" is _ε_, this refers to a stack pop operation. When _ε_ is an input symbol, it represents the end of the input (or the input symbol signalling termination of the string). ```python import netomaton as ntm states = { 'q0': 0, # initial state 'q1': 1, 'q2': 2, 'q3': 3 # final/accepting state } # a Pushdown Automaton can be thought of as a Network Automaton with a single node network = ntm.topology.from_adjacency_matrix([[1]]) # the Pushdown Automaton starts off in the q0 state initial_conditions = [states['q0']] # 'Z' is the symbol representing the bottom of the stack stack = ['Z'] # '\n' is the symbol representing the end of the input events = "aaabbb\n" def pda_rule(ctx): current_state = ctx.current_activity if current_state == states['q0'] and ctx.input == 'a' and stack[-1] == 'Z': stack.append('a') return states['q1'] elif current_state == states['q1'] and ctx.input == 'a' and stack[-1] == 'a': stack.append('a') return states['q1'] elif current_state == states['q1'] and ctx.input == 'b' and stack[-1] == 'a': stack.pop() return states['q2'] elif current_state == states['q2'] and ctx.input == 'b' and stack[-1] == 'a': stack.pop() return states['q2'] elif current_state == states['q2'] and ctx.input == '\n' and stack[-1] == 'Z': return states['q3'] else: raise Exception("input rejected") try: trajectory = ntm.evolve(initial_conditions=initial_conditions, network=network, input=events, activity_rule=pda_rule) activities = ntm.get_activities_over_time_as_list(trajectory) print("'%s' accepted (final state: %s)" % (events.strip(), activities[-1][0])) except Exception: print("'%s' rejected!" % events.strip()) ``` The program above will print `'aaabbb' accepted (final state: 3)`. If the `event` variable is changed to `aabbb\n`, the program will print `'aabbb' rejected!`. The full source code for this example can be found [here](pushdown_automata_demo.py).