A supermask of is any mask with — every bit of is also set in .

The loop

for (int s = mask; s < (1 << n); s = (s + 1) | mask) {
    // s runs over all supermasks of `mask` within n bits, increasing
}

Why it works

s + 1 increments, carrying through the trailing ones. ORing with mask re-establishes the required bits. The result is the next larger mask that still contains mask, and every supermask is visited exactly once.

Complexity

A mask of size has supermasks. Summing over all masks:

the same bound as submask enumeration — by symmetry (complement every mask).

Where supermasks are the natural direction

”How many sets contain this one”

// cnt[m] = number of input sets that are supersets of m
for (int m = 0; m < (1 << n); m++)
    for (int s = m; s < (1 << n); s = (s + 1) | m)
        cnt[m] += freq[s];

— but the same thing is with superset-sum SOS DP:

for (int i = 0; i < n; i++)
    for (int m = 0; m < (1 << n); m++)
        if (!(m >> i & 1)) cnt[m] += cnt[m | (1 << i)];

Always prefer the SOS version. See SOS DP.

Minimal covering sets

“Find the smallest superset of satisfying property ” — enumerate supermasks in increasing order and stop at the first hit. Increasing numeric order is not increasing popcount order, so if you need the smallest cardinality, sort by popcount or BFS over the mask lattice.

Requirement propagation

When a constraint says “if you take these, you must also take those”, supermask enumeration is the natural iteration for closure computations.

Submasks vs supermasks

SubmasksSupermasks
Loops = (s-1) & masks = (s+1) | mask
Orderdecreasingincreasing
Count for
Total over all masks
SOS directionsubset sum: if (m>>i&1) f[m] += f[m^(1<<i)]superset sum: if (!(m>>i&1)) f[m] += f[m|(1<<i)]
Typical usepartitioning, splittingcovering, requirements

They are duals: enumerating supermasks of is enumerating submasks of and complementing.

The Möbius/zeta transform view

Subset-sum and superset-sum are the zeta transforms of the subset lattice; SOS DP computes them in . Their inverses are the Möbius transforms, obtained by replacing += with -=:

// inverse of the subset-sum transform
for (int i = 0; i < n; i++)
    for (int m = 0; m < (1 << n); m++)
        if (m >> i & 1) f[m] -= f[m ^ (1 << i)];

Zeta, pointwise multiply, inverse zeta = OR-convolution. The superset version gives AND-convolution, and FWHT gives XOR-convolution. Recognising which of the three you need is the key skill in this area.

See also: Enumerating Submasks · SOS DP · FWHT