1 module tagion.utils.Gene;
2 
3 import std.algorithm.iteration : fold;
4 import std.range : lockstep;
5 
6 @nogc @safe
7 uint gene_count(const ulong bitstring) pure nothrow {
8     static uint count_ones(ulong BITS = ulong.sizeof * 8)(const ulong x) pure nothrow {
9         static if (BITS == 1) {
10             return x & 0x1;
11         }
12         else if (x == 0) {
13             return 0;
14         }
15         else {
16             enum HALF_BITS = BITS / 2;
17             enum MASK = ulong(1UL << (HALF_BITS)) - 1;
18             return count_ones!(HALF_BITS)(x & MASK) + count_ones!(HALF_BITS)(x >> HALF_BITS);
19         }
20     }
21 
22     return count_ones(bitstring);
23 }
24 
25 @safe
26 unittest {
27     enum SIZE_BITS = ulong.sizeof * 8;
28     {
29         const bits = cast(ulong) 0;
30         assert(bits.gene_count == 0);
31     }
32     {
33         const bits = cast(ulong) long(-1);
34         assert(bits.gene_count == SIZE_BITS);
35     }
36     {
37         const a_bits = ulong(
38                 0b00001000_00010000_00000100_00100000_00000001_00001000_10000000_00000010UL);
39         const b_bits = ulong(
40                 0b00101000_00010110_00100100_00100111_11110001_01001000_10011000_01100010);
41         assert(a_bits.gene_count == 8);
42         assert(b_bits.gene_count == 24);
43     }
44 }
45 
46 @nogc @safe
47 uint gene_count(scope const(ulong[]) bitstream) pure nothrow {
48     return bitstream
49         .fold!((a, b) => a + gene_count(b))(uint(0));
50 }
51 
52 @safe
53 ulong[] gene_xor(scope const(ulong[]) a, scope const(ulong[]) b) pure nothrow {
54     auto result = new ulong[a.length];
55     gene_xor(result, a, b);
56     return result;
57 }
58 
59 @nogc @safe
60 void gene_xor(ref scope ulong[] result, scope const(ulong[]) a, scope const(ulong[]) b) pure nothrow
61 in {
62     assert(a.length == b.length);
63     assert(result.length == b.length, "Length of a and b should bed the same");
64 }
65 do {
66     foreach (i, ref r; result) {
67         r = a[i] ^ b[i];
68     }
69 }
70 
71 @safe
72 unittest {
73     {
74         const a_bits = [0b01000001_01101101UL, 0b00010001_10011110UL];
75         assert(a_bits.gene_count == 14);
76         const b_bits = [0b01011001_00010110UL, 0b01100101_10010011UL];
77         assert(b_bits.gene_count == 15);
78         ulong[] result;
79         result.length = a_bits.length;
80         gene_xor(result, a_bits, b_bits);
81         assert(result == [0b00011000_01111011UL, 0b01110100_00001101]);
82         assert(result.gene_count == 15);
83     }
84 }