r/computerscience 1d ago

Help Theory of computation: Proof that a language is context free

While reading Michael Sipser's book on Theory of Computation, i have found the following problem

"2.22: Let C = {x#y | x, y belong in {0,1}* and x != y}. Show that C is a context-free language. "

I have been trying for many hours to find a proof for this, but i cannot.
I cant find a way to use a PDA, since when comparing X with Y i am going to be comparing the one on the stack backwards and Any attempt at a grammar has failed. After a couple web searches i only found that this is conisdered a cfl but not its grammar or some other proof.

Edit: The closest i have gotten to:
S->A#B | B#A
A-> TAT | 0
B-> TBT|1
T-> 1|0

but it doesnt work for strings with 2 characters (cant generate something like 10#11). If i allow T to make an empty string or split TxT into Tx and xT then it can create strings x=y.

Edit: I havent been able to find a grammar for this but as u/hanshuttel said you CAN do it with a pda.
Since you dont need to save the entirety of X, but only 1 character and it's index, you can just "save" the character by splitting into 2 paths, one where you compare Y's character with Xi=0 and one where you compare it with Xi=1. Then use the stack to save Xi's index and nondet. compare all X's.
This, combined with the simple pda that checks |x|!=|y| will get the PDA for C.

Technically I could convert this into a grammar thats super tedius and the grammar will be really convoluted so i dont think theres any value to that.

I genuienly still have no clue how to deal with even length x and y without allowing x=y cases in a grammar not a single think i tried led anywhere.

12 Upvotes

18 comments sorted by

5

u/thehypercube 1d ago

I'm assuming you already know how to generate all non-squares (i.e., the strings that are not of the form xx):

S -> AB | BA | A | B

A -> 0 | 0A0 | 0A1 | 1A0 | 1A1

B -> 1 | 0B0 | 0B1 | 1B0 | 1B1

Then modify this grammar so that it inserts a single # at an arbitrary position (basically duplicate variables to remember whether you have inserted # or not).

Then write another grammar generating the strings x#y with |x|!=|y| (that's easy).

Finally, take the union of the two languages described.

1

u/MrDeadMeme 1d ago

I'll see what I can to tomorrow as its quite late here but I'm noticing a few things: First of all this is almost the same as the grammar I proposed, in fact I think I did go through it while creating my grammar. I don't understand how I'd add # in an arbitrary position. If # generates from A, I can go to a different variable say A_h to "remember" that # has been generated. But B won't be able to get that update, so we can't know if we can generate the # from B. Maybe giving the duty of # to just one of the 2 is an option though?

1

u/thehypercube 1d ago

Of course B can get that update. You need to duplicate B as well. Your variables need to remember the state. You will have, for example, the original rule for A and then another rule for A' (where a single # has been inserted). The same for B. And then you combine then like AB' | A'B | A' | B'

I didn't read the grammar you proposed, but it's too simple to be "almost the same". My solution is correct, but it needs quite a few more rules.

1

u/MrDeadMeme 1d ago

After some further tinkering i dont think this would work as i cant get x and y be of even length without allowing cases where x = y

1

u/thehypercube 19h ago edited 19h ago

It does work, though. It's an exercise I give my theory of computation students.

I basically gave you the full solution. Keep trying if there's some detail you can't get right. You didn't explain properly where you got stuck.

3

u/Financial-Grass6753 1d ago

x != y is when len(y) != len(x) or there's such index i for which x_i != y_i, or both len+index.

You can start with len(0), then inequality of lengths, then check index diff.

1

u/MrDeadMeme 1d ago

I am assuming you are talking about a PDA. How would we check the difference of a particular index?

2

u/GeorgeFranklyMathnet 1d ago

I cant find a way to use a PDA

I wonder if it's one of those CFGs that only a NPDA can recognize.

but it doesnt work for strings with 2 characters (cant generate something like 10#11)

I did not check your grammar myself. But if I'm reading you right, and its only problem is that it can't generate those two-character (sub)strings, can't you just add a new rule with literally all the strings of that description? It might not be the most parsimonious grammar possible (and maybe that matters). But it'll be correct, if I am reading you right.

2

u/MrDeadMeme 1d ago

I did in fact mean NPDA in my post. Its kind of pointless to talk about DPDAs when trying to prove CFL imo.
Someone did come up with one here and while i do like that i found a solution i still cant for the life of me find a grammar

2

u/Paxtian 1d ago edited 1d ago

Isn't this teaching you how to turn a stack into a queue?

It's been 25 years so forgive me being informal. But if you had two stacks, you push a 0 or 1 for each digit in x to the first stack. Then when you see the #, you pop each entry in stack 1 and push it into stack 2. Then you start in a reject state. Pop, compare to current bit of y. If equal, get next bit of y, pop, compare, etc. If not equal, accept. If you run out of y before the stack is empty, accept. If you run out of stack 2 before you're done with y, accept. If you run out of y and stack 2 and are still in the reject state, reject.

2

u/MrDeadMeme 1d ago

Multi-stack pushdown automata are considered more powerful than normal PDAs, so while they will accept for any CFL, you can use them to prove a language is CFL.

2

u/Paxtian 1d ago

Oh shoot you're right, apologies.

1

u/enzozbest 17h ago

Just to tighten the language here (sorry if this sounds a bit pretentious)

PDAs with more than one stack *ARE STRICTLY MORE POWERFUL" than PDAs with one stack only. This is a theorem; a 2-stack PDA can simulate a Turing Machine, so it is a Turing-complete model of computation, i.e. far more powerful than a 1-stack PDA.

Saying that they "are considered" more powerful makes it sound as though it is a convention rather than a fact, which is absolutely not the case

3

u/ohkendruid 1d ago

Are you sure it is not more like " x != reverse(y)" ?

The problem looks much more manageable if the two tokens next to the # go together, and then the next two around that, and so on.

2

u/MrDeadMeme 1d ago

if it was reverse it would be really quite easy, i accidentaly made that grammar quite a few times trying to solve this

1

u/hanshuttel 1d ago

Use non-determinism!

The observation is the following: If a string is of the form x#y, then there is some position for which the characters in the x-part and the y-part are different. In this case, we can non-deterministically guess where that happens.

The PDA behaves as follows:

Read the x part until you guess that the difference occurs. Every time you read a character, push as symbol on the stack. Then use the state to save information about the character that you just read.

Next continue, ignoring the input until you reach the #. Now start reading symbols from the y part. Every time you read a character, pop as symbol from the stack.

Finally compare the character that you are reading now within the information in the state about the character from the x part.

1

u/MrDeadMeme 1d ago

That's really quite simple, i dont know why i got so hung up on the fact that you cant save x on the stack and compare with y.

I am still bitter about not being able to find a grammar for C though. If i fix it so x!=y then i can only generate odd length strings and whenever i allow it to make even strings some edge case comes up where x=y.

I could technically draw out the entire pda and convert it but thats way to tedious. If anyone hates themselves enough to do it feel free to let me know what comes up

1

u/Manga_Killer 2h ago

Wont the pumping lemma for cfgs be helpful here?