diff --git a/src/utility/bit-math.hpp b/src/utility/bit-math.hpp index a42d8de..a5a4785 100644 --- a/src/utility/bit-math.hpp +++ b/src/utility/bit-math.hpp @@ -24,7 +24,10 @@ namespace bit { /** + * Compresses the even bits of a value into the lower half, then clears the upper half. * + * @param x Value to compress. + * @return Compressed value. */ template constexpr T compress(T x) noexcept; @@ -70,6 +73,15 @@ constexpr T crossover_n(T a, T b, T mask) noexcept; template constexpr T deposit(T x, T mask) noexcept; +/** + * Interleaves bits of the lower and upper halves of a value. + * + * @param x Value to desegregate. + * @return Value with bits from the upper half of @p x interleaved with bits from the lower half. + */ +template +constexpr T desegregate(T x) noexcept; + /** * Returns the number of differing bits between two values, known as *Hamming distance*. * @@ -80,6 +92,15 @@ constexpr T deposit(T x, T mask) noexcept; template constexpr int difference(T x, T y) noexcept; +/** + * Moves bits from the lower half of a value to occupy all even bits, and clears all odd bits. + * + * @param x Value to expand. + * @return Expanded value. + */ +template +constexpr T expand(T x) noexcept; + /** * Reads bits from a value in the positions marked by a mask and returns them in the least significant bits. * @@ -101,13 +122,22 @@ template constexpr T flip(T x, int i) noexcept; /** + * Returns a value with even bits containing the first value's lower half, and odd bits containing the second value's lower half. * + * @param a First value. + * @param b Second value. + * @return Value with bits from the lower halves of @p a and @p b interleaved. */ template constexpr U interleave(T a, T b) noexcept; /** + * Merges the bits of two values using a bit mask. * + * @param a First value. + * @param b Second value. + * @param mask Bit mask with zeros where bits from @p a should be used, and ones where bits from @p b should be used. + * @return Merged value. */ template constexpr T merge(T a, T b, T mask) noexcept; @@ -121,13 +151,6 @@ constexpr T merge(T a, T b, T mask) noexcept; template constexpr T parity(T x) noexcept; -/** - * - */ -template -constexpr T swap_adjacent(T x) noexcept; - - /** * Segregates the odd and even bits of a value. * @@ -135,66 +158,16 @@ constexpr T swap_adjacent(T x) noexcept; * @return Value with even bits of @p x in the lower half, and odd bits in the upper half. */ template -T segregate(T x) -{ - T odd = bit::compress(x); - T even = bit::compress(x >> 1); - - return odd | (even << (sizeof(T) << 2)); -} - -/** - * Interleaves bits of the lower and upper halves of a value. - * - * @param x Value to desegregate. - * @return Value with bits from the upper half of @p x interleaved with bits from the lower half. - */ -template -T desegregate(T x) -{ - return bit::interleave(x, x >> (sizeof(T) << 2)); -} +constexpr T segregate(T x) noexcept; /** - * Replicates each bit in the lower half of a value. + * Swaps the each odd bit with its following even bit. * - * @param x Value to replicate. - * @return Value of @p x interleaved with itself. + * @param x Value in which adjacent bits should be swap. + * @return Copy of @p x with adjacent bits swapped. */ template -T replicate(T x) -{ - x = bit::expand(x); - return x | (x << 1); -} - -/** - * Isolates a pair of bits and returns them in the two least significant bits. - * - * @param x Diploid chromosome with interleaved alleles. - * @param i Index of the pair to isolate. - * @return Isolated pair of bits in the two least significant bits. - */ -template -T isolate(T x, int i) -{ - return (x >> (i << 1)) & 0b11; -} - -/** - * Isolates a sequence of genes and returns their alleles in the least significant bits. - * - * @param x Diploid chromosome with interleaed alleles. - * @param i Index of the first gene in the sequence. - * @param n Length of the sequence, in genes. - * @return Alleles of the sequeuence in the least significant bits. - */ -template -T isolate_n(T x, int i, int n) -{ - T mask = (T(1) << (n << 1)) - 1; - return (x >> (i << 1)) & mask; -} +constexpr T swap_adjacent(T x) noexcept; template @@ -228,13 +201,13 @@ template inline constexpr T crossover(T a, T b, int i) noexcept { T mask = (T(1) << i) - 1; - return bit::merge(b, a, mask); + return merge(b, a, mask); } template constexpr T crossover_n(T a, T b, T mask) noexcept { - T merge = ~T(0) * bit::parity(mask); + T merge = ~T(0) * parity(mask); while (mask) { @@ -242,7 +215,13 @@ constexpr T crossover_n(T a, T b, T mask) noexcept mask &= mask - 1; } - return bit::merge(a, b, merge); + return merge(a, b, merge); +} + +template +inline constexpr T desegregate(T x) noexcept +{ + return interleave(x, x >> (sizeof(T) << 2)); } template @@ -263,28 +242,6 @@ constexpr T expand(T x) noexcept return x; } -template -inline constexpr T flip(T x, int i) noexcept -{ - return x ^ (T(1) << i); -} - -template -inline constexpr U interleave(T a, T b) noexcept -{ - return expand(a) | (expand(b) << 1); -} - -/** - * For an n-bit number with r set bits, there are `n! / ((n - r)! * r!)` permutations. - */ -template -constexpr T next_permutation(T x) noexcept -{ - T y = (x | (x - 1)) + 1; - return y | ((((y & -y) / (x & -x)) >> 1) - 1); -} - template constexpr T deposit(T x, T mask) noexcept { @@ -300,6 +257,12 @@ constexpr T deposit(T x, T mask) noexcept return result; } +template +inline constexpr int difference(T x, T y) noexcept +{ + return count(x ^ y); +} + template constexpr T extract(T x, T mask) noexcept { @@ -316,13 +279,19 @@ constexpr T extract(T x, T mask) noexcept } template -inline constexpr int difference(T x, T y) noexcept +inline constexpr T flip(T x, int i) noexcept { - return count(x ^ y); + return x ^ (T(1) << i); +} + +template +inline constexpr U interleave(T a, T b) noexcept +{ + return expand(a) | (expand(b) << 1); } template -constexpr T merge(T a, T b, T mask) noexcept +inline constexpr T merge(T a, T b, T mask) noexcept { return a ^ ((a ^ b) & mask); } @@ -342,6 +311,15 @@ constexpr T parity(T x) noexcept return (0x6996 >> (x & 0xf)) & 1; } +template +constexpr T segregate(T x) noexcept +{ + T odd = compress(x); + T even = compress(x >> 1); + + return odd | (even << (sizeof(T) << 2)); +} + template constexpr T swap_adjacent(T x) noexcept {