# PDAs to CFGs ## April 2nd, 2020 - We have survived the Fool's Day without incident; let the cruelest month begin - "I'm not doing webcam anymore, because of the internet" - TODAY'S PLAN: - Convertings CFGs to PDAs - Recap converting PDA to CFG - More CFG examples - Last time, we talked a little about going from a PDA to a CFG; today, we'll recap that and hopefully go the other way, too -------------------------------------------------------------------------------- - As we've mentioned before, a PDA is just an NFA with a stack we can push/pop from, and as we've said, CFGs and PDAs are formally equivalent; you can convert from one to the other - These conversions tend to NOT be reversible; since CFGs and PDAs are both non-deterministic, a conversion just shows that if there's a sequence of operations in one that accepts, there's some sequence of operations in the other that also accepts - but not necessarily the SAME sequence (e.g. there may not be a 1-to-1 correspondence between substitutions and stack pushes/pops) - In other words, if f(CFG) = PDA, and g(PDA) = CFG, then f(g(PDA)) doesn't necessarily give me the same "PDA," even though it'll recognize the same language - Note, too, that CFGs and PDAs aren't unique for a given language; we can always add some dummy rules to get a different one - The general rules for conversion are that: - What goes up, must come down: is something gets pushed onto the stack, it should be popped eventually - For PDAs, you can always simplify down to 1 accepting state by using epsilon transitions - You can simplify things more by not popping AND pushing in a single state, but just doing 1 at a time - THEN, since there's just 1 starting state and 1 accepting state, we can convert to a CFG by starting with the variable $A_{q_{0}q_{accept}}$ - We then basically reduce each path from start/end to a single rule - "if you remember the Floyd-Warshall path algorithm, it's a similar procedure to that" - Along each path, we start with an empty stack and end with an empty stack - For the transition from state $p$ to $s$, then, there's 2 possibilities: - If we pushed nothing, then we just went from 1 state to another without changing the state - If we pushed some symbol X, then x was either: - Popped from an intermediate state at state $q$ - This gives us the rule $A_{ps} \implies A_{pq}{qs}$ - Never popped until just before the ending state $s$, meaning we can ignore it for the intermediate states (since it's just lying at the bottom of the stack not doing anything!) - This gives us the rule $A_{ps} \implies c_1A_{qr}c_2$ - $c_1/c_2$ are literal characters we've processed so far - So, we essentially just keep building up rules for this PDA to convert it to a CFG - So, we get 3 cases for our CFG (from a base case of $A_{pp} \implies \epsilon$): - 1: For rules of the form (p, c, $\epsilon$) -> (q, $\epsilon$), we have $A_{ps} \implies cA_{qs}$ - 2a: For the triple p, q, s, $A_{ps} \implies A_{pq}A_{qs}$ - 2b: For the tiples p, q, r, s, and rules: (p, c1, x) -> (q, e) (r, c2, $\epsilon$) -> (s, x) - ...we add the rule $c_1A_{qr}c_2$ - Okay, let's see an example for converting from a PDA to CFG - Suppose we have the language $L = \{ww^R | w \in \{0, 1\} \}$ - A PDA that can decide this language looks something like this (using our rule of "the same state can't push and pop in the same transition"): start-->a--($\epsilon, \epsilon$ -> \$)-->b (self-loop) b--(0, $\epsilon$ -> x)-->b--($\epsilon, \epsilon -> \epsilon$)->c (1, $\epsilon$ -> y) c--(0, x -> $\epsilon$)-->c--($\epsilon, \$ -> \epsilon$) -> D_ACCEPT (1, y -> $\epsilon$) - So, we push everything, non-deterministically decide when to "split," then try popping everything off - How do we convert this to a CFG? Let's think! - We have 6 state transitions we need to create variables for: $A_{ab}, A_{ac}, A_{ad}, A_{bc}, A_{bd}, A_{cd}$ - Our starting variable will be $A_{ad}$ - Then, for our rules: - For case 1, where the stack doesn't change, we have 2 rules: $$ A_{bd} \implies A_{cd}, A_{bc} \implies b_{cc} $$ - For case 2, there's a TON of cases (4^3=64), since we need to worry about all triples of state combination - For case 2b, for each "x" on the stack, we'll have: $\$: A_{ad} \implies A_{bc}$ $x: A_{bc} implies 0A_{bc}0$ $y: A_{bc} \implies 1A_{bc}1$ - So, this is a LOT of trouble we went through just to, basically, generate the CFG "S -> 0S0 | 1S1 | $\epsilon$" - which is why coming up with a new CFG from scratch is usually faster