source: tags/ms_r16q4/SL/SEQUENCE/AP_seq_dna.cxx

Last change on this file was 15176, checked in by westram, 8 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1#include "AP_seq_dna.hxx"
2
3#include <arb_mem.h>
4#include <AP_pro_a_nucs.hxx>
5#include <AP_filter.hxx>
6#include <ARB_Tree.hxx>
7
8
9inline bool hasGap(char c) { return c & AP_GAP; }
10inline bool isGap(char c)  { return c == AP_GAP; }
11
12inline bool notHasGap(char c) { return !hasGap(c); }
13inline bool notIsGap(char c)  { return !isGap(c); }
14
15// -------------------------------
16//      AP_sequence_parsimony
17
18char *AP_sequence_parsimony::table;
19
20AP_sequence_parsimony::AP_sequence_parsimony(const AliView *aliview)
21    : AP_sequence(aliview)
22    , seq_pars(NULL)
23{
24}
25
26AP_sequence_parsimony::~AP_sequence_parsimony() {
27    free(seq_pars);
28}
29
30AP_sequence *AP_sequence_parsimony::dup() const {
31    return new AP_sequence_parsimony(get_aliview());
32}
33
34void AP_sequence_parsimony::build_table()
35{
36    table = (char *)AP_create_dna_to_ap_bases();
37}
38
39
40
41/* --------------------------------------------------------------------------------
42 * combine(const AP_sequence *lefts, const AP_sequence *rights)
43 * set(char *isequence)
44 *
45 * for wagner & fitch parsimony algorithm
46 *
47 * Note: is_set_flag is used by AP_tree_nlen::parsimony_rek()
48 *       see ../../PARSIMONY/AP_tree_nlen.cxx@parsimony_rek
49*/
50
51// #define SHOW_SEQ
52
53void AP_sequence_parsimony::set(const char *isequence) {
54    size_t sequence_len = get_filter()->get_filtered_length();
55    ARB_alloc_aligned(seq_pars, sequence_len+1);
56    memset(seq_pars, AP_DOT, (size_t)sequence_len+1); // init with dots
57
58    const uchar *simplify = get_filter()->get_simplify_table();
59    if (!table) this->build_table();
60
61    const AP_filter *filt = get_filter();
62    if (filt->does_bootstrap()) {
63        size_t iseqlen = strlen(isequence);
64
65        for (size_t i = 0; i<sequence_len; ++i) {
66            size_t pos = filt->bootstrapped_seqpos(i); // random indices (but same for all species)
67
68            ap_assert(pos<iseqlen);
69            if (pos >= iseqlen) continue;
70
71            unsigned char c = (unsigned char)isequence[pos];
72
73#if defined(SHOW_SEQ)
74            fputc(simplify[c], stdout);
75#endif // SHOW_SEQ
76
77            seq_pars[i] = table[simplify[c]];
78        }
79    }
80    else {
81        const size_t* base_pos = filt->get_filterpos_2_seqpos();
82
83        for (size_t i = 0; i < sequence_len; ++i) {
84            size_t pos = base_pos[i];
85            unsigned char c = (unsigned char)isequence[pos];
86            seq_pars[i] = table[simplify[c]];
87
88#if defined(SHOW_SEQ)
89                fputc(simplify[c], stdout);
90#endif // SHOW_SEQ
91        }
92    }
93
94#if defined(SHOW_SEQ)
95    fputc('\n', stdout);
96#endif // SHOW_SEQ
97
98    mark_sequence_set(true);
99}
100
101void AP_sequence_parsimony::unset() {
102    freenull(seq_pars);
103    mark_sequence_set(false);
104}
105
106/** BELOW CODE CAREFULLY DESIGNED TO ALLOW VECTORIZATION
107 *
108 * If you mess with it, use "-fopt-info" or "-ftree-vectorizer-verbose=n".
109 * Make sure you still see "LOOP VECTORIZED" in the output!
110 */
111
112template <class COUNT, class SITE>
113static long do_combine(size_t sequence_len,
114                       const char * __restrict p1,
115                       const char * __restrict p2,
116                       char * __restrict p,
117                       COUNT count,
118                       SITE site) {
119
120    for (size_t idx = 0; idx<sequence_len; ++idx) { // LOOP_VECTORIZED=4 (ok, do_combine is used 4 times)
121        char c1 = p1[idx];
122        char c2 = p2[idx];
123
124        char c = c1 & c2;
125        p[idx] = (c==0)?c1|c2:c;
126
127        count.add(idx, c);
128        site.add(idx, c);
129    }
130
131    return count.sum;
132}
133
134struct count_unweighted {
135    long sum;
136    count_unweighted():sum(0){}
137    void add(size_t, char c) {
138        sum += !c;
139    }
140};
141
142struct count_weighted {
143    long sum;
144    const GB_UINT4* weights;
145    count_weighted(const GB_UINT4* w):sum(0), weights(w){}
146    void add(size_t idx, char c) {
147        sum += !c * weights[idx];
148    }
149};
150
151struct count_nothing {
152    void add(size_t, char) {}
153};
154
155struct count_mutpsite {
156    char * sites;
157    count_mutpsite(char *s):sites(s){}
158    void add(size_t idx, char c) {
159        // below code is equal to "if (!c) ++sites[idx]", the difference
160        // is that no branch is required and sites[idx] is always
161        // written, allowing vectorization.
162        //
163        // For unknown reasons gcc 4.8.1, 4.9.2 and 5.1.0
164        // refuses to vectorize 'c==0?1:0' or '!c'
165
166        sites[idx] += ((c | -c) >> 7 & 1) ^ 1;
167    }
168};
169
170AP_FLOAT AP_sequence_parsimony::combine(const AP_sequence * lefts,
171                                        const AP_sequence * rights,
172                                        char *mutation_per_site) {
173    const AP_sequence_parsimony *left = (const AP_sequence_parsimony *)lefts;
174    const AP_sequence_parsimony *right = (const AP_sequence_parsimony *)rights;
175
176     size_t sequence_len = get_sequence_length();
177    if (seq_pars == NULL) {
178        ARB_alloc_aligned(seq_pars, sequence_len + 1);
179    }
180
181    const char * p1       = left->get_sequence();
182    const char * p2       = right->get_sequence();
183    long        result   = 0;
184
185    if (get_weights()->is_unweighted()) {
186        if (mutation_per_site) {
187            result = do_combine(sequence_len, p1, p2, seq_pars,
188                                count_unweighted(), count_mutpsite(mutation_per_site));
189
190        }
191        else {
192            result = do_combine(sequence_len, p1, p2, seq_pars,
193                                count_unweighted(), count_nothing());
194        }
195    }
196    else {
197        if (mutation_per_site) {
198            result = do_combine(sequence_len, p1, p2, seq_pars,
199                                count_weighted(get_weights()->get_weights()),
200                                count_mutpsite(mutation_per_site));
201        }
202        else {
203            result = do_combine(sequence_len, p1, p2, seq_pars,
204                                count_weighted(get_weights()->get_weights()),
205                                count_nothing());
206        }
207    }
208
209#if defined(DEBUG) && 0
210#define P1 75
211#define P2 90
212    printf("Seq1: ");
213    for (long idx = P1; idx <= P2; ++idx) printf("%3i ", p1[idx]);
214    printf("\nSeq2: ");
215    for (long idx = P1; idx <= P2; ++idx) printf("%3i ", p2[idx]);
216    printf("\nCombine value: %f\n", float(result));
217#undef P1
218#undef P2
219#endif // DEBUG
220
221    inc_combine_count();
222    mark_sequence_set(true);
223
224    ap_assert(result >= 0.0);
225    return (AP_FLOAT)result;
226}
227
228void AP_sequence_parsimony::partial_match(const AP_sequence* part_, long *overlapPtr, long *penaltyPtr) const {
229    // matches the partial sequences 'part_' against 'this'
230    // '*penaltyPtr' is set to the number of mismatches (possibly weighted)
231    // '*overlapPtr' is set to the number of base positions both sequences overlap
232    //          example:
233    //          fullseq      'XXX---XXX'        'XXX---XXX'
234    //          partialseq   '-XX---XX-'        '---XXX---'
235    //          overlap       7                  3
236    //
237    // algorithm is similar to AP_sequence_parsimony::combine()
238    // Note: changes done here should also be be applied to AP_seq_protein.cxx@partial_match_impl
239
240    const AP_sequence_parsimony *part = (const AP_sequence_parsimony *)part_;
241
242    const char *pf = get_sequence();
243    const char *pp = part->get_sequence();
244
245    const AP_weights *weights = get_weights();
246
247    long min_end; // minimum of both last non-gap positions
248    for (min_end = get_sequence_length()-1; min_end >= 0; --min_end) {
249        char both = pf[min_end]|pp[min_end];
250        if (notHasGap(both)) { // last non-gap found
251            if (notHasGap(pf[min_end])) { // occurred in full sequence
252                for (; min_end >= 0; --min_end) { // search same in partial sequence
253                    if (notHasGap(pp[min_end])) break;
254                }
255            }
256            else {
257                ap_assert(notHasGap(pp[min_end])); // occurred in partial sequence
258                for (; min_end >= 0; --min_end) { // search same in full sequence
259                    if (notHasGap(pf[min_end])) break;
260                }
261            }
262            break;
263        }
264    }
265
266    long penalty = 0;
267    long overlap = 0;
268
269    if (min_end >= 0) {
270        long max_start; // maximum of both first non-gap positions
271        for (max_start = 0; max_start <= min_end; ++max_start) {
272            char both = pf[max_start]|pp[max_start];
273            if (notHasGap(both)) { // first non-gap found
274                if (notHasGap(pf[max_start])) { // occurred in full sequence
275                    for (; max_start <= min_end; ++max_start) { // search same in partial
276                        if (notHasGap(pp[max_start])) break;
277                    }
278                }
279                else {
280                    ap_assert(notHasGap(pp[max_start])); // occurred in partial sequence
281                    for (; max_start <= min_end; ++max_start) { // search same in full
282                        if (notHasGap(pf[max_start])) break;
283                    }
284                }
285                break;
286            }
287        }
288
289        if (max_start <= min_end) { // if sequences overlap
290            for (long idx = max_start; idx <= min_end; ++idx) {
291                if ((pf[idx]&pp[idx]) == 0) { // bases are distinct (aka mismatch)
292                    penalty += weights->weight(idx);
293                }
294            }
295            overlap = min_end-max_start+1;
296        }
297    }
298
299    *overlapPtr = overlap;
300    *penaltyPtr = penalty;
301}
302
303AP_FLOAT AP_sequence_parsimony::count_weighted_bases() const {
304    static char *hits = 0;
305    if (!hits) {
306        ARB_alloc(hits, 256);
307        memset(hits, 1, 256); // count ambiguous characters half
308
309        hits[AP_A] = 2; // count real characters full
310        hits[AP_C] = 2;
311        hits[AP_G] = 2;
312        hits[AP_T] = 2;
313
314        hits[AP_GAP] = 0; // don't count gaps
315        hits[AP_DOT] = 0; // don't count dots (and other stuff)
316    }
317
318    const AP_weights *weights = get_weights();
319    const  char      *p       = get_sequence();
320
321    long   sum          = 0;
322    size_t sequence_len = get_sequence_length();
323
324    for (size_t i = 0; i<sequence_len; ++i) {
325        sum += hits[safeCharIndex(p[i])] * weights->weight(i);
326    }
327
328    AP_FLOAT wcount = sum * 0.5;
329    return wcount;
330}
331
332uint32_t AP_sequence_parsimony::checksum() const {
333    const char *seq = get_sequence();
334    return GB_checksum(seq, sizeof(*seq)*get_sequence_length(), 0, NULL);
335}
336
337bool AP_sequence_parsimony::equals(const AP_sequence_parsimony *other) const {
338    const char *seq  = get_sequence();
339    const char *oseq = other->get_sequence();
340
341    size_t len = get_sequence_length();
342    for (size_t p = 0; p<len; ++p) {
343        if (seq[p] != oseq[p]) return false;
344    }
345    return true;
346}
347
Note: See TracBrowser for help on using the repository browser.