4.2Operations on Languages
When designing an algorithm for a problem, it is often helpful to decompose the problem into simpler sub-problems. We can do something similar when designing algorithms for languages as well. In particular, we will now consider operations on languages that allow us to combine languages, similar to how propositional connectives () let us combine propositions.
These operations are:
complement
intersection
union
concatenation
Kleene star (aka Kleene closure)
The last 3 are called regular operations.
Given an alphabet , we define to be the set of all strings. For example, when , then . A language over the alphabet is a subset of .
4.2.1Concatenation¶
Given two strings and , we denote their concatenation by .
Alternative Definition Attempt 1¶
Let’s first try to design an algorithm that constructs . To be more precise, we want an algorithm that prints the strings in , one by one.
If and are finite, it is easy to do it using the following algorithm:
for x in A:
for y in B:
print x+yNote that the pseudocode uses the Python notation for string concatenation.
What about when is infinite (e.g. if )? In this case, we say that the algorithm succeeds if every string in is eventually printed by the algorithm.
Taking a closer look, we realize that when is finite, the algorithm succeeds even when is infinite. Unfortunately, it is unclear at this point how to modify the algorithm to be successful if both and are infinite. We leave this as an advanced exercise for now.
Exercise 1 (Advanced exercise)
Given a language , an algorithm is said to enumerate if every string in is eventually printed by .
Suppose that there are algorithms and that enumerate and , respectively. Design an algorithm that enumerates . Your algorithm should work even when both and are infinite.
Alternative Definition Attempt 2¶
Let’s instead try to build on cases of that are easier to understand.
Suppose consists of a single string , i.e. . Then, is easy to describe: it is the set of strings that are obtained by appending with a string in .
We can then define iteratively as follows: is the union of the sets over all .[1]
4.2.2Kleene star¶
Consider the following algorithm that, roughly speaking, generates , given a subroutine concat" that computes the concatenation of two languages:
k = 0
initialise Lstar to contain only the empty string
while(true):
for j = 1 up to k:
Lstar = concat(Lstar, L)Closure¶
The proof follows by taking the finite automata for , and , and modifying them appropriately.
For complement, this is easy: let be the finite automaton for . Then, the finite automaton for is obtained by swapping accept and reject states in . The others seem difficult. We will need the power of non-determinism to deal with them.
If you are comfortable with set notation, .