Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 48

Decidability of Emptiness and Finiteness for CFLs

Recommended resources

Hello! Welcome back.

In our last lesson, we explored the CYK algorithm, a powerful dynamic programming method for solving the membership problem for Context-Free Languages (CFLs). This gave us our first example of a decidable problem for this class of languages.

Today, we continue our investigation into the properties of CFLs by tackling two more fundamental decision problems. This lesson addresses the learning outcome: Formulate and solve the decision problems of emptiness and finiteness for CFLs by analyzing their grammars. We will develop algorithms to answer:

  1. Emptiness: Is the language generated by a given Context-Free Grammar (CFG) empty?
  2. Finiteness: Does a given CFG generate a finite or infinite number of strings?

These questions are not about a single string, but about the language as a whole. The algorithms to solve them involve analyzing the structure of the grammar's production rules—a task analogous to static analysis in compilers or verifying properties of complex systems, which should connect with your experience in software engineering and system design.

1. The Emptiness Problem

A decision problem is a question with a "yes" or "no" answer. The emptiness problem for CFLs is formally stated as:

  • Given a CFG , is ?

A naive approach, such as trying to generate strings to see if we find one, is not a valid algorithm. If the language is indeed empty, this process would run forever. We need an algorithm that is guaranteed to halt.

The solution lies in working backward from the terminals. A grammar generates a non-empty language if and only if the start symbol is capable of deriving at least one string of terminals. We can determine this by identifying all the variables that can generate terminal strings.

The Marking Algorithm

The core idea is to find all the "generating" variables—those that can eventually produce a string of only terminals. We can do this iteratively:

  1. Base Case: Any terminal symbol is, by definition, "generated".
  2. Inductive Step: A variable is "generating" if there is a production where all symbols in the string (which can be terminals or other variables) are already known to be "generating".

We repeat this process until no new generating variables can be found. If the start symbol is marked as generating by the end of this process, the language is not empty. Otherwise, it is empty.

The following video provides an excellent intuitive explanation of this marking procedure.

7. Decision Problems for Automata and Grammars

This clip from an MIT OpenCourseWare lecture by Prof. Michael Sipser explains the algorithm for deciding the emptiness of a CFG. It uses a clear, step-by-step marking process to determine if the start symbol can generate any terminal string.

Watch the segment from 53:38 to 58:33. Focus on how the algorithm works backward from the terminals to mark variables, and why this process guarantees a correct decision.

Formalizing the Algorithm

Let's formalize this procedure, as described in the lecture notes from St. Francis Xavier University. This frames the algorithm as a proof that the emptiness problem is decidable.

Decidable Problems for Context-Free Languages

These notes provide a formal description of the algorithm for deciding the emptiness problem (denoted E_CFG). This will reinforce the video's intuition with a more rigorous, proof-based perspective.

Read Section 3.2, 'Emptiness Problem' (pages 6-7). Pay close attention to the proof of Theorem 11, which constructs a Turing machine to perform the marking algorithm we just discussed.

As the notes detail, the algorithm is:
Given a CFG :

  1. Mark all terminal symbols in .
  2. Repeat until no new variables are marked in an iteration:
    • For each rule in , if all symbols have already been marked, then mark the variable .
  3. If the start symbol is marked, then is not empty.
  4. If is not marked, then is empty.

This algorithm is guaranteed to terminate because in each step of the loop, we can only mark more variables, and there are a finite number of variables in the grammar.

To see this algorithm applied to concrete examples, the next video walks through several grammars.

Decision Properties of Context Free Language Part 1 | Emptiness Problem (C55)

This tutorial video demonstrates the emptiness algorithm on three different grammars, making the process very concrete.

Watch from 03:54 to 13:55. The presenter calls the process 'eliminating non-terminating variables,' which is equivalent to our marking algorithm. Follow along with the three examples to solidify your understanding.

Test your understanding!

Consider the following CFG:




Is the language generated by this grammar empty? Justify your answer using the marking algorithm.

Show answer

Let's apply the marking algorithm.

  1. Initial Marks: Mark all terminals: a, c. ( is a special case; a variable going to is generating).
  2. Iteration 1:
    • From , we know can generate a terminal string (the empty one). So, we mark A.
    • From , since c is marked, we mark C.
  3. Iteration 2:
    • Look at . a is marked and A is now marked. So this rule is fine, but A is already marked.
    • Look at . A is marked, but B is not. We cannot mark S.
    • Look at . C is marked, but D is not. We cannot mark B.
    • Look at . d is not a terminal in our alphabet, so we can't use this rule. Let's assume d was a typo for c. Even with , c is marked but D is not, so we cannot mark D. If the rule was where , we could mark D. But as written, D cannot generate a terminal string. D is non-generating.
  4. Iteration 3: No new variables were marked in the last step. The algorithm terminates.

Conclusion: The marked variables are . The start symbol is not marked. Therefore, the language generated by this grammar is empty. The variable can never fully resolve to a string of terminals because cannot.


2. The Finiteness Problem

Next, we ask whether a grammar's language is finite or infinite.

  • Given a CFG , is finite?

The source of infinite strings in a CFL is recursion. Specifically, if a variable can be part of a derivation that expands to include itself, it may be possible to repeat this derivation an arbitrary number of times, generating infinitely many strings.

For example, a rule like allows to generate . This happens if can derive a string containing itself, formally written as , where or contains at least one terminal.

The Graph-Based Algorithm

We can detect this kind of useful recursion by modeling the grammar as a directed graph.

Algorithm To Decide Whether CFL Is Finite

This article from Gate Vidyalay presents a clear, step-by-step algorithm to decide if a CFL is finite by detecting cycles in a variable dependency graph.

Read the entire article. Focus on the two main steps: simplifying the grammar and then constructing the directed graph. Understand why the presence of a cycle implies an infinite language.

The algorithm is as follows:

  1. Simplify the Grammar: First, eliminate all non-generating and unreachable variables from the grammar. This is crucial. A recursive variable only contributes to an infinite language if it is useful—that is, it can be reached from the start symbol AND it can generate a string of terminals. Simplifying the grammar ensures we only consider such variables.

  2. Construct a Dependency Graph: Create a directed graph where the nodes are the variables of the (simplified) grammar. For every production in the grammar, draw a directed edge from variable to variable .

  3. Check for Cycles: Determine if the graph contains any cycles. Standard graph traversal algorithms like Depth-First Search (DFS) can do this.

  4. Decision:

    • If the graph contains a cycle, the language is infinite.
    • If the graph does not contain a cycle, the language is finite.

Why does this work? A cycle in the graph, say , signifies that the variable is recursive (). Since we already removed all non-generating variables, we know that this can also be part of a derivation that produces a terminal string. Combining these facts, we can construct infinitely many distinct strings, proving the language is infinite.

Let's look at the first example from the article.

Problem-01:



(Assume C has a rule like , which is missing but implied by the problem being well-formed. Let's add .)

The grammar is already simplified. The dependency graph has nodes .

  • gives edges and .
  • gives edges and .
  • gives an edge .

The resulting graph is acyclic. Therefore, the language is finite.

Now consider the second example.

Problem-02:



The graph has nodes .

  • gives edges and a self-loop .
  • gives edges and .
  • gives edges and .

This graph contains multiple cycles (e.g., the self-loop and the mutual recursion ). Therefore, the language is infinite.


Conclusion

In this lesson, we have added two more powerful tools to our analytical toolkit for Context-Free Languages. We've shown that we can algorithmically decide fundamental properties of the entire language generated by a grammar, not just its individual strings.

Key Takeaways:

  • The emptiness problem for CFLs is decidable. The algorithm works by iteratively marking all "generating" variables that can produce terminal strings and checking if the start symbol gets marked.
  • The finiteness problem for CFLs is also decidable. The algorithm involves constructing a dependency graph from a simplified grammar and checking for cycles. A cycle implies the language is infinite; no cycles means it is finite.
  • These algorithms are efficient and rely on analyzing the grammar's structure, a common theme in formal language theory and compiler construction.
  • Unlike regular languages, however, not all decision problems for CFLs are decidable. For instance, the equivalence problem (is ?) and the universality problem (is ? ) are undecidable for CFLs. This is a crucial distinction and a hint at the limits of computation we will soon explore.

Preview of the Next Lesson:
We have reached the limits of what pushdown automata and context-free grammars can do. To model more complex computational tasks and to formally define what "computation" itself means, we need a more powerful model. In the next lesson, we will be introduced to the Turing Machine, the foundational model for all of modern computer science and the final step up in the Chomsky Hierarchy we will study.