source: tags/arb_5.2/AWTC/AWTC_constructSequence.cxx

Last change on this file was 5885, checked in by westram, 15 years ago
  • moved fast-aligner to separate library
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.4 KB
Line 
1/*********************************************************************************
2 *  Coded by Ralf Westram (coder@reallysoft.de) in 1998                          *
3 *  Institute of Microbiology (Technical University Munich)                      *
4 *  http://www.mikro.biologie.tu-muenchen.de/                                    *
5 *********************************************************************************/
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <memory.h>
10#include <ctype.h>
11#include <string.h>
12// #include <sys/time.h>
13#include <time.h> // SuSE 7.3
14
15#include <arbdb.h>
16#include <arbdbt.h>
17#include <aw_root.hxx>
18#include <aw_window.hxx>
19
20// #include "awtc_fast_aligner.hxx"
21#include "awtc_seq_search.hxx"
22#include "awtc_constructSequence.hxx"
23
24#define SAME_SEQUENCE (-1),(-1)
25
26static inline int min(int i1, int i2)           {return i1<i2 ? i1 : i2;}
27
28static inline int basesMatch(char c1, char c2)
29{
30    return toupper(c1)==toupper(c2);
31}
32static inline int inversBasesMatch(char c1, char c2)
33{
34    c1 = toupper(c1);
35    c2 = toupper(c2);
36
37    switch (c1) {
38        case 'A': return c2=='T' || c2=='U';
39        case 'C': return c2=='G';
40        case 'G': return c2=='C';
41        case 'T':
42        case 'U': return c2=='A';
43        case 'N': return 1;
44        default: awtc_assert(0);
45    }
46
47    return c1==c2;
48}
49
50static inline char *strndup(const char *seq, int length) {
51    char *neu = new char[length+1];
52
53    memcpy(neu, seq, length);
54    neu[length] = 0;
55
56    return neu;
57}
58static inline const char *lstr(const char *s, int len) {
59    static char *lstr_ss = 0;
60
61    freeset(lstr_ss, strndup(s,len));
62    return lstr_ss;
63}
64#ifdef DEBUG
65static inline void dumpPart(int num, const AWTC_CompactedSubSequence *comp)
66{
67    printf("[%02i] ",num);
68
69#define SHOWLEN 40
70
71    const char *text = comp->text();
72    int len = comp->length();
73
74    awtc_assert(len);
75
76    if (len<=SHOWLEN)
77    {
78        printf("'%s'\n", lstr(text,len));
79    }
80    else
81    {
82        printf("'%s...", lstr(text, SHOWLEN));
83        printf("%s'\n", lstr(text+len-SHOWLEN, SHOWLEN));
84    }
85}
86#else
87static inline void dumpPart(int, const AWTC_CompactedSubSequence *) {}
88#endif
89
90
91#ifdef DEBUG
92# define TEST_UNIQUE_SET
93#endif
94#define UNIQUE_VALUE (-123)
95
96// ---------
97// class Way
98// ---------
99
100class Way
101{
102    int *my_way;        // 1..n for normal parts -1..-n for reverse parts
103    int my_length;
104    int my_score;
105    int my_maxlength;
106
107public:
108
109    Way(int maxlength) : my_length(0), my_score(0), my_maxlength(maxlength) {my_way = new int[maxlength];}
110    ~Way()                                  {delete [] my_way;}
111
112    Way(const Way& w)
113    {
114        my_maxlength    = w.my_maxlength;
115        my_length   = w.my_length;
116        my_score    = w.my_score;
117
118        my_way      = new int[my_maxlength];
119
120        memcpy(my_way, w.my_way, sizeof(my_way[0])*my_length);
121    }
122
123    Way& operator=(const Way& w)
124    {
125        if (&w!=this)
126        {
127            if (my_maxlength<w.my_maxlength)
128            {
129                delete [] my_way;
130                my_way = new int[w.my_maxlength];
131            }
132
133            my_maxlength    = w.my_maxlength;
134            my_length       = w.my_length;
135            my_score        = w.my_score;
136
137            memcpy(my_way, w.my_way, sizeof(my_way[0])*my_length);
138        }
139
140        return *this;
141    }
142
143    void add(int partNum, int reverse, int Score) {
144        awtc_assert(my_length<my_maxlength);
145        partNum++;  // recode cause partNum==0 cannot be negative
146        my_way[my_length++] = reverse ? -partNum : partNum;
147        my_score += Score;
148    }
149    void shorten(int Score) {
150        my_length--;
151        my_score -= Score;
152    }
153
154    int score() const       {return my_score; /*my_length ? my_score/my_length : 0;*/}
155    int length() const      {return my_length;}
156    int way(int num, int& reverse) const {reverse = my_way[num]<0; return abs(my_way[num])-1;}
157
158    void dump() const {
159        int l;
160
161        printf("Way my_length=%2i my_score=%5i score()=%5i:", my_length, my_score, score());
162
163        for (l=0; l<my_length; l++) {
164            int reverse;
165            int partNum = way(l, reverse);
166            printf(" %3i%c", partNum, reverse ? 'r' : ' ');
167        }
168
169        printf("\n");
170    }
171};
172
173// -------------
174// class Overlap
175// -------------
176
177class Overlap           // matrix which stores overlap data
178{
179    int parts;          // no of parts
180    int *ol;            // how much the both sequence parts overlap
181    int *sc;            // which score we calculated for this overlap
182
183    int offset(int f,int fReverse, int t, int tReverse) const
184    {
185        int off = parts*2 * (t*2 + tReverse)  +  (f*2 + fReverse);
186        return off;
187    }
188
189    void findWayFrom(Way *w, Way *best, int partNum, int reverse, int *used, int minMatchingBases) const;
190
191public:
192
193    Overlap(int Parts)
194    {
195        parts = Parts;
196        int sizeq = parts*2*parts*2;
197        ol = new int[sizeq];
198        sc = new int[sizeq];
199
200#ifdef TEST_UNIQUE_SET
201        int off;
202        for (off=0; off<sizeq; off++)
203        {
204            ol[off] = UNIQUE_VALUE;
205            sc[off] = UNIQUE_VALUE;
206        }
207#endif
208    }
209
210    ~Overlap() { delete [] ol; delete [] sc; }
211
212    int overlap(int f, int fReverse, int t, int tReverse) const             {return ol[offset(f,fReverse,t,tReverse)];}
213    int score(int f, int fReverse, int t, int tReverse) const               {return sc[offset(f,fReverse,t,tReverse)];}
214
215    void set(int off, int theOverlap, int theScore)
216    {
217#ifdef TEST_UNIQUE_SET
218        awtc_assert(ol[off]==UNIQUE_VALUE);
219        awtc_assert(sc[off]==UNIQUE_VALUE);
220#endif
221        ol[off] = theOverlap;
222        sc[off] = theScore;
223    }
224    void set(int f,int fReverse, int t, int tReverse, int theOverlap, int theScore)     {set(offset(f,fReverse,t,tReverse), theOverlap, theScore);}
225
226    void setall(int f, int t, int theOverlap, int theScore)
227    {
228        int off = offset(f,0,t,0);
229
230        set(off,        theOverlap, theScore);
231        set(off+1,      theOverlap, theScore);
232        set(off+parts*2,    theOverlap, theScore);
233        set(off+parts*2+1,  theOverlap, theScore);
234    }
235
236    Way findWay(int minMatchingBases) const;
237    void dump() const;
238};
239
240void Overlap::findWayFrom(Way *w, Way *best, int partNum, int reverse, int *used, int minMatchingBases) const
241{
242    used[partNum] = reverse ? -1 : 1;
243
244    int l;
245
246    for (l=0; l<parts; l++)
247    {
248        if (!used[l])
249        {
250            int rev;
251
252            for (rev=0; rev<2; rev++)
253            {
254                int scoreForPartialWay = score(partNum, reverse, l, rev);
255
256                if (scoreForPartialWay>=minMatchingBases)
257                {
258                    w->add(l, rev, scoreForPartialWay);
259                    if (w->score() > best->score()) {
260                        *best = *w;
261                        printf("new best ");
262                        best->dump();
263                    }
264
265                    findWayFrom(w, best, l, rev, used, minMatchingBases);
266                    w->shorten(scoreForPartialWay);
267                }
268            }
269        }
270    }
271
272    used[partNum] = 0;
273}
274
275Way Overlap::findWay(int minMatchingBases) const
276{
277    int l;
278    int *used = new int[parts];
279    Way w(parts);
280    Way best(parts);
281
282    for (l=0; l<parts; l++) {
283        used[l] = 0;
284    }
285
286    for (l=0; l<parts; l++) {
287        int rev;
288        for (rev=0; rev<2; rev++) {
289            w.add(l,rev,0);
290            findWayFrom(&w, &best, l, rev, used, minMatchingBases);
291            w.shorten(0);
292        }
293    }
294
295    delete [] used;
296    return best;
297}
298
299void Overlap::dump() const
300{
301#ifdef DEBUG
302    printf("-------------------------------\n");
303    for (int y=-1; y<parts; y++) {
304        for (int yR=0; yR<2; yR++) {
305            for (int x=-1; x<parts; x++) {
306                for (int xR=0; xR<2; xR++) {
307                    if (x==-1 || y==-1) {
308                        if (!xR && !yR)     printf("%4i   ", x==-1 ? y : x);
309                        else        printf("       ");
310                    } else {
311                        printf("%3i|%-3i", overlap(x,xR,y,yR), score(x,xR,y,yR));
312                    }
313                }
314            }
315            printf("\n");
316        }
317    }
318    printf("-------------------------------\n");
319#endif
320}
321
322// ------------------------------------------------------------------------------------------------------------------------
323
324static inline int calcScore(int overlap, int mismatches)
325{
326    return overlap-2*mismatches;
327}
328void overlappingBases(AWTC_CompactedSubSequence *comp1, int reverse1, AWTC_CompactedSubSequence *comp2, int reverse2, int& bestOverlap, int& bestScore)
329{
330    int len = 1;
331    int maxcmp = min(comp1->length(), comp2->length());
332
333    bestOverlap = 0;
334    bestScore   = 0;
335
336    if (reverse1)
337    {
338        if (reverse2)   // both are reversed -> compare reverse start of comp1 with reverse end of comp2
339        {
340            const char *start1 = comp1->text();
341            const char *end2 = comp2->text(comp2->length());
342
343            while (len<=maxcmp)
344            {
345                int l;
346                int mismatches = 0;
347
348                for (l=0; l<len; l++) {
349                    if (!basesMatch(start1[-l], end2[-l])) {
350                        mismatches++;
351                    }
352                }
353
354                int score = calcScore(len, mismatches);
355                if (score>=bestScore) {
356                    bestOverlap = len;
357                    bestScore   = score;
358                }
359
360                len++;
361                start1++;
362            }
363        }
364        else    // comp1 is reversed -> compare reverse start of comp1 with start of comp2
365        {
366            const char *start1 = comp1->text();
367            const char *start2 = comp2->text();
368
369            while (len<=maxcmp)
370            {
371                int l;
372                int mismatches = 0;
373
374                for (l=0; l<len; l++) {
375                    if (!inversBasesMatch(start1[-l], start2[l])) {
376                        mismatches++;
377                    }
378                }
379
380                int score = calcScore(len, mismatches);
381                if (score>=bestScore) {
382                    bestOverlap = len;
383                    bestScore   = score;
384                }
385
386                len++;
387                start1++;
388            }
389        }
390    }
391    else if (reverse2)  // comp2 is reversed -> compare end of comp1 with reverse end of comp2
392    {
393        const char *end1 = comp1->text(comp1->length()-1);
394        const char *end2 = comp2->text(comp2->length()-1);
395
396        while (len<=maxcmp)
397        {
398            int l;
399            int mismatches = 0;
400
401            for (l=0; l<len; l++) {
402                if (!inversBasesMatch(end1[l],end2[-l])) {
403                    mismatches++;
404                }
405            }
406
407            int score = calcScore(len, mismatches);
408            if (score>=bestScore) {
409                bestOverlap = len;
410                bestScore   = score;
411            }
412
413            len++;
414            end1--;
415        }
416    }
417    else    // both normal -> compare end of comp1 whith start of comp2
418    {
419        const char *end1 = comp1->text(comp1->length()-1);
420        const char *start2 = comp2->text();
421
422        while (len<=maxcmp)
423        {
424            int l;
425            int mismatches = 0;
426
427            for (l=0; l<len; l++) {
428                if (!basesMatch(end1[l], start2[l])) {
429                    mismatches++;
430                }
431            }
432
433            int score = calcScore(len, mismatches);
434            if (score>=bestScore) {
435                bestOverlap = len;
436                bestScore   = score;
437            }
438
439            len++;
440            end1--;
441        }
442    }
443}
444
445typedef AWTC_CompactedSubSequence *AWTC_CompactedSubSequencePointer;
446
447char *AWTC_constructSequence(int parts, const char **seqs, int minMatchingBases, char **refSeq)
448{
449    Overlap lap(parts);
450    AWTC_CompactedSubSequencePointer *comp = new AWTC_CompactedSubSequencePointer[parts];
451
452    int s;
453    for (s=0; s<parts; s++) {
454        comp[s] = new AWTC_CompactedSubSequence(seqs[s], strlen(seqs[s]), "contructed by AWTC_constructSequence()");
455        if (comp[s]->length()==0) {
456            printf("AWTC_constructSequence called with empty sequence (seq #%i)\n", s);
457            return NULL;
458        }
459    }
460
461    for (s=0; s<parts; s++) {
462        dumpPart(s,comp[s]);
463        lap.setall(s,s,SAME_SEQUENCE);  // set diagonal entries to SAME_SEQUENCE (= "a sequence can't overlap with itself")
464        for (int s2=s+1; s2<parts; s2++) {
465            awtc_assert(s!=s2);
466            for (int sR=0; sR<2; sR++) {
467                for (int s2R=0; s2R<2; s2R++) {
468                    awtc_assert(s!=s2);
469                    int overlap;
470                    int score;
471
472                    overlappingBases(comp[s], sR, comp[s2], s2R, overlap, score);
473
474                    lap.set(s, sR, s2, s2R, overlap, score);
475                    lap.set(s2, !s2R, s, !sR, overlap, score);
476                }
477            }
478        }
479    }
480
481    lap.dump();
482
483    // find the best way through the array
484
485    Way w = lap.findWay(minMatchingBases);
486    w.dump();
487
488    // concatenate parts
489
490    int sequenceLength = 0;
491    for (s=0; s<w.length(); s++)    // calculate length
492    {
493        int rev2;
494        int part2 = w.way(s,rev2);
495
496        sequenceLength += comp[part2]->length();
497
498        if (s)
499        {
500            int rev1;
501            int part1 = w.way(s-1, rev1);
502
503            sequenceLength -= lap.overlap(part1, rev1, part2, rev2);
504        }
505    }
506
507    char *resultSeq = new char[sequenceLength+1];
508    *refSeq = new char[sequenceLength+1];
509    int off = 0;
510
511    for (s=0; s<w.length(); s++)    // construct sequence
512    {
513        int rev2;
514        int part2 = w.way(s,rev2);
515
516        sequenceLength += comp[part2]->length();
517
518        if (s)
519        {
520            int rev1;
521            int part1 = w.way(s-1, rev1);
522
523            sequenceLength -= lap.overlap(part1, rev1, part2, rev2);
524
525            // @@@@ hier fehlt noch fast alles
526
527        }
528    }
529
530    // frees
531
532    for (s=0; s<parts; s++) {
533        delete comp[s];
534    }
535    delete [] comp;
536
537    return NULL;
538}
539
540#ifdef DEBUG
541# define TEST_THIS_MODULE
542#endif
543
544#ifdef TEST_THIS_MODULE
545// typedef const char *cstr;
546// typedef char *str;
547
548#define PARTS           10
549#define OVERLAPPING_BASES   100
550
551static inline int startOf(int len, int partNum)
552{
553    awtc_assert(len>0);
554    awtc_assert(partNum>0);
555    int s = (len/PARTS)*partNum - GB_random(OVERLAPPING_BASES);
556    return s>0 ? (s<len ? s : len-1) : 0;
557}
558
559static inline int lengthOf(int start, int len)
560{
561    awtc_assert(len>0);
562    awtc_assert(start>=0);
563    int s = len/PARTS + GB_random(2*OVERLAPPING_BASES);
564    return s>0 ? ((start+s)<=len ? s : len-start) : 1;
565}
566
567char *AWTC_testConstructSequence(const char *testWithSequence)
568{
569    int basesInSeq = 0;
570    char *compressed = strdup(testWithSequence);
571
572    {
573        const char *s = testWithSequence;
574        while(*s)
575        {
576            if (*s!='-' && *s!='.')
577            {
578                compressed[basesInSeq++] = *s;
579            }
580            s++;
581        }
582    }
583
584    int    parts = PARTS;
585    char **part  = new char*[PARTS];
586    int    p;
587
588    printf("AWTC_testConstructSequence: len(=no of bases) = %5i\n", basesInSeq);
589
590    int last_end = -1;
591
592    for (p=0; p<parts; p++)
593    {
594        int start = p==0 ? 0 : last_end - (25+GB_random(75));
595
596        if (start<0)                start = 0;
597        else if (start>=basesInSeq) start = basesInSeq-1;
598
599        int llen = p<PARTS-1 ? GB_random(basesInSeq/parts+200) : basesInSeq-start;
600        if (start+llen > basesInSeq) llen = basesInSeq-start;
601
602        int end = start+llen-1;
603        awtc_assert(end<basesInSeq);
604
605        int overlap = last_end-start+1;
606        awtc_assert(overlap>0 || p==0);
607
608        int count = 0;
609        int l;
610        for (l=0; l<overlap; l++)
611        {
612            if (strchr("-.",compressed[last_end+l])==NULL)
613                count++;
614        }
615
616        printf("[%02i] start=%-5i llen=%-5i end=%-5i overlap=%-5i basesInOverlap=%-5i", p, start, llen, end, overlap, count);
617        last_end = end;
618        awtc_assert(start+llen<=basesInSeq);
619        part[p] = strndup(compressed+start, llen);
620        if (GB_random(2)) {
621            char     T_or_U;
622            GB_ERROR error = GBT_determine_T_or_U(GB_AT_RNA, &T_or_U, "reverse-complement");
623            if (error) aw_message(error);
624            GBT_reverseComplementNucSequence(part[p], llen, T_or_U);
625            printf(" (reverted)");
626        }
627        printf("\n");
628    }
629
630    for (p=0; p<parts; p++)
631    {
632        int   l;
633        int   llen = strlen(part[p]);
634        char *s    = part[p];
635
636        for (l=0; l<llen; l++)
637        {
638            if (s[l]!='-' && s[l]!='.')
639            {
640                break;
641            }
642        }
643
644        if (l==llen)    // seq is empty
645        {
646            int q;
647
648            for (q=p+1; q<parts; q++)
649            {
650                part[q-1] = part[q];
651            }
652            parts--;    // skip it
653            p--;
654        }
655
656        part[p] = s;
657    }
658
659    if (parts<PARTS) printf("deleted %i empty parts\n", PARTS-parts);
660
661    for (p=0; p<parts; p++) // insert some errors into sequences
662    {
663        int   changes = 0;
664        char *s       = part[p];
665
666        while (*s) {
667            if (strchr("-.", *s)==NULL) {
668                if (GB_frandom() < 0.05 ) { // error-probability
669                    *s = "ACGT"[GB_random(4)];
670                    changes++;
671                }
672            }
673            s++;
674        }
675        printf("[%02i] base-errors = %i\n", p, changes);
676    }
677
678    char *neu = AWTC_constructSequence(parts, (const char**)part, 10, NULL);
679
680    for (p=0; p<parts; p++) delete [] part[p];
681    delete [] part;
682
683    if (!neu) printf("AWTC_constructSequence() returned NULL\n");
684
685    return neu;
686}
687
688#endif
689/* TEST_THIS_MODULE */
690
Note: See TracBrowser for help on using the repository browser.