~ubuntu-branches/ubuntu/vivid/cctools/vivid

« back to all changes in this revision

Viewing changes to sand/src/sequence_filter.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2011-05-07 09:05:00 UTC
  • Revision ID: james.westby@ubuntu.com-20110507090500-lqpmdtwndor6e7os
Tags: upstream-3.3.2
ImportĀ upstreamĀ versionĀ 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (C) 2009- The University of Notre Dame
 
3
This software is distributed under the GNU General Public License.
 
4
See the file COPYING for details.
 
5
*/
 
6
 
 
7
#include <stdio.h>
 
8
#include <sys/time.h>
 
9
#include <math.h>
 
10
#include <limits.h>
 
11
#include <stdarg.h>
 
12
#include <stdlib.h>
 
13
 
 
14
#include "sequence_filter.h"
 
15
#include "itable.h"
 
16
 
 
17
#define EVEN_MASK 0xCCCCCCCCCCCCCCCCULL
 
18
#define ODD_MASK  0x3333333333333333ULL
 
19
 
 
20
unsigned short short_masks[8] = { 65535, 16383, 4095, 1023, 255, 63, 15, 3 };
 
21
 
 
22
#define SHORT_MASK_8 65535
 
23
#define SHORT_MASK_7 16383
 
24
#define SHORT_MASK_6 4095
 
25
#define SHORT_MASK_5 1023
 
26
#define SHORT_MASK_4 255
 
27
#define SHORT_MASK_3 63
 
28
#define SHORT_MASK_2 15
 
29
#define SHORT_MASK_1 3
 
30
 
 
31
static int k = 22;
 
32
static mer_t k_mask = 0;
 
33
static int WINDOW_SIZE = 22;
 
34
static mer_t repeat_mask = 0;
 
35
 
 
36
#define MER_VALUE(mer) ( (mer & (EVEN_MASK & k_mask)) | ((~mer) & (ODD_MASK & k_mask)) )
 
37
 
 
38
struct mer_list_elem_s
 
39
{
 
40
        int seq_num;
 
41
        short loc;
 
42
        char dir;
 
43
        struct mer_list_elem_s * next;
 
44
};
 
45
 
 
46
typedef struct mer_list_elem_s mer_list_element;
 
47
 
 
48
struct mer_hash_element_s
 
49
{
 
50
        mer_t mer;
 
51
        mer_list_element * mle;
 
52
        unsigned char count;
 
53
        struct mer_hash_element_s * next;
 
54
};
 
55
typedef struct mer_hash_element_s mer_hash_element;
 
56
 
 
57
struct cand_list_element_s
 
58
{
 
59
        int cand1;
 
60
        int cand2;
 
61
        char dir;
 
62
        int count;
 
63
        short loc1;
 
64
        short loc2;
 
65
        struct cand_list_element_s * next;
 
66
};
 
67
typedef struct cand_list_element_s cand_list_element;
 
68
 
 
69
/* These are globals referenced directly by sand_filter_mer_seq. */
 
70
/* This needs to be cleaned up. */
 
71
 
 
72
int curr_rect_x = 0;
 
73
int curr_rect_y = 0;
 
74
int rectangle_size = 1000;
 
75
unsigned long total_cand = 0;
 
76
 
 
77
static int MER_TABLE_BUCKETS = 5000011; //20000003;
 
78
static int CAND_TABLE_BUCKETS= 5000011; //20000003;
 
79
static struct cseq ** all_seqs = 0;
 
80
static cand_list_element ** candidates;
 
81
static mer_hash_element ** mer_table;
 
82
static struct itable * repeat_mer_table = 0;
 
83
static int num_seqs = 0;
 
84
 
 
85
static int start_x = 0;
 
86
static int end_x = 0;
 
87
static int start_y = 0;
 
88
static int end_y = 0;
 
89
static int same_rect;
 
90
 
 
91
#define in_range(x, s, e) (  ((s) <= (x)) && ((x) < (e))   )
 
92
 
 
93
void add_sequence_to_mer(mer_t mer, int i, char dir, short loc);
 
94
mer_hash_element * find_mer(mer_t mer);
 
95
void free_mer_table();
 
96
void free_mer_hash_element(mer_hash_element * mhe);
 
97
void free_mer_table();
 
98
void free_cand_table();
 
99
mer_list_element * create_mer_list_element(int seq_num, char dir, short loc);
 
100
mer_hash_element * get_mer_hash_element(mer_t mer);
 
101
void free_mer_list_element(mer_list_element * mle);
 
102
void mer_generate_cands(mer_hash_element * mhe);
 
103
void print_8mer(unsigned short mer);
 
104
void set_k_mask();
 
105
mer_t make_mer(const char * str);
 
106
 
 
107
void add_candidate(int seq, int cand, char dir, mer_t mer, short loc1, short loc2);
 
108
void free_cand_list_element(cand_list_element * cle);
 
109
 
 
110
void find_all_kmers(int seq_num);
 
111
void find_minimizers(int seq_num);
 
112
minimizer get_minimizer(int seq_num, int window_start);
 
113
mer_t get_kmer(struct cseq *c, int i);
 
114
void print_16mer(mer_t mer16);
 
115
mer_t rev_comp_mer(mer_t mer);
 
116
 
 
117
void print_mhe(FILE * file, mer_hash_element * mhe);
 
118
 
 
119
void init_cand_table( int buckets )
 
120
{
 
121
        int i;
 
122
        CAND_TABLE_BUCKETS = buckets;
 
123
        candidates = malloc(CAND_TABLE_BUCKETS * sizeof(cand_list_element *));
 
124
        for (i=0; i < CAND_TABLE_BUCKETS; i++)
 
125
        {
 
126
                candidates[i] = 0;
 
127
        }
 
128
}
 
129
 
 
130
void init_mer_table( int buckets )
 
131
{
 
132
        int i;
 
133
        MER_TABLE_BUCKETS = buckets;
 
134
        mer_table = malloc(MER_TABLE_BUCKETS * sizeof(mer_hash_element *));
 
135
        for (i=0; i < MER_TABLE_BUCKETS; i++)
 
136
        {
 
137
                mer_table[i] = 0;
 
138
        }
 
139
}
 
140
 
 
141
int load_seqs(FILE * input )
 
142
{
 
143
        int seq_count = sequence_count(input);
 
144
 
 
145
        all_seqs = malloc(seq_count*sizeof(struct cseq *));
 
146
        struct cseq *c;
 
147
 
 
148
        while ((c=cseq_read(input))) {
 
149
                all_seqs[num_seqs++] = c;
 
150
        }
 
151
 
 
152
        return num_seqs;
 
153
 
 
154
}
 
155
 
 
156
int load_seqs_two_files(FILE * f1, int * end1, FILE * f2, int * end2)
 
157
{
 
158
        num_seqs = 0;
 
159
        int count1 = sequence_count(f1);
 
160
        int count2 = sequence_count(f2);
 
161
 
 
162
        all_seqs = malloc((count1+count2)*sizeof(struct cseq *));
 
163
        struct cseq *c;
 
164
 
 
165
        while((c = cseq_read(f1))) {
 
166
                all_seqs[num_seqs++] = c;
 
167
        }
 
168
 
 
169
        *end1 = num_seqs;
 
170
 
 
171
        while((c = cseq_read(f2))) {
 
172
                all_seqs[num_seqs++] = c;
 
173
        }
 
174
 
 
175
        *end2 = num_seqs;
 
176
 
 
177
        return num_seqs;
 
178
 
 
179
}
 
180
 
 
181
// Loads up a set of mers from a file and stores them.
 
182
// These mers cannot be treated as minimizers.
 
183
int init_repeat_mer_table(FILE * repeats, unsigned long buckets, int max_mer_repeat)
 
184
{
 
185
        // Estimate the number of buckets here by dividing the file
 
186
        // size by 25.
 
187
        if (buckets == 0)
 
188
        {
 
189
                unsigned long curr_pos = ftell(repeats);
 
190
                fseek(repeats, 0, SEEK_END);
 
191
                unsigned long end_pos = ftell(repeats);
 
192
                buckets = (end_pos - curr_pos) / 25;
 
193
                fseek(repeats, curr_pos, SEEK_SET);
 
194
        }
 
195
 
 
196
        char str[1024];
 
197
        int *count = malloc(sizeof(int));;
 
198
        mer_t mer, rev;
 
199
        repeat_mer_table = itable_create(buckets);
 
200
        if (k_mask == 0) set_k_mask();
 
201
 
 
202
        while (fscanf(repeats, ">%d %s\n", count, str) == 2)
 
203
        {
 
204
                if (*count >= max_mer_repeat)
 
205
                {
 
206
                        mer = make_mer(str);
 
207
                        rev = rev_comp_mer(mer);
 
208
                        if (MER_VALUE(mer) < MER_VALUE(rev))
 
209
                                itable_insert(repeat_mer_table, mer, count);
 
210
                        else
 
211
                                itable_insert(repeat_mer_table, rev, count);
 
212
                }
 
213
                count = malloc(sizeof(int));
 
214
        }
 
215
 
 
216
        return itable_size(repeat_mer_table);
 
217
}
 
218
 
 
219
mer_t make_mer(const char * str)
 
220
{
 
221
        mer_t mer = 0;
 
222
        int i;
 
223
        int len = strlen(str);
 
224
        for (i=0; i<len; i++)
 
225
        {
 
226
                mer = (mer << 2) | base_to_num(str[i]);
 
227
        }
 
228
        return mer;
 
229
}
 
230
 
 
231
void rearrange_seqs_for_dist_framework()
 
232
{
 
233
        int i;
 
234
 
 
235
        struct cseq ** top = malloc(rectangle_size*(sizeof(struct cseq *)));
 
236
        struct cseq ** bottom = malloc(rectangle_size*(sizeof(struct cseq*)));
 
237
 
 
238
        for (i=0; i < num_seqs; i+=2)
 
239
        {
 
240
                top[i/2] = all_seqs[i];
 
241
                bottom[i/2] = all_seqs[i+1];
 
242
        }
 
243
        for (i=0; i<rectangle_size; i++)
 
244
        {
 
245
                all_seqs[i] = top[i];
 
246
                all_seqs[i+rectangle_size] = bottom[i];
 
247
        }
 
248
 
 
249
        free(top);
 
250
        free(bottom);
 
251
}
 
252
 
 
253
int compare_cand(const void * pair1, const void * pair2)
 
254
{
 
255
 
 
256
        // If c1.cand1 < c2.cand1, return a negative number, meaning less than.
 
257
        // If c1.cand1 and c2.cand1 are equal, check the second one.
 
258
        int diff = ((candidate_t *) pair1)->cand1 - ((candidate_t *) pair2)->cand1;
 
259
        if (!diff) return ((candidate_t *) pair1)->cand2 - ((candidate_t *) pair2)->cand2;
 
260
        return diff;
 
261
}
 
262
 
 
263
int output_candidate_list( FILE * file, candidate_t * list, int total_output )
 
264
{
 
265
        if (!list) return 0;
 
266
 
 
267
        int i;
 
268
        int total_printed = 0;
 
269
 
 
270
        for (i=0; i<total_output; i++)
 
271
        {
 
272
                candidate_t pair = list[i];
 
273
                fprintf(file, "%s\t%s\t%d\t%d\t%d\n", all_seqs[pair.cand1]->name, all_seqs[pair.cand2]->name, pair.dir, pair.loc1, (pair.dir == 1) ? pair.loc2 : all_seqs[pair.cand2]->num_bases - pair.loc2 - k);
 
274
                total_printed++;
 
275
        }
 
276
        return total_printed;
 
277
}
 
278
 
 
279
candidate_t * retrieve_candidates(int * total_cand_ret)
 
280
{
 
281
        int curr_index;
 
282
        int total_output = 0;
 
283
 
 
284
        cand_list_element * cle;
 
285
 
 
286
        candidate_t * candidate_list = malloc(total_cand*sizeof(struct candidate_s));
 
287
 
 
288
        for (curr_index = 0; curr_index < CAND_TABLE_BUCKETS; curr_index++)
 
289
        {
 
290
                cle = candidates[curr_index];   
 
291
                while (cle)
 
292
                {
 
293
                        if (cle->count >= 1) 
 
294
                        {
 
295
                                candidate_list[total_output].cand1 = cle->cand1;
 
296
                                candidate_list[total_output].cand2 = cle->cand2;
 
297
                                candidate_list[total_output].dir = cle->dir;
 
298
                                candidate_list[total_output].loc1 = cle->loc1;
 
299
                                candidate_list[total_output].loc2 = cle->loc2;
 
300
                                total_output++;
 
301
                        }
 
302
                        cle = cle->next;
 
303
                }
 
304
                free_cand_list_element(candidates[curr_index]);
 
305
                candidates[curr_index] = 0;
 
306
        }
 
307
 
 
308
        *total_cand_ret = total_output;
 
309
        qsort(candidate_list, total_output, sizeof(struct candidate_s), compare_cand);
 
310
        return candidate_list;
 
311
 
 
312
}
 
313
 
 
314
void generate_candidates()
 
315
{
 
316
        int curr_bucket;
 
317
 
 
318
        mer_hash_element * mhe, *old_mhe;
 
319
 
 
320
        for(curr_bucket = 0; curr_bucket < MER_TABLE_BUCKETS; curr_bucket++)
 
321
        {
 
322
                mhe = mer_table[curr_bucket];
 
323
                while (mhe)
 
324
                {
 
325
                        mer_generate_cands(mhe);
 
326
                        old_mhe = mhe;
 
327
                        mhe = mhe->next;
 
328
                        free(old_mhe);
 
329
                }
 
330
                mer_table[curr_bucket] = 0;
 
331
        }
 
332
}
 
333
 
 
334
void mer_generate_cands(mer_hash_element * mhe)
 
335
{
 
336
        if (!mhe) return;
 
337
 
 
338
        mer_list_element *head, *curr;
 
339
 
 
340
        head = mhe->mle;
 
341
 
 
342
        while (head)
 
343
        {
 
344
                curr = head->next;
 
345
                while (curr)
 
346
                {
 
347
                        add_candidate(head->seq_num, curr->seq_num, head->dir * curr->dir, mhe->mer, head->loc, curr->loc);
 
348
                        curr = curr->next;
 
349
                }
 
350
                head = head->next;
 
351
        }
 
352
 
 
353
        free_mer_list_element(mhe->mle);
 
354
        mhe->mle = 0;
 
355
}
 
356
 
 
357
void print_mer_table(FILE * file)
 
358
{
 
359
        int curr_bucket;
 
360
        mer_hash_element * mhe, *old_mhe;
 
361
        for (curr_bucket = 0; curr_bucket < MER_TABLE_BUCKETS; curr_bucket++)
 
362
        {
 
363
                mhe = mer_table[curr_bucket];
 
364
                while (mhe)
 
365
                {
 
366
                        print_mhe(file, mhe);
 
367
                        old_mhe = mhe;
 
368
                        mhe = mhe->next;
 
369
                }
 
370
        }
 
371
}
 
372
 
 
373
void print_mhe(FILE * file, mer_hash_element * mhe)
 
374
{
 
375
        if (!mhe) return;
 
376
 
 
377
        mer_list_element *head, *curr;
 
378
        head = mhe->mle;
 
379
        char mer_str[k+1];
 
380
 
 
381
        while(head)
 
382
        {
 
383
                curr = head->next;
 
384
                while (curr)
 
385
                {
 
386
                        translate_kmer(mhe->mer, mer_str, k);
 
387
                        fprintf(file, "%s\t%d\t%s\t%s\t%d\n", mer_str, mhe->count, all_seqs[head->seq_num]->name, all_seqs[curr->seq_num]->name, (int) (head->dir * curr->dir));
 
388
                        curr = curr->next;
 
389
                }
 
390
                head = head->next;
 
391
        }
 
392
}
 
393
 
 
394
mer_t rev_comp_mer(mer_t mer)
 
395
{
 
396
        mer_t new_mer = 0;
 
397
        int i;
 
398
        for (i = 0; i < k; i++)
 
399
        {
 
400
                // Build new_mer by basically popping off the LSB of mer (mer >> 2)
 
401
                // and pushing to the LSB of new_mer.
 
402
                new_mer = new_mer << 2;
 
403
                new_mer = new_mer | (mer & 3);
 
404
                mer = mer >> 2;
 
405
        }
 
406
        // Now it's reversed, so complement it, but mask it by k_mask so only the important bits get complemented.
 
407
        return (~new_mer) & k_mask;
 
408
}
 
409
 
 
410
 
 
411
void find_all_kmers(int seq_num)
 
412
{
 
413
        mer_t mer16;
 
414
        int i;
 
415
        int end = all_seqs[seq_num]->num_bases - 15;
 
416
 
 
417
        for (i = 0; i<end; i+=8)
 
418
        {
 
419
                mer16 = get_kmer(all_seqs[seq_num], i);
 
420
                add_sequence_to_mer(mer16, seq_num, (char) 1, (short) i);
 
421
        }
 
422
}
 
423
 
 
424
// Each time you move the window, you add a new kmer.
 
425
// Then do the following two things.
 
426
// 1. Check if the new kmer is less than the current minimizer.
 
427
//    If so, set it as the new one.
 
428
// 2. Is the current absolute minimizer now outside the window?
 
429
//    If so, check the window to find a NEW absolute minimizer, and add it.
 
430
void find_minimizers(int seq_num)
 
431
{
 
432
        int i;
 
433
        int end = all_seqs[seq_num]->num_bases - k + 1;
 
434
        mer_t mer, rev, mer_val, rev_val;
 
435
 
 
436
        minimizer window[WINDOW_SIZE];
 
437
        minimizer abs_min;
 
438
        int abs_min_index = 0;
 
439
        int index;
 
440
        int j;
 
441
 
 
442
        memset(&abs_min,0,sizeof(abs_min));
 
443
        abs_min.value = MINIMIZER_MAX;
 
444
        abs_min.dir = 0;
 
445
 
 
446
        // First, just populate the first window and get the first minimizer.
 
447
        for (i = 0; i < WINDOW_SIZE; i++)
 
448
        {
 
449
                mer = get_kmer(all_seqs[seq_num], i);
 
450
                rev = rev_comp_mer(mer);
 
451
                mer_val = MER_VALUE(mer);
 
452
                rev_val = MER_VALUE(rev);
 
453
 
 
454
                if (mer_val < rev_val)
 
455
                {
 
456
                        window[i].mer = mer;
 
457
                        window[i].value = mer_val;
 
458
                        window[i].dir = 1;
 
459
                        window[i].loc = i;
 
460
                }
 
461
                else
 
462
                {
 
463
                        window[i].mer = rev;
 
464
                        window[i].value = rev_val;
 
465
                        window[i].dir = -1;
 
466
                        window[i].loc = i;
 
467
                }
 
468
                if (window[i].value < abs_min.value)
 
469
                {
 
470
                        abs_min = window[i];
 
471
                        abs_min_index = i;
 
472
                }
 
473
        }
 
474
 
 
475
        // Add the absolute minimizer for the first window.
 
476
        add_sequence_to_mer(abs_min.mer, seq_num, abs_min.dir, abs_min.loc);
 
477
 
 
478
        for (i = WINDOW_SIZE; i < end; i++)
 
479
        {
 
480
                index = i%WINDOW_SIZE;
 
481
 
 
482
                // First, add the new k-mer to the window, evicting the k-mer that is
 
483
                // no longer in the window
 
484
                mer = get_kmer(all_seqs[seq_num], i);
 
485
                rev = rev_comp_mer(mer);
 
486
                mer_val = MER_VALUE(mer);
 
487
                rev_val = MER_VALUE(rev);
 
488
 
 
489
                if (mer_val < rev_val)
 
490
                {
 
491
                        window[index].mer = mer;
 
492
                        window[index].value = mer_val;
 
493
                        window[index].dir = 1;
 
494
                        window[index].loc = i;
 
495
                }
 
496
                else
 
497
                {
 
498
                        window[index].mer = rev;
 
499
                        window[index].value = rev_val;
 
500
                        window[index].dir = -1;
 
501
                        window[index].loc = i;
 
502
                }
 
503
 
 
504
                // Now, check if the new k-mer is better than the current absolute minimizer.
 
505
                //if (window[index].value < abs_min.value)
 
506
                if (window[index].value < abs_min.value)
 
507
                {
 
508
                        // If so, set it as the new absolute minimizer and add this sequence to the mer table
 
509
                        abs_min = window[index];
 
510
                        abs_min_index = index;
 
511
                        add_sequence_to_mer(abs_min.mer, seq_num, abs_min.dir, abs_min.loc);
 
512
                }
 
513
                // Now, check if the current absolute minimizer is out of the window
 
514
                // We just replaced index, so if abs_min_index == index, we just evicted
 
515
                // the current minimizer.
 
516
                else if (abs_min_index == index)
 
517
                {
 
518
                        // Find the new minimizer
 
519
                        // If runtime starts to suffer I can implement something better than a linear search,
 
520
                        // but because WINDOW_SIZE is a small constant (around 20) it should be OK.
 
521
                        abs_min.value = MINIMIZER_MAX;
 
522
                        abs_min.dir = 0;
 
523
                        for (j = 0; j < WINDOW_SIZE; j++)
 
524
                        {
 
525
                                if (window[j].value < abs_min.value)
 
526
                                {
 
527
                                        abs_min = window[j];
 
528
                                        abs_min_index = j;
 
529
                                }
 
530
                        }
 
531
                        // Add the new current minimizer to the mer table.
 
532
                        add_sequence_to_mer(abs_min.mer, seq_num, abs_min.dir, abs_min.loc);
 
533
                }
 
534
        }
 
535
}
 
536
 
 
537
// Gets the next minimizer for this sequence.  Returns 1 if it worked, 0 if we're at the end of the sequence.
 
538
int get_next_minimizer(int seq_num, minimizer * next_minimizer )
 
539
{
 
540
        static int i = 0;
 
541
        static int index = 0;
 
542
        static minimizer * window = 0;
 
543
        static minimizer abs_min = {0, ULONG_MAX, -1, 0};
 
544
        static int abs_min_index = 0;
 
545
        static int prev_seq_num = -1;
 
546
        static int end;
 
547
 
 
548
        mer_t mer, rev, mer_val, rev_val;
 
549
 
 
550
        // Re-initialize everything if the sequence we are using changes.
 
551
        if (seq_num != prev_seq_num)
 
552
        {
 
553
                if (!window) window = malloc(WINDOW_SIZE*sizeof(minimizer));
 
554
                i = 0;
 
555
                index = 0;
 
556
                abs_min.mer = 0;
 
557
                abs_min.value = ULONG_MAX;
 
558
                abs_min.dir = 0;
 
559
                abs_min.loc = -1;
 
560
                abs_min_index = 0;
 
561
                end = all_seqs[seq_num]->num_bases - k + 1;
 
562
                prev_seq_num = seq_num;
 
563
        }
 
564
 
 
565
        // If we haven't populated the whole window yet, do so now.
 
566
        if (i == 0)
 
567
        {
 
568
                index = i;
 
569
                for (i = 0; i < WINDOW_SIZE; i++)
 
570
                {
 
571
                        // Get the current mer, its reverse complement, and its minimizer values.
 
572
                        mer = get_kmer(all_seqs[seq_num], i);
 
573
                        rev = rev_comp_mer(mer);
 
574
                        mer_val = MER_VALUE(mer);
 
575
                        rev_val = MER_VALUE(rev);
 
576
 
 
577
                        // Add them to the window.
 
578
 
 
579
                        if (mer_val < rev_val)
 
580
                        {
 
581
                                window[index].mer = mer;
 
582
                                window[index].value = mer_val;
 
583
                                window[index].dir = 1;
 
584
                                window[index].loc = i;
 
585
                        }
 
586
                        else
 
587
                        {
 
588
                                window[index].mer = rev;
 
589
                                window[index].value = rev_val;
 
590
                                window[index].dir = -1;
 
591
                                window[index].loc = i;
 
592
                        }
 
593
                        if (window[index].value < abs_min.value)
 
594
                        {
 
595
                                abs_min = window[index];
 
596
                                abs_min_index = index;
 
597
                        }
 
598
                }
 
599
 
 
600
                // Now, return the minimizer we found (it will be the first minimizer for the list)
 
601
                *next_minimizer = abs_min;
 
602
 
 
603
                return 1;
 
604
        }
 
605
 
 
606
        // Otherwise, we can just continue on from the current position of i.
 
607
        for ( ; i < end; i++)
 
608
        {
 
609
                index = i%WINDOW_SIZE;
 
610
 
 
611
                // First, add the new k-mer to the window, evicting the k-mer that is
 
612
                // no longer in the window
 
613
                mer = get_kmer(all_seqs[seq_num], i);
 
614
                rev = rev_comp_mer(mer);
 
615
                mer_val = MER_VALUE(mer);
 
616
                rev_val = MER_VALUE(rev);
 
617
 
 
618
                if (mer_val < rev_val)
 
619
                {
 
620
                        window[index].mer = mer;
 
621
                        window[index].value = mer_val;
 
622
                        window[index].dir = 1;
 
623
                        window[index].loc = i;
 
624
                }
 
625
                else
 
626
                {
 
627
                        window[index].mer = rev;
 
628
                        window[index].value = rev_val;
 
629
                        window[index].dir = -1;
 
630
                        window[index].loc = i;
 
631
                }
 
632
 
 
633
                // Now, check if the new k-mer is better than the current absolute minimizer.
 
634
                if (window[index].value < abs_min.value)
 
635
                {
 
636
                        // If so, set it as the new absolute minimizer and add this sequence to the mer table
 
637
                        abs_min = window[index];
 
638
                        abs_min_index = index;
 
639
                        *next_minimizer = abs_min;
 
640
                        i++;  // Increment i so we won't process this k-mer again.
 
641
                        return 1;
 
642
                }
 
643
                // Now, check if the current absolute minimizer is out of the window
 
644
                // We just replaced index, so if abs_min_index == index, we just evicted
 
645
                // the current minimizer.
 
646
                else if (abs_min_index == index)
 
647
                {
 
648
                        // Find the new minimizer
 
649
                        // If runtime starts to suffer I can implement something better than a linear search,
 
650
                        // but because WINDOW_SIZE is a small constant (around 20) it should be OK.
 
651
                        int j;
 
652
                        abs_min.value = ULONG_MAX;
 
653
                        abs_min.dir = 0;
 
654
                        for (j = 0; j < WINDOW_SIZE; j++)
 
655
                        {
 
656
                                if (window[j].value < abs_min.value)
 
657
                                {
 
658
                                        abs_min = window[j];
 
659
                                        abs_min_index = j;
 
660
                                }
 
661
                        }
 
662
                        // Add the new current minimizer to the mer table.
 
663
                        *next_minimizer = abs_min;
 
664
                        i++;   // Increment i so we won't process this k-mer again.
 
665
                        return 1;
 
666
                }
 
667
        }
 
668
 
 
669
        // We made it to the end of the sequence without finding a new minimizer, so we are done.
 
670
        return 0;
 
671
}
 
672
 
 
673
mer_t get_kmer(struct cseq *c, int curr)
 
674
{
 
675
        // Which mer does this kmer start in? 
 
676
        int which_mer = curr/8;
 
677
        int which_base = curr%8;
 
678
        unsigned short curr_mer = 0;
 
679
        mer_t mer = 0;
 
680
 
 
681
        int bases_left = k;
 
682
 
 
683
        // Start from the first base and push k bases.
 
684
        while (bases_left > 0)
 
685
        {
 
686
                // We can fit the rest of this short inside mer, so do it.
 
687
                if ((bases_left >= 8) || (bases_left > (8-which_base)))
 
688
                {
 
689
                        // Mask out everything before which_base
 
690
                        curr_mer = c->data[which_mer] & short_masks[which_base];
 
691
 
 
692
                        // Push mer so that there is enough space for curr_mer
 
693
                        mer = mer << ( (8-which_base)*2 );
 
694
 
 
695
                        // Add curr_mer onto mer.
 
696
                        mer = mer | (mer_t) curr_mer;
 
697
 
 
698
                        bases_left -= (8 - which_base);
 
699
                        which_mer++;
 
700
                        which_base = 0;
 
701
                }
 
702
                // Now we're down to the last few bases and we need to handle overflow.
 
703
                else
 
704
                {
 
705
                        // The bases in this short will be enough
 
706
 
 
707
                        // Make enough room for the rest of the bases
 
708
                        mer = mer << bases_left*2;
 
709
 
 
710
                        // Shift the curr mer to the end and mask it out.
 
711
                        curr_mer = c->data[which_mer];
 
712
 
 
713
                        int mercount = c->num_bases/8;
 
714
                        if (c->num_bases%8 > 0) { mercount++; }
 
715
 
 
716
                        if ((mercount-1) == which_mer) { curr_mer = curr_mer << ((8-(c->num_bases - (8*which_mer)))*2); }
 
717
                        curr_mer = (curr_mer >> ((8 - (bases_left+which_base))*2 )) & short_masks[8-bases_left];
 
718
 
 
719
                        // Now add it on to mer.
 
720
                        mer = mer | curr_mer;
 
721
 
 
722
                        bases_left = 0;
 
723
                }
 
724
        }
 
725
        return mer;
 
726
}
 
727
 
 
728
void print_8mer(unsigned short mer)
 
729
{
 
730
        char str[9];
 
731
        int i;
 
732
        for (i=0; i<8; i++)
 
733
        {
 
734
                str[i] = num_to_base((mer >> ((8-1)-i)*2) & 3);
 
735
        }
 
736
        str[8] = '\0';
 
737
 
 
738
        printf("%s\n", str);
 
739
}
 
740
 
 
741
void translate_kmer(mer_t mer, char * str, int length)
 
742
{
 
743
        //print_mer(stderr, mer);
 
744
        int i;
 
745
 
 
746
        //int int_len = sizeof(mer_t)*8;
 
747
 
 
748
        // 2 bits represent each base. So, to get the first base, we the
 
749
        // two most significant bits. To get the second base, the two second
 
750
        // most significant bits, etc. In other, we need to bit shift all but
 
751
        // 2 (aka bitshift 14 to the right) when i = 0, bitshift 12 when i=1,
 
752
        // etc.
 
753
        // We mask by 3 to make sure we only have the two numbers and nothing
 
754
        // but 0's in the rest.
 
755
        for (i=0; i<length; i++)
 
756
        {
 
757
                str[i] = num_to_base((mer >> ((length-1)-i)*2) & 3);
 
758
        }
 
759
        str[length] = '\0';
 
760
}
 
761
 
 
762
 
 
763
void add_sequence_to_mer(mer_t mer, int seq_num, char dir, short loc)
 
764
{
 
765
        // Store the sequence and its reverse complement as the same key.
 
766
 
 
767
        if (repeat_mer_table && itable_lookup(repeat_mer_table, mer)) return;
 
768
 
 
769
        mer_list_element * mle, * new_mle;
 
770
 
 
771
        // This will create it if it doesn't exist.
 
772
        mer_hash_element * mhe = get_mer_hash_element(mer);
 
773
 
 
774
        // Check that the list exists.
 
775
        if (!mhe->mle)
 
776
        {
 
777
                // If not, create it, increment the count and we're done.
 
778
                new_mle = create_mer_list_element(seq_num, dir, loc);
 
779
                mhe->mle = new_mle;
 
780
                mhe->count++;
 
781
                return;
 
782
        }
 
783
 
 
784
        // If a list does exist, add this sequence it.
 
785
 
 
786
        mle = mhe->mle;
 
787
 
 
788
        // Because we add one sequence at a time, this will be at the front
 
789
        // if it has ever had this mer before, so we don't add it twice.
 
790
        if (mle->seq_num == seq_num) return;
 
791
 
 
792
        new_mle = create_mer_list_element(seq_num, dir, loc);
 
793
        new_mle->next = mle;
 
794
        mhe->mle = new_mle;
 
795
        mhe->count++;
 
796
        
 
797
}
 
798
 
 
799
mer_list_element * create_mer_list_element(int seq_num, char dir, short loc)
 
800
{
 
801
        mer_list_element * new_mle = malloc(sizeof(*new_mle));
 
802
        new_mle->seq_num = seq_num;
 
803
        new_mle->dir = dir;
 
804
        new_mle->loc = loc;
 
805
        new_mle->next = 0;
 
806
 
 
807
        return new_mle;
 
808
}
 
809
 
 
810
mer_hash_element * get_mer_hash_element(mer_t mer)
 
811
{
 
812
        int bucket = mer % MER_TABLE_BUCKETS;
 
813
        mer_hash_element * mhe;
 
814
 
 
815
        // If there are no hash elements in this bucket
 
816
        // Add a new one.
 
817
        if (!mer_table[bucket])
 
818
        {
 
819
                mhe = malloc(sizeof(*mhe));
 
820
                mhe->mer = mer;
 
821
                mhe->count = 0;
 
822
                mhe->mle = 0;
 
823
                mhe->next = 0;
 
824
                mer_table[bucket] = mhe;
 
825
                return mhe;
 
826
        }
 
827
 
 
828
        mhe = find_mer(mer);
 
829
 
 
830
        // If this bucket is not empty, but does not contain this mer, add it.
 
831
        if (!mhe) {
 
832
                mer_hash_element * new_mhe = malloc(sizeof(*new_mhe));
 
833
                new_mhe->mer = mer;
 
834
                new_mhe->count = 0;
 
835
                new_mhe->mle = 0;
 
836
                new_mhe->next = mer_table[bucket];
 
837
                mer_table[bucket] = new_mhe;
 
838
                return new_mhe;
 
839
        } else {
 
840
                return mhe;
 
841
        }
 
842
}
 
843
 
 
844
mer_hash_element * find_mer(mer_t mer)
 
845
{
 
846
        int bucket = mer % MER_TABLE_BUCKETS;
 
847
 
 
848
        mer_hash_element * mhe = mer_table[bucket];
 
849
 
 
850
        while (mhe)
 
851
        {
 
852
                if (mhe->mer == mer) { return mhe; }
 
853
                mhe = mhe->next;
 
854
        }
 
855
 
 
856
        return 0;
 
857
}
 
858
 
 
859
void free_mer_table()
 
860
{
 
861
        int curr_mhe = 0;
 
862
 
 
863
        for (; curr_mhe < MER_TABLE_BUCKETS; curr_mhe++)
 
864
        {
 
865
                free_mer_hash_element(mer_table[curr_mhe]);
 
866
        }
 
867
}
 
868
 
 
869
void free_mer_hash_element(mer_hash_element * mhe)
 
870
{
 
871
        if (!mhe) return;
 
872
 
 
873
        free_mer_list_element(mhe->mle);
 
874
        mer_hash_element * n = mhe->next;
 
875
        free(mhe);
 
876
        free_mer_hash_element(n);
 
877
}
 
878
 
 
879
void free_mer_list_element(mer_list_element * mle)
 
880
{
 
881
        if (!mle) return;
 
882
 
 
883
        mer_list_element * n = mle->next;
 
884
        free(mle);
 
885
        free_mer_list_element(n);
 
886
}
 
887
 
 
888
void set_k(int new_k)
 
889
{
 
890
        k = new_k;
 
891
        set_k_mask();
 
892
}
 
893
 
 
894
void set_window_size(int new_size)
 
895
{
 
896
        WINDOW_SIZE = new_size;
 
897
}
 
898
 
 
899
void set_k_mask()
 
900
{
 
901
        int i;
 
902
 
 
903
        k_mask = 0;
 
904
        for (i=0; i<k; i++)
 
905
        {
 
906
                // Push it over two bits and or by binary 11
 
907
                // This amounts to pushing two 1's onto the right side.
 
908
                k_mask = (k_mask << 2) | 3;
 
909
        }
 
910
}
 
911
 
 
912
void load_mer_table()
 
913
{
 
914
        int curr_col, end_col, curr_row, end_row;
 
915
        curr_col = curr_rect_x*rectangle_size;
 
916
        end_col = curr_col+rectangle_size;
 
917
        if (end_col > num_seqs) { end_col = num_seqs; }
 
918
 
 
919
        curr_row = curr_rect_y*rectangle_size;
 
920
        end_row = curr_row+rectangle_size;
 
921
        if (end_row > num_seqs) { end_row = num_seqs; }
 
922
 
 
923
        load_mer_table_subset(curr_col, end_col, curr_row, end_row, (curr_rect_x == curr_rect_y));
 
924
}
 
925
 
 
926
void load_mer_table_subset(int curr_col, int end_col, int curr_row, int end_row, int is_same_rect)
 
927
{
 
928
 
 
929
        mer_t repeat_mask_rev;
 
930
 
 
931
        if (k_mask == 0) { set_k_mask(); }
 
932
        repeat_mask_rev = rev_comp_mer(repeat_mask);
 
933
        if (MER_VALUE(repeat_mask_rev) < MER_VALUE(repeat_mask)) repeat_mask = repeat_mask_rev;
 
934
 
 
935
        start_x = curr_col;
 
936
        end_x = end_col;
 
937
        start_y = curr_row;
 
938
        end_y = end_row;
 
939
        same_rect = is_same_rect;
 
940
 
 
941
        // This is an imaginary matrix, but we're loading all the sequences
 
942
        // on a given rectangle, defined by curr_rect_x, curr_rect_y and rectangle_size.
 
943
        // Load the mers in each of these sequences, then we'll output any matches.
 
944
 
 
945
        for ( ; curr_col < end_col; curr_col++ )
 
946
        {
 
947
                find_minimizers(curr_col);
 
948
        }
 
949
 
 
950
        // If we are on the diagonal, don't need to add both, because they are the same.
 
951
        if (is_same_rect) { return; }
 
952
 
 
953
        for ( ; curr_row < end_row; curr_row++ )
 
954
        {
 
955
                find_minimizers(curr_row);
 
956
        }
 
957
}
 
958
 
 
959
cand_list_element * create_new_cle(int seq1, int seq2, int dir, int loc1, int loc2)
 
960
{
 
961
        cand_list_element * new_cle = malloc(sizeof(*new_cle));
 
962
        if (seq1 < seq2)
 
963
        {
 
964
                new_cle->cand1 = seq1;
 
965
                new_cle->cand2 = seq2;
 
966
                new_cle->loc1 = loc1;
 
967
                new_cle->loc2 = loc2;
 
968
        }
 
969
        else
 
970
        {
 
971
                new_cle->cand2 = seq1;
 
972
                new_cle->cand1 = seq2;
 
973
                new_cle->loc2 = loc1;
 
974
                new_cle->loc1 = loc2;
 
975
        }
 
976
        new_cle->dir = dir;
 
977
        new_cle->next = 0;
 
978
        new_cle->count = 1;
 
979
 
 
980
        return new_cle;
 
981
}
 
982
 
 
983
int should_compare_cands(int c1, int c2)
 
984
{
 
985
        // If the two rectangles are equal, then we are intended to compare
 
986
        // two from the same rectangle, so return 1.
 
987
        if (same_rect) { return 1; }
 
988
 
 
989
        // Otherwise, return false if they are in the same rectangle,
 
990
        // true otherwise.
 
991
        if (in_range(c1, start_x, end_x) && in_range(c2, start_x, end_x)) {  return 0; }
 
992
        if (in_range(c1, start_y, end_y) && in_range(c2, start_y, end_y)) { return 0; }
 
993
 
 
994
        return 1;
 
995
}
 
996
 
 
997
void add_candidate(int seq, int cand, char dir, mer_t min, short loc1, short loc2)
 
998
{
 
999
        // Unless this is a diagonal, ones from the same block have already been compared.
 
1000
        // If I don't do this step, then ones from the same block on the same axis
 
1001
        // could get compared, because we don't really distinguish them.
 
1002
 
 
1003
        if (!should_compare_cands(seq, cand)) return;
 
1004
 
 
1005
        int index = (seq*cand*499);
 
1006
        if (index < 0) { index *= -1; }
 
1007
        index = index % CAND_TABLE_BUCKETS;
 
1008
 
 
1009
        cand_list_element * cle = candidates[index];
 
1010
        // There are no candidate pairs in this bucket
 
1011
        if (!cle)
 
1012
        {
 
1013
                candidates[index] = create_new_cle(seq, cand, dir, loc1, loc2);
 
1014
 
 
1015
                total_cand++;
 
1016
                return;
 
1017
        }
 
1018
 
 
1019
        // This bucket has candidate pairs, if ours is one of them just leave
 
1020
        // because we've already printed it out.
 
1021
        while (cle)
 
1022
        {
 
1023
                if ((cle->cand1 == seq) && (cle->cand2 == cand) && (cle->dir == dir))
 
1024
                {
 
1025
                        cle->count++;
 
1026
                        return;
 
1027
                }
 
1028
                else if ((cle->cand2 == seq) && (cle->cand1 == cand) && (cle->dir == dir))
 
1029
                {
 
1030
                        cle->count++;
 
1031
                        return;
 
1032
                }
 
1033
                cle = cle->next;
 
1034
        }
 
1035
 
 
1036
        // If we made it this far, we did not find this candidate pair, so add it.
 
1037
        cand_list_element * new_cle = create_new_cle(seq, cand, dir, loc1, loc2);
 
1038
        new_cle->next = candidates[index];
 
1039
        candidates[index] = new_cle;
 
1040
        total_cand++;
 
1041
        return;
 
1042
 
 
1043
}
 
1044
 
 
1045
void free_cand_table()
 
1046
{
 
1047
        int i;
 
1048
 
 
1049
        for (i = 0; i < CAND_TABLE_BUCKETS; i++)
 
1050
        {
 
1051
                free_cand_list_element(candidates[i]);
 
1052
                candidates[i] = 0;
 
1053
        }
 
1054
}
 
1055
 
 
1056
void free_cand_list_element(cand_list_element * cle)
 
1057
{
 
1058
        if (!cle) return;
 
1059
 
 
1060
        cand_list_element * n = cle->next;
 
1061
        free(cle);
 
1062
        free_cand_list_element(n);
 
1063
}
 
1064