Traversing+Subsets+of+a+Set

determines the [|power set] of a set, or a subset of the power set with certain properties such as equal [|cardinality]. Represented by a bitboard, this is useful to loop over possible occupancies of a set of rays or lines, and to look for magic factors with a certain cardinality. || toc =Enumerating All Subsets=
 * Home * Programming * Algorithms * Traversing Subsets of a Set**
 * [[image:200px-Hypercubeorder_binary.svg.png link="http://en.wikipedia.org/wiki/File:Hypercubeorder_binary.svg"]] ||~ || **Traversing Subsets of a Set**
 * 4D-hypercube ||~ ||^ ||

All Subsets of the Universal Set
To enumerate all subsets of the universal set -1 is obvious, but takes some time. Assuming one loop cycle takes one nano-second, it would still take 18,446,744,073 seconds or about 585 years! code format="cpp" // enumerate all subsets of the universal set -1 void enumerateAllSubsetsOfTheBitboardUniverse { U64 n = 0; do { doSomeThingWithSubset(n); n++; } while ( n ); } code 

All Subsets of any Set
code format="cpp" // enumerate all subsets of set d void enumerateAllSubsets(U64 d) { U64 n = 0; do { doSomeThingWithSubset(n); n = (n - d) & d;  } while ( n ); } code This is how the Carry-Rippler, introduced by Marcel van Kervinck and later by Steffan Westcott works: we first set all "unused" bits of the set by oring the One's Complement of d. The increment ripples a possible carry through all unused bits - and finally we clear all unused bits again by intersection with the set d: code n = ((n | ~d) + 1) & d; code We can safely replace bitwise-or by add, since unused bits are always zero: code n = ((n + ~d) + 1) & d; code Replacing One's Complement by Two's Complement minus one code n = ((n + (-d-1) + 1) & d; code leaves the final expression code n = (n - d) & d; code =Subsets with equal Cardinality= Traversing subsets with one bit set was already mentioned in the Bitboard Serialization topic.

Equal cardinality subsets have **S**ame **n**umber **o**f **o**ne **b**its - thus **Snoob**, as synonym of the iterator-function. To use snoob in a loop: code format="cpp" U64 x, y, first = 0x0f; // traverse all 4-bit sequences for (x = first; (y = snoob(x)) > x; x = y)  doSomethingWith(y); code 

Snoobing the Universe
We add the LS1B (smallest) to the set, to get a greater number. The former LS1B becomes zero with overflow. If the next higher bit was zero, it takes the carry and the number of set bits didn't change - two flipped bits. Otherwise, if the carry ripples through, leaving further zero(s), we need to set least significant bits accordingly, to keep the cardinality equal. Thus, we xor ripple to get the flipped bits as ones. We shift this sequence right, until it becomes the least significant bits (divide by smallest). To take the two compensating bits off, we need to further divide by 4 (leading or trailing shift right 2). Get the next higher number with the same number of one bits (Snoob) was devised by Bill Gosper as HAKMEM 175 in PDP-6 Assembly and elaborated in Hacker's Delight by Henry S. Warren, Jr..

code format="cpp" // get next greater value with same number of one bits // Taken from "Hacker's Delight" by Henry S. Warren, Jr. // originally appeared as HAKMEM ITEM 175 (Bill Gosper) U64 snoob (U64 x) { U64 smallest, ripple, ones; smallest = x & -x; ripple = x + smallest; ones = x ^ ripple; ones = (ones >> 2) / smallest; return ripple | ones; } code

Modified Snoob
Division by power of two replaced by De Bruijn bitscan and shift right: code format="cpp" const U64 deBruijn = C64(0x03f79d71b4cb0a89);

const unsigned int deBruijnLookup[64] = // or unsigned char {   0,  1, 48,  2, 57, 49, 28,  3,   61, 58, 50, 42, 38, 29, 17,  4,   62, 55, 59, 36, 53, 51, 43, 22,   45, 39, 33, 30, 24, 18, 12,  5,   63, 47, 56, 27, 60, 41, 37, 16,   54, 35, 52, 21, 44, 32, 23, 11,   46, 26, 40, 15, 34, 20, 31, 10,   25, 14, 19,  9, 13,  8,  7,  6, };

// get next greater value with same number of one bits U64 snoob (U64 x) { U64 smallest, ripple, ones; smallest = x & (0-x); ripple  = x + smallest; ones    = x ^ ripple; ones    = (ones >> 2) >> deBruijnLookup[(smallest*deBruijn) >> 58]; return ripple | ones; } code Due to implicit modulo(64) of the shift amount by the processor code (ones >> i) >> 2 == (ones >> 2) >> i might not equal to ones >> (2 + i)! code

Reverse Snoob
based on One's Complement: code format="cpp" // get next less value with same number of one bits U64 rSnoob (U64 sub) { return ~snoob(~sub); } code or to safe some bitscans code format="cpp" // get next less value with same number of one bits U64 rSnoob (U64 sub) { if ( sub & 1 ) return ~snoob(~sub); U64 lsb = sub & (0-sub); return sub ^ lsb ^ (lsb>>1); } code

Snoobing any Sets
combining the Carry Rippler with Snoob - a little more complicated code set: ... 1110 0110 0x..e6 e.g. all subsets with two set bits: ... 0000 0110 0x..06 ... 0010 0010 0x..22 ... 0010 0100 0x..24 ... 0100 0010 0x..42 ... 0100 0100 0x..44 ... 0110 0000 0x..60 ... 1000 0010 0x..82 ... 1000 0100 0x..84 ... 1010 0000 0x..a0 ... 1100 0000 0x..c0 code

code format="cpp" // get next greater subset of set with same number of one bits U64 snoob (U64 sub, U64 set) { U64 tmp = sub-1; U64 rip = set & (tmp + (sub & (0-sub)) - set); for(sub = (tmp & sub) ^ rip; sub &= sub-1; rip ^= tmp, set ^= tmp) tmp = set & (0-set); return rip; } code

code format="cpp" // get next less set of a subset with same number of one bits U64 rSnoob (U64 sub, U64 set) { return ~snoob(~sub & set, set) & set; } code

=See also=
 * Bitboard Serialization
 * Magic Bitboards

=External Links= > media type="custom" key="25061518"
 * [|Partially ordered set from Wikipedia]
 * [|Power set from Wikipedia]
 * Led Zeppelin - [|Dazed and Confused], [|YouTube] Video, Lost Performances (2/5)

=References= =What links here?= include page="Traversing Subsets of a Set" component="backlinks" limit="40"
 * Up one Level**