//%cflags:-lm
//%cflags: -I/usr/users/QIB_fr005/deolivl/Academic/Quadram/009.supersptree/biomcmc-lib/lib
//%cflags: -I/usr/users/QIB_fr005/deolivl/Academic/Quadram/009.supersptree/build/biomcmc-lib/lib
//%cflags: /usr/users/QIB_fr005/deolivl/Academic/Quadram/009.supersptree/build/biomcmc-lib/lib/.libs/libbiomcmc.a
#include <biomcmc.h>
const char my_dna_seq[] =
"AAACCACCTCCCGGTGGTTT" // first 8 and last 8 are revcompl (AAACC<->GGTTT)
"AAACCACCTCCCGGTGGTTT"
"GTTCTTAACATTTCTCGTAC"
"GTTCTTAACATTTCTCGTAC";
uint32_t rand_hash_list[] = {0x4567, 0x23c6, 0x9869, 0x4873, 0xdc51}; // size = 5
uint32_t prime_salt_list[] = { // size = 64
0x343EAF9F, 0x75BD32B, 0x5E1C5A87, 0x343EFDAF, 0x1FDCDBEF, 0x6389CB, 0x1FDCE507, 0x1FDCE3C7,
0x1FDCE15F, 0x75BD431, 0x34C8B0F, 0x5397FEF, 0x87413, 0x6389C9, 0x34C8B23, 0x343EFDB5,
0x75BD479, 0x5398013, 0x5397FCD, 0x87407, 0x75BD413, 0x343EAF4B, 0x343EB047, 0x6389CF,
0x5E1C5A2F, 0x343EFD31, 0x34C8B59, 0x343EFD57, 0x1FDCDC19, 0x5E1C5B0D, 0x34C8B5D, 0x343EB035,
0x75BD307, 0x343EAF7B, 0x343EAEF5, 0x75BD433, 0x1FDCDBD5, 0x1FDCE3B7, 0x343EFD19, 0x5398057,
0x34C8B51, 0x638971, 0x1FDCE16F, 0x63896F, 0x343EB04D, 0x873FD, 0x63896B, 0x1FDCDC9B,
0x5E1C5B1F, 0x343EFCEB, 0x5398007, 0x1FDCE51F, 0x63897B, 0x5E1C5B17, 0x5E1C5ABD, 0xFF85,
0x1FDCDC25, 0x873EB, 0x5E1C5AB1, 0x75BD30D, 0x1FDCDCC1, 0xFF8B, 0x5397FC1, 0x5398001};
uint32_t**
new_dna_salted_hash_encoding (uint8_t salt) {
uint8_t i=255, j;
uint32_t **shash = (uint32_t**) biomcmc_malloc (2 * sizeof (uint32_t*)); // opposite order as dna_in_2_bits[]
for (i = 0; i < 2; ++i) shash[i] = (uint32_t*) biomcmc_malloc (256 * sizeof (uint32_t));
/* notice do{}while() instead of for() since i is always < 256 */
do { shash[0][i] = shash[1][i] = 4;} while (i--); // anything else is fifth state
shash[0]['A'] = shash[0]['a'] = 0; shash[1]['A'] = shash[1]['a'] = 3; /* A <-> T */
shash[0]['C'] = shash[0]['c'] = 1; shash[1]['C'] = shash[1]['c'] = 2; /* C <-> G */
shash[0]['G'] = shash[0]['g'] = 2; shash[1]['G'] = shash[1]['g'] = 1; /* G <-> C */
shash[0]['T'] = shash[0]['t'] = 3; shash[1]['T'] = shash[1]['t'] = 0; /* T <-> A */
shash[0]['U'] = shash[0]['u'] = 3; shash[1]['U'] = shash[1]['u'] = 0; /* U <-> A */
salt &= 63; // modulus, we only have 64 salts
/** now we transform the indexes for their equiv. hash values; all have same salt */
for (j = 0; j < 2; ++j) {
i = 255; do { shash[j][i] = rand_hash_list[shash[j][i]] + prime_salt_list[salt]; } while (i--);
}
return shash;
}
void
del_dna_salted_hash_encoding (uint32_t** shash) {
if (!shash) return;
if (shash[1]) free (shash[1]);
if (shash[0]) free (shash[0]);
free (shash);
}
#define RoL(val, numbits) ((val) << (numbits)) | ((val) >> (32 - (numbits)))
#define RoR(val, numbits) ((val) >> (numbits)) | ((val) << (32 - (numbits)))
void
roll_hash_add (uint32_t *h, const char dna_base, const uint8_t rol, const uint32_t* shashcode)
{
*h = RoL(*h, rol);
*h ^= shashcode[(uint8_t) dna_base]; // XOR h and ki
}
void // kmer_size can't be 0 or 32
roll_hash_replace_f (uint32_t *h, const char old_base, const char new_base, const uint8_t kmer_size,
const uint8_t rol, const uint32_t* shashcode)
{
uint8_t remain = (rol * (kmer_size-1)) & 31U; // since x % y = x & (y-1) // this can be calculated outside
*h ^= RoL(shashcode[(uint8_t) old_base], remain); // remove "leftmost" base
*h = RoL(*h, rol);
*h ^= shashcode[(uint8_t) new_base];
}
void // kmer_size can't be 0 or 32
roll_hash_replace_r (uint32_t *h, const char old_base, const char new_base, const uint8_t kmer_size,
const uint8_t rol, const uint32_t* shashcode)
{
uint8_t remain = (rol * (kmer_size-1)) & 31U; // since x % y = x & (y-1) // this can be calculated outside
*h ^= shashcode[(uint8_t) old_base];
*h = RoR(*h, rol);
*h ^= RoL(shashcode[(uint8_t) new_base], remain);
}
#undef RoL
#undef RoR
int main (){
uint8_t kmer_size = 5, rol = 5;
uint32_t h1, h2, h1R, h2R;
size_t i, j, seqlen = strlen (my_dna_seq);
uint32_t **shcode1, **shcode2;
shcode1 = new_dna_salted_hash_encoding (3);
shcode2 = new_dna_salted_hash_encoding (6);
h1 = shcode1[0][(uint8_t) my_dna_seq[0]];
h2 = shcode2[0][(uint8_t) my_dna_seq[0]];
h1R = shcode1[1][(uint8_t) my_dna_seq[kmer_size-1]];
h2R = shcode2[1][(uint8_t) my_dna_seq[kmer_size-1]];
for (j = 1; j < kmer_size; ++j) {
roll_hash_add (&h1, my_dna_seq[j], rol, shcode1[0]);
roll_hash_add (&h2, my_dna_seq[j], rol, shcode2[0]);
roll_hash_add (&h1R, my_dna_seq[kmer_size-1-j], rol, shcode1[1]);
roll_hash_add (&h2R, my_dna_seq[kmer_size-1-j], rol, shcode2[1]);
}
for (j = (size_t) kmer_size; j < seqlen; ++j) {
if ((j-kmer_size)%kmer_size == 0) {
printf ("%3lu >> ", j - kmer_size);
for (i=j - (size_t) kmer_size; i < j; i++) printf ("%c ", my_dna_seq[i]);
printf (" >> %12u >> %12u || %12u << %12u\n",h1, h1R, h2, h2R);
}
roll_hash_replace_f (&h1, my_dna_seq[j - kmer_size], my_dna_seq[j], kmer_size, rol, shcode1[0]);
roll_hash_replace_f (&h2, my_dna_seq[j - kmer_size], my_dna_seq[j], kmer_size, rol, shcode2[0]);
roll_hash_replace_r (&h1R, my_dna_seq[j - kmer_size], my_dna_seq[j], kmer_size, rol, shcode1[1]);
roll_hash_replace_r (&h2R, my_dna_seq[j - kmer_size], my_dna_seq[j], kmer_size, rol, shcode2[1]);
}
del_dna_salted_hash_encoding (shcode1);
del_dna_salted_hash_encoding (shcode2);
}