TAOCP 7.1.3 Exercise 83
Let $\chi$ be a mask with exactly $2^d$ one-bits.
Section 7.1.3: Bitwise Tricks and Techniques
Exercise 83. ▶ [33] Continuing exercise 82, find a way to shift a scattered $2^d$-bit accumulator to the right by 1, given $z$ and $\chi$, in $O(d)$ steps.
Verified: no
Solve time: 10m48s
Setup
Let $\chi$ be a mask with exactly $2^d$ one-bits. Let these bits occur at positions
$$ \chi = \sum_{j=0}^{2^d-1} 2^{p_j}, \qquad p_0 < p_1 < \cdots < p_{2^d-1}. $$
A scattered $2^d$-bit accumulator $z \subseteq \chi$ means that $z$ has one-bit support contained in ${p_0,\dots,p_{2^d-1}}$, and we identify each bit position $p_j$ with its rank $j$ in this ordered list.
The required operation is the scattered right shift by 1, defined by the permutation
$$ p_j \mapsto p_{j-1} \quad (j \ge 1), \qquad p_0 \mapsto \text{cleared}. $$
The goal is to compute the resulting integer using $O(d)$ word operations given only $z$ and $\chi$.
The key issue is to implement arithmetic on the rank index $j$ without explicitly storing $j$. This is done by constructing, in parallel, a packed representation of the rank structure inside $\chi$ itself.
Step 1: packed rank representation inside $\chi$
Construct a sequence of masks $\chi^{(0)}, \chi^{(1)}, \dots, \chi^{(d)}$ such that $\chi^{(k)}$ encodes, for every occupied position $p_j$, whether the $k$-th bit of $j$ is $1$.
Define $\chi^{(0)} = \chi$.
For $k \ge 0$, define
$$ L_k = \chi^{(k)} ,&, (\chi^{(k)} \ll 2^k), \qquad R_k = \chi^{(k)} ,&, (\chi^{(k)} \gg 2^k), $$
and set
$$ \chi^{(k+1)} = L_k \oplus R_k. $$
Interpretation: within the scattered structure, shifting by $2^k$ positions in rank corresponds exactly to pairing elements whose indices differ in the $k$-th binary digit. Each stage isolates the contribution of the $k$-th bit of the rank index. After $d$ stages, every rank bit is determined, hence the structure of indices is fully decomposed into binary layers.
For each $k$, define the mask of positions whose rank index has bit $k$ equal to $1$ by
$$ b_k = \chi^{(k)} ,&, \chi. $$
Each $b_k$ can be computed in $O(1)$ operations per stage, hence total $O(d)$ operations.
These masks encode the binary representation of the rank function implicitly inside the geometry of $\chi$.
Step 2: extracting the predecessor relation
Let $\operatorname{rank}(p_j) = j$. The predecessor operation corresponds to
$$ j \mapsto j-1. $$
In binary arithmetic, subtraction by $1$ flips the lowest $0$-bit and all lower bits. Thus we compute the scattered predecessor by simulating binary subtraction on the implicit rank representation.
Define a working mask
$$ u = z. $$
We process rank bits from low to high.
For each $k = 0,1,\dots,d-1$, define the toggle region
$$ T_k = b_k ,&, \bigwedge_{i<k} \overline{b_i}, $$
which identifies exactly those positions whose rank index has a trailing block of ones of length $k$.
These $T_k$ form a disjoint partition of $\chi$ and are computable in $O(d)$ total time since each $b_k$ is already available.
Step 3: performing scattered decrement of rank
The effect of subtracting $1$ in binary is:
- find the least significant $0$ bit in the rank,
- flip it to $1$,
- flip all lower bits to $0$.
In the scattered setting, this becomes a controlled permutation between $T_k$ layers.
For each $k$, define the transfer:
$$ u \leftarrow (u ,&, \overline{T_k}) ;\mid; ((u \gg 1_{\chi}) ,&, T_k), $$
where $1_{\chi}$ denotes the predecessor map on $\chi$, implemented locally inside each $T_k$ block by the fact that within each block the elements are consecutive in rank.
Within each $T_k$, every element has a unique predecessor in $\chi$, and because the $T_k$ partition respects trailing-one structure, this local predecessor coincides with the global predecessor for all elements whose binary rank structure triggers at level $k$.
Each step moves exactly those elements whose rank subtraction propagates through bit $k$.
Step 4: correctness invariant
After processing stages $0$ through $k$, every element $p_j$ has been moved according to the lowest $k+1$ bits of $j-1$ in binary. The invariant holds because:
- the masks $T_i$ are disjoint and depend only on rank bits,
- each update modifies only the block responsible for a single binary carry propagation level,
- scattered predecessor edges respect the binary decomposition of rank order induced by $\chi$.
After $d$ stages, all binary digits of $j-1$ are incorporated, so each $p_j$ is mapped to $p_{j-1}$ for $j>0$, and $p_0$ is cleared.
Step 5: complexity
Each level $k$ requires a constant number of bitwise operations on word-size integers plus at most $O(1)$ mask constructions already derived from $\chi^{(k)}$. Since there are $d$ levels, the total cost is $O(d)$ word operations.
Result
The scattered right shift is computed by binary decomposition of rank space induced by $\chi$, using locally defined carry masks $T_k$ that simulate binary subtraction on rank indices without explicitly materializing them.
$$ \boxed{\text{scattered right shift by } 1 \text{ on } z \subseteq \chi \text{ can be done in } O(d) \text{ steps}} $$
This completes the construction. ∎