Is the following union of CFL and non-CFL CFL itself? - automata

I'm a TA, and was asked the following by a student. Embarrassingly, I couldn't come up with an answer, so I turn to you guys.
We know that L_1 = {a^n b^n c^n} is non-CFL.
We also know that L_2 = {a^i b^k c^j : i != k } is context free.
What about the union of those? (it is obviously non-regular)
Is it context free?

We select as our universe the language U = {a^i b^j c^k | i, j, k in N}.
Then L_1^C = {a^i b^j c^k | i!=j or j != k} = {a^i b^j c^k | i!=j} union {a^i b^j c^k | j != k} = L_A union L_B. Notice that L_A = L_2.
By DeMorgan, L_1 union L_2 = (L_1^C intersect L_2^C)^C = ((L_A union L_B) intersect L_2^C)^C, which by the distributive law is ((L_A intersect L_2^C) union (L_B intersect L_2^C))^C.
Recall that since L_A = L_2, we get (L_B intersect L_2^C)^C. By DeMorgan, we can render this as L_B^C union L_2. We have already admitted that L_2 is context-free. The complement of L_B in our universe is {a^i b^j c^k | j=k}, which is also context free. The union of two context free languages is also context free, so yes, L_1 union L_2 is context free.
Having gone through the formalities, the intuition is obvious: L_1 union L_2 is equivalent to saying that either i != j (the number of a's and b's is different) OR the number of b's and c's is the same. If you think about it, this perfectly captures the requirements of the languages: if i != j, we're OK by the second part; the only way we can fail to be in L_2 is if we already know for a fact that i = j, and we only have to worry about guaranteeing j = k.
In boolean logic: (a and b) or (not a) is equivalent to (b or (not a)).
A CFG for the language is the following:
S := A | C
A := aA | B
B := lambda | bBc
C := Cc | D | E
D := a | aD | aDb
E := b | Eb | aEb
You can get a PDA via top-down or bottom-up parser constructions.

Related

Questions about building a Bayesian network

Example: Suppose we choose the ordering M, J, A, B, E
P(J | M) = P(J)? No
P(A | J, M) = P(A | J)? P(A | J, M) = P(A)? No
How do you know that P(A|J, M) = P(A) is the only condition that A depends on M? Is it possible that only J is dependent on A?

Simple refl-based proof problem in Lean (but not in Agda)

In an attempt to define skew heaps in Lean and prove some results, I have defined a type for trees together with a fusion operation:
inductive tree : Type
| lf : tree
| nd : tree -> nat -> tree -> tree
def fusion : tree -> tree -> tree
| lf t2 := t2
| t1 lf := t1
| (nd l1 x1 r1) (nd l2 x2 r2) :=
if x1 <= x2
then nd (fusion r1 (nd l2 x2 r2)) x1 l1
else nd (fusion (nd l1 x1 l1) r2) x2 l2
Then, even for an extremely simple result such as
theorem fusion_lf : ∀ (t : tree), fusion lf t = t := sorry
I'm stuck. I really have no clue for starting to write this proof. If I start like this:
begin
intro t,
induction t with g x d,
refl,
end
I can use refl for the case where t is lf, but not if it is a nd.
I'm a bit at a lost, since in Agda, it is really easy. If I define this:
data tree : Set where
lf : tree
nd : tree -> ℕ -> tree -> tree
fusion : tree -> tree -> tree
fusion lf t2 = t2
fusion t1 lf = t1
fusion (nd l1 x1 r1) (nd l2 x2 r2) with x1 ≤? x2
... | yes _ = nd (fusion r1 (nd l2 x2 r2)) x1 l1
... | no _ = nd (fusion (nd l1 x1 r1) r2) x2 l2
then the previous result is obtained directly with a refl:
fusion_lf : ∀ t -> fusion lf t ≡ t
fusion_lf t = refl
What I have missed?
This proof works.
theorem fusion_lf : ∀ (t : tree), fusion lf t = t :=
λ t, by cases t; simp [fusion]
If you try #print fusion.equations._eqn_1 or #print fusion.equations._eqn_2 and so on, you can see the lemmas that simp [fusion] will use. The case splits are not exactly the same as the case splits in the pattern matching, because the case splits in the pattern matching actually duplicate the case lf lf. This is why I needed to do cases t. Usually the equation lemmas are definitional equalities, but this time they are not, and honestly I don't know why.

Folding Set to make a new Set

Say I have a type Prop for propositions:
type Prop =
| P of string
| Disjunction of Prop * Prop
| Conjunction of Prop * Prop
| Negation of Prop
Where:
• A "p" representing the atom P,
• Disjunction(A "P", A "q") representing the proposition P ∨ q.
• Conjunction(A "P", A "q") representing the proposition P ∧ q.
• Negation(A "P") representing the proposition ¬P.
I'm supposed to use a set-based representation of formulas in disjunctive normal form. Since conjunction is commutative, associative and (a ∧ a) is equivalent to a it is convenient to represent a basic conjunct bc by its set of literals litOf(bc).
bc is defined as: A literal is an atom or the negation of an atom and a basic conjunct is a conjunction of literals
This leads me to the function for litOf:
let litOf bc =
Set.fold (fun acc (Con(x, y)) -> Set.add (x, y) acc) Set.empty bc
I'm pretty sure my litOf is wrong, and I get an error on the (Con(x,y)) part saying: "Incomplete pattern m
atches on this expression. For example, the value 'Dis (_, _)' may indicate a cas
e not covered by the pattern(s).", which I also have no clue what actually means in this context.
Any hints to how I can procede?
I assume your example type Prop changed on the way from keyboard to here, and orginally looked like this:
type Prop =
| P of string
| Dis of Prop * Prop
| Con of Prop * Prop
| Neg of Prop
There are several things that tripped you up:
Set.fold operates on input that is a set, and does something for each element in the set. In your case, the input is a boolean clause, and the output is a set.
You did not fully define what constitutes a literal. For a conjunction, the set of literals is the union of the literals on the left and on the right side. But what about a disjunction? The compiler error message means exactly that.
Here's what I think you are after:
let rec literals = function
| P s -> Set.singleton s
| Dis (x, y) -> Set.union (literals x) (literals y)
| Con (x, y) -> Set.union (literals x) (literals y)
| Neg x -> literals x
With that, you will get
> literals (Dis (P "A", Neg (Con (P "B", Con (P "A", P "C")))))
val it : Set<string> = set ["A"; "B"; "C"]

Follow sets Top-Down parsing

I have a question for the Follow sets of the following rules:
L -> CL'
L' -> epsilon
| ; L
C -> id:=G
|if GC
|begin L end
I have computed that the Follow(L) is in the Follow(L'). Also Follow(L') is in the Follow(L) so they both will contain: {end, $}. However, as L' is Nullable will the Follow(L) contain also the Follow(C)?
I have computed that the Follow(C) = First(L') and also Follow(C) subset Follow(L) = { ; $ end}.
In the answer the Follow(L) and Follow(L') contain only {end, $}, but shouldn't it contain ; as well from the Follow(C) as L' can be null?
Thanks
However, as L' is Nullable will the Follow(L) contain also the Follow(C)?
The opposite. Follow(C) will contain Follow(L). Think of the following sentence:
...Lx...
where X is some terminal and thus is in Follow(L). This could be expanded to:
...CL'x...
and further to:
...Cx...
So what follows L, can also follow C. The opposite is not necessarily true.
To calculate follows, think of a graph, where the nodes are (NT, n) which means non-terminal NT with the length of tokens as follow (in LL(1), n is either 1 or 0). The graph for yours would look like this:
_______
|/_ \
(L, 1)----->(L', 1) _(C, 1)
| \__________|____________/| |
| | |
| | |
| _______ | |
V |/_ \ V V
(L, 0)----->(L', 0) _(C, 0)
\_______________________/|
Where (X, n)--->(Y, m) means the follows of length n of X, depend on follows of length m of Y (of course, m <= n). That is to calculate (X, n), first you should calculate (Y, m), and then you should look at every rule that contains X on the right hand side and Y on the left hand side e.g.:
Y -> ... X REST
take what REST expands to with length n - m for every m in [0, n) and then concat every result with every follow from the (Y, m) set. You can calculate what REST expands to while calculating the firsts of REST, simply by holding a flag saying whether REST completely expands to that first, or partially. Furthermore, add firsts of REST with length n as follows of X too. For example:
S -> A a b c
A -> B C d
C -> epsilon | e | f g h i
Then to find follows of B with length 3 (which are e d a, d a b and f g h), we look at the rule:
A -> B C d
and we take the sentence C d, and look at what it can produce:
"C d" with length 0 (complete):
"C d" with length 1 (complete):
d
"C d" with length 2 (complete):
e d
"C d" with length 3 (complete or not):
f g h
Now we take these and merge with follow(A, m):
follow(A, 0):
epsilon
follow(A, 1):
a
follow(A, 2):
a b
follow(A, 3):
a b c
"C d" with length 0 (complete) concat follow(A, 3):
"C d" with length 1 (complete) concat follow(A, 2):
d a b
"C d" with length 2 (complete) concat follow(A, 1):
e d a
"C d" with length 3 (complete or not) concat follow(A, 0) (Note: follow(X, 0) is always epsilon):
f g h
Which is the set we were looking for. So in short, the algorithm becomes:
Create the graph of follow dependencies
Find the connected components and create a DAG out of it.
Traverse the DAG from the end (from the nodes that don't have any dependency) and calculate the follows with the algorithm above, having calculated firsts beforehand.
It's worth noting that the above algorithm is for any LL(K). For LL(1), the situation is much simpler.

How to match multiple copies of a value?

F#'s pattern matching is very powerful so it felt natural to write:
match (tuple1, tuple2) with
| ((a, a), (a, a)) -> "all values are the same"
| ((a, b), (a, b)) -> "tuples are the same"
| ((a, b), (a, c)) -> "first values are the same"
// etc
However, the first pattern match gives a compiler error:
'a' is bound twice in this pattern
Is there a cleaner way to do it than the following?
match (tuple1, tuple2) with
| ((a, b), (c, d)) when a = b && b = c && c = d -> "all values are the same"
| ((a, b), (c, d)) when a = c && b = d -> "tuples are the same"
| ((a, b), (c, d)) when a = c -> "first values are the same"
// etc
This is a perfect use case for F#'s "active patterns". You can define a couple of them like this:
let (|Same|_|) (a, b) =
if a = b then Some a else None
let (|FstEqual|_|) ((a, _), (c, _)) =
if a = c then Some a else None
And then clean up your pattern matching with them; note how the first case (where all values are equal) uses the nested Same pattern to check that the first and second elements of the tuple are equal:
match tuple1, tuple2 with
| Same (Same x) ->
"all values are the same"
| Same (x, y) ->
"tuples are the same"
| FstEqual a ->
"first values are the same"
| _ ->
failwith "TODO"
Performance tip: I like to mark simple active patterns like these with inline -- since the logic within the active patterns is simple (just a few IL instructions), it makes sense to inline them and avoid the overhead of a function call.
You can use parameterized active patterns to remedy the issue.
let (|TuplePairPattern|_|) ((p1, p2), (p3, p4)) ((a, b), (c, d)) =
let matched =
[(p1, a); (p2, b); (p3, c); (p4, d)]
|> Seq.groupBy fst
|> Seq.map (snd >> Set.ofSeq)
|> Seq.forall (fun s -> Set.count s = 1)
if matched then Some () else None
Particularly, you should define a pattern in a form of literals (chars, strings, etc).
match tuple1, tuple2 with
| TuplePairPattern(('a', 'a'), ('a', 'a')) -> "all values are the same"
| TuplePairPattern(('a', 'b'), ('a', 'b')) -> "tuples are the same"
| TuplePairPattern(("a", "b"), ("a", "c")) -> "first values are the same"
// etc
I think, the most elegant way can be accomplished by combining two excellent answers provided by #Stephen Swensen and #pad.
The first idea is that the structure (a tuple containing two tuples) can be unpacked once, instead of doing it in every match case.
The second idea is working with sequences of values, all of which must be equal to each other.
Here's the code:
let comparer ((a,b),(c,d)) =
let same = Set.ofSeq >> Set.count >> ((=) 1)
if same[a; b; c; d] then "all values are the same"
elif same[a; c] && same[b; d] then "tuples are the same"
elif same[a; c] then "first values are the same"
else "none of above"
You may change elif's into a match, but does not seem feasible to me.
In practice, I would probably unpack the tuples up-front and then do a series of if / then / else expressions:
let a,b = tuple1
let c,d = tuple2
if a = b && b = c && c = d then "all values are the same"
elif a = c && b = d then "tuples are the same"
elif a = c then "first values are the same"
...
If you find yourself doing this frequently, an active pattern might be warranted (and in the case of 2-tuples, a complete active pattern would be doable and likely preferable - exhaustive matches are "safer" than non-exhaustive matches). Or, perhaps you need a more sophisticated data structure.

Resources