Merge develop to Release_2_8_3_Branch
[jalview.git] / src / jalview / analysis / AlignSeq.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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    * Returns the given sequence with all of the given gap characters removed.
808    * 
809    * @param gapChars
810    *          a string of characters to be treated as gaps
811    * @param seq
812    *          the input sequence
813    * 
814    * @return
815    */
816   public static String extractGaps(String gapChars, String seq)
817   {
818     if (gapChars == null || seq == null)
819     {
820       return null;
821     }
822     StringTokenizer str = new StringTokenizer(seq, gapChars);
823     StringBuilder newString = new StringBuilder(seq.length());
824
825     while (str.hasMoreTokens())
826     {
827       newString.append(str.nextToken());
828     }
829
830     return newString.toString();
831   }
832
833   /**
834    * DOCUMENT ME!
835    * 
836    * @param i1
837    *          DOCUMENT ME!
838    * @param i2
839    *          DOCUMENT ME!
840    * @param i3
841    *          DOCUMENT ME!
842    * 
843    * @return DOCUMENT ME!
844    */
845   public int max(int i1, int i2, int i3)
846   {
847     int max = i1;
848
849     if (i2 > i1)
850     {
851       max = i2;
852     }
853
854     if (i3 > max)
855     {
856       max = i3;
857     }
858
859     return max;
860   }
861
862   /**
863    * DOCUMENT ME!
864    * 
865    * @param i1
866    *          DOCUMENT ME!
867    * @param i2
868    *          DOCUMENT ME!
869    * 
870    * @return DOCUMENT ME!
871    */
872   public int max(int i1, int i2)
873   {
874     int max = i1;
875
876     if (i2 > i1)
877     {
878       max = i2;
879     }
880
881     return max;
882   }
883
884   /**
885    * DOCUMENT ME!
886    * 
887    * @param s
888    *          DOCUMENT ME!
889    * @param type
890    *          DOCUMENT ME!
891    * 
892    * @return DOCUMENT ME!
893    */
894   public int[] stringToInt(String s, String type)
895   {
896     int[] seq1 = new int[s.length()];
897
898     for (int i = 0; i < s.length(); i++)
899     {
900       // String ss = s.substring(i, i + 1).toUpperCase();
901       char c = s.charAt(i);
902       if ('a' <= c && c <= 'z')
903       {
904         // TO UPPERCASE !!!
905         c -= ('a' - 'A');
906       }
907
908       try
909       {
910         seq1[i] = charToInt[c]; // set accordingly from setType
911         if (seq1[i] < 0 || seq1[i] > defInt) // set from setType: 23 for
912                                              // peptides, or 4 for NA.
913         {
914           seq1[i] = defInt;
915         }
916
917       } catch (Exception e)
918       {
919         seq1[i] = defInt;
920       }
921     }
922
923     return seq1;
924   }
925
926   /**
927    * DOCUMENT ME!
928    * 
929    * @param g
930    *          DOCUMENT ME!
931    * @param mat
932    *          DOCUMENT ME!
933    * @param n
934    *          DOCUMENT ME!
935    * @param m
936    *          DOCUMENT ME!
937    * @param psize
938    *          DOCUMENT ME!
939    */
940   public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
941           int psize)
942   {
943     int max = -1000;
944     int min = 1000;
945
946     for (int i = 0; i < n; i++)
947     {
948       for (int j = 0; j < m; j++)
949       {
950         if (mat[i][j] >= max)
951         {
952           max = mat[i][j];
953         }
954
955         if (mat[i][j] <= min)
956         {
957           min = mat[i][j];
958         }
959       }
960     }
961
962     System.out.println(max + " " + min);
963
964     for (int i = 0; i < n; i++)
965     {
966       for (int j = 0; j < m; j++)
967       {
968         int x = psize * i;
969         int y = psize * j;
970
971         // System.out.println(mat[i][j]);
972         float score = (float) (mat[i][j] - min) / (float) (max - min);
973         g.setColor(new Color(score, 0, 0));
974         g.fillRect(x, y, psize, psize);
975
976         // System.out.println(x + " " + y + " " + score);
977       }
978     }
979   }
980
981   /**
982    * Compute a globally optimal needleman and wunsch alignment between two
983    * sequences
984    * 
985    * @param s1
986    * @param s2
987    * @param type
988    *          AlignSeq.DNA or AlignSeq.PEP
989    */
990   public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2,
991           String type)
992   {
993     AlignSeq as = new AlignSeq(s1, s2, type);
994
995     as.calcScoreMatrix();
996     as.traceAlignment();
997     return as;
998   }
999
1000   /**
1001    * 
1002    * @return mapping from positions in S1 to corresponding positions in S2
1003    */
1004   public jalview.datamodel.Mapping getMappingFromS1(boolean allowmismatch)
1005   {
1006     ArrayList<Integer> as1 = new ArrayList<Integer>(), as2 = new ArrayList<Integer>();
1007     int pdbpos = s2.getStart() + getSeq2Start() - 2;
1008     int alignpos = s1.getStart() + getSeq1Start() - 2;
1009     int lp2 = pdbpos - 3, lp1 = alignpos - 3;
1010     boolean lastmatch = false;
1011     // and now trace the alignment onto the atom set.
1012     for (int i = 0; i < astr1.length(); i++)
1013     {
1014       char c1 = astr1.charAt(i), c2 = astr2.charAt(i);
1015       if (c1 != '-')
1016       {
1017         alignpos++;
1018       }
1019
1020       if (c2 != '-')
1021       {
1022         pdbpos++;
1023       }
1024
1025       if (allowmismatch || c1 == c2)
1026       {
1027         // extend mapping interval
1028         if (lp1 + 1 != alignpos || lp2 + 1 != pdbpos)
1029         {
1030           as1.add(Integer.valueOf(alignpos));
1031           as2.add(Integer.valueOf(pdbpos));
1032         }
1033         lastmatch = true;
1034         lp1 = alignpos;
1035         lp2 = pdbpos;
1036       }
1037       else
1038       {
1039         // extend mapping interval
1040         if (lastmatch)
1041         {
1042           as1.add(Integer.valueOf(lp1));
1043           as2.add(Integer.valueOf(lp2));
1044         }
1045         lastmatch = false;
1046       }
1047     }
1048     // construct range pairs
1049
1050     int[] mapseq1 = new int[as1.size() + (lastmatch ? 1 : 0)], mapseq2 = new int[as2
1051             .size() + (lastmatch ? 1 : 0)];
1052     int i = 0;
1053     for (Integer ip : as1)
1054     {
1055       mapseq1[i++] = ip;
1056     }
1057     ;
1058     i = 0;
1059     for (Integer ip : as2)
1060     {
1061       mapseq2[i++] = ip;
1062     }
1063     ;
1064     if (lastmatch)
1065     {
1066       mapseq1[mapseq1.length - 1] = alignpos;
1067       mapseq2[mapseq2.length - 1] = pdbpos;
1068     }
1069     MapList map = new MapList(mapseq1, mapseq2, 1, 1);
1070
1071     jalview.datamodel.Mapping mapping = new Mapping(map);
1072     mapping.setTo(s2);
1073     return mapping;
1074   }
1075
1076   /**
1077    * matches ochains against al and populates seqs with the best match between
1078    * each ochain and the set in al
1079    * 
1080    * @param ochains
1081    * @param al
1082    * @param dnaOrProtein
1083    * @param removeOldAnnots
1084    *          when true, old annotation is cleared before new annotation
1085    *          transferred
1086    * @return List<List<SequenceI> originals, List<SequenceI> replacement,
1087    *         List<AlignSeq> alignment between each>
1088    */
1089   public static List<List<? extends Object>> replaceMatchingSeqsWith(
1090           List<SequenceI> seqs, List<AlignmentAnnotation> annotations,
1091           List<SequenceI> ochains,
1092           AlignmentI al, String dnaOrProtein, boolean removeOldAnnots)
1093   {
1094     List<SequenceI> orig = new ArrayList<SequenceI>(), repl = new ArrayList<SequenceI>();
1095     List<AlignSeq> aligs = new ArrayList<AlignSeq>();
1096     if (al != null && al.getHeight() > 0)
1097     {
1098       ArrayList<SequenceI> matches = new ArrayList<SequenceI>();
1099       ArrayList<AlignSeq> aligns = new ArrayList<AlignSeq>();
1100   
1101       for (SequenceI sq : ochains)
1102       {
1103         SequenceI bestm = null;
1104         AlignSeq bestaseq = null;
1105         int bestscore = 0;
1106         for (SequenceI msq : al.getSequences())
1107         {
1108           AlignSeq aseq = doGlobalNWAlignment(msq, sq,
1109                   dnaOrProtein);
1110           if (bestm == null || aseq.getMaxScore() > bestscore)
1111           {
1112             bestscore = aseq.getMaxScore();
1113             bestaseq = aseq;
1114             bestm = msq;
1115           }
1116         }
1117         System.out.println("Best Score for " + (matches.size() + 1) + " :"
1118                 + bestscore);
1119         matches.add(bestm);
1120         aligns.add(bestaseq);
1121         al.deleteSequence(bestm);
1122       }
1123       for (int p = 0, pSize = seqs.size(); p < pSize; p++)
1124       {
1125         SequenceI sq, sp = seqs.get(p);
1126         int q;
1127         if ((q = ochains.indexOf(sp)) > -1)
1128         {
1129           seqs.set(p, sq = matches.get(q));
1130           orig.add(sp);
1131           repl.add(sq);
1132           sq.setName(sp.getName());
1133           sq.setDescription(sp.getDescription());
1134           Mapping sp2sq;
1135           sq.transferAnnotation(sp, sp2sq = aligns.get(q).getMappingFromS1(false));
1136           aligs.add(aligns.get(q));
1137           int inspos = -1;
1138           for (int ap = 0; ap < annotations.size();)
1139           {
1140             if (annotations.get(ap).sequenceRef == sp)
1141             {
1142               if (inspos == -1)
1143               {
1144                 inspos = ap;
1145               }
1146               if (removeOldAnnots) {
1147                 annotations.remove(ap);
1148               } else {
1149                 AlignmentAnnotation alan = annotations.remove(ap);
1150                 alan.liftOver(sq, sp2sq);
1151                 alan.setSequenceRef(sq);
1152                 sq.addAlignmentAnnotation(alan);
1153               }
1154             }
1155             else
1156             {
1157               ap++;
1158             }
1159           }
1160           if (sq.getAnnotation() != null && sq.getAnnotation().length > 0)
1161           {
1162             annotations.addAll(inspos == -1 ? annotations.size() : inspos,
1163                     Arrays.asList(sq.getAnnotation()));
1164           }
1165         }
1166       }
1167     }
1168     return Arrays.asList(orig, repl, aligs);
1169   }
1170
1171   /**
1172    * compute the PID vector used by the redundancy filter.
1173    * 
1174    * @param originalSequences
1175    *          - sequences in alignment that are to filtered
1176    * @param omitHidden
1177    *          - null or strings to be analysed (typically, visible portion of
1178    *          each sequence in alignment)
1179    * @param start
1180    *          - first column in window for calculation
1181    * @param end
1182    *          - last column in window for calculation
1183    * @param ungapped
1184    *          - if true then use ungapped sequence to compute PID
1185    * @return vector containing maximum PID for i-th sequence and any sequences
1186    *         longer than that seuqence
1187    */
1188   public static float[] computeRedundancyMatrix(
1189           SequenceI[] originalSequences, String[] omitHidden, int start,
1190           int end, boolean ungapped)
1191   {
1192     int height = originalSequences.length;
1193     float[] redundancy = new float[height];
1194     int[] lngth = new int[height];
1195     for (int i = 0; i < height; i++)
1196     {
1197       redundancy[i] = 0f;
1198       lngth[i] = -1;
1199     }
1200
1201     // long start = System.currentTimeMillis();
1202
1203     float pid;
1204     String seqi, seqj;
1205     for (int i = 0; i < height; i++)
1206     {
1207
1208       for (int j = 0; j < i; j++)
1209       {
1210         if (i == j)
1211         {
1212           continue;
1213         }
1214
1215         if (omitHidden == null)
1216         {
1217           seqi = originalSequences[i].getSequenceAsString(start, end);
1218           seqj = originalSequences[j].getSequenceAsString(start, end);
1219         }
1220         else
1221         {
1222           seqi = omitHidden[i];
1223           seqj = omitHidden[j];
1224         }
1225         if (lngth[i] == -1)
1226         {
1227           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqi);
1228           lngth[i] = ug.length();
1229           if (ungapped)
1230           {
1231             seqi = ug;
1232           }
1233         }
1234         if (lngth[j] == -1)
1235         {
1236           String ug = AlignSeq.extractGaps(Comparison.GapChars, seqj);
1237           lngth[j] = ug.length();
1238           if (ungapped)
1239           {
1240             seqj = ug;
1241           }
1242         }
1243         pid = Comparison.PID(seqi, seqj);
1244
1245         // use real sequence length rather than string length
1246         if (lngth[j] < lngth[i])
1247         {
1248           redundancy[j] = Math.max(pid, redundancy[j]);
1249         }
1250         else
1251         {
1252           redundancy[i] = Math.max(pid, redundancy[i]);
1253         }
1254
1255       }
1256     }
1257     return redundancy;
1258   }
1259 }