ba7e520e4be08450e63f262e892dbb8a41cfb007
[jalview.git] / src / jalview / analysis / AlignSeq.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.analysis;
22
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.AlignmentI;
25 import jalview.datamodel.Mapping;
26 import jalview.datamodel.Sequence;
27 import jalview.datamodel.SequenceI;
28 import jalview.schemes.ResidueProperties;
29 import jalview.schemes.ScoreMatrix;
30 import jalview.util.Comparison;
31 import jalview.util.Format;
32 import jalview.util.MapList;
33 import jalview.util.MessageManager;
34
35 import java.awt.Color;
36 import java.awt.Graphics;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.StringTokenizer;
41
42 /**
43  * 
44  * 
45  * @author $author$
46  * @version $Revision$
47  */
48 public class AlignSeq
49 {
50   public static final String PEP = "pep";
51
52   public static final String DNA = "dna";
53
54   static String[] dna =
55   { "A", "C", "G", "T", "-" };
56
57   // "C", "T", "A", "G", "-"};
58   static String[] pep =
59   { "A", "R", "N", "D", "C", "Q", "E", "G", "H", "I", "L", "K", "M", "F",
60       "P", "S", "T", "W", "Y", "V", "B", "Z", "X", "-" };
61
62   int[][] score;
63
64   int[][] E;
65
66   int[][] F;
67
68   int[][] traceback;
69
70   int[] seq1;
71
72   int[] seq2;
73
74   SequenceI s1;
75
76   SequenceI s2;
77
78   public String s1str;
79
80   public String s2str;
81
82   int maxi;
83
84   int maxj;
85
86   int[] aseq1;
87
88   int[] aseq2;
89
90   public String astr1 = "";
91
92   public String astr2 = "";
93
94   /** DOCUMENT ME!! */
95   public int seq1start;
96
97   /** DOCUMENT ME!! */
98   public int seq1end;
99
100   /** DOCUMENT ME!! */
101   public int seq2start;
102
103   /** DOCUMENT ME!! */
104   public int seq2end;
105
106   int count;
107
108   /** DOCUMENT ME!! */
109   public int maxscore;
110
111   float pid;
112
113   int prev = 0;
114
115   int gapOpen = 120;
116
117   int gapExtend = 20;
118
119   int[][] lookup = ResidueProperties.getBLOSUM62();
120
121   String[] intToStr = pep;
122
123   int defInt = 23;
124
125   StringBuffer output = new StringBuffer();
126
127   String type;
128
129   private int[] charToInt;
130
131   /**
132    * Creates a new AlignSeq object.
133    * 
134    * @param s1
135    *          DOCUMENT ME!
136    * @param s2
137    *          DOCUMENT ME!
138    * @param type
139    *          DOCUMENT ME!
140    */
141   public AlignSeq(SequenceI s1, SequenceI s2, String type)
142   {
143     SeqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(),
144             type);
145   }
146
147   /**
148    * Creates a new AlignSeq object.
149    * 
150    * @param s1
151    *          DOCUMENT ME!
152    * @param s2
153    *          DOCUMENT ME!
154    * @param type
155    *          DOCUMENT ME!
156    */
157   public AlignSeq(SequenceI s1, String string1, SequenceI s2,
158           String string2, String type)
159   {
160     SeqInit(s1, string1.toUpperCase(), s2, string2.toUpperCase(), type);
161   }
162
163   /**
164    * DOCUMENT ME!
165    * 
166    * @return DOCUMENT ME!
167    */
168   public int getMaxScore()
169   {
170     return maxscore;
171   }
172
173   /**
174    * DOCUMENT ME!
175    * 
176    * @return DOCUMENT ME!
177    */
178   public int getSeq2Start()
179   {
180     return seq2start;
181   }
182
183   /**
184    * DOCUMENT ME!
185    * 
186    * @return DOCUMENT ME!
187    */
188   public int getSeq2End()
189   {
190     return seq2end;
191   }
192
193   /**
194    * DOCUMENT ME!
195    * 
196    * @return DOCUMENT ME!
197    */
198   public int getSeq1Start()
199   {
200     return seq1start;
201   }
202
203   /**
204    * DOCUMENT ME!
205    * 
206    * @return DOCUMENT ME!
207    */
208   public int getSeq1End()
209   {
210     return seq1end;
211   }
212
213   /**
214    * DOCUMENT ME!
215    * 
216    * @return DOCUMENT ME!
217    */
218   public String getOutput()
219   {
220     return output.toString();
221   }
222
223   /**
224    * DOCUMENT ME!
225    * 
226    * @return DOCUMENT ME!
227    */
228   public String getAStr1()
229   {
230     return astr1;
231   }
232
233   /**
234    * DOCUMENT ME!
235    * 
236    * @return DOCUMENT ME!
237    */
238   public String getAStr2()
239   {
240     return astr2;
241   }
242
243   /**
244    * DOCUMENT ME!
245    * 
246    * @return DOCUMENT ME!
247    */
248   public int[] getASeq1()
249   {
250     return aseq1;
251   }
252
253   /**
254    * DOCUMENT ME!
255    * 
256    * @return DOCUMENT ME!
257    */
258   public int[] getASeq2()
259   {
260     return aseq2;
261   }
262
263   /**
264    * DOCUMENT ME!
265    * 
266    * @return DOCUMENT ME!
267    */
268   public SequenceI getS1()
269   {
270     return s1;
271   }
272
273   /**
274    * DOCUMENT ME!
275    * 
276    * @return DOCUMENT ME!
277    */
278   public SequenceI getS2()
279   {
280     return s2;
281   }
282
283   /**
284    * 
285    * @return aligned instance of Seq 1
286    */
287   public SequenceI getAlignedSeq1()
288   {
289     SequenceI alSeq1 = new Sequence(s1.getName(), getAStr1());
290     alSeq1.setStart(s1.getStart() + getSeq1Start() - 1);
291     alSeq1.setEnd(s1.getStart() + getSeq1End() - 1);
292     alSeq1.setDatasetSequence(s1.getDatasetSequence() == null ? s1 : s1
293             .getDatasetSequence());
294     return alSeq1;
295   }
296
297   /**
298    * 
299    * @return aligned instance of Seq 2
300    */
301   public SequenceI getAlignedSeq2()
302   {
303     SequenceI alSeq2 = new Sequence(s2.getName(), getAStr2());
304     alSeq2.setStart(s2.getStart() + getSeq2Start() - 1);
305     alSeq2.setEnd(s2.getStart() + getSeq2End() - 1);
306     alSeq2.setDatasetSequence(s2.getDatasetSequence() == null ? s2 : s2
307             .getDatasetSequence());
308     return alSeq2;
309   }
310
311   /**
312    * Construct score matrix for sequences with standard DNA or PEPTIDE matrix
313    * 
314    * @param s1
315    *          - sequence 1
316    * @param string1
317    *          - string to use for s1
318    * @param s2
319    *          - sequence 2
320    * @param string2
321    *          - string to use for s2
322    * @param type
323    *          DNA or PEPTIDE
324    */
325   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
326           String string2, String type)
327   {
328     this.s1 = s1;
329     this.s2 = s2;
330     setDefaultParams(type);
331     SeqInit(string1, string2);
332   }
333
334   /**
335    * Construct score matrix for sequences with custom substitution matrix
336    * 
337    * @param s1
338    *          - sequence 1
339    * @param string1
340    *          - string to use for s1
341    * @param s2
342    *          - sequence 2
343    * @param string2
344    *          - string to use for s2
345    * @param scoreMatrix
346    *          - substitution matrix to use for alignment
347    */
348   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
349           String string2, ScoreMatrix scoreMatrix)
350   {
351     this.s1 = s1;
352     this.s2 = s2;
353     setType(scoreMatrix.isDNA() ? AlignSeq.DNA : AlignSeq.PEP);
354     lookup = scoreMatrix.getMatrix();
355   }
356
357   /**
358    * construct score matrix for string1 and string2 (after removing any existing
359    * gaps
360    * 
361    * @param string1
362    * @param string2
363    */
364   private void SeqInit(String string1, String string2)
365   {
366     s1str = extractGaps(jalview.util.Comparison.GapChars, string1);
367     s2str = extractGaps(jalview.util.Comparison.GapChars, string2);
368
369     if (s1str.length() == 0 || s2str.length() == 0)
370     {
371       output.append("ALL GAPS: "
372               + (s1str.length() == 0 ? s1.getName() : " ")
373               + (s2str.length() == 0 ? s2.getName() : ""));
374       return;
375     }
376
377     // System.out.println("lookuip " + rt.freeMemory() + " "+ rt.totalMemory());
378     seq1 = new int[s1str.length()];
379
380     // System.out.println("seq1 " + rt.freeMemory() +" " + rt.totalMemory());
381     seq2 = new int[s2str.length()];
382
383     // System.out.println("seq2 " + rt.freeMemory() + " " + rt.totalMemory());
384     score = new int[s1str.length()][s2str.length()];
385
386     // System.out.println("score " + rt.freeMemory() + " " + rt.totalMemory());
387     E = new int[s1str.length()][s2str.length()];
388
389     // System.out.println("E " + rt.freeMemory() + " " + rt.totalMemory());
390     F = new int[s1str.length()][s2str.length()];
391     traceback = new int[s1str.length()][s2str.length()];
392
393     // System.out.println("F " + rt.freeMemory() + " " + rt.totalMemory());
394     seq1 = stringToInt(s1str, type);
395
396     // System.out.println("seq1 " + rt.freeMemory() + " " + rt.totalMemory());
397     seq2 = stringToInt(s2str, type);
398
399     // System.out.println("Seq2 " + rt.freeMemory() + " " + rt.totalMemory());
400     // long tstart = System.currentTimeMillis();
401     // calcScoreMatrix();
402     // long tend = System.currentTimeMillis();
403     // System.out.println("Time take to calculate score matrix = " +
404     // (tend-tstart) + " ms");
405     // printScoreMatrix(score);
406     // System.out.println();
407     // printScoreMatrix(traceback);
408     // System.out.println();
409     // printScoreMatrix(E);
410     // System.out.println();
411     // /printScoreMatrix(F);
412     // System.out.println();
413     // tstart = System.currentTimeMillis();
414     // traceAlignment();
415     // tend = System.currentTimeMillis();
416     // System.out.println("Time take to traceback alignment = " + (tend-tstart)
417     // + " ms");
418   }
419
420   private void setDefaultParams(String type)
421   {
422     setType(type);
423
424     if (type.equals(AlignSeq.PEP))
425     {
426       lookup = ResidueProperties.getDefaultPeptideMatrix();
427     }
428     else if (type.equals(AlignSeq.DNA))
429     {
430       lookup = ResidueProperties.getDefaultDnaMatrix();
431     }
432   }
433
434   private void setType(String type2)
435   {
436     this.type = type2;
437     if (type.equals(AlignSeq.PEP))
438     {
439       intToStr = pep;
440       charToInt = ResidueProperties.aaIndex;
441       defInt = ResidueProperties.maxProteinIndex;
442     }
443     else if (type.equals(AlignSeq.DNA))
444     {
445       intToStr = dna;
446       charToInt = ResidueProperties.nucleotideIndex;
447       defInt = ResidueProperties.maxNucleotideIndex;
448     }
449     else
450     {
451       output.append("Wrong type = dna or pep only");
452       throw new Error(MessageManager.formatMessage("error.unknown_type_dna_or_pep", new String[]{type2}));
453     }
454   }
455
456   /**
457    * DOCUMENT ME!
458    */
459   public void traceAlignment()
460   {
461     // Find the maximum score along the rhs or bottom row
462     int max = -9999;
463
464     for (int i = 0; i < seq1.length; i++)
465     {
466       if (score[i][seq2.length - 1] > max)
467       {
468         max = score[i][seq2.length - 1];
469         maxi = i;
470         maxj = seq2.length - 1;
471       }
472     }
473
474     for (int j = 0; j < seq2.length; j++)
475     {
476       if (score[seq1.length - 1][j] > max)
477       {
478         max = score[seq1.length - 1][j];
479         maxi = seq1.length - 1;
480         maxj = j;
481       }
482     }
483
484     // System.out.println(maxi + " " + maxj + " " + score[maxi][maxj]);
485     int i = maxi;
486     int j = maxj;
487     int trace;
488     maxscore = score[i][j] / 10;
489
490     seq1end = maxi + 1;
491     seq2end = maxj + 1;
492
493     aseq1 = new int[seq1.length + seq2.length];
494     aseq2 = new int[seq1.length + seq2.length];
495
496     count = (seq1.length + seq2.length) - 1;
497
498     while ((i > 0) && (j > 0))
499     {
500       if ((aseq1[count] != defInt) && (i >= 0))
501       {
502         aseq1[count] = seq1[i];
503         astr1 = s1str.charAt(i) + astr1;
504       }
505
506       if ((aseq2[count] != defInt) && (j > 0))
507       {
508         aseq2[count] = seq2[j];
509         astr2 = s2str.charAt(j) + astr2;
510       }
511
512       trace = findTrace(i, j);
513
514       if (trace == 0)
515       {
516         i--;
517         j--;
518       }
519       else if (trace == 1)
520       {
521         j--;
522         aseq1[count] = defInt;
523         astr1 = "-" + astr1.substring(1);
524       }
525       else if (trace == -1)
526       {
527         i--;
528         aseq2[count] = defInt;
529         astr2 = "-" + astr2.substring(1);
530       }
531
532       count--;
533     }
534
535     seq1start = i + 1;
536     seq2start = j + 1;
537
538     if (aseq1[count] != defInt)
539     {
540       aseq1[count] = seq1[i];
541       astr1 = s1str.charAt(i) + astr1;
542     }
543
544     if (aseq2[count] != defInt)
545     {
546       aseq2[count] = seq2[j];
547       astr2 = s2str.charAt(j) + astr2;
548     }
549   }
550
551   /**
552    * DOCUMENT ME!
553    */
554   public void printAlignment(java.io.PrintStream os)
555   {
556     // TODO: Use original sequence characters rather than re-translated
557     // characters in output
558     // Find the biggest id length for formatting purposes
559     String s1id = s1.getName(), s2id = s2.getName();
560     int maxid = s1.getName().length();
561     if (s2.getName().length() > maxid)
562     {
563       maxid = s2.getName().length();
564     }
565     if (maxid > 30)
566     {
567       maxid = 30;
568       // JAL-527 - truncate the sequence ids
569       if (s1.getName().length() > maxid)
570       {
571         s1id = s1.getName().substring(0, 30);
572       }
573       if (s2.getName().length() > maxid)
574       {
575         s2id = s2.getName().substring(0, 30);
576       }
577     }
578     int len = 72 - maxid - 1;
579     int nochunks = ((aseq1.length - count) / len) + 1;
580     pid = 0;
581
582     output.append("Score = " + score[maxi][maxj] + "\n");
583     output.append("Length of alignment = " + (aseq1.length - count) + "\n");
584     output.append("Sequence ");
585     output.append(new Format("%" + maxid + "s").form(s1.getName()));
586     output.append(" :  " + s1.getStart() + " - " + s1.getEnd()
587             + " (Sequence length = " + s1str.length() + ")\n");
588     output.append("Sequence ");
589     output.append(new Format("%" + maxid + "s").form(s2.getName()));
590     output.append(" :  " + s2.getStart() + " - " + s2.getEnd()
591             + " (Sequence length = " + s2str.length() + ")\n\n");
592
593     for (int j = 0; j < nochunks; j++)
594     {
595       // Print the first aligned sequence
596       output.append(new Format("%" + (maxid) + "s").form(s1id) + " ");
597
598       for (int i = 0; i < len; i++)
599       {
600         if ((i + (j * len)) < astr1.length())
601         {
602           output.append(astr1.charAt(i + (j * len)));
603         }
604       }
605
606       output.append("\n");
607       output.append(new Format("%" + (maxid) + "s").form(" ") + " ");
608
609       // Print out the matching chars
610       for (int i = 0; i < len; i++)
611       {
612         if ((i + (j * len)) < astr1.length())
613         {
614           if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
615                   && !jalview.util.Comparison.isGap(astr1.charAt(i
616                           + (j * len))))
617           {
618             pid++;
619             output.append("|");
620           }
621           else if (type.equals("pep"))
622           {
623             if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
624                     astr2.charAt(i + (j * len))) > 0)
625             {
626               output.append(".");
627             }
628             else
629             {
630               output.append(" ");
631             }
632           }
633           else
634           {
635             output.append(" ");
636           }
637         }
638       }
639
640       // Now print the second aligned sequence
641       output = output.append("\n");
642       output = output.append(new Format("%" + (maxid) + "s").form(s2id)
643               + " ");
644
645       for (int i = 0; i < len; i++)
646       {
647         if ((i + (j * len)) < astr2.length())
648         {
649           output.append(astr2.charAt(i + (j * len)));
650         }
651       }
652
653       output = output.append("\n\n");
654     }
655
656     pid = pid / (aseq1.length - count) * 100;
657     output = output.append(new Format("Percentage ID = %2.2f\n\n")
658             .form(pid));
659
660     try
661     {
662       os.print(output.toString());
663     } catch (Exception ex)
664     {
665     }
666   }
667
668   /**
669    * DOCUMENT ME!
670    * 
671    * @param mat
672    *          DOCUMENT ME!
673    */
674   public void printScoreMatrix(int[][] mat)
675   {
676     int n = seq1.length;
677     int m = seq2.length;
678
679     for (int i = 0; i < n; i++)
680     {
681       // Print the top sequence
682       if (i == 0)
683       {
684         Format.print(System.out, "%8s", s2str.substring(0, 1));
685
686         for (int jj = 1; jj < m; jj++)
687         {
688           Format.print(System.out, "%5s", s2str.substring(jj, jj + 1));
689         }
690
691         System.out.println();
692       }
693
694       for (int j = 0; j < m; j++)
695       {
696         if (j == 0)
697         {
698           Format.print(System.out, "%3s", s1str.substring(i, i + 1));
699         }
700
701         Format.print(System.out, "%3d ", mat[i][j] / 10);
702       }
703
704       System.out.println();
705     }
706   }
707
708   /**
709    * DOCUMENT ME!
710    * 
711    * @param i
712    *          DOCUMENT ME!
713    * @param j
714    *          DOCUMENT ME!
715    * 
716    * @return DOCUMENT ME!
717    */
718   public int findTrace(int i, int j)
719   {
720     int t = 0;
721     int max = score[i - 1][j - 1] + (lookup[seq1[i]][seq2[j]] * 10);
722
723     if (F[i][j] > max)
724     {
725       max = F[i][j];
726       t = -1;
727     }
728     else if (F[i][j] == max)
729     {
730       if (prev == -1)
731       {
732         max = F[i][j];
733         t = -1;
734       }
735     }
736
737     if (E[i][j] >= max)
738     {
739       max = E[i][j];
740       t = 1;
741     }
742     else if (E[i][j] == max)
743     {
744       if (prev == 1)
745       {
746         max = E[i][j];
747         t = 1;
748       }
749     }
750
751     prev = t;
752
753     return t;
754   }
755
756   /**
757    * DOCUMENT ME!
758    */
759   public void calcScoreMatrix()
760   {
761     int n = seq1.length;
762     int m = seq2.length;
763
764     // top left hand element
765     score[0][0] = lookup[seq1[0]][seq2[0]] * 10;
766     E[0][0] = -gapExtend;
767     F[0][0] = 0;
768
769     // Calculate the top row first
770     for (int j = 1; j < m; j++)
771     {
772       // What should these values be? 0 maybe
773       E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
774       F[0][j] = -gapExtend;
775
776       score[0][j] = max(lookup[seq1[0]][seq2[j]] * 10, -gapOpen, -gapExtend);
777
778       traceback[0][j] = 1;
779     }
780
781     // Now do the left hand column
782     for (int i = 1; i < n; i++)
783     {
784       E[i][0] = -gapOpen;
785       F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
786
787       score[i][0] = max(lookup[seq1[i]][seq2[0]] * 10, E[i][0], F[i][0]);
788       traceback[i][0] = -1;
789     }
790
791     // Now do all the other rows
792     for (int i = 1; i < n; i++)
793     {
794       for (int j = 1; j < m; j++)
795       {
796         E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
797         F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
798
799         score[i][j] = max(score[i - 1][j - 1]
800                 + (lookup[seq1[i]][seq2[j]] * 10), E[i][j], F[i][j]);
801         traceback[i][j] = findTrace(i, j);
802       }
803     }
804   }
805
806   /**
807    * DOCUMENT ME!
808    * 
809    * @param gapChar
810    *          DOCUMENT ME!
811    * @param seq
812    *          DOCUMENT ME!
813    * 
814    * @return DOCUMENT ME!
815    */
816   public static String extractGaps(String gapChar, String seq)
817   {
818     StringTokenizer str = new StringTokenizer(seq, gapChar);
819     StringBuffer newString = new StringBuffer();
820
821     while (str.hasMoreTokens())
822     {
823       newString.append(str.nextToken());
824     }
825
826     return newString.toString();
827   }
828
829   /**
830    * DOCUMENT ME!
831    * 
832    * @param i1
833    *          DOCUMENT ME!
834    * @param i2
835    *          DOCUMENT ME!
836    * @param i3
837    *          DOCUMENT ME!
838    * 
839    * @return DOCUMENT ME!
840    */
841   public int max(int i1, int i2, int i3)
842   {
843     int max = i1;
844
845     if (i2 > i1)
846     {
847       max = i2;
848     }
849
850     if (i3 > max)
851     {
852       max = i3;
853     }
854
855     return max;
856   }
857
858   /**
859    * DOCUMENT ME!
860    * 
861    * @param i1
862    *          DOCUMENT ME!
863    * @param i2
864    *          DOCUMENT ME!
865    * 
866    * @return DOCUMENT ME!
867    */
868   public int max(int i1, int i2)
869   {
870     int max = i1;
871
872     if (i2 > i1)
873     {
874       max = i2;
875     }
876
877     return max;
878   }
879
880   /**
881    * DOCUMENT ME!
882    * 
883    * @param s
884    *          DOCUMENT ME!
885    * @param type
886    *          DOCUMENT ME!
887    * 
888    * @return DOCUMENT ME!
889    */
890   public int[] stringToInt(String s, String type)
891   {
892     int[] seq1 = new int[s.length()];
893
894     for (int i = 0; i < s.length(); i++)
895     {
896       // String ss = s.substring(i, i + 1).toUpperCase();
897       char c = s.charAt(i);
898       if ('a' <= c && c <= 'z')
899       {
900         // TO UPPERCASE !!!
901         c -= ('a' - 'A');
902       }
903
904       try
905       {
906         seq1[i] = charToInt[c]; // set accordingly from setType
907         if (seq1[i] < 0 || seq1[i] > defInt) // set from setType: 23 for
908                                              // peptides, or 4 for NA.
909         {
910           seq1[i] = defInt;
911         }
912
913       } catch (Exception e)
914       {
915         seq1[i] = defInt;
916       }
917     }
918
919     return seq1;
920   }
921
922   /**
923    * DOCUMENT ME!
924    * 
925    * @param g
926    *          DOCUMENT ME!
927    * @param mat
928    *          DOCUMENT ME!
929    * @param n
930    *          DOCUMENT ME!
931    * @param m
932    *          DOCUMENT ME!
933    * @param psize
934    *          DOCUMENT ME!
935    */
936   public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
937           int psize)
938   {
939     int max = -1000;
940     int min = 1000;
941
942     for (int i = 0; i < n; i++)
943     {
944       for (int j = 0; j < m; j++)
945       {
946         if (mat[i][j] >= max)
947         {
948           max = mat[i][j];
949         }
950
951         if (mat[i][j] <= min)
952         {
953           min = mat[i][j];
954         }
955       }
956     }
957
958     System.out.println(max + " " + min);
959
960     for (int i = 0; i < n; i++)
961     {
962       for (int j = 0; j < m; j++)
963       {
964         int x = psize * i;
965         int y = psize * j;
966
967         // System.out.println(mat[i][j]);
968         float score = (float) (mat[i][j] - min) / (float) (max - min);
969         g.setColor(new Color(score, 0, 0));
970         g.fillRect(x, y, psize, psize);
971
972         // System.out.println(x + " " + y + " " + score);
973       }
974     }
975   }
976
977   /**
978    * Compute a globally optimal needleman and wunsch alignment between two
979    * sequences
980    * 
981    * @param s1
982    * @param s2
983    * @param type
984    *          AlignSeq.DNA or AlignSeq.PEP
985    */
986   public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2,
987           String type)
988   {
989     AlignSeq as = new AlignSeq(s1, s2, type);
990
991     as.calcScoreMatrix();
992     as.traceAlignment();
993     return as;
994   }
995
996   /**
997    * 
998    * @return mapping from positions in S1 to corresponding positions in S2
999    */
1000   public jalview.datamodel.Mapping getMappingFromS1(boolean allowmismatch)
1001   {
1002     ArrayList<Integer> as1 = new ArrayList<Integer>(), as2 = new ArrayList<Integer>();
1003     int pdbpos = s2.getStart() + getSeq2Start() - 2;
1004     int alignpos = s1.getStart() + getSeq1Start() - 2;
1005     int lp2 = pdbpos - 3, lp1 = alignpos - 3;
1006     boolean lastmatch = false;
1007     // and now trace the alignment onto the atom set.
1008     for (int i = 0; i < astr1.length(); i++)
1009     {
1010       char c1 = astr1.charAt(i), c2 = astr2.charAt(i);
1011       if (c1 != '-')
1012       {
1013         alignpos++;
1014       }
1015
1016       if (c2 != '-')
1017       {
1018         pdbpos++;
1019       }
1020
1021       if (allowmismatch || c1 == c2)
1022       {
1023         // extend mapping interval
1024         if (lp1 + 1 != alignpos || lp2 + 1 != pdbpos)
1025         {
1026           as1.add(Integer.valueOf(alignpos));
1027           as2.add(Integer.valueOf(pdbpos));
1028         }
1029         lastmatch = true;
1030         lp1 = alignpos;
1031         lp2 = pdbpos;
1032       }
1033       else
1034       {
1035         // extend mapping interval
1036         if (lastmatch)
1037         {
1038           as1.add(Integer.valueOf(lp1));
1039           as2.add(Integer.valueOf(lp2));
1040         }
1041         lastmatch = false;
1042       }
1043     }
1044     // construct range pairs
1045
1046     int[] mapseq1 = new int[as1.size() + (lastmatch ? 1 : 0)], mapseq2 = new int[as2
1047             .size() + (lastmatch ? 1 : 0)];
1048     int i = 0;
1049     for (Integer ip : as1)
1050     {
1051       mapseq1[i++] = ip;
1052     }
1053     ;
1054     i = 0;
1055     for (Integer ip : as2)
1056     {
1057       mapseq2[i++] = ip;
1058     }
1059     ;
1060     if (lastmatch)
1061     {
1062       mapseq1[mapseq1.length - 1] = alignpos;
1063       mapseq2[mapseq2.length - 1] = pdbpos;
1064     }
1065     MapList map = new MapList(mapseq1, mapseq2, 1, 1);
1066
1067     jalview.datamodel.Mapping mapping = new Mapping(map);
1068     mapping.setTo(s2);
1069     return mapping;
1070   }
1071
1072   /**
1073    * matches ochains against al and populates seqs with the best match between
1074    * each ochain and the set in al
1075    * 
1076    * @param ochains
1077    * @param al
1078    * @param dnaOrProtein
1079    * @param removeOldAnnots
1080    *          when true, old annotation is cleared before new annotation
1081    *          transferred
1082    * @return List<List<SequenceI> originals, List<SequenceI> replacement,
1083    *         List<AlignSeq> alignment between each>
1084    */
1085   public static List<List<? extends Object>> replaceMatchingSeqsWith(
1086           List<SequenceI> seqs, List<AlignmentAnnotation> annotations,
1087           List<SequenceI> ochains,
1088           AlignmentI al, String dnaOrProtein, boolean removeOldAnnots)
1089   {
1090     List<SequenceI> orig = new ArrayList<SequenceI>(), repl = new ArrayList<SequenceI>();
1091     List<AlignSeq> aligs = new ArrayList<AlignSeq>();
1092     if (al != null && al.getHeight() > 0)
1093     {
1094       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
1095       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
1096   
1097       for (SequenceI sq : ochains)
1098       {
1099         SequenceI bestm = null;
1100         AlignSeq bestaseq = null;
1101         int bestscore = 0;
1102         for (SequenceI msq : al.getSequences())
1103         {
1104           AlignSeq aseq = doGlobalNWAlignment(msq, sq,
1105                   dnaOrProtein);
1106           if (bestm == null || aseq.getMaxScore() > bestscore)
1107           {
1108             bestscore = aseq.getMaxScore();
1109             bestaseq = aseq;
1110             bestm = msq;
1111           }
1112         }
1113         System.out.println("Best Score for " + (matches.size() + 1) + " :"
1114                 + bestscore);
1115         matches.add(bestm);
1116         aligns.add(bestaseq);
1117         al.deleteSequence(bestm);
1118       }
1119       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
1120       {
1121         SequenceI sq, sp = seqs.get(p);
1122         int q;
1123         if ((q = ochains.indexOf(sp)) > -1)
1124         {
1125           seqs.set(p, sq = matches.get(q));
1126           orig.add(sp);
1127           repl.add(sq);
1128           sq.setName(sp.getName());
1129           sq.setDescription(sp.getDescription());
1130           Mapping sp2sq;
1131           sq.transferAnnotation(sp, sp2sq = aligns.get(q).getMappingFromS1(false));
1132           aligs.add(aligns.get(q));
1133           int inspos = -1;
1134           for (int ap = 0; ap < annotations.size();)
1135           {
1136             if (annotations.get(ap).sequenceRef == sp)
1137             {
1138               if (inspos == -1)
1139               {
1140                 inspos = ap;
1141               }
1142               if (removeOldAnnots) {
1143                 annotations.remove(ap);
1144               } else {
1145                 AlignmentAnnotation alan = annotations.remove(ap);
1146                 alan.liftOver(sq, sp2sq);
1147                 alan.setSequenceRef(sq);
1148                 sq.addAlignmentAnnotation(alan);
1149               }
1150             }
1151             else
1152             {
1153               ap++;
1154             }
1155           }
1156           if (sq.getAnnotation() != null && sq.getAnnotation().length > 0)
1157           {
1158             annotations.addAll(inspos, Arrays.asList(sq.getAnnotation()));
1159           }
1160         }
1161       }
1162     }
1163     return Arrays.asList(orig, repl, aligs);
1164   }
1165
1166   /**
1167    * compute the PID vector used by the redundancy filter.
1168    * 
1169    * @param originalSequences
1170    *          - sequences in alignment that are to filtered
1171    * @param omitHidden
1172    *          - null or strings to be analysed (typically, visible portion of
1173    *          each sequence in alignment)
1174    * @param start
1175    *          - first column in window for calculation
1176    * @param end
1177    *          - last column in window for calculation
1178    * @param ungapped
1179    *          - if true then use ungapped sequence to compute PID
1180    * @return vector containing maximum PID for i-th sequence and any sequences
1181    *         longer than that seuqence
1182    */
1183   public static float[] computeRedundancyMatrix(
1184           SequenceI[] originalSequences, String[] omitHidden, int start,
1185           int end, boolean ungapped)
1186   {
1187     int height = originalSequences.length;
1188     float[] redundancy = new float[height];
1189     int[] lngth = new int[height];
1190     for (int i = 0; i < height; i++)
1191     {
1192       redundancy[i] = 0f;
1193       lngth[i] = -1;
1194     }
1195
1196     // long start = System.currentTimeMillis();
1197
1198     float pid;
1199     String seqi, seqj;
1200     for (int i = 0; i < height; i++)
1201     {
1202
1203       for (int j = 0; j < i; j++)
1204       {
1205         if (i == j)
1206         {
1207           continue;
1208         }
1209
1210         if (omitHidden == null)
1211         {
1212           seqi = originalSequences[i].getSequenceAsString(start, end);
1213           seqj = originalSequences[j].getSequenceAsString(start, end);
1214         }
1215         else
1216         {
1217           seqi = omitHidden[i];
1218           seqj = omitHidden[j];
1219         }
1220         if (lngth[i] == -1)
1221         {
1222           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqi);
1223           lngth[i] = ug.length();
1224           if (ungapped)
1225           {
1226             seqi = ug;
1227           }
1228         }
1229         if (lngth[j] == -1)
1230         {
1231           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqj);
1232           lngth[j] = ug.length();
1233           if (ungapped)
1234           {
1235             seqj = ug;
1236           }
1237         }
1238         pid = Comparison.PID(seqi, seqj);
1239
1240         // use real sequence length rather than string length
1241         if (lngth[j] < lngth[i])
1242         {
1243           redundancy[j] = Math.max(pid, redundancy[j]);
1244         }
1245         else
1246         {
1247           redundancy[i] = Math.max(pid, redundancy[i]);
1248         }
1249
1250       }
1251     }
1252     return redundancy;
1253   }
1254 }