Wednesday, October 8, 2008

Generating permutation covers: part II

In a prior entry, we reduced the problem of generating a minimal permutation cover of a set S of N elements to that of constructing a minimal tuple cover of S0 U ... U SM, where Si is the set of all subsets of S with cardinality i, M = (N − 1)/2 and N is odd. We do this construction recursively on m = 0,...,M.

Suppose then that we have a minimal tuple cover T of S0 U ... U Sm, i.e. a minimal set of m-tuples of different elements jointly covering all subsets of S with cardinality ≤ m, and we want to extend T to a minimal set T' of (m + 1)-tuples jointly covering S0 U ... U Sm U Sm + 1. We state without proof the following

Lemma. If mN/2, a miminal tuple cover of S0 U ... U Sm has cardinality C(N,m).

So, |T| = C(N,m) and we want to extend T to a set T' by assigning to each tuple τ of T one or more tuples of the form τa, a in S − range(τ), in such a way that all subsets of Sm + 1 are covered and the final number of elements of the cover |T'| is C(N,m + 1).

When extending a tuple τ of T we will disregard the order of its elements, so basically we are identifying τ with range(τ); this reduction still yields C(N,m) different elements, since every element of Sm must be covered by some tuple of T. So the extension mapping T T' relates elements of Sm to elements of Sm + 1, and in fact can be regarded as a subset of the graph induced by inclusion between elements of these two sets.

It is easy to see that each element of Sm is the source of (Nm) arrows, whereas m + 1 arrows arrive at each element of Sm + 1. Our job is then to select C(N,m + 1) arrows from the diagram above so that all the elements from the source and the destination set are met by at least one arrow. This selection process has to maintain some balance so that no source or destination element is left unattended: for instance, if we select for each element of Sm + 1 an arbitrary arrow arriving at it there is the possibility that some elements of Sm are not visited by any of the selected arrows. The following is a balanced selection criterion: given a fixed injection f : SmSm + 1 and function g : Sm + 1Sm, both compatible with the inclusion relationship between Sm and Sm + 1 (that is, X is a subset of f(X) and Y a superset of g(Y)), we select an arrow XY iff

Y = f(X) or (X = g(Y) and Y is not in f(Sm)).

It is obvious that this criterion does not leave any X or Y unvisited. The number of selected arrows coincides with the number of elements in Sm + 1, which is C(N,m + 1) as required. In the following we suppose, without loss of generality, that S is the set {0,...,N − 1}. Constructively defining an inclusion compatible injection from Sm to Sm + 1 is not a trivial task, but fortunately for us a paper from Pudlák, Turzík and Poljak provides the definition of such an injection f along with an algorithm χ : Sm + 1 → {true,false} that checks whether a given Y belongs to f(Sm). We adopt the following definition for g:

g(Y) := Y − max(Y),

which leads to this algorithm for generating Τ' from Τ:

Τ' ← Ø
for every τ in Τ
····X ← range(τ)
····af(X) − X {the one element added to X by f}
····Τ'Τ' U {τ·a}
····for i = max(X) + 1 to N − 1
········YX U {i}
········if not χ(Y) then
············Τ'Τ' U {τ·i}
········end if
····end for
end for

Note that the double loop over (X,i) is designed in such a way that it only visits the XY arrows where X = g(Y), which is maximally efficient and saves us the need to explicity compute g. The complete Τ0 = Ø → Τ1 → ··· → ΤM process can be inlined to avoid generating the intermediate Τi covers.

tuple-cover(m,N,τ,Τ) {initial call: tuple-cover(0,N,Ø,Τ) with Τ empty}
if m = (N − 1)/2 then
····ΤΤ U {τ}
····X ← range(τ)
····af(X) − X
····tuple-cover(m + 1,N,τ·a,Τ)
····for i = max(X) + 1 to N − 1
········YX U {i}
········if not χ(Y) then
············cover(m + 1,N,τ·i,Τ)
········end if
····end for
end if

In order to leverage the tuple cover algorithm to construct a minimal permutation cover, the only missing piece is finding a bijection d : SMSM such that Xd(X) = Ø for all X in SM, as we already saw. The aforementioned paper from Pudlák et al. provides also such a function (which, in fact, is used for the construction of f). Having all the necessary components, the following is the full algorithm for constructing a minimal permutation cover on S = {0,...,N − 1}.

if N is even then
····N'N − 1
end if
Σ ← Ø
Τ ← Ø
for every τ in Τ
····find τ' in Τ with range(τ') = d(range(τ))
····aS − range(τ) − range(τ')
····σ τ·a·reverse(τ')
····if N is even then
········ΣΣ U {N'·σ}
········ΣΣ U {σ·N'}
···· else
········ΣΣ U {σ}
····end if
end for

A C++ implementation of the algorithm is available (Boost used). The following are the different covers generated for |S| = 1,...,8.

|S|permutation cover
2(ab), (ba)
3(acb), (bac), (cba)

In a later entry we will see a practical application of permutation covers in the context of database querying.

No comments :